From 405b8a16934f629fa602cfd71a69df2b31e2c7aa Mon Sep 17 00:00:00 2001 From: cDc Date: Tue, 9 Oct 2018 12:20:43 +0300 Subject: [PATCH] parse XMP stored inside EXIF --- TinyEXIF.cpp | 41 +++++++++++++++++++++++++++-------------- TinyEXIF.h | 1 + 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/TinyEXIF.cpp b/TinyEXIF.cpp index b12b05e..91daa74 100644 --- a/TinyEXIF.cpp +++ b/TinyEXIF.cpp @@ -159,11 +159,15 @@ public: bool IsRational() const { return format == 5 || format == 10; } bool IsSRational() const { return format == 10; } bool IsFloat() const { return format == 11; } + bool IsUndefined() const { return format == 7; } + std::string FetchString() const { + return parseString(buf, length, GetData(), tiff_header_start, len, alignIntel); + } bool Fetch(std::string& val) const { if (format != 2 || length == 0) return false; - val = parseString(buf, length, GetData(), tiff_header_start, len, alignIntel); + val = FetchString(); return true; } bool Fetch(uint8_t& val) const { @@ -392,6 +396,14 @@ void EXIFInfo::parseIFDImage(EntryParser& parser, unsigned& exif_sub_ifd_offset, // Parse tag as Exif IFD void EXIFInfo::parseIFDExif(EntryParser& parser) { switch (parser.GetTag()) { + case 0x02bc: + // XMP Metadata (Adobe technote 9-14-02) + if (parser.IsUndefined()) { + const std::string strXML(parser.FetchString()); + parseFromXMPSegmentXML(strXML.c_str(), (unsigned)strXML.length()); + } + break; + case 0x829a: // Exposure time in seconds parser.Fetch(ExposureTime); @@ -931,6 +943,16 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) { // PARAM: 'len' length of buffer // int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) { + unsigned offs = 29; // current offset into buffer + if (!buf || len < offs) + return PARSE_ABSENT_DATA; + if (!std::equal(buf, buf+offs, "http://ns.adobe.com/xap/1.0/\0")) + return PARSE_ABSENT_DATA; + if (offs >= len) + return PARSE_CORRUPT_DATA; + return parseFromXMPSegmentXML((const char*)(buf + offs), len - offs); +} +int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) { struct Tools { static const char* strrnstr(const char* haystack, const char* needle, size_t len) { const size_t needle_len(strlen(needle)); @@ -951,24 +973,15 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) { } }; - unsigned offs = 29; // current offset into buffer - if (!buf || len < offs) - return PARSE_ABSENT_DATA; - if (!std::equal(buf, buf+offs, "http://ns.adobe.com/xap/1.0/\0")) - return PARSE_ABSENT_DATA; - if (offs >= len) - return PARSE_CORRUPT_DATA; - len -= offs; - // Skip xpacket end section so that tinyxml2 lib parses the section correctly. - const char* const strXMP((const char*)(buf + offs)), *strEnd; - if ((strEnd=Tools::strrnstr(strXMP, "FirstChildElement("rdf:RDF")) == NULL || (document=document->FirstChildElement("rdf:Description")) == NULL) diff --git a/TinyEXIF.h b/TinyEXIF.h index 0513452..8ff7d4a 100644 --- a/TinyEXIF.h +++ b/TinyEXIF.h @@ -121,6 +121,7 @@ public: // but can be called for special cases where only the XMP section is // available (i.e., a blob starting with the bytes "http://ns.adobe.com/xap/1.0/\0"). int parseFromXMPSegment(const uint8_t* buf, unsigned len); + int parseFromXMPSegmentXML(const char* szXML, unsigned len); // Set all data members to default values. // Should be called before parsing a new stream.