diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp index 123df50b..7bc292a6 100644 --- a/src/jpgimage.cpp +++ b/src/jpgimage.cpp @@ -86,10 +86,21 @@ namespace Exiv2 { const char JpegBase::xmpId_[] = "http://ns.adobe.com/xap/1.0/\0"; const char Photoshop::ps3Id_[] = "Photoshop 3.0\0"; - const char Photoshop::bimId_[] = "8BIM"; + const char* Photoshop::irbId_[] = {"8BIM", "AgHg", "DCSR", "PHUT"}; const uint16_t Photoshop::iptc_ = 0x0404; const uint16_t Photoshop::preview_ = 0x040c; + bool Photoshop::isIrb(const byte* pPsData, + long sizePsData) + { + if (sizePsData < 4) return false; + for (size_t i = 0; i < (sizeof irbId_) / (sizeof *irbId_); i++) { + assert(strlen(irbId_[i]) == 4); + if (memcmp(pPsData, irbId_[i], 4) == 0) return true; + } + return false; + } + bool Photoshop::valid(const byte* pPsData, long sizePsData) { @@ -126,8 +137,7 @@ namespace Exiv2 { std::cerr << "Photoshop::locateIrb: "; #endif // Data should follow Photoshop format, if not exit - while ( position <= sizePsData - 12 - && memcmp(pPsData + position, Photoshop::bimId_, 4) == 0) { + while (position <= sizePsData - 12 && isIrb(pPsData + position, 4)) { const byte *hrd = pPsData + position; position += 4; uint16_t type = getUShort(pPsData + position, bigEndian); @@ -237,7 +247,7 @@ namespace Exiv2 { DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { byte tmpBuf[12]; - std::memcpy(tmpBuf, Photoshop::bimId_, 4); + std::memcpy(tmpBuf, Photoshop::irbId_[0], 4); us2Data(tmpBuf + 4, iptc_, bigEndian); tmpBuf[6] = 0; tmpBuf[7] = 0; diff --git a/src/jpgimage.hpp b/src/jpgimage.hpp index 048b8436..4cbc8054 100644 --- a/src/jpgimage.hpp +++ b/src/jpgimage.hpp @@ -64,10 +64,20 @@ namespace Exiv2 { struct EXIV2API Photoshop { // Todo: Public for now static const char ps3Id_[]; //!< %Photoshop marker - static const char bimId_[]; //!< %Photoshop marker + static const char* irbId_[]; //!< %Photoshop IRB markers static const uint16_t iptc_; //!< %Photoshop IPTC marker static const uint16_t preview_; //!< %Photoshop preview marker + /*! + @brief Checks an IRB + + @param pPsData Existing IRB buffer + @param sizePsData Size of the IRB buffer + @return true if the IRB marker is known and the buffer is big enough to check this;
+ false otherwise + */ + static bool isIrb(const byte* pPsData, + long sizePsData); /*! @brief Validates all IRBs diff --git a/src/psdimage.cpp b/src/psdimage.cpp index bd2d2f41..c2d8b857 100644 --- a/src/psdimage.cpp +++ b/src/psdimage.cpp @@ -39,6 +39,7 @@ EXIV2_RCSID("@(#) $Id$") # include "exv_conf.h" #endif #include "psdimage.hpp" +#include "jpgimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" @@ -56,11 +57,9 @@ EXIV2_RCSID("@(#) $Id$") // Extend this helper to a proper class with all required functionality, // then move it here or into a separate file? -const uint32_t kPhotoshopResourceType = 0x3842494d; // '8BIM' - //! @cond IGNORE struct PhotoshopResourceBlock { - uint32_t resourceType; // always kPhotoshopResourceType + uint32_t resourceType; // one of the markers in Photoshop::irbId_[] uint16_t resourceId; unsigned char resourceName[2]; // Pascal string (length byte + characters), padded to an even size -- this assumes the empty string uint32_t resourceDataSize; @@ -215,14 +214,11 @@ namespace Exiv2 { throw Error(3, "Photoshop"); } - // read resource type and ID - uint32_t resourceType = getULong(buf, bigEndian); - uint16_t resourceId = getUShort(buf + 4, bigEndian); - - if (resourceType != kPhotoshopResourceType) + if (!Photoshop::isIrb(buf, 4)) { break; // bad resource type } + uint16_t resourceId = getUShort(buf + 4, bigEndian); uint32_t resourceNameLength = buf[6] & ~1; // skip the resource name, plus any padding @@ -447,7 +443,8 @@ namespace Exiv2 { // read resource type and ID uint32_t resourceType = getULong(buf, bigEndian); - if (resourceType != kPhotoshopResourceType) { + if (!Photoshop::isIrb(buf, 4)) + { throw Error(3, "Photoshop"); // bad resource type } uint16_t resourceId = getUShort(buf + 4, bigEndian); @@ -493,11 +490,12 @@ namespace Exiv2 { && resourceId != kPhotoshopResourceID_ExifInfo && resourceId != kPhotoshopResourceID_XMPPacket) { #ifdef DEBUG + std::cerr << std::hex << "copy : resourceType: " << resourceType << "\n"; std::cerr << std::hex << "copy : resourceId: " << resourceId << "\n"; std::cerr << std::dec; #endif // Copy resource block to new PSD file - ul2Data(buf, kPhotoshopResourceType, bigEndian); + ul2Data(buf, resourceType, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); us2Data(buf, resourceId, bigEndian); if (outIo.write(buf, 2) != 2) throw Error(21); @@ -577,8 +575,7 @@ namespace Exiv2 { std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_IPTC_NAA << "\n"; std::cerr << std::dec << "Writing IPTC_NAA: size: " << rawIptc.size_ << "\n"; #endif - ul2Data(buf, kPhotoshopResourceType, bigEndian); - if (out.write(buf, 4) != 4) throw Error(21); + if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_IPTC_NAA, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name @@ -618,8 +615,7 @@ namespace Exiv2 { std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_ExifInfo << "\n"; std::cerr << std::dec << "Writing ExifInfo: size: " << blob.size() << "\n"; #endif - ul2Data(buf, kPhotoshopResourceType, bigEndian); - if (out.write(buf, 4) != 4) throw Error(21); + if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_ExifInfo, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name @@ -663,8 +659,7 @@ namespace Exiv2 { std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_XMPPacket << "\n"; std::cerr << std::dec << "Writing XMPPacket: size: " << xmpPacket.size() << "\n"; #endif - ul2Data(buf, kPhotoshopResourceType, bigEndian); - if (out.write(buf, 4) != 4) throw Error(21); + if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_XMPPacket, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name diff --git a/test/bugfixes-test.sh b/test/bugfixes-test.sh index 8243d23d..f5464353 100755 --- a/test/bugfixes-test.sh +++ b/test/bugfixes-test.sh @@ -210,6 +210,17 @@ cp -f ../data/exiv2-empty.jpg $filename $bin/exiv2 -u -v -M"add Exif.Image.Make Canon" -M"add Exif.CanonCs.0x0001 Short 1" -M"add Exif.CanonCs.0x0000 Short 2" $filename $bin/exiv2 -u -v -PEkyct $filename +num=800 +for type in 8BIM AgHg DCSR PHUT; do + for format in jpg psd; do + echo "------> Bug $num ($type in $format) <-------" >&2 + filename=exiv2-bug$num-$type.$format + cp -f ../data/$filename . + $bin/exiv2 -u -v -M'set Exif.Photo.UserComment Test' $filename + $bin/exiv2 -u -pt $filename + done +done + ) > $results 2>&1 # ---------------------------------------------------------------------- diff --git a/test/data/bugfixes-test.out b/test/data/bugfixes-test.out index a0be5055..05123983 100644 Binary files a/test/data/bugfixes-test.out and b/test/data/bugfixes-test.out differ diff --git a/test/data/exiv2-bug800-8BIM.jpg b/test/data/exiv2-bug800-8BIM.jpg new file mode 100644 index 00000000..9b74fd39 Binary files /dev/null and b/test/data/exiv2-bug800-8BIM.jpg differ diff --git a/test/data/exiv2-bug800-8BIM.psd b/test/data/exiv2-bug800-8BIM.psd new file mode 100644 index 00000000..964b352b Binary files /dev/null and b/test/data/exiv2-bug800-8BIM.psd differ diff --git a/test/data/exiv2-bug800-AgHg.jpg b/test/data/exiv2-bug800-AgHg.jpg new file mode 100644 index 00000000..3d0ba1e7 Binary files /dev/null and b/test/data/exiv2-bug800-AgHg.jpg differ diff --git a/test/data/exiv2-bug800-AgHg.psd b/test/data/exiv2-bug800-AgHg.psd new file mode 100644 index 00000000..e75dc132 Binary files /dev/null and b/test/data/exiv2-bug800-AgHg.psd differ diff --git a/test/data/exiv2-bug800-DCSR.jpg b/test/data/exiv2-bug800-DCSR.jpg new file mode 100644 index 00000000..28161936 Binary files /dev/null and b/test/data/exiv2-bug800-DCSR.jpg differ diff --git a/test/data/exiv2-bug800-DCSR.psd b/test/data/exiv2-bug800-DCSR.psd new file mode 100644 index 00000000..19e0939b Binary files /dev/null and b/test/data/exiv2-bug800-DCSR.psd differ diff --git a/test/data/exiv2-bug800-PHUT.jpg b/test/data/exiv2-bug800-PHUT.jpg new file mode 100644 index 00000000..f8327579 Binary files /dev/null and b/test/data/exiv2-bug800-PHUT.jpg differ diff --git a/test/data/exiv2-bug800-PHUT.psd b/test/data/exiv2-bug800-PHUT.psd new file mode 100644 index 00000000..c0077602 Binary files /dev/null and b/test/data/exiv2-bug800-PHUT.psd differ