void PngChunk::decode(Image* pImage, const byte* pData, long size) { assert(pImage != 0); assert(pData != 0); // look for a tEXt chunk long index = 8; index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE; while(index < size-PNG_CHUNK_HEADER_SIZE) { while (index < size-PNG_CHUNK_HEADER_SIZE && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4) && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4) && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4)) { if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "IEND", 4)) throw Error(14); index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE; } if (index < size-PNG_CHUNK_HEADER_SIZE) { // we found a tEXt, zTXt, or iTXt field // get the key, it's a null terminated string at the chunk start const byte *key = &PNG_CHUNK_DATA(pData, index, 0); int keysize=0; for ( ; key[keysize] != 0 ; keysize++) { // look if we reached the end of the file (it might be corrupted) if (8+index+keysize >= size) throw Error(14); } DataBuf arr = parsePngChunk(pData, size, index, keysize); #ifdef DEBUG std::cerr << "Exiv2::PngChunk::decode: Found PNG chunk: " << std::string((const char*)key) << " :: " << std::string((const char*)arr.pData_, 32) << "\n"; #endif parseChunkContent(pImage, key, arr); index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE; } } } // PngChunk::decode
DataBuf PngChunk::parsePngChunk(const byte* pData, long size, long& index, int keysize) { DataBuf arr; if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4)) { // Extract a deflate compressed Latin-1 text chunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zTXt field\n"; #endif // we get the compression method after the key const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1); if ( *compressionMethod != 0x00 ) { // then it isn't zlib compressed and we are sunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: Non-standard zTXt compression method.\n"; #endif throw Error(14); } // compressed string after the compression technique spec const byte* compressedText = &PNG_CHUNK_DATA(pData, index, keysize+2); unsigned int compressedTextSize = getLong(&pData[index], bigEndian)-keysize-2; // security check, also considering overflow wraparound from the addition -- // we may endup with a /smaller/ index if we wrap all the way around long firstIndex = (long)(compressedText - pData); long onePastLastIndex = firstIndex + compressedTextSize; if ( onePastLastIndex > size || onePastLastIndex <= firstIndex) throw Error(14); zlibUncompress(compressedText, compressedTextSize, arr); } else if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4)) { // Extract a non-compressed Latin-1 text chunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a tEXt field\n"; #endif // the text comes after the key, but isn't null terminated const byte* text = &PNG_CHUNK_DATA(pData, index, keysize+1); long textsize = getLong(&pData[index], bigEndian)-keysize-1; // security check, also considering overflow wraparound from the addition -- // we may endup with a /smaller/ index if we wrap all the way around long firstIndex = (long)(text - pData); long onePastLastIndex = firstIndex + textsize; if ( onePastLastIndex > size || onePastLastIndex <= firstIndex) throw Error(14); arr.alloc(textsize); arr = DataBuf(text, textsize); } else if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4)) { // Extract a deflate compressed or uncompressed UTF-8 text chunk // we get the compression flag after the key const byte* compressionFlag = &PNG_CHUNK_DATA(pData, index, keysize+1); // we get the compression method after the compression flag const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1); // language description string after the compression technique spec const byte* languageText = &PNG_CHUNK_DATA(pData, index, keysize+1); unsigned int languageTextSize = getLong(&pData[index], bigEndian)-keysize-1; // translated keyword string after the language description const byte* translatedKeyText = &PNG_CHUNK_DATA(pData, index, keysize+1); unsigned int translatedKeyTextSize = getLong(&pData[index], bigEndian)-keysize-1; if ( *compressionFlag == 0x00 ) { // then it's an uncompressed iTXt chunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: We found an uncompressed iTXt field\n"; #endif // the text comes after the translated keyword, but isn't null terminated const byte* text = &PNG_CHUNK_DATA(pData, index, keysize+1); long textsize = getLong(&pData[index], bigEndian)-keysize-1; // security check, also considering overflow wraparound from the addition -- // we may endup with a /smaller/ index if we wrap all the way around long firstIndex = (long)(text - pData); long onePastLastIndex = firstIndex + textsize; if ( onePastLastIndex > size || onePastLastIndex <= firstIndex) throw Error(14); arr.alloc(textsize); arr = DataBuf(text, textsize); } else if ( *compressionMethod == 0x00 ) { // then it's a zlib compressed iTXt chunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zlib compressed iTXt field\n"; #endif // the compressed text comes after the translated keyword, but isn't null terminated const byte* compressedText = &PNG_CHUNK_DATA(pData, index, keysize+1); long compressedTextSize = getLong(&pData[index], bigEndian)-keysize-1; // security check, also considering overflow wraparound from the addition -- // we may endup with a /smaller/ index if we wrap all the way around long firstIndex = (long)(compressedText - pData); long onePastLastIndex = firstIndex + compressedTextSize; if ( onePastLastIndex > size || onePastLastIndex <= firstIndex) throw Error(14); zlibUncompress(compressedText, compressedTextSize, arr); } else { // then it isn't zlib compressed and we are sunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: Non-standard iTXt compression method.\n"; #endif throw Error(14); } } else { #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a field, not expected though\n"; #endif throw Error(14); } return arr; } // PngChunk::parsePngChunk
void PngChunk::decode(Image* pImage, const byte* pData, long size, int* outWidth, int* outHeight) { assert(pImage != 0); assert(pData != 0); assert(outWidth != 0); assert(outHeight != 0); long index = 8; // extract width and height from IHDR chunk, which *must* be the first chunk in the PNG file if (strncmp((const char *)PNG_CHUNK_TYPE(pData, index), "IHDR", 4) == 0) { *outWidth = getLong((const byte*)&PNG_CHUNK_DATA(pData, index, 0), bigEndian); *outHeight = getLong((const byte*)&PNG_CHUNK_DATA(pData, index, 4), bigEndian); } // look for a tEXt chunk index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE; while(index < size-PNG_CHUNK_HEADER_SIZE) { while (index < size-PNG_CHUNK_HEADER_SIZE && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4) && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4) && strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4)) { if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "IEND", 4)) throw Error(14); index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE; } if (index < size-PNG_CHUNK_HEADER_SIZE) { // we found a tEXt, zTXt, or iTXt field // get the key, it's a null terminated string at the chunk start const byte *key = &PNG_CHUNK_DATA(pData, index, 0); int keysize=0; for ( ; key[keysize] != 0 ; keysize++) { // look if we reached the end of the file (it might be corrupted) if (8+index+keysize >= size) throw Error(14); } DataBuf arr = parsePngChunk(pData, size, index, keysize); #ifdef DEBUG std::cerr << "Exiv2::PngChunk::decode: Found PNG chunk: " << std::string((const char*)key) << " :: " << std::string((const char*)arr.pData_, 32) << "\n"; #endif parseChunkContent(pImage, key, arr); index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE; } } } // PngChunk::decode