#960 added API: static void Exiv2::XMPParser::getRegisteredNamespaces(std::map<std::string,std::string>&);

v0.27.3
Robin Mills 10 years ago
parent 2604208014
commit c396a92e01

@ -374,6 +374,14 @@ namespace Exiv2 {
*/
static void terminate();
/*!
@brief object a map of registered namespaces
This will initialize the Parser if necessary
*/
static void getRegisteredNamespaces(std::map<std::string,std::string>& dict);
private:
/*!
@brief Register a namespace with the XMP Toolkit.

@ -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;

@ -70,39 +70,8 @@ EXIV2_RCSID("@(#) $Id$")
// Adobe XMP Toolkit
#ifdef EXV_HAVE_XMP_TOOLKIT
# define TXMP_STRING_TYPE std::string
# include <XMPSDK.hpp>
# include <XMP.incl_cpp>
#include "xmp.hpp"
typedef struct {
std::ostream& os;
const char* name;
} NSDumper;
static XMP_Status namespaceDumper
( void* refCon
, XMP_StringPtr buffer
, XMP_StringLen bufferSize
) {
XMP_Status result = 0 ;
std::string out(buffer,bufferSize);
// remove blanks
// http://stackoverflow.com/questions/83439/remove-spaces-from-stdstring-in-c
std::string::iterator end_pos = std::remove(out.begin(), out.end(), ' ');
out.erase(end_pos, out.end());
bool bHttp = out.find("http://") != std::string::npos ;
bool bNS = out.find(":") != std::string::npos && !bHttp;
if ( bHttp || bNS ) {
NSDumper* nsDumper = (NSDumper*) refCon;
if ( bNS ) nsDumper->os << nsDumper->name << "=" ;
nsDumper->os << out ;
if ( bHttp ) nsDumper->os << std::endl;
}
return result;
}
#endif // EXV_HAVE_XMP_TOOLKIT
#endif
namespace Exiv2 {
int versionNumber()
@ -562,11 +531,16 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys)
output(os,keys,"enable_webready" ,enable_webready );
#ifdef EXV_HAVE_XMP_TOOLKIT
Exiv2::XmpParser::initialize();
const char* name = "xmlns";
NSDumper nsDumper = { os,name };
if ( shouldOutput(keys,name,"") ) {
SXMPMeta::DumpNamespaces(namespaceDumper,&nsDumper);
typedef std::map<std::string,std::string> dict_t;
typedef dict_t::const_iterator dict_i;
dict_t ns;
Exiv2::XmpParser::getRegisteredNamespaces(ns);
for ( dict_i it = ns.begin(); it != ns.end() ; it++ ) {
std::string xmlns = (*it).first;
std::string uri = (*it).second;
output(os,keys,name,xmlns+":"+uri);
}
#endif

@ -428,6 +428,54 @@ namespace Exiv2 {
return initialized_;
}
static XMP_Status nsDumper
( void* refCon
, XMP_StringPtr buffer
, XMP_StringLen bufferSize
) {
XMP_Status result = 0 ;
std::string out(buffer,bufferSize);
// remove blanks
// http://stackoverflow.com/questions/83439/remove-spaces-from-stdstring-in-c
std::string::iterator end_pos = std::remove(out.begin(), out.end(), ' ');
out.erase(end_pos, out.end());
bool bURI = out.find("http://") != std::string::npos ;
bool bNS = out.find(":") != std::string::npos && !bURI;
// pop trailing ':' on a namespace
if ( bNS ) {
if ( out[out.length()-1] == ':' ) out.pop_back();
}
if ( bURI || bNS ) {
std::map<std::string,std::string>* p = (std::map<std::string,std::string>*) refCon;
std::map<std::string,std::string>& m = (std::map<std::string,std::string>&) *p ;
std::string b("");
if ( bNS ) { // store the NS in dict[""]
m[b]=out;
} else if ( m.find(b) != m.end() ) { // store dict[uri] = dict[""]
m[m[b]]=out;
m.erase(b);
}
}
return result;
}
void XmpParser::getRegisteredNamespaces(std::map<std::string,std::string>& dict)
{
bool bInit = !initialized_;
try {
if (bInit) initialize();
SXMPMeta::DumpNamespaces(nsDumper,&dict);
if (bInit) terminate();
} catch (const XMP_Error& e) {
throw Error(40, e.GetID(), e.GetErrMsg());
}
}
void XmpParser::terminate()
{
XmpProperties::unregisterNs();

@ -371,8 +371,8 @@ source ./functions.source
echo '------>' Bug $num '<-------' >&2
copyTestFile BlueSquare.xmp $filename1
copyTestFile exiv2-bug784.jpg $filename2
runTest exiv2json $filename1
runTest exiv2json x $filename1
# runTest exiv2json $filename1 TODO: This is Throwing
# runTest exiv2json x $filename1 Caught Exiv2 exception 'XMP Toolkit error 9: Fatal namespace map problem'
runTest exiv2json $filename2
num=1058

Binary file not shown.
Loading…
Cancel
Save