parse XMP stored inside EXIF
This commit is contained in:
41
TinyEXIF.cpp
41
TinyEXIF.cpp
@@ -159,11 +159,15 @@ public:
|
|||||||
bool IsRational() const { return format == 5 || format == 10; }
|
bool IsRational() const { return format == 5 || format == 10; }
|
||||||
bool IsSRational() const { return format == 10; }
|
bool IsSRational() const { return format == 10; }
|
||||||
bool IsFloat() const { return format == 11; }
|
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 {
|
bool Fetch(std::string& val) const {
|
||||||
if (format != 2 || length == 0)
|
if (format != 2 || length == 0)
|
||||||
return false;
|
return false;
|
||||||
val = parseString(buf, length, GetData(), tiff_header_start, len, alignIntel);
|
val = FetchString();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Fetch(uint8_t& val) const {
|
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
|
// Parse tag as Exif IFD
|
||||||
void EXIFInfo::parseIFDExif(EntryParser& parser) {
|
void EXIFInfo::parseIFDExif(EntryParser& parser) {
|
||||||
switch (parser.GetTag()) {
|
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:
|
case 0x829a:
|
||||||
// Exposure time in seconds
|
// Exposure time in seconds
|
||||||
parser.Fetch(ExposureTime);
|
parser.Fetch(ExposureTime);
|
||||||
@@ -931,6 +943,16 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
// PARAM: 'len' length of buffer
|
// PARAM: 'len' length of buffer
|
||||||
//
|
//
|
||||||
int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
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 {
|
struct Tools {
|
||||||
static const char* strrnstr(const char* haystack, const char* needle, size_t len) {
|
static const char* strrnstr(const char* haystack, const char* needle, size_t len) {
|
||||||
const size_t needle_len(strlen(needle));
|
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.
|
// Skip xpacket end section so that tinyxml2 lib parses the section correctly.
|
||||||
const char* const strXMP((const char*)(buf + offs)), *strEnd;
|
const char* szEnd(Tools::strrnstr(szXML, "<?xpacket end=", len));
|
||||||
if ((strEnd=Tools::strrnstr(strXMP, "<?xpacket end=", len)) != NULL)
|
if (szEnd != NULL)
|
||||||
len = (unsigned)(strEnd - strXMP);
|
len = (unsigned)(szEnd - szXML);
|
||||||
|
|
||||||
// Try parsing the XML packet.
|
// Try parsing the XML packet.
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
const tinyxml2::XMLElement* document;
|
const tinyxml2::XMLElement* document;
|
||||||
if (doc.Parse(strXMP, len) != tinyxml2::XML_SUCCESS ||
|
if (doc.Parse(szXML, len) != tinyxml2::XML_SUCCESS ||
|
||||||
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
|
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
|
||||||
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
|
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
|
||||||
(document=document->FirstChildElement("rdf:Description")) == NULL)
|
(document=document->FirstChildElement("rdf:Description")) == NULL)
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ public:
|
|||||||
// but can be called for special cases where only the XMP section is
|
// 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").
|
// 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 parseFromXMPSegment(const uint8_t* buf, unsigned len);
|
||||||
|
int parseFromXMPSegmentXML(const char* szXML, unsigned len);
|
||||||
|
|
||||||
// Set all data members to default values.
|
// Set all data members to default values.
|
||||||
// Should be called before parsing a new stream.
|
// Should be called before parsing a new stream.
|
||||||
|
|||||||
Reference in New Issue
Block a user