[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a

Maximiliano Curia maxy at moszumanska.debian.org
Thu Jul 13 17:39:38 UTC 2017


Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=3fe5ebb

The following commit has been merged in the master branch:
commit 3fe5ebb8ca702635ef5cbdb91ff75d4fa1085fa7
Author: HumanDynamo <caulier.gilles at gmail.com>
Date:   Sun Jul 27 09:23:08 2008 +0000

    PNG file format parser.
    - Refactoring code: main loop to parse PNG chunk contents go to pngimage class. pngchunk only play with chunk contents
    - Implement PNG writting mode : all metadata are supported:
     * UTF8 comment as "Description" iTXt chunk (compressed)
     * XMP data as iTXt chunk (uncompressed as XMP spec instruction)
     * IPTC data as zTXt chunk (compressed and encoded as ImageMagick method)
     * EXIF data as zTXt chunk (compressed and encoded as ImageMagick method)
    
    Note: writting mode resample metadata chunk to follow list given behind. There are several ways where other programs writte metadata in other place.
    For ex : digiKam 0.9.x or ImageMagick 5.x writte Exif and Iptc to an tEXt chunk (uncompressed)
             ImageMagick 5.x writte Xmp to an uncompressed tEXt chunk
             ImageMagick 6.x writte Xmp to a compressed zTXt chunk.
---
 src/pngchunk.cpp | 639 +++++++++++++++++++++++++++++++------------------------
 src/pngchunk.hpp | 151 +++++++++----
 src/pngimage.cpp | 312 +++++++++++++++++++++++----
 src/pngimage.hpp |  38 ++--
 4 files changed, 759 insertions(+), 381 deletions(-)

diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index bcf0e66..a785612 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -39,12 +39,7 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
 
 //#define DEBUG 1
 
-// some defines to make it easier
-#define PNG_CHUNK_TYPE(data, index)  &data[index+4]
-#define PNG_CHUNK_DATA(data, index, offset) data[8+index+offset]
-#define PNG_CHUNK_HEADER_SIZE 12
-
-// To uncompress text chunck
+// To uncompress or compress text chunk
 #include <zlib.h>
 
 #include "pngchunk.hpp"
@@ -64,200 +59,144 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
 
 URLs to find informations about PNG chunks :
 
-tEXt and zTXt chuncks : http://www.vias.org/pngguide/chapter11_04.html
-iTXt chunck           : http://www.vias.org/pngguide/chapter11_05.html
-PNG tags              : http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
+tEXt and zTXt chunks : http://www.vias.org/pngguide/chapter11_04.html
+iTXt chunk           : http://www.vias.org/pngguide/chapter11_05.html
+PNG tags             : http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
 
 */
 
 // *****************************************************************************
-// local declarations
-namespace {
-    // Return the checked length of a PNG chunk
-    long chunkLength(const Exiv2::byte* pData, long index);
-}
-
-// *****************************************************************************
 // class member definitions
-namespace Exiv2 {
-
-    void PngChunk::decode(Image*      pImage,
-                          const byte* pData,
-                          long        size,
-                          int*        outWidth,
-                          int*        outHeight)
+namespace Exiv2 
+{
+    void PngChunk::decodeIHDRChunk(const DataBuf& data,
+                                   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);
-        }
+        // Extract image width and height from IHDR chunk.
 
-        // 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
+        *outWidth  = getLong((const byte*)data.pData_,     bigEndian);
+        *outHeight = getLong((const byte*)data.pData_ + 4, bigEndian);
 
-                // get the key, it's a null terminated string at the chunk start
-                const byte *key = &PNG_CHUNK_DATA(pData, index, 0);
+    } // PngChunk::decodeIHDRChunk
 
-                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);
-                }
+    void PngChunk::decodeTXTChunk(Image*         pImage,
+                                  const DataBuf& data,
+                                  TxtChunkType   type)
+    {
+        DataBuf key = keyTXTChunk(data);
 
-                DataBuf arr = parsePngChunk(pData, size, index, keysize);
+#ifdef DEBUG
+        std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: " 
+                  << std::string((const char*)key.pData_) << "
";
+#endif
+        DataBuf arr = parseTXTChunk(data, key.size_, type);
 
 #ifdef DEBUG
-                std::cerr << "Exiv2::PngChunk::decode: Found PNG chunk: "
-                          << std::string((const char*)key) << " :: "
-                          << std::string((const char*)arr.pData_, 32) << "
";
+        std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk data: " 
+                  << std::string((const char*)arr.pData_, 32) << "
";
 #endif
+        parseChunkContent(pImage, key.pData_, arr);
 
-                parseChunkContent(pImage, key, arr);
+    } // PngChunk::decodeTXTChunk
 
-                index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE;
-            }
+    DataBuf PngChunk::keyTXTChunk(const DataBuf& data, bool stripHeader)
+    {
+        // From a tEXt, zTXt, or iTXt chunk,
+        // we get the key, it's a null terminated string at the chunk start
+
+        const byte *key = data.pData_ + (stripHeader ? 8 : 0);
+
+        // Find null string at end of key.
+        int keysize=0;
+        for ( ; key[keysize] != 0 ; keysize++)
+        {
+            // look if keysize is valid.
+            if (keysize >= data.size_)
+                throw Error(14);
         }
 
-    } // PngChunk::decode
+        return DataBuf(key, keysize);
 
-    DataBuf PngChunk::parsePngChunk(const byte* pData, long size, long& index, int keysize)
+    } // PngChunk::keyTXTChunk
+
+    DataBuf PngChunk::parseTXTChunk(const DataBuf& data, 
+                                    int            keysize, 
+                                    TxtChunkType   type)
     {
         DataBuf arr;
 
-        if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4))
+        if(type == zTXt_Chunk)
         {
             // Extract a deflate compressed Latin-1 text chunk
 
-#ifdef DEBUG
-            std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zTXt field
";
-#endif
             // we get the compression method after the key
-            const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1);
+            const byte* compressionMethod = data.pData_ + 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.
";
+                std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard zTXt compression method.
";
 #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);
+            const byte* compressedText      = data.pData_ + keysize + 2;
+            unsigned int compressedTextSize = data.size_  - keysize - 2;
 
             zlibUncompress(compressedText, compressedTextSize, arr);
         }
-        else if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4))
+        else if(type == tEXt_Chunk)
         {
             // Extract a non-compressed Latin-1 text chunk
-#ifdef DEBUG
-            std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a tEXt field
";
-#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);
+            // the text comes after the key, but isn't null terminated
+            const byte* text = data.pData_ + keysize + 1;
+            long textsize    = data.size_  - keysize - 1;
 
             arr.alloc(textsize);
             arr = DataBuf(text, textsize);
         }
-        else if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4))
+        else if(type == iTXt_Chunk)
         {
             // 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);
+            const byte* compressionFlag   = data.pData_ + keysize + 1;
             // we get the compression method after the compression flag
-            const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1);
+            const byte* compressionMethod = data.pData_ + keysize + 2;
             // 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;
+            std::string languageText((const char*)(data.pData_ + keysize + 3));
+            unsigned int languageTextSize = languageText.size();
             // 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;
+            std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize));
+            unsigned int translatedKeyTextSize = translatedKeyText.size();
 
-            if ( *compressionFlag == 0x00 )
+            if ( compressionFlag[0] == 0x00 )
             {
                 // then it's an uncompressed iTXt chunk
 #ifdef DEBUG
-                std::cerr << "Exiv2::PngChunk::parsePngChunk: We found an uncompressed iTXt field
";
+                std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field
";
 #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);
+                const byte* text = data.pData_ + keysize + 3 + languageTextSize + translatedKeyTextSize;
+                long textsize    = data.size_ - (keysize + 3 + languageTextSize + translatedKeyTextSize);
 
                 arr.alloc(textsize);
                 arr = DataBuf(text, textsize);
             }
-            else if ( *compressionMethod == 0x00 )
+            else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 )
             {
                 // then it's a zlib compressed iTXt chunk
 #ifdef DEBUG
-                std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zlib compressed iTXt field
";
+                std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field
";
 #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);
+                const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
+                long compressedTextSize    = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
 
                 zlibUncompress(compressedText, compressedTextSize, arr);
             }
@@ -265,7 +204,7 @@ namespace Exiv2 {
             {
                 // then it isn't zlib compressed and we are sunk
 #ifdef DEBUG
-                std::cerr << "Exiv2::PngChunk::parsePngChunk: Non-standard iTXt compression method.
";
+                std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.
";
 #endif
                 throw Error(14);
             }
@@ -273,12 +212,12 @@ namespace Exiv2 {
         else
         {
 #ifdef DEBUG
-            std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a field, not expected though
";
+            std::cerr << "Exiv2::PngChunk::parseTXTChunk: We found a field, not expected though
";
 #endif
             throw Error(14);
         }
 
-    return arr;
+        return arr;
 
     } // PngChunk::parsePngChunk
 
@@ -314,7 +253,7 @@ namespace Exiv2 {
                 if (pos !=-1)
                 {
 #ifdef DEBUG
-                    std::cerr << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "
";
+                    std::cout << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "
";
 #endif
                     pos = pos + sizeof(exifHeader);
                     ByteOrder bo = TiffParser::decode(pImage->exifData(),
@@ -360,7 +299,7 @@ namespace Exiv2 {
 #endif
                     xmpPacket = xmpPacket.substr(idx);
                 }
-                if (XmpParser::decode(pImage->xmpData(), xmpPacket))
+                if (XmpParser::decode(pImage->xmpData(), xmpPacket)) 
                 {
 #ifndef SUPPRESS_WARNINGS
                     std::cerr << "Warning: Failed to decode XMP metadata.
";
@@ -387,7 +326,7 @@ namespace Exiv2 {
 #endif
                     xmpPacket = xmpPacket.substr(idx);
                 }
-                if (XmpParser::decode(pImage->xmpData(), xmpPacket))
+                if (XmpParser::decode(pImage->xmpData(), xmpPacket)) 
                 {
 #ifndef SUPPRESS_WARNINGS
                     std::cerr << "Warning: Failed to decode XMP metadata.
";
@@ -407,6 +346,254 @@ namespace Exiv2 {
 
     } // PngChunk::parseChunkContent
 
+    DataBuf PngChunk::makeMetadataChunk(const DataBuf& metadata, MetadataType type, bool compress)
+    {
+        if (type == comment_Data)
+        {
+            DataBuf key(11);
+            memcpy(key.pData_, "Description", 11);
+            DataBuf rawData = makeUtf8TxtChunk(key, metadata, compress);
+            return rawData;
+        }
+        else if (type == exif_Data)
+        {
+            DataBuf tmp(4);
+            memcpy(tmp.pData_, "exif", 4);
+            DataBuf rawProfile = writeRawProfile(metadata, tmp);
+            DataBuf key(17 + tmp.size_);
+            memcpy(key.pData_,      "Raw profile type ", 17);
+            memcpy(key.pData_ + 17, tmp.pData_, tmp.size_);
+            DataBuf rawData = makeAsciiTxtChunk(key, rawProfile, compress);
+            return rawData;
+        }
+        else if (type == iptc_Data)
+        {
+            DataBuf tmp(4);
+            memcpy(tmp.pData_, "iptc", 4);
+            DataBuf rawProfile = writeRawProfile(metadata, tmp);
+            DataBuf key(17 + tmp.size_);
+            memcpy(key.pData_,      "Raw profile type ", 17);
+            memcpy(key.pData_ + 17, tmp.pData_, tmp.size_);
+            DataBuf rawData = makeAsciiTxtChunk(key, rawProfile, compress);
+            return rawData;
+        }
+        else if (type == xmp_Data)
+        {
+            DataBuf key(17);
+            memcpy(key.pData_, "XML:com.adobe.xmp", 17);
+            DataBuf rawData = makeUtf8TxtChunk(key, metadata, compress);
+            return rawData;
+        }
+
+        return DataBuf();
+
+    } // PngChunk::makeMetadataChunk
+
+    void PngChunk::zlibUncompress(const byte*  compressedText, 
+                                  unsigned int compressedTextSize, 
+                                  DataBuf&     arr)
+    {
+        uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
+        int zlibResult;
+
+        do
+        {
+            arr.alloc(uncompressedLen);
+            zlibResult = uncompress((Bytef*)arr.pData_, &uncompressedLen,
+                                    compressedText, compressedTextSize);
+
+            if (zlibResult == Z_OK)
+            {
+                // then it is all OK
+                arr.alloc(uncompressedLen);
+            }
+            else if (zlibResult == Z_BUF_ERROR)
+            {
+                // the uncompressedArray needs to be larger
+#ifdef DEBUG
+                std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for decompression.
";
+#endif
+                uncompressedLen *= 2;
+
+                // DoS protection. can't be bigger than 64k
+                if ( uncompressedLen > 131072 )
+                    break;
+            }
+            else
+            {
+                // something bad happened
+                throw Error(14);
+            }
+        }
+        while (zlibResult == Z_BUF_ERROR);
+
+        if (zlibResult != Z_OK)
+            throw Error(14);
+
+    } // PngChunk::zlibUncompress
+
+    void PngChunk::zlibCompress(const byte*  text, 
+                                unsigned int textSize, 
+                                DataBuf&     arr)
+    {
+        uLongf compressedLen = textSize * 2; // just a starting point
+        int zlibResult;
+
+        do
+        {
+            arr.alloc(compressedLen);
+            zlibResult = compress2((Bytef*)arr.pData_, &compressedLen,
+                                   text, textSize, Z_BEST_COMPRESSION);
+
+            if (zlibResult == Z_OK)
+            {
+                // then it is all OK
+                arr.alloc(compressedLen);
+            }
+            else if (zlibResult == Z_BUF_ERROR)
+            {
+                // the compressedArray needs to be larger
+#ifdef DEBUG
+                std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for compression.
";
+#endif
+                compressedLen *= 2;
+
+                // DoS protection. can't be bigger than 64k
+                if ( compressedLen > 131072 )
+                    break;
+            }
+            else
+            {
+                // something bad happened
+                throw Error(14);
+            }
+        }
+        while (zlibResult == Z_BUF_ERROR);
+
+        if (zlibResult != Z_OK)
+            throw Error(14);
+
+    } // PngChunk::zlibCompress
+
+    DataBuf PngChunk::makeAsciiTxtChunk(const DataBuf& key, const DataBuf& data, bool compress)
+    {
+        DataBuf type(4);
+        DataBuf data4crc;
+        DataBuf chunkData;
+        byte    chunkDataSize[4];
+        byte    chunkCRC[4];
+
+        if (compress)
+        {
+            // Compressed text chunk using ZLib.
+            // Data format    : key ("zTXt") + 0x00 + compression type (0x00) + compressed data
+            // Chunk structure: data lenght (4 bytes) + chunk type (4 bytes) + compressed data + CRC (4 bytes)
+
+            memcpy(type.pData_, "zTXt", 4);
+
+            DataBuf compressedData;
+            zlibCompress(data.pData_, data.size_, compressedData);
+
+            data4crc.alloc(key.size_ + 1 + 1 + compressedData.size_);
+            memcpy(data4crc.pData_,                 key.pData_,            key.size_);
+            memcpy(data4crc.pData_ + key.size_,     "

-- 
exiv2 packaging



More information about the pkg-kde-commits mailing list