#539: Make registration of namespaces actually work (Vladimir Nadvornik, S M Ryan)

This commit is contained in:
Andreas Huggel 2008-01-24 14:32:18 +00:00
parent 1b1df1e649
commit 2e3672d211
10 changed files with 122 additions and 21 deletions

View File

@ -54,6 +54,9 @@ set Xmp.tiff.ImageDescription lang=de-DE TIFF Bildbeschreibung
# Register a namespace which Exiv2 doesn't know yet with a prefix.
reg ns myNamespace/
# Add a property in the new custom namespace.
set Xmp.ns.myProperty myValue
# There are no built-in Exiv2 value types for structures, qualifiers and
# nested types. However, these can be added by using an XmpText value and a
# path as the key.
@ -65,7 +68,7 @@ set Xmp.xmpDM.videoFrameSize/stDim:unit inch
# Add an element with a qualifier (using the namespace registered earlier)
set Xmp.dc.publisher James Bond
set Xmp.dc.publisher/?ns:role secret agent
set Xmp.dc.publisher[1]/?ns:role secret agent
# Add a qualifer to an array element of Xmp.dc.creator (added above)
set Xmp.dc.creator[2]/?ns:role programmer

View File

@ -75,6 +75,10 @@ try {
// image, namespaces are decoded and registered at the same time.
Exiv2::XmpProperties::registerNs("myNamespace/", "ns");
// -------------------------------------------------------------------------
// Add a property in the new custom namespace.
xmpData["Xmp.ns.myProperty"] = "myValue";
// -------------------------------------------------------------------------
// There are no specialized values for structures, qualifiers and nested
// types. However, these can be added by using an XmpTextValue and a path as

View File

@ -1413,7 +1413,7 @@ namespace Action {
std::cout << _("Reg ") << modifyCmd.key_ << "=\""
<< modifyCmd.value_ << "\"" << std::endl;
}
Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_);
// Registration has been done immediately after parsing the command.
}
Modify::AutoPtr Modify::clone() const

View File

@ -1015,6 +1015,12 @@ namespace {
modifyCmd.explicitType_ = explicitType;
modifyCmd.value_ = value;
if (cmdId == reg) {
// Registration needs to be done immediately as the new namespaces are
// looked up during parsing of subsequent lines (to validate XMP keys).
Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_);
}
return true;
} // parseLine

View File

@ -43,6 +43,8 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <cstdlib>
// *****************************************************************************
// class member definitions
@ -812,16 +814,57 @@ namespace Exiv2 {
XmpProperties::NsRegistry XmpProperties::nsRegistry_;
const XmpNsInfo* XmpProperties::lookupNsRegistry(const XmpNsInfo::Prefix& prefix)
{
for (NsRegistry::const_iterator i = nsRegistry_.begin();
i != nsRegistry_.end(); ++i) {
if (i->second == prefix) return &(i->second);
}
return 0;
}
void XmpProperties::registerNs(const std::string& ns,
const std::string& prefix)
{
std::string ns2 = ns;
if ( ns2.substr(ns2.size() - 1, 1) != "/"
&& ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/";
nsRegistry_[ns2] = prefix;
// Allocated memory is freed when the namespace is unregistered.
// Using malloc/free for better system compatibility in case
// users don't unregister their namespaces explicitely.
XmpNsInfo xn;
char* c = static_cast<char*>(std::malloc(ns2.size() + 1));
std::strcpy(c, ns2.c_str());
xn.ns_ = c;
c = static_cast<char*>(std::malloc(prefix.size() + 1));
std::strcpy(c, prefix.c_str());
xn.prefix_ = c;
xn.xmpPropertyInfo_ = 0;
xn.desc_ = "";
nsRegistry_[ns2] = xn;
XmpParser::registerNs(ns2, prefix);
}
void XmpProperties::unregisterNs(const std::string& ns)
{
NsRegistry::iterator i = nsRegistry_.find(ns);
if (i != nsRegistry_.end()) {
XmpParser::unregisterNs(ns);
std::free(const_cast<char*>(i->second.prefix_));
std::free(const_cast<char*>(i->second.ns_));
nsRegistry_.erase(i);
}
}
void XmpProperties::unregisterNs()
{
NsRegistry::iterator i = nsRegistry_.begin();
while (i != nsRegistry_.end()) {
NsRegistry::iterator kill = i++;
unregisterNs(kill->first);
}
}
std::string XmpProperties::prefix(const std::string& ns)
{
std::string ns2 = ns;
@ -829,7 +872,7 @@ namespace Exiv2 {
NsRegistry::const_iterator i = nsRegistry_.find(ns2);
std::string p;
if (i != nsRegistry_.end()) {
p = i->second;
p = i->second.prefix_;
}
else {
const XmpNsInfo* xn = find(xmpNsInfo, XmpNsInfo::Ns(ns2));
@ -840,13 +883,8 @@ namespace Exiv2 {
std::string XmpProperties::ns(const std::string& prefix)
{
std::string n;
for (NsRegistry::const_iterator i = nsRegistry_.begin();
i != nsRegistry_.end(); ++i) {
if (i->second == prefix) {
return i->first;
}
}
const XmpNsInfo* xn = lookupNsRegistry(XmpNsInfo::Prefix(prefix));
if (xn != 0) return xn->ns_;
return nsInfo(prefix)->ns_;
}
@ -894,7 +932,9 @@ namespace Exiv2 {
const XmpNsInfo* XmpProperties::nsInfo(const std::string& prefix)
{
const XmpNsInfo* xn = find(xmpNsInfo, XmpNsInfo::Prefix(prefix));
const XmpNsInfo::Prefix pf(prefix);
const XmpNsInfo* xn = lookupNsRegistry(pf);
if (!xn) xn = find(xmpNsInfo, pf);
if (!xn) throw Error(35, prefix);
return xn;
}

View File

@ -181,13 +181,33 @@ namespace Exiv2 {
@brief Register namespace \em ns with preferred prefix \em prefix.
If the namespace is a known or previously registered namespace, the
prefix is overwritten. This also invalidates XMP keys generated with
the previous prefix.
prefix is overwritten.
@note This invalidates XMP keys generated with the previous prefix.
*/
static void registerNs(const std::string& ns, const std::string& prefix);
/*!
@brief Unregister a custom namespace \em ns.
The function only has an effect if there is a namespace \em ns
registered earlier, it does not unregister built-in namespaces.
@note This invalidates XMP keys generated in this namespace.
*/
static void unregisterNs(const std::string& ns);
/*!
@brief Unregister all custom namespaces.
The function only unregisters namespaces registered earlier, it does not
unregister built-in namespaces.
@note This invalidates XMP keys generated in any custom namespace.
*/
static void unregisterNs();
private:
typedef std::map<std::string, std::string> NsRegistry;
typedef std::map<std::string, XmpNsInfo> NsRegistry;
static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix);
static NsRegistry nsRegistry_;
}; // class XmpProperties

View File

@ -371,6 +371,7 @@ namespace Exiv2 {
void XmpParser::terminate()
{
XmpProperties::unregisterNs();
if (initialized_) {
#ifdef EXV_HAVE_XMP_TOOLKIT
SXMPMeta::Terminate();
@ -394,7 +395,20 @@ namespace Exiv2 {
initialize();
return true;
#endif
} // XmpParser::registerNs
} // XmpParser::registerNs
void XmpParser::unregisterNs(const std::string& ns)
{
#ifdef EXV_HAVE_XMP_TOOLKIT
try {
// Throws XMP Toolkit error 8: Unimplemented method XMPMeta::DeleteNamespace
// SXMPMeta::DeleteNamespace(ns.c_str());
}
catch (const XMP_Error& e) {
throw Error(40, e.GetID(), e.GetErrMsg());
}
#endif
} // XmpParser::unregisterNs
#ifdef EXV_HAVE_XMP_TOOLKIT
int XmpParser::decode( XmpData& xmpData,

View File

@ -257,6 +257,7 @@ namespace Exiv2 {
*/
class XmpParser {
friend void XmpProperties::registerNs(const std::string&, const std::string&);
friend void XmpProperties::unregisterNs(const std::string&);
public:
/*!
@brief Decode XMP metadata from an XMP packet \em xmpPacket into
@ -299,7 +300,7 @@ namespace Exiv2 {
*/
static bool initialize();
/*!
@brief Terminate the XMP Toolkit.
@brief Terminate the XMP Toolkit and unregister custom namespaces.
Call this method when the XmpParser is no longer needed to
allow the XMP Toolkit to cleanly shutdown.
@ -316,6 +317,12 @@ namespace Exiv2 {
*/
static bool registerNs(const std::string& ns,
const std::string& prefix);
/*!
@brief Delete a namespace from the XMP Toolkit.
XmpProperties::unregisterNs calls this to synchronize namespaces.
*/
static void unregisterNs(const std::string& ns);
// DATA
static bool initialized_; //! Indicates if the XMP Toolkit has been initialized

View File

@ -54,6 +54,9 @@ set Xmp.tiff.ImageDescription lang=de-DE TIFF Bildbeschreibung
# Register a namespace which Exiv2 doesn't know yet with a prefix.
reg ns myNamespace/
# Add a property in the new custom namespace.
set Xmp.ns.myProperty myValue
# There are no built-in Exiv2 value types for structures, qualifiers and
# nested types. However, these can be added by using an XmpText value and a
# path as the key.
@ -65,7 +68,7 @@ set Xmp.xmpDM.videoFrameSize/stDim:unit inch
# Add an element with a qualifier (using the namespace registered earlier)
set Xmp.dc.publisher James Bond
set Xmp.dc.publisher/?ns:role secret agent
set Xmp.dc.publisher[1]/?ns:role secret agent
# Add a qualifer to an array element of Xmp.dc.creator (added above)
set Xmp.dc.creator[2]/?ns:role programmer

View File

@ -293,6 +293,7 @@ Xmp.dc.format XmpText 10 image/jpeg
Xmp.dc.creator XmpSeq 3 1) The first creator, 2) The second creator, 3) And another one
Xmp.dc.description LangAlt 2 lang="x-default" Hello, World, lang="de-DE" Hallo, Welt
Xmp.tiff.ImageDescription LangAlt 2 lang="x-default" TIFF image description, lang="de-DE" TIFF Bildbeschreibung
Xmp.ns.myProperty XmpText 7 myValue
Xmp.xmpDM.videoFrameSize/stDim:w XmpText 2 16
Xmp.xmpDM.videoFrameSize/stDim:h XmpText 1 9
Xmp.xmpDM.videoFrameSize/stDim:unit XmpText 4 inch
@ -323,7 +324,8 @@ Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
dc:five="256"
dc:six="false"
dc:seven="Seven"
dc:format="image/jpeg">
dc:format="image/jpeg"
ns:myProperty="myValue">
<dc:subject>
<rdf:Bag>
<rdf:li>Palmtree</rdf:li>
@ -427,11 +429,12 @@ Set Xmp.dc.description "Hello, World" (LangAlt)
Set Xmp.tiff.ImageDescription "TIFF image description" (LangAlt)
Set Xmp.tiff.ImageDescription "lang=de-DE TIFF Bildbeschreibung" (LangAlt)
Reg ns="myNamespace/"
Set Xmp.ns.myProperty "myValue" (XmpText)
Set Xmp.xmpDM.videoFrameSize/stDim:w "16" (XmpText)
Set Xmp.xmpDM.videoFrameSize/stDim:h "9" (XmpText)
Set Xmp.xmpDM.videoFrameSize/stDim:unit "inch" (XmpText)
Set Xmp.dc.publisher "James Bond" (XmpBag)
Set Xmp.dc.publisher/?ns:role "secret agent" (XmpText)
Set Xmp.dc.publisher[1]/?ns:role "secret agent" (XmpText)
Set Xmp.dc.creator[2]/?ns:role "programmer" (XmpText)
Set Xmp.xmpBJ.JobRef "type=Bag" (XmpText)
Set Xmp.xmpBJ.JobRef[1]/stJob:name "Birthday party" (XmpText)
@ -457,8 +460,9 @@ Xmp.dc.creator[2]/?ns:role XmpText 10 programmer
Xmp.dc.creator[3] XmpText 18 3) And another one
Xmp.dc.description LangAlt 2 lang="x-default" Hello, World, lang="de-DE" Hallo, Welt
Xmp.dc.publisher XmpText 0 type="Bag"
Xmp.dc.publisher/?ns:role XmpText 12 secret agent
Xmp.dc.publisher[1] XmpText 10 James Bond
Xmp.dc.publisher[1]/?ns:role XmpText 12 secret agent
Xmp.ns.myProperty XmpText 7 myValue
Xmp.tiff.ImageDescription LangAlt 2 lang="x-default" TIFF image description, lang="de-DE" TIFF Bildbeschreibung
Xmp.xmpDM.videoFrameSize XmpText 0 type="Struct"
Xmp.xmpDM.videoFrameSize/stDim:w XmpText 2 16