|
|
|
@ -3,13 +3,20 @@
|
|
|
|
|
// Sample program to print metadata in JSON format
|
|
|
|
|
|
|
|
|
|
#include <exiv2/exiv2.hpp>
|
|
|
|
|
#include <exiv2/value.hpp>
|
|
|
|
|
#include "Jzon.h"
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
|
|
|
# ifndef __MINGW__
|
|
|
|
@ -17,11 +24,6 @@
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) || defined(__MINGW__)
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#ifndef PATH_MAX
|
|
|
|
@ -42,11 +44,13 @@ struct Token {
|
|
|
|
|
int i; // index (indexed from 1) eg History[1]/stEvt:action
|
|
|
|
|
};
|
|
|
|
|
typedef std::vector<Token> Tokens;
|
|
|
|
|
typedef std::set<std::string> Namespaces;
|
|
|
|
|
|
|
|
|
|
// "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle"
|
|
|
|
|
bool getToken(std::string& in,Token& token)
|
|
|
|
|
bool getToken(std::string& in,Token& token,Namespaces* pNS=NULL)
|
|
|
|
|
{
|
|
|
|
|
bool result = false;
|
|
|
|
|
bool ns = false;
|
|
|
|
|
|
|
|
|
|
token.n = "" ;
|
|
|
|
|
token.a = false ;
|
|
|
|
@ -58,6 +62,7 @@ bool getToken(std::string& in,Token& token)
|
|
|
|
|
in = in.substr(1,std::string::npos);
|
|
|
|
|
if ( in.length() == 0 && C != ']' ) token.n += c;
|
|
|
|
|
if ( C == '/' || C == '[' || C == ':' || C == '.' || C == ']' || in.length() == 0 ) {
|
|
|
|
|
ns |= C == '/' ;
|
|
|
|
|
token.a = C == '[' ;
|
|
|
|
|
if ( C == ']' ) token.i = std::atoi(token.n.c_str()); // encoded string first index == 1
|
|
|
|
|
result = token.n.length() > 0 ;
|
|
|
|
@ -65,6 +70,8 @@ bool getToken(std::string& in,Token& token)
|
|
|
|
|
token.n += c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ns && pNS) pNS->insert(token.n);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -95,15 +102,18 @@ Jzon::Node& recursivelyBuildTree(Jzon::Node& root,Tokens& tokens,size_t k)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build the json tree for this key. return location and discover the name
|
|
|
|
|
Jzon::Node& objectForKey(const std::string Key,Jzon::Object& root,std::string& name)
|
|
|
|
|
Jzon::Node& objectForKey(const std::string Key,Jzon::Object& root,std::string& name,Namespaces* pNS=NULL)
|
|
|
|
|
{
|
|
|
|
|
// Parse the key
|
|
|
|
|
Tokens tokens ;
|
|
|
|
|
Token token ;
|
|
|
|
|
std::string input = Key ; // Example: "XMP.xmp.MP.RegionInfo/MPRI:Regions[1]/MPReg:Rectangle"
|
|
|
|
|
while ( getToken(input,token) ) tokens.push_back(token);
|
|
|
|
|
while ( getToken(input,token,pNS) ) tokens.push_back(token);
|
|
|
|
|
size_t l = tokens.size()-1; // leave leaf name to push()
|
|
|
|
|
name = tokens[l].n ;
|
|
|
|
|
|
|
|
|
|
// The second token. For example: XMP.dc is a namespace
|
|
|
|
|
if ( pNS && tokens.size() > 1 ) pNS->insert(tokens[1].n);
|
|
|
|
|
return recursivelyBuildTree(root,tokens,l-1);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
@ -293,15 +303,39 @@ try {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef EXV_HAVE_XMP_TOOLKIT
|
|
|
|
|
if ( option == 'a' || option == 'x' ) {
|
|
|
|
|
|
|
|
|
|
Exiv2::XmpData &xmpData = image->xmpData();
|
|
|
|
|
if ( !xmpData.empty() ) {
|
|
|
|
|
// get the xmpData and recursively parse into a Jzon Object
|
|
|
|
|
Namespaces namespaces;
|
|
|
|
|
for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) {
|
|
|
|
|
std::string name ;
|
|
|
|
|
Jzon::Node& object = objectForKey(i->key(),root,name);
|
|
|
|
|
Jzon::Node& object = objectForKey(i->key(),root,name,&namespaces);
|
|
|
|
|
push(object,name,i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the namespace dictionary from XMP
|
|
|
|
|
typedef std::map<std::string,std::string> dict_t;
|
|
|
|
|
typedef std::map<std::string,std::string>::const_iterator dict_i;
|
|
|
|
|
dict_t nsDict;
|
|
|
|
|
Exiv2::XmpParser::getRegisteredNamespaces(nsDict);
|
|
|
|
|
|
|
|
|
|
// create and populate a Jzon::Object for the namespaces
|
|
|
|
|
Jzon::Object xmlns;
|
|
|
|
|
for ( Namespaces::const_iterator it = namespaces.begin() ; it != namespaces.end() ; it++ ) {
|
|
|
|
|
std::string ns = *it ;
|
|
|
|
|
std::string uri = nsDict[ns];
|
|
|
|
|
xmlns.Add(ns,uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add xmlns as Xmp.xmlns
|
|
|
|
|
root.Get("Xmp").AsObject().Add("xmlns",xmlns);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Jzon::Writer writer(root,Jzon::StandardFormat);
|
|
|
|
|
writer.Write();
|
|
|
|
|
std::cout << writer.GetResult() << std::endl;
|
|
|
|
|