/** Read JPEG_APP1 marker (Exif profile) @param dib Input FIBITMAP @param dataptr Pointer to the APP1 marker @param datalen APP1 marker length @return Returns TRUE if successful, FALSE otherwise */ BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { // marker identifying string for Exif = "Exif\0\0" BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Intel order BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Motorola order unsigned int length = datalen; BYTE *profile = (BYTE*)dataptr; // verify the identifying string if(memcmp(exif_signature, profile, sizeof(exif_signature)) == 0) { // Exif profile profile += sizeof(exif_signature); length -= sizeof(exif_signature); // check the endianess order BOOL bMotorolaOrder = TRUE; if(memcmp(profile, lsb_first, sizeof(lsb_first)) == 0) { // Exif section in Intel order bMotorolaOrder = FALSE; } else { if(memcmp(profile, msb_first, sizeof(msb_first)) == 0) { // Exif section in Motorola order bMotorolaOrder = TRUE; } else { // Invalid Exif alignment marker return FALSE; } } // this is the offset to the first IFD unsigned long first_offset = ReadUint32(bMotorolaOrder, profile + 4); if (first_offset < 8 || first_offset > 16) { // This is usually set to 8 // but PENTAX Optio 230 has it set differently, and uses it as offset. FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value"); return FALSE; } // process Exif directories return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder); } return FALSE; }
/// ctor; parses event data CameraEventData(prVoid* pEventData) :m_uiEventCode(0) { BYTE* pbData = reinterpret_cast<BYTE*>(pEventData); std::vector<BYTE>& vecBuffer = GetBuffer(); vecBuffer.assign(pbData, pbData + 12);// at least 12 bytes // read length of event data prUInt32 uiLength = ReadUint32(); vecBuffer.assign(pbData, pbData + uiLength); unsigned int uiNumParams = (uiLength - 12) / 4; Parse(uiNumParams); }
int32_t UnpackSavedataBin(EdpPacket* pkg, cJSON** desc_obj, uint8_t** bin_data, uint32_t* bin_len) { int8_t* desc_str; if (ReadStr(pkg, &desc_str)) return ERR_UNPACK_SAVED_BIN_DESC; *desc_obj = cJSON_Parse((const char *)desc_str); free(desc_str); if (*desc_obj == 0) return ERR_UNPACK_SAVED_PARSEDESC; if (ReadUint32(pkg, bin_len)) return ERR_UNPACK_SAVED_BINLEN; if (ReadBytes(pkg, bin_data, *bin_len)) return ERR_UNPACK_SAVED_BINDATA; my_assert(pkg->_read_pos == pkg->_write_pos); return 0; }
/** Process a IFD offset Returns the offset and the metadata model for this tag */ static void processIFDOffset(FITAG *tag, const char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) { // get the IFD offset *subdirOffset = ReadUint32(msb_order, pval); // select a tag info table switch(FreeImage_GetTagID(tag)) { case TAG_EXIF_OFFSET: *md_model = TagLib::EXIF_EXIF; break; case TAG_GPS_OFFSET: *md_model = TagLib::EXIF_GPS; break; case TAG_INTEROP_OFFSET: *md_model = TagLib::EXIF_INTEROP; break; } }
static void ReadType1MsgBody(const PRUint8 *inBuf, PRUint32 start) { const PRUint8 *cursor = inBuf + start; PRUint32 flags; PrintBuf("flags", cursor, 4); // read flags flags = ReadUint32(cursor); PrintFlags(flags); // type 1 message may not include trailing security buffers if ((flags & kNegotiateDomainSupplied) | (flags & kNegotiateWorkstationSupplied)) { SecBuf secbuf; ReadSecBuf(&secbuf, cursor); PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length); ReadSecBuf(&secbuf, cursor); PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length); } }
int32_t UnpackCmdReq(EdpPacket* pkg, int8_t** cmdid, uint16_t* cmdid_len, int8_t** req, uint32_t* req_len) { uint32 remainlen; int32_t rc; if (ReadRemainlen(pkg, &remainlen)) return ERR_UNPACK_CMDREQ; rc = ReadUint16(pkg, cmdid_len); if (rc) return rc; if (ReadBytes(pkg, (uint8_t**)cmdid, *cmdid_len)) return ERR_UNPACK_CMDREQ; rc = ReadUint32(pkg, req_len); if (rc) return rc; if (ReadBytes(pkg, (uint8_t**)req, *req_len)) return ERR_UNPACK_CMDREQ; my_assert(pkg->_read_pos == pkg->_write_pos); return 0; }
/** * * Loads a chunk from the old savegame * */ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) { byte *base_ptr = (byte*)base; for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) { if (((chunk->type & OC_TTD) && _savegame_type == SGT_TTO) || ((chunk->type & OC_TTO) && _savegame_type != SGT_TTO)) { /* TTD(P)-only chunk, but TTO savegame || TTO-only chunk, but TTD/TTDP savegame */ continue; } byte *ptr = (byte*)chunk->ptr; if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr; for (uint i = 0; i < chunk->amount; i++) { /* Handle simple types */ if (GetOldChunkType(chunk->type) != 0) { switch (GetOldChunkType(chunk->type)) { /* Just read the byte and forget about it */ case OC_NULL: ReadByte(ls); break; case OC_CHUNK: /* Call function, with 'i' as parameter to tell which item we * are going to read */ if (!chunk->proc(ls, i)) return false; break; case OC_ASSERT: DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value); if (ls->total_read != chunk->offset + _bump_assert_value) throw std::exception(); default: break; } } else { uint64 res = 0; /* Reading from the file: bits 16 to 23 have the FILE type */ switch (GetOldChunkFileType(chunk->type)) { case OC_FILE_I8: res = (int8)ReadByte(ls); break; case OC_FILE_U8: res = ReadByte(ls); break; case OC_FILE_I16: res = (int16)ReadUint16(ls); break; case OC_FILE_U16: res = ReadUint16(ls); break; case OC_FILE_I32: res = (int32)ReadUint32(ls); break; case OC_FILE_U32: res = ReadUint32(ls); break; default: NOT_REACHED(); } /* When both pointers are NULL, we are just skipping data */ if (base_ptr == NULL && chunk->ptr == NULL) continue; /* Writing to the var: bits 8 to 15 have the VAR type */ if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset; /* Write the data */ switch (GetOldChunkVarType(chunk->type)) { case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break; case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break; case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break; case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break; case OC_VAR_I32:*(int32 *)ptr = res; break; case OC_VAR_U32:*(uint32*)ptr = res; break; case OC_VAR_I64:*(int64 *)ptr = res; break; case OC_VAR_U64:*(uint64*)ptr = res; break; default: NOT_REACHED(); } /* Increase pointer base for arrays when looping */ if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type); } } } return true; }
/** Process Exif directory @param dib Input FIBITMAP @param tiffp Pointer to the TIFF header @param offset 0th IFD offset @param length Length of the datafile @param msb_order Endianess order of the datafile @return */ static BOOL jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) { WORD de, nde; std::stack<WORD> destack; // directory entries stack std::stack<BYTE*> ifdstack; // IFD stack std::stack<TagLib::MDMODEL> modelstack; // metadata model stack // Keep a list of already visited IFD to avoid stack overflows // when recursive/cyclic directory structures exist. // This kind of recursive Exif file was encountered with Kodak images coming from // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W std::map<DWORD, int> visitedIFD; #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry)) // set the metadata model to Exif TagLib::MDMODEL md_model = TagLib::EXIF_MAIN; // set the pointer to the first IFD and follow it were it leads. BYTE *ifdp = (BYTE*)tiffp + offset; de = 0; do { // if there is anything on the stack then pop it off if(!destack.empty()) { ifdp = ifdstack.top(); ifdstack.pop(); de = destack.top(); destack.pop(); md_model = modelstack.top(); modelstack.pop(); } // remember that we've visited this directory so that we don't visit it again later DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de ); if(visitedIFD.find(visited) != visitedIFD.end()) { continue; } else { visitedIFD[visited] = 1; // processed } // determine how many entries there are in the current IFD nde = ReadUint16(msb_order, ifdp); for(; de < nde; de++) { char *pde = NULL; // pointer to the directory entry char *pval = NULL; // pointer to the tag value // create a tag FITAG *tag = FreeImage_CreateTag(); if(!tag) return FALSE; // point to the directory entry pde = (char*) DIR_ENTRY_ADDR(ifdp, de); // get the tag ID FreeImage_SetTagID(tag, ReadUint16(msb_order, pde)); // get the tag format WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2); if((tag_type - 1) >= EXIF_NUM_FORMATS) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // break out of the for loop break; } FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type); // get number of components FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4)); // get the size of the tag value in bytes FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth((WORD)FreeImage_GetTagType(tag))); if(FreeImage_GetTagLength(tag) <= 4) { // 4 bytes or less and value is in the dir entry itself pval = pde + 8; } else { // if its bigger than 4 bytes, the directory entry contains an offset // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data DWORD offset_value = ReadUint32(msb_order, pde + 8); if(offset_value > length) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } // now check if offset + tag length exceeds buffer if(offset_value > length - FreeImage_GetTagLength(tag)) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } pval = (char*)(tiffp + offset_value); } // check for a IFD offset BOOL isIFDOffset = FALSE; switch(FreeImage_GetTagID(tag)) { case TAG_EXIF_OFFSET: case TAG_GPS_OFFSET: case TAG_INTEROP_OFFSET: case TAG_MAKER_NOTE: isIFDOffset = TRUE; break; } if(isIFDOffset) { DWORD sub_offset = 0; TagLib::MDMODEL next_mdmodel = md_model; BYTE *next_ifd = ifdp; // get offset and metadata model if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) { processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)pval + sub_offset; } else { processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)tiffp + sub_offset; } if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) { // push our current directory state onto the stack ifdstack.push(ifdp); // bump to the next entry de++; destack.push(de); // push our current metadata model modelstack.push(md_model); // push new state onto of stack to cause a jump ifdstack.push(next_ifd); destack.push(0); // select a new metadata model modelstack.push(next_mdmodel); // delete the tag as it won't be stored nor deleted in the for() loop FreeImage_DeleteTag(tag); break; // break out of the for loop } else { // unsupported camera model, canon maker tag or or something unknown // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } } else { // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } // delete the tag FreeImage_DeleteTag(tag); } // for(nde) // additional thumbnail data is skipped } while (!destack.empty()); return TRUE; }
/** Process a standard Exif tag */ static void processExifTag(FIBITMAP *dib, FITAG *tag, char *pval, BOOL msb_order, TagLib::MDMODEL md_model) { char defaultKey[16]; int n; DWORD i; // allocate a buffer to store the tag value BYTE *exif_value = (BYTE*)malloc(FreeImage_GetTagLength(tag) * sizeof(BYTE)); memset(exif_value, 0, FreeImage_GetTagLength(tag) * sizeof(BYTE)); // get the tag value switch(FreeImage_GetTagType(tag)) { case FIDT_SHORT: { WORD *value = (WORD*)&exif_value[0]; for(i = 0; i < FreeImage_GetTagCount(tag); i++) { value[i] = ReadUint16(msb_order, pval + i * sizeof(WORD)); } FreeImage_SetTagValue(tag, value); break; } case FIDT_SSHORT: { short *value = (short*)&exif_value[0]; for(i = 0; i < FreeImage_GetTagCount(tag); i++) { value[i] = ReadInt16(msb_order, pval + i * sizeof(short)); } FreeImage_SetTagValue(tag, value); break; } case FIDT_LONG: { DWORD *value = (DWORD*)&exif_value[0]; for(i = 0; i < FreeImage_GetTagCount(tag); i++) { value[i] = ReadUint32(msb_order, pval + i * sizeof(DWORD)); } FreeImage_SetTagValue(tag, value); break; } case FIDT_SLONG: { LONG *value = (LONG*)&exif_value[0]; for(i = 0; i < FreeImage_GetTagCount(tag); i++) { value[i] = ReadInt32(msb_order, pval + i * sizeof(LONG)); } FreeImage_SetTagValue(tag, value); break; } case FIDT_RATIONAL: { n = sizeof(DWORD); DWORD *value = (DWORD*)&exif_value[0]; for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) { // read a sequence of (numerator, denominator) value[i] = ReadUint32(msb_order, n*i + (char*)pval); } FreeImage_SetTagValue(tag, value); break; } case FIDT_SRATIONAL: { n = sizeof(LONG); LONG *value = (LONG*)&exif_value[0]; for(i = 0; i < 2 * FreeImage_GetTagCount(tag); i++) { // read a sequence of (numerator, denominator) value[i] = ReadInt32(msb_order, n*i + (char*)pval); } FreeImage_SetTagValue(tag, value); break; } case FIDT_BYTE: case FIDT_ASCII: case FIDT_SBYTE: case FIDT_UNDEFINED: case FIDT_FLOAT: case FIDT_DOUBLE: default: FreeImage_SetTagValue(tag, pval); break; } if(md_model == TagLib::EXIF_MAKERNOTE_CANON) { // A single Canon tag can have multiple values within processCanonMakerNoteTag(dib, tag); } else { TagLib& s = TagLib::instance(); WORD tag_id = FreeImage_GetTagID(tag); // get the tag key and description const char *key = s.getTagFieldName(md_model, tag_id, defaultKey); FreeImage_SetTagKey(tag, key); const char *description = s.getTagDescription(md_model, tag_id); FreeImage_SetTagDescription(tag, description); // store the tag if(key) { FreeImage_SetMetadata(s.getFreeImageModel(md_model), dib, key, tag); } } // free the temporary buffer free(exif_value); }
/** Process a maker note IFD offset Returns the offset and the metadata model for this tag */ static void processMakerNote(FIBITMAP *dib, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) { FITAG *tagMake = NULL; *subdirOffset = 0; *md_model = TagLib::UNKNOWN; // Determine the camera model and makernote format // WARNING: note that Maker may be NULL sometimes so check its value before using it // (NULL pointer checking is done by FreeImage_strnicmp) FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "Make", &tagMake); const char *Maker = (char*)FreeImage_GetTagValue(tagMake); if((strncmp("OLYMP\x00\x01", pval, 7) == 0) || (strncmp("OLYMP\x00\x02", pval, 7) == 0) || (strncmp("EPSON", pval, 5) == 0) || (strncmp("AGFA", pval, 4) == 0)) { // Olympus Type 1 Makernote // Epson and Agfa use Olympus maker note standard, // see: http://www.ozhiker.com/electronics/pjmt/jpeg_info/ *md_model = TagLib::EXIF_MAKERNOTE_OLYMPUSTYPE1; *subdirOffset = 8; } else if(strncmp("OLYMPUS\x00\x49\x49\x03\x00", pval, 12) == 0) { // Olympus Type 2 Makernote // !!! NOT YET SUPPORTED !!! *subdirOffset = 0; *md_model = TagLib::UNKNOWN; } else if(strncmp("Nikon", pval, 5) == 0) { /* There are two scenarios here: * Type 1: * :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... * :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ * Type 3: * :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*... * :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200 */ if (pval[6] == 1) { // Nikon type 1 Makernote *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE1; *subdirOffset = 8; } else if (pval[6] == 2) { // Nikon type 3 Makernote *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE3; *subdirOffset = 18; } else { // Unsupported makernote data ignored *md_model = TagLib::UNKNOWN; } } else if(Maker && (FreeImage_strnicmp("NIKON", Maker, 5) == 0)) { // Nikon type 2 Makernote *md_model = TagLib::EXIF_MAKERNOTE_NIKONTYPE2; *subdirOffset = 0; } else if(Maker && (FreeImage_strnicmp("Canon", Maker, 5) == 0)) { // Canon Makernote *md_model = TagLib::EXIF_MAKERNOTE_CANON; *subdirOffset = 0; } else if(Maker && (FreeImage_strnicmp("Casio", Maker, 5) == 0)) { // Casio Makernote if(strncmp("QVC\x00\x00\x00", pval, 6) == 0) { // Casio Type 2 Makernote *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE2; *subdirOffset = 6; } else { // Casio Type 1 Makernote *md_model = TagLib::EXIF_MAKERNOTE_CASIOTYPE1; *subdirOffset = 0; } } else if ((strncmp("FUJIFILM", pval, 8) == 0) || (Maker && (FreeImage_strnicmp("Fujifilm", Maker, 8) == 0))) { // Fujifile Makernote // Fujifilm's Makernote always use Intel order altough the Exif section maybe in Intel order or in Motorola order. // If msb_order == TRUE, the Makernote won't be read: // the value of ifdStart will be 0x0c000000 instead of 0x0000000c and the MakerNote section will be discarded later // in jpeg_read_exif_dir because the IFD is too high *md_model = TagLib::EXIF_MAKERNOTE_FUJIFILM; DWORD ifdStart = (DWORD) ReadUint32(msb_order, pval + 8); *subdirOffset = ifdStart; } else if(memcmp("KYOCERA \x00\x00\x00", pval, 22) == 0) { *md_model = TagLib::EXIF_MAKERNOTE_KYOCERA; *subdirOffset = 22; } else if(Maker && (FreeImage_strnicmp("Minolta", Maker, 7) == 0)) { // Minolta maker note *md_model = TagLib::EXIF_MAKERNOTE_MINOLTA; *subdirOffset = 0; } else if(memcmp("Panasonic\x00\x00\x00", pval, 12) == 0) { // Panasonic maker note *md_model = TagLib::EXIF_MAKERNOTE_PANASONIC; *subdirOffset = 12; } else if(Maker && ((FreeImage_strnicmp("Pentax", Maker, 6) == 0) || (FreeImage_strnicmp("Asahi", Maker, 5) == 0))) { // Pentax maker note if(strncmp("AOC\x00", pval, 4) == 0) { // Type 2 Pentax Makernote *md_model = TagLib::EXIF_MAKERNOTE_PENTAX; *subdirOffset = 6; } else { // Type 1 Pentax Makernote *md_model = TagLib::EXIF_MAKERNOTE_ASAHI; *subdirOffset = 0; } } else if((strncmp("SONY CAM", pval, 8) == 0) || (strncmp("SONY DSC", pval, 8) == 0)) { *md_model = TagLib::EXIF_MAKERNOTE_SONY; *subdirOffset = 12; } }
/** Read and decode JPEG_APP1 marker (Exif profile) @param dib Input FIBITMAP @param dataptr Pointer to the APP1 marker @param datalen APP1 marker length @return Returns TRUE if successful, FALSE otherwise */ BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { // marker identifying string for Exif = "Exif\0\0" BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Intel order BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Motorola order unsigned int length = datalen; BYTE *profile = (BYTE*)dataptr; // verify the identifying string if(memcmp(exif_signature, profile, sizeof(exif_signature)) == 0) { // Exif profile - TIFF header with 2 IFDs. 0th - the image attributes, 1st - may be used for thumbnail profile += sizeof(exif_signature); length -= sizeof(exif_signature); // read the TIFF header (8 bytes) // check the endianess order BOOL bMotorolaOrder = TRUE; if(memcmp(profile, lsb_first, sizeof(lsb_first)) == 0) { // Exif section in Intel order bMotorolaOrder = FALSE; } else { if(memcmp(profile, msb_first, sizeof(msb_first)) == 0) { // Exif section in Motorola order bMotorolaOrder = TRUE; } else { // Invalid Exif alignment marker return FALSE; } } // this is the offset to the first IFD (Image File Directory) unsigned long first_offset = ReadUint32(bMotorolaOrder, profile + 4); if (first_offset > length) { // bad Exif data return FALSE; } /* Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset => tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D if (first_offset < 8 || first_offset > 16) { // This is usually set to 8 // but PENTAX Optio 230 has it set differently, and uses it as offset. FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value"); return FALSE; } */ // process Exif directories return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder); } return FALSE; }
/** Process Exif directory @param dib Input FIBITMAP @param tiffp Pointer to the TIFF header @param offset 0th IFD offset @param length Length of the datafile @param msb_order Endianess order of the datafile @return */ static BOOL jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) { WORD de, nde; std::stack<WORD> destack; // directory entries stack std::stack<const BYTE*> ifdstack; // IFD stack std::stack<TagLib::MDMODEL> modelstack; // metadata model stack // Keep a list of already visited IFD to avoid stack overflows // when recursive/cyclic directory structures exist. // This kind of recursive Exif file was encountered with Kodak images coming from // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W std::map<DWORD, int> visitedIFD; /* "An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e. the number of fields), followed by a sequence of 12-byte field entries, followed by a 4-byte offset of the next IFD (or 0 if none)." The "next IFD" (1st IFD) is the thumbnail. */ #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry)) // set the metadata model to Exif TagLib::MDMODEL md_model = TagLib::EXIF_MAIN; // set the pointer to the first IFD (0th IFD) and follow it were it leads. const BYTE *ifd0th = (BYTE*)tiffp + offset; const BYTE *ifdp = ifd0th; de = 0; do { // if there is anything on the stack then pop it off if(!destack.empty()) { ifdp = ifdstack.top(); ifdstack.pop(); de = destack.top(); destack.pop(); md_model = modelstack.top(); modelstack.pop(); } // remember that we've visited this directory and entry so that we don't visit it again later DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de ); if(visitedIFD.find(visited) != visitedIFD.end()) { continue; } else { visitedIFD[visited] = 1; // processed } // determine how many entries there are in the current IFD nde = ReadUint16(msb_order, ifdp); for(; de < nde; de++) { char *pde = NULL; // pointer to the directory entry char *pval = NULL; // pointer to the tag value // create a tag FITAG *tag = FreeImage_CreateTag(); if(!tag) return FALSE; // point to the directory entry pde = (char*) DIR_ENTRY_ADDR(ifdp, de); // get the tag ID FreeImage_SetTagID(tag, ReadUint16(msb_order, pde)); // get the tag type WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2); if((tag_type - 1) >= EXIF_NUM_FORMATS) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // break out of the for loop break; } FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type); // get number of components FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4)); // check that tag length (size of the tag value in bytes) will fit in a DWORD unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag)); if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) { FreeImage_DeleteTag(tag); // jump to next entry continue; } FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * tag_data_width); if(FreeImage_GetTagLength(tag) <= 4) { // 4 bytes or less and value is in the dir entry itself pval = pde + 8; } else { // if its bigger than 4 bytes, the directory entry contains an offset // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data DWORD offset_value = ReadUint32(msb_order, pde + 8); if(offset_value > length) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } // now check that length does not exceed the buffer size if(FreeImage_GetTagLength(tag) > length - offset_value) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } pval = (char*)(tiffp + offset_value); } // check for a IFD offset BOOL isIFDOffset = FALSE; switch(FreeImage_GetTagID(tag)) { case TAG_EXIF_OFFSET: case TAG_GPS_OFFSET: case TAG_INTEROP_OFFSET: case TAG_MAKER_NOTE: isIFDOffset = TRUE; break; } if(isIFDOffset) { DWORD sub_offset = 0; TagLib::MDMODEL next_mdmodel = md_model; const BYTE *next_ifd = ifdp; // get offset and metadata model if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) { processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)pval + sub_offset; } else { processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)tiffp + sub_offset; } if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) { // push our current directory state onto the stack ifdstack.push(ifdp); // bump to the next entry de++; destack.push(de); // push our current metadata model modelstack.push(md_model); // push new state onto of stack to cause a jump ifdstack.push(next_ifd); destack.push(0); // select a new metadata model modelstack.push(next_mdmodel); // delete the tag as it won't be stored nor deleted in the for() loop FreeImage_DeleteTag(tag); break; // break out of the for loop } else { // unsupported camera model, canon maker tag or something unknown // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } } else { // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } // delete the tag FreeImage_DeleteTag(tag); } // for(nde) // additional thumbnail data is skipped } while (!destack.empty()); // // --- handle thumbnail data --- // const WORD entriesCount0th = ReadUint16(msb_order, ifd0th); DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th)); if((next_offset == 0) || (next_offset >= length)) { return TRUE; //< no thumbnail } const BYTE* const ifd1st = (BYTE*)tiffp + next_offset; const WORD entriesCount1st = ReadUint16(msb_order, ifd1st); unsigned thCompression = 0; unsigned thOffset = 0; unsigned thSize = 0; for(int e = 0; e < entriesCount1st; e++) { // point to the directory entry const BYTE* base = DIR_ENTRY_ADDR(ifd1st, e); // check for buffer overflow const size_t remaining = (size_t)base + 12 - (size_t)tiffp; if(remaining >= length) { // bad IFD1 directory, ignore it return FALSE; } // get the tag ID WORD tag = ReadUint16(msb_order, base); // get the tag type WORD type = ReadUint16(msb_order, base + sizeof(WORD)); // get number of components DWORD count = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD)); // get the tag value DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD)); switch(tag) { case TAG_COMPRESSION: // Tiff Compression Tag (should be COMPRESSION_OJPEG (6), but is not always respected) thCompression = offset; break; case TAG_JPEG_INTERCHANGE_FORMAT: // Tiff JPEGInterchangeFormat Tag thOffset = offset; break; case TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: // Tiff JPEGInterchangeFormatLength Tag thSize = offset; break; // ### X and Y Resolution ignored, orientation ignored case TAG_X_RESOLUTION: // XResolution case TAG_Y_RESOLUTION: // YResolution case TAG_RESOLUTION_UNIT: // ResolutionUnit case TAG_ORIENTATION: // Orientation break; default: break; } } if(/*thCompression != 6 ||*/ thOffset == 0 || thSize == 0) { return TRUE; } if(thOffset + thSize > length) { return TRUE; } // load the thumbnail const BYTE *thLocation = tiffp + thOffset; FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(thLocation), thSize); FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem); FreeImage_CloseMemory(hmem); // store the thumbnail FreeImage_SetThumbnail(dib, thumbnail); // then delete it FreeImage_Unload(thumbnail); return TRUE; }
/** Read and decode JPEG_APP1 marker (Exif profile) @param dib Input FIBITMAP @param data Pointer to the APP1 marker @param length APP1 marker length @return Returns TRUE if successful, FALSE otherwise */ BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *data, unsigned length) { // marker identifying string for Exif = "Exif\0\0" BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Classic TIFF signature - little-endian order BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Classic TIFF signature - big-endian order // profile size is up to 32-bit DWORD dwProfileLength = (DWORD)length; BYTE *pbProfile = (BYTE*)data; // verify the identifying string if(memcmp(exif_signature, pbProfile, sizeof(exif_signature)) == 0) { // This is an Exif profile // should contain a TIFF header with up to 2 IFDs (IFD stands for 'Image File Directory') // 0th IFD : the image attributes, 1st IFD : may be used for thumbnail pbProfile += sizeof(exif_signature); dwProfileLength -= sizeof(exif_signature); // read the TIFF header (8 bytes) // check the endianess order BOOL bBigEndian = TRUE; if(memcmp(pbProfile, lsb_first, sizeof(lsb_first)) == 0) { // Exif section is in little-endian order bBigEndian = FALSE; } else { if(memcmp(pbProfile, msb_first, sizeof(msb_first)) == 0) { // Exif section is in big-endian order bBigEndian = TRUE; } else { // Invalid Exif alignment marker return FALSE; } } // this is the offset to the first IFD (Image File Directory) DWORD dwFirstOffset = ReadUint32(bBigEndian, pbProfile + 4); if (dwFirstOffset > dwProfileLength) { // bad Exif data return FALSE; } /* Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset => tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D if (dwFirstOffset < 8 || dwFirstOffset > 16) { // This is usually set to 8 // but PENTAX Optio 230 has it set differently, and uses it as offset. FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value"); return FALSE; } */ // process Exif directories, starting with Exif-TIFF IFD return jpeg_read_exif_dir(dib, pbProfile, dwFirstOffset, dwProfileLength, 0, bBigEndian, TagLib::EXIF_MAIN); } return FALSE; }
static nsresult ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg) { // make sure inBuf is long enough to contain a meaningful type2 msg. // // 0 NTLMSSP Signature // 8 NTLM Message Type // 12 Target Name // 20 Flags // 24 Challenge // 32 targetInfo // 48 start of optional data blocks // if (inLen < NTLM_TYPE2_HEADER_LEN) return NS_ERROR_UNEXPECTED; const uint8_t *cursor = reinterpret_cast<const uint8_t*>(inBuf); // verify NTLMSSP signature if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) return NS_ERROR_UNEXPECTED; cursor += sizeof(NTLM_SIGNATURE); // verify Type-2 marker if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0) return NS_ERROR_UNEXPECTED; cursor += sizeof(NTLM_TYPE2_MARKER); // Read target name security buffer: ... // ... read target length. uint32_t targetLen = ReadUint16(cursor); // ... skip next 16-bit "allocated space" value. ReadUint16(cursor); // ... read offset from inBuf. uint32_t offset = ReadUint32(cursor); mozilla::CheckedInt<uint32_t> targetEnd = offset; targetEnd += targetLen; // Check the offset / length combo is in range of the input buffer, including // integer overflow checking. if (MOZ_LIKELY(targetEnd.isValid() && targetEnd.value() <= inLen)) { msg->targetLen = targetLen; msg->target = reinterpret_cast<const uint8_t*>(inBuf) + offset; } else { // Do not error out, for (conservative) backward compatibility. msg->targetLen = 0; msg->target = nullptr; } // read flags msg->flags = ReadUint32(cursor); // read challenge memcpy(msg->challenge, cursor, sizeof(msg->challenge)); cursor += sizeof(msg->challenge); LOG(("NTLM type 2 message:\n")); LogBuf("target", reinterpret_cast<const uint8_t*> (msg->target), msg->targetLen); LogBuf("flags", reinterpret_cast<const uint8_t*> (&msg->flags), 4); LogFlags(msg->flags); LogBuf("challenge", msg->challenge, sizeof(msg->challenge)); // Read (and skip) the reserved field ReadUint32(cursor); ReadUint32(cursor); // Read target name security buffer: ... // ... read target length. uint32_t targetInfoLen = ReadUint16(cursor); // ... skip next 16-bit "allocated space" value. ReadUint16(cursor); // ... read offset from inBuf. offset = ReadUint32(cursor); mozilla::CheckedInt<uint32_t> targetInfoEnd = offset; targetInfoEnd += targetInfoLen; // Check the offset / length combo is in range of the input buffer, including // integer overflow checking. if (MOZ_LIKELY(targetInfoEnd.isValid() && targetInfoEnd.value() <= inLen)) { msg->targetInfoLen = targetInfoLen; msg->targetInfo = reinterpret_cast<const uint8_t*>(inBuf) + offset; } else { NS_ERROR("failed to get NTLMv2 target info"); return NS_ERROR_UNEXPECTED; } return NS_OK; }
bool HTTPTracker::updateData(const QByteArray & data) { //#define DEBUG_PRINT_RESPONSE #ifdef DEBUG_PRINT_RESPONSE Out(SYS_TRK | LOG_DEBUG) << "Data : " << endl; Out(SYS_TRK | LOG_DEBUG) << QString(data) << endl; #endif // search for dictionary, there might be random garbage infront of the data int i = 0; while (i < data.size()) { if (data[i] == 'd') break; i++; } if (i == data.size()) { failures++; failed(i18n("Invalid response from tracker")); return false; } BDecoder dec(data, false, i); BNode* n = 0; try { n = dec.decode(); } catch (...) { failures++; failed(i18n("Invalid data from tracker")); return false; } if (!n || n->getType() != BNode::DICT) { failures++; failed(i18n("Invalid response from tracker")); return false; } BDictNode* dict = (BDictNode*)n; if (dict->getData("failure reason")) { BValueNode* vn = dict->getValue("failure reason"); error = vn->data().toString(); delete n; failures++; failed(error); return false; } if (dict->getData("warning message")) { BValueNode* vn = dict->getValue("warning message"); warning = vn->data().toString(); } else warning.clear(); BValueNode* vn = dict->getValue("interval"); // if no interval is specified, use 5 minutes if (vn) interval = vn->data().toInt(); else interval = 5 * 60; vn = dict->getValue("incomplete"); if (vn) leechers = vn->data().toInt(); vn = dict->getValue("complete"); if (vn) seeders = vn->data().toInt(); BListNode* ln = dict->getList("peers"); if (!ln) { // no list, it might however be a compact response vn = dict->getValue("peers"); if (vn && vn->data().getType() == Value::STRING) { QByteArray arr = vn->data().toByteArray(); for (int i = 0;i < arr.size();i += 6) { Uint8 buf[6]; for (int j = 0;j < 6;j++) buf[j] = arr[i + j]; Uint32 ip = ReadUint32(buf, 0); addPeer(net::Address(ip, ReadUint16(buf, 4)), false); } } } else { for (Uint32 i = 0;i < ln->getNumChildren();i++) { BDictNode* dict = dynamic_cast<BDictNode*>(ln->getChild(i)); if (!dict) continue; BValueNode* ip_node = dict->getValue("ip"); BValueNode* port_node = dict->getValue("port"); if (!ip_node || !port_node) continue; net::Address addr(ip_node->data().toString(), port_node->data().toInt()); addPeer(addr, false); } } // Check for IPv6 compact peers vn = dict->getValue("peers6"); if (vn && vn->data().getType() == Value::STRING) { QByteArray arr = vn->data().toByteArray(); for (int i = 0;i < arr.size();i += 18) { Q_IPV6ADDR ip; memcpy(ip.c, arr.data() + i, 16); quint16 port = ReadUint16((const Uint8*)arr.data() + i, 16); addPeer(net::Address(ip, port), false); } } delete n; return true; }
void JavaExecuter::run() { init(); std::string workingDir = combineString(Config::getInstant()->getTmpUserPath(), DIR_SEPARTOR, runId); int port = 0, status; int server_sock = CreateServerSocket(&port); struct sockaddr_un un; socklen_t len = sizeof(un); if(server_sock < 0) { BLOG("JavaExecuter::run(): create server sock error", SYSCALL_ERROR); this->_result = SERVER_ERROR; return; } pid_t pid = fork(); if(pid < 0) { BLOG("JavaExecuter::run() fork error", SYSCALL_ERROR); this->_result = SERVER_ERROR; return; } if(pid == 0) { close(server_sock); if(chdir(workingDir.c_str()) == -1) { LLOG("Fail to change working dir to " + workingDir, SYSCALL_ERROR); raise(SIGKILL); return; } std::string rootPath = Config::getInstant()->getRootPath(); if(stdinFileName[0] != '/' && stdinFileName[0] != '.') { stdinFileName = rootPath + stdinFileName; } if(stdoutFileName[0] != '/' && stdoutFileName[0] != '/') { stdoutFileName = rootPath + stdoutFileName; } std::string minMem = combineString("-Xms", limitMemory / 2 + 200, 'k'); std::string maxMem = combineString("-Xmx", limitMemory + 200, 'k'); std::string javaLib = combineString("-Djava.library.path=", rootPath, "bin"); std::string jarPath = combineString(rootPath, "bin/JavaSandbox.jar"); std::string portStr = combineString(port); std::string limitTimeStr = combineString(limitTime); std::string limitMemoryStr = combineString(limitMemory); std::string limitOutputStr = combineString(limitOutput); std::string uidStr = combineString(Config::getInstant()->getJobUID()); std::string gidStr = combineString(Config::getInstant()->getJobGID()); for(int i = 0; i < 100; i++) close(i); execlp("java", minMem.c_str(), maxMem.c_str(), javaLib.c_str(), "-jar", jarPath.c_str(), portStr.c_str(), limitTimeStr.c_str(), limitMemoryStr.c_str(), limitOutputStr.c_str(), uidStr.c_str(), gidStr.c_str(), stdinFileName.c_str(), stdoutFileName.c_str(), NULL); LLOG("JavaExecuter()::run() Fail to run java", SYSCALL_ERROR); exit(-1); } else { //parent while(1) { //the accept function will be interuppted by the SIGCHLD signal int client_sock = accept(server_sock, (struct sockaddr*)&un, &len); if(client_sock < 0) { if(errno != EINTR) { BLOG("JavaExecuter::run() fail to accept", SYSCALL_ERROR); close(server_sock); this->_result = SERVER_ERROR; return; }else if(waitpid(pid, &status, WNOHANG) > 0) { break; } } else { unsigned int _time, _memory; while(ReadUint32(client_sock, &_time) >= 0 && ReadUint32(client_sock, &_memory) >= 0) { this->_runnedTime = _time; this->_runnedMemory = _memory; judgeThread->updateRunInfo(_time, _memory); } close(client_sock); while(waitpid(pid, &status, 0) < 0 && errno != ECHILD) { } break; } } close(server_sock); if(WIFSIGNALED(status)) { switch(WTERMSIG(status)) { case SIGXCPU: this->_result = TIME_LIMIT_EXCEEDED; break; default: DLOG(ERROR) << "Java process was terminated by signal " << WTERMSIG(status); this->_result = RUNTIME_ERROR; } } else { this->_result = WEXITSTATUS(status); if(this->_result == 1) { this->_result = SERVER_ERROR; }else{ if(this->_result) this->_result += 1000; } if(this->_result == 0) { this->_result = TraceProcess::NORMAL; if(this->_runnedMemory > limitMemory) { this->_result = MEMORY_LIMIT_EXCEEDED; } if(this->_runnedTime > limitTime) { this->_result = TIME_LIMIT_EXCEEDED; } } } } }