From b6106905d5fca5692d66cb9d1d99ada0d0830fa9 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Wed, 10 Jul 2024 11:50:40 +0400 Subject: [PATCH 01/20] adds XMP-Toolkit-SDK as a submodule --- .gitmodules | 3 + src/CMakeLists.txt | 6 +- xmpsdk/CMakeLists.txt | 165 +++++++++++++++++++++------ xmpsdk/XMP-Toolkit-SDK | 1 + xmpsdk/sal_compat.h | 30 +++++ xmpsdk/third-party/expat/lib/expat.h | 4 + 6 files changed, 169 insertions(+), 40 deletions(-) create mode 100644 .gitmodules create mode 160000 xmpsdk/XMP-Toolkit-SDK create mode 100644 xmpsdk/sal_compat.h create mode 100644 xmpsdk/third-party/expat/lib/expat.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..2a87d44862 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "xmpsdk/XMP-Toolkit-SDK"] + path = xmpsdk/XMP-Toolkit-SDK + url = https://github.com/adobe/XMP-Toolkit-SDK.git diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ccf04e9c32..6670920d20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -209,7 +209,9 @@ if(EXIV2_ENABLE_XMP OR EXIV2_ENABLE_EXTERNAL_XMP) endif() if(EXIV2_ENABLE_XMP) - target_sources(exiv2lib PRIVATE $) +# target_sources(exiv2lib PRIVATE $) + target_link_libraries(exiv2lib PRIVATE exiv2-xmp exiv2-xmp-interface) + target_compile_definitions(exiv2lib PUBLIC EXV_ADOBE_XMPSDK=2016) elseif(EXIV2_ENABLE_EXTERNAL_XMP) target_link_libraries(exiv2lib PUBLIC ${XMPSDK_LIBRARY}) target_include_directories(exiv2lib PUBLIC ${XMPSDK_INCLUDE_DIR}) @@ -313,7 +315,7 @@ set(requires_private_for_pc_file write_basic_package_version_file(exiv2-config-version.cmake COMPATIBILITY ExactVersion) -install(TARGETS exiv2lib EXPORT exiv2-targets) +install(TARGETS exiv2lib exiv2-xmp exiv2-xmp-interface EXPORT exiv2-targets) include(CMakePackageConfigHelpers) configure_package_config_file( diff --git a/xmpsdk/CMakeLists.txt b/xmpsdk/CMakeLists.txt index 0156317d10..299e9deddf 100644 --- a/xmpsdk/CMakeLists.txt +++ b/xmpsdk/CMakeLists.txt @@ -1,46 +1,135 @@ add_library( - exiv2-xmp OBJECT - src/ExpatAdapter.cpp - src/MD5.cpp - src/ParseRDF.cpp - src/UnicodeConversions.cpp - src/WXMPIterator.cpp - src/WXMPMeta.cpp - src/WXMPUtils.cpp - src/XML_Node.cpp - src/XMPCore_Impl.cpp - src/XMPIterator.cpp - src/XMPMeta-GetSet.cpp - src/XMPMeta-Parse.cpp - src/XMPMeta-Serialize.cpp - src/XMPMeta.cpp - src/XMPUtils-FileInfo.cpp - src/XMPUtils.cpp - include/MD5.h - include/TXMPIterator.hpp - include/TXMPMeta.hpp - include/TXMPUtils.hpp - include/XMP_Const.h - include/XMP_Environment.h - include/XMP.incl_cpp - include/XMPSDK.hpp - include/XMP_Version.h + exiv2-xmp OBJECT + XMP-Toolkit-SDK/public/include/XMP_Const.h + XMP-Toolkit-SDK/public/include/XMP_Environment.h + XMP-Toolkit-SDK/public/include/XMP_Version.h + XMP-Toolkit-SDK/public/include/TXMPFiles.hpp + XMP-Toolkit-SDK/public/include/TXMPIterator.hpp + XMP-Toolkit-SDK/public/include/TXMPMeta.hpp + XMP-Toolkit-SDK/public/include/TXMPUtils.hpp + XMP-Toolkit-SDK/public/include/XMP.hpp + XMP-Toolkit-SDK/public/include/XMP_IO.hpp + + XMP-Toolkit-SDK/source/Endian.h + XMP-Toolkit-SDK/source/EndianUtils.hpp + XMP-Toolkit-SDK/source/ExpatAdapter.hpp + XMP-Toolkit-SDK/source/Host_IO.hpp + XMP-Toolkit-SDK/source/IOUtils.cpp + XMP-Toolkit-SDK/source/IOUtils.hpp + XMP-Toolkit-SDK/source/PerfUtils.cpp + XMP-Toolkit-SDK/source/PerfUtils.hpp + XMP-Toolkit-SDK/source/SafeStringAPIs.cpp + XMP-Toolkit-SDK/source/SafeStringAPIs.h + XMP-Toolkit-SDK/source/SafeTypes.h + XMP-Toolkit-SDK/source/SuppressSAL.h + XMP-Toolkit-SDK/source/UnicodeConversions.cpp + XMP-Toolkit-SDK/source/UnicodeConversions.hpp + XMP-Toolkit-SDK/source/UnicodeInlines.incl_cpp + XMP-Toolkit-SDK/source/XIO.cpp + XMP-Toolkit-SDK/source/XIO.hpp + XMP-Toolkit-SDK/source/XML_Node.cpp + XMP-Toolkit-SDK/source/XMLParserAdapter.hpp + XMP-Toolkit-SDK/source/XMPFiles_IO.cpp + XMP-Toolkit-SDK/source/XMPFiles_IO.hpp + XMP-Toolkit-SDK/source/XMP_LibUtils.cpp + XMP-Toolkit-SDK/source/XMP_LibUtils.hpp + XMP-Toolkit-SDK/source/XMP_ProgressTracker.cpp + XMP-Toolkit-SDK/source/XMP_ProgressTracker.hpp + + XMP-Toolkit-SDK/XMPCore/source/ExpatAdapter.cpp + XMP-Toolkit-SDK/XMPCore/source/ParseRDF.cpp + XMP-Toolkit-SDK/XMPCore/source/WXMPMeta.cpp + XMP-Toolkit-SDK/XMPCore/source/WXMPUtils.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPCore_Impl.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPIterator.cpp + XMP-Toolkit-SDK/XMPCore/source/WXMPIterator.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPMeta.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPMeta-GetSet.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPMeta-Parse.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPMeta-Serialize.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPUtils.cpp + XMP-Toolkit-SDK/XMPCore/source/XMPUtils-FileInfo.cpp + + XMP-Toolkit-SDK/third-party/zuid/interfaces/MD5.cpp ) -target_include_directories(exiv2-xmp SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/xmpsdk/include ${EXPAT_INCLUDE_DIRS}) +target_compile_features(exiv2-xmp PUBLIC cxx_std_20) + +# XMP-Toolkit-SDK includes expat as "third-party/expat/lib/expat.h". +# A wrapper header at xmpsdk/third-party/expat/lib/expat.h redirects +# this to the system expat via #include (angle brackets). +# Note: XMP-Toolkit-SDK/source/ is intentionally NOT on the include path. +# SDK files use "source/..." relative includes (resolved via the SDK root), +# and adding source/ directly causes a case-insensitive collision on Windows +# (Cygwin/MSYS2) between SDK's Endian.h and system . +target_include_directories(exiv2-xmp PRIVATE + $ + $ + $ + $ + ${EXPAT_INCLUDE_DIRS} +) # Prevent a denial-service-attack related to XML entity expansion ("billion laughs attack"). See https://bugzilla.redhat.com/show_bug.cgi?id=888769 -target_compile_definitions(exiv2-xmp PRIVATE BanAllEntityUsage=1) +target_compile_definitions(exiv2-xmp PUBLIC BanAllEntityUsage=1) + +# Mark XMP SDK headers as SYSTEM includes for consuming targets (e.g. exiv2lib). +# This suppresses most compiler warnings originating from third-party SDK headers +# when exiv2 is built with -Werror. +target_include_directories(exiv2-xmp SYSTEM PUBLIC + $ + $ + $ +) + +# Interface library grouping compiler workarounds for targets that include XMP +# SDK headers and are built with -Werror. Link against this alongside exiv2-xmp. +# +# GCC never suppresses #warning directives from system headers (unlike Clang), +# so the SYSTEM include dirs above are not enough. XMPCommonDefines.h includes +# , which GCC 15+ flags as deprecated in C++20 via #warning. With +# -Werror this becomes fatal (-Werror=cpp). +add_library(exiv2-xmp-interface INTERFACE) +target_compile_options(exiv2-xmp-interface INTERFACE $<$:-Wno-error=cpp>) + +if (WIN32) + target_sources(exiv2-xmp PRIVATE XMP-Toolkit-SDK/source/Host_IO-Win.cpp) + target_compile_definitions(exiv2-xmp PRIVATE XML_STATIC) + target_compile_definitions(exiv2-xmp PUBLIC WIN_ENV) + target_compile_definitions(exiv2-xmp PRIVATE WIN32 UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS) +endif () + +if (WIN32 AND NOT MSVC) + # Non-MSVC compilers (Clang, GCC) on Windows lack MSVC's header + # which defines SAL annotations used by the XMP SDK's SafeStringAPIs.h. + # Force-include our compatibility shim that defines them as empty. + # See sal_compat.h for details. + target_compile_options(exiv2-xmp PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/sal_compat.h) +endif () -if(WIN32) - target_compile_definitions(exiv2-xmp PRIVATE XML_STATIC) -endif() +if (MINGW) + # https://stackoverflow.com/questions/18551409/localtime-r-support-on-mingw + target_compile_definitions(exiv2-xmp PRIVATE _POSIX_THREAD_SAFE_FUNCTIONS) +endif () -if(MINGW) - # https://stackoverflow.com/questions/18551409/localtime-r-support-on-mingw - target_compile_definitions(exiv2-xmp PRIVATE _POSIX_THREAD_SAFE_FUNCTIONS) -endif() +if (APPLE) + target_sources(exiv2-xmp PRIVATE XMP-Toolkit-SDK/source/Host_IO-POSIX.cpp) + target_compile_definitions(exiv2-xmp PUBLIC MAC_ENV) +elseif (UNIX) + target_sources(exiv2-xmp PRIVATE XMP-Toolkit-SDK/source/Host_IO-POSIX.cpp) + target_compile_definitions(exiv2-xmp PUBLIC UNIX_ENV) + # The SDK's EndianUtils.hpp only auto-detects endianness for GCC on + # x86/x86_64/SPARC under UNIX_ENV. For other architectures (ARM, RISC-V, + # etc.) or non-GCC compilers, define it explicitly. + include(TestBigEndian) + test_big_endian(IS_BIG_ENDIAN) + if (IS_BIG_ENDIAN) + target_compile_definitions(exiv2-xmp PRIVATE kBigEndianHost=1) + else () + target_compile_definitions(exiv2-xmp PRIVATE kBigEndianHost=0) + endif () +endif () -if(BUILD_SHARED_LIBS) - set_property(TARGET exiv2-xmp PROPERTY POSITION_INDEPENDENT_CODE ON) -endif() +if (BUILD_SHARED_LIBS) + set_property(TARGET exiv2-xmp PROPERTY POSITION_INDEPENDENT_CODE ON) +endif () diff --git a/xmpsdk/XMP-Toolkit-SDK b/xmpsdk/XMP-Toolkit-SDK new file mode 160000 index 0000000000..581c41213d --- /dev/null +++ b/xmpsdk/XMP-Toolkit-SDK @@ -0,0 +1 @@ +Subproject commit 581c41213ddcee1fbc72cbb532531102a6617a25 diff --git a/xmpsdk/sal_compat.h b/xmpsdk/sal_compat.h new file mode 100644 index 0000000000..4156f831a9 --- /dev/null +++ b/xmpsdk/sal_compat.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// SAL (Source Annotation Language) compatibility for non-MSVC compilers on Windows. +// +// The XMP-Toolkit-SDK uses MSVC SAL annotations (e.g. _Check_return_wat_, +// _In_z_, _Out_z_cap_) in SafeStringAPIs.h. These annotations are defined +// in MSVC's header. The SDK's SuppressSAL.h provides empty +// definitions for all SAL macros, but only activates on non-Windows +// platforms (#if !defined(_WIN32) && !defined(_WIN64)). +// +// Non-MSVC compilers on Windows (e.g. MSYS2-Clang, MinGW-GCC) define +// _WIN32 but don't ship MSVC's , so the SAL macros remain undefined +// and compilation fails. +// +// This header works around the issue by temporarily undefining _WIN32/_WIN64 +// so that SuppressSAL.h's guard condition passes and the SAL macros get +// defined as empty. push_macro/pop_macro restores _WIN32/_WIN64 afterward +// so the rest of the build sees them normally. +// +// Used via -include in the meson build for non-MSVC Windows compilers. + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(_MSC_VER) +#pragma push_macro("_WIN32") +#pragma push_macro("_WIN64") +#undef _WIN32 +#undef _WIN64 +#include "source/SuppressSAL.h" +#pragma pop_macro("_WIN64") +#pragma pop_macro("_WIN32") +#endif diff --git a/xmpsdk/third-party/expat/lib/expat.h b/xmpsdk/third-party/expat/lib/expat.h new file mode 100644 index 0000000000..9cfe98d3b1 --- /dev/null +++ b/xmpsdk/third-party/expat/lib/expat.h @@ -0,0 +1,4 @@ +// Wrapper to redirect XMP-Toolkit-SDK's hardcoded expat include to the system expat. +// Using angle brackets so the search skips this wrapper (found via the deep relative +// path "third-party/expat/lib/expat.h") and finds the system expat.h directly. +#include From f5c7ee5375c0e874c9bf8513f4ee2738f12b38ce Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Wed, 10 Jul 2024 11:55:55 +0400 Subject: [PATCH 02/20] removes in source copy of XMP-Toolkit-sdk --- xmpsdk/include/MD5.h | 49 - xmpsdk/include/TXMPIterator.hpp | 235 -- xmpsdk/include/TXMPMeta.hpp | 1803 -------------- xmpsdk/include/TXMPUtils.hpp | 965 -------- xmpsdk/include/XMP.incl_cpp | 63 - xmpsdk/include/XMPSDK.hpp | 89 - xmpsdk/include/XMP_Const.h | 1311 ---------- xmpsdk/include/XMP_Environment.h | 164 -- xmpsdk/include/XMP_Version.h | 45 - .../include/client-glue/TXMPIterator.incl_cpp | 226 -- xmpsdk/include/client-glue/TXMPMeta.incl_cpp | 935 ------- xmpsdk/include/client-glue/TXMPUtils.incl_cpp | 493 ---- xmpsdk/include/client-glue/WXMPFiles.hpp | 167 -- xmpsdk/include/client-glue/WXMPIterator.hpp | 83 - xmpsdk/include/client-glue/WXMPMeta.hpp | 622 ----- xmpsdk/include/client-glue/WXMPUtils.hpp | 322 --- xmpsdk/include/client-glue/WXMP_Common.hpp | 123 - xmpsdk/src/ExpatAdapter.cpp | 507 ---- xmpsdk/src/ExpatAdapter.hpp | 50 - xmpsdk/src/MD5.cpp | 235 -- xmpsdk/src/ParseRDF.cpp | 1296 ---------- xmpsdk/src/UnicodeConversions.cpp | 1665 ------------- xmpsdk/src/UnicodeConversions.hpp | 121 - xmpsdk/src/UnicodeInlines.incl_cpp | 129 - xmpsdk/src/WXMPIterator.cpp | 188 -- xmpsdk/src/WXMPMeta.cpp | 1310 ---------- xmpsdk/src/WXMPUtils.cpp | 626 ----- xmpsdk/src/XMLParserAdapter.hpp | 140 -- xmpsdk/src/XML_Node.cpp | 463 ---- xmpsdk/src/XMPCore_Impl.cpp | 1468 ----------- xmpsdk/src/XMPCore_Impl.hpp | 534 ---- xmpsdk/src/XMPIterator.cpp | 736 ------ xmpsdk/src/XMPIterator.hpp | 148 -- xmpsdk/src/XMPMeta-GetSet.cpp | 1212 --------- xmpsdk/src/XMPMeta-Parse.cpp | 1306 ---------- xmpsdk/src/XMPMeta-Serialize.cpp | 1342 ---------- xmpsdk/src/XMPMeta.cpp | 1653 ------------- xmpsdk/src/XMPMeta.hpp | 418 ---- xmpsdk/src/XMPUtils-FileInfo.cpp | 1346 ---------- xmpsdk/src/XMPUtils.cpp | 2157 ----------------- xmpsdk/src/XMPUtils.hpp | 221 -- xmpsdk/src/XMP_BuildInfo.h | 22 - 42 files changed, 26988 deletions(-) delete mode 100644 xmpsdk/include/MD5.h delete mode 100644 xmpsdk/include/TXMPIterator.hpp delete mode 100644 xmpsdk/include/TXMPMeta.hpp delete mode 100644 xmpsdk/include/TXMPUtils.hpp delete mode 100644 xmpsdk/include/XMP.incl_cpp delete mode 100644 xmpsdk/include/XMPSDK.hpp delete mode 100644 xmpsdk/include/XMP_Const.h delete mode 100644 xmpsdk/include/XMP_Environment.h delete mode 100644 xmpsdk/include/XMP_Version.h delete mode 100644 xmpsdk/include/client-glue/TXMPIterator.incl_cpp delete mode 100644 xmpsdk/include/client-glue/TXMPMeta.incl_cpp delete mode 100644 xmpsdk/include/client-glue/TXMPUtils.incl_cpp delete mode 100644 xmpsdk/include/client-glue/WXMPFiles.hpp delete mode 100644 xmpsdk/include/client-glue/WXMPIterator.hpp delete mode 100644 xmpsdk/include/client-glue/WXMPMeta.hpp delete mode 100644 xmpsdk/include/client-glue/WXMPUtils.hpp delete mode 100644 xmpsdk/include/client-glue/WXMP_Common.hpp delete mode 100644 xmpsdk/src/ExpatAdapter.cpp delete mode 100644 xmpsdk/src/ExpatAdapter.hpp delete mode 100644 xmpsdk/src/MD5.cpp delete mode 100644 xmpsdk/src/ParseRDF.cpp delete mode 100644 xmpsdk/src/UnicodeConversions.cpp delete mode 100644 xmpsdk/src/UnicodeConversions.hpp delete mode 100644 xmpsdk/src/UnicodeInlines.incl_cpp delete mode 100644 xmpsdk/src/WXMPIterator.cpp delete mode 100644 xmpsdk/src/WXMPMeta.cpp delete mode 100644 xmpsdk/src/WXMPUtils.cpp delete mode 100644 xmpsdk/src/XMLParserAdapter.hpp delete mode 100644 xmpsdk/src/XML_Node.cpp delete mode 100644 xmpsdk/src/XMPCore_Impl.cpp delete mode 100644 xmpsdk/src/XMPCore_Impl.hpp delete mode 100644 xmpsdk/src/XMPIterator.cpp delete mode 100644 xmpsdk/src/XMPIterator.hpp delete mode 100644 xmpsdk/src/XMPMeta-GetSet.cpp delete mode 100644 xmpsdk/src/XMPMeta-Parse.cpp delete mode 100644 xmpsdk/src/XMPMeta-Serialize.cpp delete mode 100644 xmpsdk/src/XMPMeta.cpp delete mode 100644 xmpsdk/src/XMPMeta.hpp delete mode 100644 xmpsdk/src/XMPUtils-FileInfo.cpp delete mode 100644 xmpsdk/src/XMPUtils.cpp delete mode 100644 xmpsdk/src/XMPUtils.hpp delete mode 100644 xmpsdk/src/XMP_BuildInfo.h diff --git a/xmpsdk/include/MD5.h b/xmpsdk/include/MD5.h deleted file mode 100644 index 5556049b2f..0000000000 --- a/xmpsdk/include/MD5.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __MD5_h__ -#define __MD5_h__ - -/* - * This is the header file for the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5_CTX structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' - * header definitions; now uses stuff from dpkg's config.h - * - Ian Jackson . - * Still in the public domain. - */ - -#include - -#include - -/* MSVC doesn't provide C99 types, but it has MS specific variants */ -#ifdef _MSC_VER -typedef unsigned __int32 uint32_t; -#endif - -typedef unsigned char md5byte; -typedef uint32_t UWORD32; - -struct MD5_CTX { - UWORD32 buf[4]; - UWORD32 bytes[2]; - UWORD32 in[16]; -}; - -extern void MD5Init(struct MD5_CTX *context); -extern void MD5Update(struct MD5_CTX *context, md5byte const *buf, unsigned len); -extern void MD5Final(unsigned char digest[16], struct MD5_CTX *context); -extern void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); - -#endif diff --git a/xmpsdk/include/TXMPIterator.hpp b/xmpsdk/include/TXMPIterator.hpp deleted file mode 100644 index 33c73a1fbb..0000000000 --- a/xmpsdk/include/TXMPIterator.hpp +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef __TXMPIterator_hpp__ -#define __TXMPIterator_hpp__ 1 - -#if ( ! __XMP_hpp__ ) - #error "Do not directly include, use XMPSDK.hpp" -#endif - -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================= -/// \file TXMPIterator.hpp -/// \brief API for access to the XMP Toolkit iteration services. -/// -/// \c TXMPIterator is the template class providing iteration services for the XMP Toolkit. It must -/// be instantiated with a string class such as \c std::string. See the instructions in XMPSDK.hpp, and -/// the Overview for a discussion of the overall architecture of the XMP API. -// ================================================================================================= - -// ================================================================================================= -/// \class TXMPIterator TXMPIterator.hpp -/// @brief API for access to the XMP Toolkit iteration services. -/// -/// \c TXMPIterator provides a uniform means to iterate over the schema and properties within an XMP -/// object. \c TXMPIterator is a template class which must be instantiated with a string class such -/// as \c std::string. See the instructions in XMPSDK.hpp, and the Overview for a discussion of the -/// overall architecture of the XMP API. Access these functions through the concrete class, -/// \c SXMPIterator. -/// -/// @note Only XMP object iteration is currently available. Future development may include iteration -/// over global tables, such as registered namespaces. -/// -/// To understand how iteration works, you should have a thorough understanding of the XMP data -/// tree, as described in the XMP Specification Part 1. You might also find it helpful to create -/// some complex XMP and examine the output of \c TXMPMeta::DumpObject(). -/// -/// \li The top of the XMP data tree is a single root node. This does not explicitly appear in the -/// dump and is never visited by an iterator; that is, it is never returned from -/// \c TXMPIterator::Next(). -/// -/// \li Beneath the root are schema nodes; these collect the top-level properties in the same -/// namespace. They are created and destroyed implicitly. -/// -/// \li Beneath the schema nodes are the property nodes. The nodes below a property node depend on -/// its type (simple, struct, or array) and whether it has qualifiers. -/// -/// A \c TXMPIterator constructor defines a starting point for the iteration, and options that -/// control how it proceeds. By default, iteration starts at the root and visits all nodes beneath -/// it in a depth-first manner. The root node iteself is not visited; the first visited node is a -/// schema node. You can provide a schema name or property path to select a different starting node. -/// By default, this visits the named root node first then all nodes beneath it in a depth-first -/// manner. -/// -/// The function \c TXMPIterator::Next() delivers the schema URI, path, and option flags for the -/// node being visited. If the node is simple, it also delivers the value. Qualifiers for this node -/// are visited next. The fields of a struct or items of an array are visited after the qualifiers -/// of the parent. -/// -/// You can specify options when constructing the iteration object to control how the iteration is -/// performed. -/// -/// \li \c #kXMP_IterJustChildren - Visit just the immediate children of the root. Skip the root -/// itself and all nodes below the immediate children. This omits the qualifiers of the immediate -/// children, the qualifier nodes being below what they qualify. -/// \li \c #kXMP_IterJustLeafNodes - Visit just the leaf property nodes and their qualifiers. -/// \li \c #kXMP_IterJustLeafName - Return just the leaf component of the node names. The default -/// is to return the full path name. -/// \li \c #kXMP_IterIncludeAliases - Include aliases as part of the iteration. Since aliases are -/// not actual nodes the default iteration does not visit them. -/// \li \c #kXMP_IterOmitQualifiers - Do not visit the qualifiers of a node. -// ================================================================================================= - -#include "client-glue/WXMPIterator.hpp" - -template class TXMPIterator { - -public: - - // --------------------------------------------------------------------------------------------- - /// @brief Assignment operator, assigns the internal ref and increments the ref count. - /// - /// Assigns the internal reference from an existing object and increments the reference count on - /// the underlying internal XMP iterator. - /// - /// @param rhs An existing iteration object. - - void operator= ( const TXMPIterator & rhs ); - - // --------------------------------------------------------------------------------------------- - /// @brief Copy constructor, creates a client object refering to the same internal object. - /// - /// Creates a new client iterator that refers to the same underlying iterator as an existing object. - /// - /// @param original An existing iteration object to copy. - - TXMPIterator ( const TXMPIterator & original ); - - // --------------------------------------------------------------------------------------------- - /// @brief Constructs an iterator for properties within a schema in an XMP object. - /// - /// See the class description for the general operation of an XMP object iterator. - /// Overloaded forms are provided to iterate the entire data tree, - /// a subtree rooted at a specific node, or properties within a specific schema. - /// - /// @param xmpObj The XMP object over which to iterate. - /// - /// @param schemaNS Optional schema namespace URI to restrict the iteration. To visit all of the - /// schema, pass 0 or the empty string "". - /// - /// @param propName Optional property name to restrict the iteration. May be an arbitrary path - /// expression. If provided, a schema URI must also be provided. To visit all properties, pass 0 - /// or the empty string "". - /// - /// @param options Option flags to control the iteration. A logical OR of these bit flag constants: - /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees. - /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes. - /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path. - /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers. - /// - /// @return The new TXMPIterator object. - - TXMPIterator ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief Constructs an iterator for a subtree of properties within an XMP object. - /// - /// See the class description for the general operation of an XMP object iterator. Overloaded - /// forms are provided to iterate the entire data tree, a subtree rooted at a specific node, or - /// properties within a specific schema. - /// - /// @param xmpObj The XMP object over which to iterate. - /// - /// @param schemaNS Optional schema namespace URI to restrict the iteration. To visit all of the - /// schema, pass 0 or the empty string "". - /// - /// @param options Option flags to control the iteration. A logical OR of these bit flag constants: - /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees. - /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes. - /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path. - /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers. - /// - /// @return The new TXMPIterator object. - - TXMPIterator ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief Constructs an iterator for the entire data tree within an XMP object. - /// - /// See the class description for the general operation of an XMP object iterator. Overloaded - /// forms are provided to iterate the entire data tree, a subtree rooted at a specific node, or - /// properties within a specific schema. - /// - /// @param xmpObj The XMP object over which to iterate. - /// - /// @param options Option flags to control the iteration. A logical OR of these bit flag constants: - /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees. - /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes. - /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path. - /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers. - /// - /// @return The new \c TXMPIterator object. - - TXMPIterator ( const TXMPMeta & xmpObj, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief Constructs an iterator for the global tables of the XMP toolkit. Not implemented. - - TXMPIterator ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - /// @brief Destructor, typical virtual destructor. - - virtual ~TXMPIterator() throw(); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Next() visits the next node in the iteration. - /// - /// Proceeds to the next node according to the options specified on creation of this object, and - /// delivers the schema URI, path, and option flags for the node being visited. If the node is - /// simple, it also delivers the value. - /// - /// @param schemaNS [out] A string object in which to return the assigned the schema namespace - /// URI of the current property. Can be null if the value is not wanted. - /// - /// @param propPath [out] A string object in which to return the XPath name of the current - /// property. Can be null if the value is not wanted. - /// - /// @param propValue [out] A string object in which to return the value of the current - /// property. Can be null if the value is not wanted. - /// - /// @param options [out] A buffer in which to return the flags describing the current property, - /// which are a logical OR of \c #XMP_OptionBits bit-flag constants. - /// - /// @return True if there was another node to visit, false if the iteration is complete. - - bool Next ( tStringObj * schemaNS = 0, - tStringObj * propPath = 0, - tStringObj * propValue = 0, - XMP_OptionBits * options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Skip() skips some portion of the remaining iterations. - /// - /// @param options Option flags to control the iteration, a logical OR of these bit-flag - /// constants: - /// \li \c #kXMP_IterSkipSubtree - Skip the subtree below the current node. - /// \li \c #kXMP_IterSkipSiblings - Skip the subtree below and remaining siblings of the current node. - - void Skip ( XMP_OptionBits options ); - -private: - - XMPIteratorRef iterRef; - - TXMPIterator(); // ! Hidden, must choose property or table iteration. - -}; // class TXMPIterator - -// ================================================================================================= - -#endif // __TXMPIterator_hpp__ diff --git a/xmpsdk/include/TXMPMeta.hpp b/xmpsdk/include/TXMPMeta.hpp deleted file mode 100644 index 0bf04e15ac..0000000000 --- a/xmpsdk/include/TXMPMeta.hpp +++ /dev/null @@ -1,1803 +0,0 @@ -#ifndef __TXMPMeta_hpp__ -#define __TXMPMeta_hpp__ 1 - -#if ( ! __XMP_hpp__ ) - #error "Do not directly include, use XMPSDK.hpp" -#endif - -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================= -/// \file TXMPMeta.hpp -/// \brief API for access to the XMP Toolkit core services. -/// -/// \c TXMPMeta is the template class providing the core services of the XMP Toolkit. It must be -/// instantiated with a string class such as \c std::string. Read the Toolkit Overview for -/// information about the overall architecture of the XMP API, and the documentation for \c XMPSDK.hpp -/// for specific instantiation instructions. -/// -/// Access these functions through the concrete class, \c SXMPMeta. -// ================================================================================================= - -// ================================================================================================= -/// \class TXMPMeta TXMPMeta.hpp -/// \brief API for access to the XMP Toolkit core services. -/// -/// \c TXMPMeta is the template class providing the core services of the XMP Toolkit. It should be -/// instantiated with a string class such as \c std::string. Read the Toolkit Overview for -/// information about the overall architecture of the XMP API, and the documentation for \c XMPSDK.hpp -/// for specific instantiation instructions. -/// -/// Access these functions through the concrete class, \c SXMPMeta. -/// -/// You can create \c TXMPMeta objects (also called XMP objects) from metadata that you construct, -/// or that you obtain from files using the XMP Toolkit's XMPFiles component; see \c TXMPFiles.hpp. -// ================================================================================================= - -template class TXMPIterator; -template class TXMPUtils; - -// ------------------------------------------------------------------------------------------------- - -template class TXMPMeta { - -public: - - // ============================================================================================= - // Initialization and termination - // ============================== - - // --------------------------------------------------------------------------------------------- - /// \name Initialization and termination - /// - /// @{ - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetVersionInfo() retrieves runtime version information. - /// - /// The header \c XMPVersion.hpp defines a static version number for the XMP Toolkit, which - /// describes the version of the API used at client compile time. It is not necessarily the same - /// as the runtime version. Do not base runtime decisions on the static version alone; you can, - /// however, compare the runtime and static versions. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). The - /// function can be called before calling \c TXMPMeta::Initialize(). - /// - /// @param info [out] A buffer in which to return the version information. - - static void GetVersionInfo ( XMP_VersionInfo * info ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Initialize() explicitly initializes the XMP Toolkit before use. */ - - /// Initializes the XMP Toolkit. - /// - /// Call this function before making any other calls to the \c TXMPMeta functions, except - /// \c TXMPMeta::GetVersionInfo(). - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @return True on success. */ - static bool Initialize(); - // --------------------------------------------------------------------------------------------- - /// @brief \c Terminate() explicitly terminates usage of the XMP Toolkit. - /// - /// Frees structures created on initialization. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - - static void Terminate(); - - /// @} - - // ============================================================================================= - // Constuctors and destructor - // ========================= - - // --------------------------------------------------------------------------------------------- - /// \name Constructors and destructor - /// @{ - - // --------------------------------------------------------------------------------------------- - /// @brief Default constructor, creates an empty object. - /// - /// The default constructor creates a new empty \c TXMPMeta object. - /// - /// @return The new object. */ - TXMPMeta(); - - // --------------------------------------------------------------------------------------------- - /// @brief Copy constructor, creates a client object refering to the same internal object. - /// - /// The copy constructor creates a new \c TXMPMeta object that refers to the same internal XMP - /// object. as an existing \c TXMPMeta object. - /// - /// @param original The object to copy. - /// - /// @return The new object. */ - - TXMPMeta ( const TXMPMeta & original ); - - // --------------------------------------------------------------------------------------------- - /// @brief Assignment operator, assigns the internal reference and increments the reference count. - /// - /// The assignment operator assigns the internal ref from the rhs object and increments the - /// reference count on the underlying internal XMP object. - - void operator= ( const TXMPMeta & rhs ); - - // --------------------------------------------------------------------------------------------- - /// @brief Reconstructs an XMP object from an internal reference. - /// - /// This constructor creates a new \c TXMPMeta object that refers to the underlying reference object - /// of an existing \c TXMPMeta object. Use to safely pass XMP objects across DLL boundaries. - /// - /// @param xmpRef The underlying reference object, obtained from some other XMP object with - /// \c TXMPMeta::GetInternalRef(). - /// - /// @return The new object. - - TXMPMeta ( XMPMetaRef xmpRef ); - - // --------------------------------------------------------------------------------------------- - /// @brief Constructs an object and parse one buffer of RDF into it. - /// - /// This constructor creates a new \c TXMPMeta object and populates it with metadata from a - /// buffer containing serialized RDF. This buffer must be a complete RDF parse stream. - /// - /// The result of passing serialized data to this function is identical to creating an empty - /// object then calling \c TXMPMeta::ParseFromBuffer(). To use the constructor, however, the RDF - /// must be complete. If you need to parse data from multiple buffers, create an empty object - /// and use \c TXMPMeta::ParseFromBuffer(). - /// - /// @param buffer A pointer to the buffer of RDF to be parsed. Can be null if the length is 0; - /// in this case, the function creates an empty object. - /// - /// @param xmpSize The length in bytes of the buffer. - /// - /// @return The new object. - - TXMPMeta ( XMP_StringPtr buffer, - XMP_StringLen xmpSize ); - - // --------------------------------------------------------------------------------------------- - /// @brief Destructor, typical virtual destructor. */ - virtual ~TXMPMeta() throw(); - - /// @} - - // ============================================================================================= - // Global state functions - // ====================== - - // --------------------------------------------------------------------------------------------- - /// \name Global option flags - /// @{ - /// Global option flags affect the overall behavior of the XMP Toolkit. The available options - /// will be declared in \c XMP_Const.h. There are none in this version of the Toolkit. - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetGlobalOptions() retrieves the set of global option flags. There are none in - /// this version of the Toolkit. - /// - /// This function is static; you can make the call from the class without instantiating it. - /// - /// @return A logical OR of global option bit-flag constants. - - static XMP_OptionBits GetGlobalOptions(); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetGlobalOptions() updates the set of global option flags. There are none in this - /// version of the Toolkit. - /// - /// The entire set is replaced with the new values. If only one flag is to be modified, use - /// \c TXMPMeta::GetGlobalOptions() to obtain the current set, modify the desired flag, then use - /// this function to reset the value. - /// - /// This function is static; you can make the call from the class without instantiating it. - /// - /// @param options A logical OR of global option bit-flag constants. - - static void SetGlobalOptions ( XMP_OptionBits options ); - - /// @} - - // --------------------------------------------------------------------------------------------- - /// \name Internal data structure dump utilities - /// @{ - /// - /// These are debugging utilities that dump internal data structures, to be handled by - /// client-defined callback described in \c XMP_Const.h. - /// - /// @see Member function \c TXMPMeta::DumpObject() - - // --------------------------------------------------------------------------------------------- - /// @brief \c DumpNamespaces() sends the list of registered namespace URIs and prefixes to a handler. - /// - /// For debugging. Invokes a client-defined callback for each line of output. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param outProc The client-defined procedure to handle each line of output. - /// - /// @param clientData A pointer to client-defined data to pass to the handler. - /// - /// @return A success-fail status value, returned from the handler. Zero is success, failure - /// values are client-defined. - - static XMP_Status DumpNamespaces ( XMP_TextOutputProc outProc, - void * clientData ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DumpAliases() sends the list of registered aliases and corresponding actuals to a handler. - /// - /// For debugging. Invokes a client-defined callback for each line of output. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param outProc The client-defined procedure to handle each line of output. - /// - /// @param clientData A pointer to client-defined data to pass to the handler. - /// - /// @return A success-fail status value, returned from the handler. Zero is success, failure - /// values are client-defined. - - static XMP_Status DumpAliases ( XMP_TextOutputProc outProc, - void * clientData ); - - /// @} - - // --------------------------------------------------------------------------------------------- - /// \name Namespace Functions - /// @{ - /// - /// Namespaces must be registered before use in namespace URI parameters or path expressions. - /// Within the XMP Toolkit the registered namespace URIs and prefixes must be unique. Additional - /// namespaces encountered when parsing RDF are automatically registered. - /// - /// The namespace URI should always end in an XML name separator such as '/' or '#'. This is - /// because some forms of RDF shorthand catenate a namespace URI with an element name to form a - /// new URI. - - // --------------------------------------------------------------------------------------------- - /// @brief \c RegisterNamespace() registers a namespace URI with a prefix. - /// - /// If the the prefix is in use, the URI of the existing prefix is overwritten. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param namespaceURI The URI for the namespace. Must be a valid XML URI. - /// - /// @param prefix The prefix to be used. Must be a valid XML name. - /// - /// @note No checking is done on either the URI or the prefix. */ - - static void RegisterNamespace ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetNamespacePrefix() obtains the prefix for a registered namespace URI, and - /// reports whether the URI is registered. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param namespaceURI The URI for the namespace. Must not be null or the empty string. It is - /// not an error if the namespace URI is not registered. - /// - /// @param namespacePrefix [out] A string object in which to return the prefix registered for - /// this URI, with a terminating colon character, ':'. If the namespace is not registered, this - /// string is not modified. - /// - /// @return True if the namespace URI is registered. - - static bool GetNamespacePrefix ( XMP_StringPtr namespaceURI, - tStringObj * namespacePrefix ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetNamespaceURI() obtains the URI for a registered namespace prefix, and reports - /// whether the prefix is registered. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param namespacePrefix The prefix for the namespace. Must not be null or the empty string. - /// It is not an error if the namespace prefix is not registered. - /// - /// @param namespaceURI [out] A string object in which to return the URI registered for this - /// prefix. If the prefix is not registered, this string is not modified. - /// - /// @return True if the namespace prefix is registered. - - static bool GetNamespaceURI ( XMP_StringPtr namespacePrefix, - tStringObj * namespaceURI ); - - // --------------------------------------------------------------------------------------------- - /// @brief Not implemented. - /// - /// Deletes a namespace from the registry. Does nothing if the URI is not registered, or if the - /// parameter is null or the empty string. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param namespaceURI The URI for the namespace. - - static void DeleteNamespace ( XMP_StringPtr namespaceURI ); - - /// @} - - // --------------------------------------------------------------------------------------------- - /// \name Alias functions - /// @{ - /// - /// Aliases in XMP serve the same purpose as Windows file shortcuts, Mac OS file aliases, or - /// UNIX file symbolic links. The aliases are multiple names for the same property. One - /// distinction of XMP aliases is that they are ordered. An alias name points to an actual name; - /// the primary significance of the actual name is that it is the preferred name for output, - /// generally the most widely recognized name. - /// - /// XMP restricts the names that can be aliased. The alias must be a top-level property name, - /// not a field within a structure or an element within an array. The actual can be a top-level - /// property name, the first element within a top-level array, or the default element in an - /// alt-text array. This does not mean the alias can only be a simple property; you can alias a - /// top-level structure or array to an identical top-level structure or array, or to the first - /// item of an array of structures. - - // --------------------------------------------------------------------------------------------- - /// @brief \c RegisterAlias() associates an alias name with an actual name. - /// - /// Defines an alias mapping from one namespace/property to another. Both property names must be - /// simple names. An alias can be a direct mapping, where the alias and actual have the same - /// data type. It is also possible to map a simple alias to an item in an array. This can either - /// be to the first item in the array, or to the 'x-default' item in an alt-text array. Multiple - /// alias names can map to the same actual, as long as the forms match. It is a no-op to - /// reregister an alias in an identical fashion. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string. - /// - /// @param aliasProp The name of the alias. Must be a simple name, not null or the empty string - /// and not a general path expression. - /// - /// @param actualNS The namespace URI for the actual. Must not be null or the empty string. - /// - /// @param actualProp The name of the actual. Must be a simple name, not null or the empty string - /// and not a general path expression. - /// - /// @param arrayForm Provides the array form for simple aliases to an array item. This is needed - /// to know what kind of array to create if set for the first time via the simple alias. Pass - /// \c #kXMP_NoOptions, the default value, for all direct aliases regardless of whether the actual - /// data type is an array or not. One of these constants: - /// - /// \li \c #kXMP_NoOptions - This is a direct mapping. The actual data type does not matter. - /// \li \c #kXMP_PropValueIsArray - The actual is an unordered array, the alias is to the - /// first element of the array. - /// \li \c #kXMP_PropArrayIsOrdered - The actual is an ordered array, the alias is to the - /// first element of the array. - /// \li \c #kXMP_PropArrayIsAlternate - The actual is an alternate array, the alias is to the - /// first element of the array. - /// \li \c #kXMP_PropArrayIsAltText - The actual is an alternate text array, the alias is to - /// the 'x-default' element of the array. */ - - static void RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm = kXMP_NoOptions ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ResolveAlias() reports whether a name is an alias, and what it is aliased to. - /// - /// Output strings are not written until return, so you can use this to - /// "reduce" a path to the base form as follows: - ///
-    ///   isAlias = SXMPMeta::ResolveAlias ( ns.c_str(), path.c_str(), &ns, &path, 0 );
-    /// 
- /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string. - /// - /// @param aliasProp The name of the alias. Can be an arbitrary path expression path, must not - /// null or the empty string. - /// - /// @param actualNS [out] A string object in which to return the namespace URI for the actual. - /// Not modified if the given name is not an alias. Can be null if the namespace URI is not wanted. - /// - /// @param actualProp [out] A string object in which to return the path of the actual. - /// Not modified if the given name is not an alias. Can be null if the actual's path is not wanted. - /// - /// @param arrayForm [out] A string object in which to return the array form of the actual. This - /// is 0 (\c #kXMP_NoOptions) if the alias and actual forms match, otherwise it is the options - /// passed to \c TXMPMeta::RegisterAlias(). Not modified if the given name is not an alias. Can - /// be null if the actual's array form is not wanted. - /// - /// @return True if the provided name is an alias. - - static bool ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - tStringObj * actualNS, - tStringObj * actualProp, - XMP_OptionBits * arrayForm ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DeleteAlias() deletes an alias. - /// - /// This deletes only the registration of the alias, it does not delete the actual property. - /// It deletes any view of the property through the alias name. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string. - /// - /// @param aliasProp The name of the alias. Must be a simple name, not null or the empty string - /// and not a general path expression. It is not an error to provide - /// a name that has not been registered as an alias. - - static void DeleteAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c RegisterStandardAliases() registers all of the built-in aliases for a standard namespace. - /// - /// The built-in aliases are documented in the XMP Specification. This function registers the - /// aliases in the given namespace; that is, it creates the aliases from this namespace to - /// actuals in other namespaces. - /// - /// This function is static; make the call directly from the concrete class (\c SXMPMeta). - /// - /// @param schemaNS The namespace URI for the aliases. Must not be null or the empty string. - - static void RegisterStandardAliases ( XMP_StringPtr schemaNS ); - - /// @} - - // ============================================================================================= - // Basic property manipulation functions - // ===================================== - - // *** Should add discussion of schemaNS and propName prefix usage. - - // --------------------------------------------------------------------------------------------- - /// \name Accessing property values - /// @{ - /// - /// The property value accessors all take a property specification; the top level namespace URI - /// (the "schema" namespace) and the basic name of the property being referenced. See the - /// introductory discussion of path expression usage for more information. - /// - /// The accessor functions return true if the specified property exists. If it does, output - /// parameters return the value (if any) and option flags describing the property. The option - /// bit-flag constants that describe properties are \c kXMP_PropXx and - /// \c kXMP_ArrayIsXx. See \c #kXMP_PropValueIsURI and following, and macros \c #XMP_PropIsSimple - /// and following in \c XMP_Const.h. If the property exists and has a value, it is returned as a - /// Unicode string in UTF-8 encoding. Arrays and the non-leaf levels of structs do not have - /// values. - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty() reports whether a property exists, and retrieves its value. - /// - /// This is the simplest property accessor. Use this to retrieve the values of top-level simple - /// properties, or after using the path composition functions in \c TXMPUtils. - /// - /// When specifying a namespace and path (in this and all other accessors): - /// \li If a namespace URI is specified, it must be for a registered namespace. - /// \li If the namespace is specified only by a prefix in the property name path, - /// it must be a registered prefix. - /// \li If both a URI and path prefix are present, they must be corresponding - /// parts of a registered namespace. - /// - /// @param schemaNS The namespace URI for the property. The URI must be for a registered - /// namespace. Can be null or the empty string if the first component of the \c propName path - /// contains a namespace prefix. - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string. The first component can be a namespace prefix; if present without a - /// \c schemaNS value, the prefix specifies the namespace. The prefix must be for a registered - /// namespace, and if a namespace URI is specified, must match the registered prefix for that - /// namespace. - /// - /// @param propValue [out] A string object in which to return the value of the property, if the - /// property exists and has a value. Arrays and non-leaf levels of structs do not have values. - /// Can be null if the value is not wanted. - /// - /// @param options A buffer in which to return option flags describing the property. Can be null - /// if the flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - tStringObj * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetArrayItem() provides access to items within an array. - /// - /// Reports whether the item exists; if it does, and if it has a value, the function retrieves - /// the value. Items are accessed by an integer index, where the first item has index 1. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem - /// to specify the last existing array item. - /// - /// @param itemValue [out] A string object in which to return the value of the array item, if it - /// has a value. Arrays and non-leaf levels of structs do not have values. Can be null if the - /// value is not wanted. - /// - /// @param options [out] A buffer in which to return the option flags describing the array item. - /// Can be null if the flags are not wanted. - /// - /// @return True if the array item exists. - - bool GetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - tStringObj * itemValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetStructField() provides access to fields within a nested structure. - /// - /// Reports whether the field exists; if it does, and if it has a value, the function retrieves - /// the value. - /// - /// @param schemaNS The namespace URI for the struct; see \c GetProperty(). - /// - /// @param structName The name of the struct. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field. Same URI and prefix usage as the \c schemaNS - /// and \c structName parameters. - /// - /// @param fieldName The name of the field. Must be a single XML name, must not be null or the - /// empty string. Same URI and prefix usage as the \c schemaNS and \c structName parameters. - /// - /// @param fieldValue [out] A string object in which to return the value of the field, if the - /// field has a value. Arrays and non-leaf levels of structs do not have values. Can be null if - /// the value is not wanted. - /// - /// @param options [out] A buffer in which to return the option flags describing the field. Can - /// be null if the flags are not wanted. - /// - /// @return True if the field exists. - - bool GetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - tStringObj * fieldValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetQualifier() provides access to a qualifier attached to a property. - /// - /// @note In this version of the Toolkit, qualifiers are supported only for simple leaf properties. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property to which the qualifier is attached. Can be a - /// general path expression, must not be null or the empty string; see \c GetProperty() for - /// namespace prefix usage. - /// - /// @param qualNS The namespace URI for the qualifier. Same URI and prefix usage as the - /// \c schemaNS and \c propName parameters. - /// - /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or - /// the empty string. Same URI and prefix usage as the \c schemaNS and \c propName parameters. - /// - /// @param qualValue [out] A string object in which to return the value of the qualifier, if the - /// qualifier has a value. Arrays and non-leaf levels of structs do not have values. Can be null - /// if the value is not wanted. - /// - /// @param options [out] A buffer in which to return the option flags describing the qualifier. - /// Can be null if the flags are not wanted. - /// - /// @return True if the qualifier exists. - - bool GetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - tStringObj * qualValue, - XMP_OptionBits * options ) const; - - /// @} - - // ============================================================================================= - - // --------------------------------------------------------------------------------------------- - /// \name Creating properties and setting their values - /// @{ - /// - /// These functions all take a property specification; the top level namespace URI (the "schema" - /// namespace) and the basic name of the property being referenced. See the introductory - /// discussion of path expression usage for more information. - /// - /// All of the functions take a UTF-8 encoded Unicode string for the property value. Arrays and - /// non-leaf levels of structs do not have values. The value can be passed as an - /// \c #XMP_StringPtr (a pointer to a null-terminated string), or as a string object - /// (\c tStringObj). - - /// Each function takes an options flag that describes the property. You can use these functions - /// to create empty arrays and structs by setting appropriate option flags. When you assign a - /// value, all levels of a struct that are implicit in the assignment are created if necessary. - /// \c TXMPMeta::AppendArrayItem() implicitly creates the named array if necessary. - /// - /// The allowed option bit-flags include: - /// \li \c #kXMP_PropValueIsStruct - Can be used to create an empty struct. - /// A struct is implicitly created when the first field is set. - /// \li \c #kXMP_PropValueIsArray - By default, a general unordered array (bag). - /// \li \c #kXMP_PropArrayIsOrdered - An ordered array. - /// \li \c #kXMP_PropArrayIsAlternate - An alternative array. - /// \li \c #kXMP_PropArrayIsAltText - An alt-text array. Each array element must - /// be a simple property with an \c xml:lang attribute. - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty() creates or sets a property value. - /// - /// This is the simplest property setter. Use it for top-level simple properties, or after using - /// the path composition functions in \c TXMPUtils. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new value, a pointer to a null terminated UTF-8 string. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty() creates or sets a property value using a string object. - /// - /// Overloads the basic form of the function, allowing you to pass a string object - /// for the item value. It is otherwise identical; see details in the canonical form. - - void SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const tStringObj & propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetArrayItem() creates or sets the value of an item within an array. - /// - /// Items are accessed by an integer index, where the first item has index 1. This function - /// creates the item if necessary, but the array itself must already exist Use - /// \c AppendArrayItem() to create arrays. A new item is automatically appended if the index is the - /// array size plus 1. To insert a new item before or after an existing item, use option flags. - /// - /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem - /// to specify the last existing array item. - /// - /// @param itemValue The new item value, a null-terminated UTF-8 string, if the array item has a - /// value. - /// - /// @param options Option flags describing the array type and insertion location for a new item; - /// a logical OR of allowed bit-flag constants. The type, if specified, must match the existing - /// array type, \c #kXMP_PropArrayIsOrdered, \c #kXMP_PropArrayIsAlternate, or - /// \c #kXMP_PropArrayIsAltText. Default (0 or \c #kXMP_NoOptions) matches the existing array type. - /// - /// To insert a new item before or after the specified index, set flag \c #kXMP_InsertBeforeItem - /// or \c #kXMP_InsertAfterItem. - - void SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetArrayItem() creates or sets the value of an item within an array using a string object. - /// - /// Overloads the basic form of the function, allowing you to pass a string object in which to - /// return the item value. It is otherwise identical; see details in the canonical form. - - void SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - const tStringObj & itemValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c AppendArrayItem() adds an item to an array, creating the array if necessary. - /// - /// This function simplifies construction of an array by not requiring that you pre-create an - /// empty array. The array that is assigned is created automatically if it does not yet exist. - /// If the array exists, it must have the form specified by the options. Each call appends a new - /// item to the array. - /// - /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param arrayOptions Option flags describing the array type to create; a logical OR of - /// allowed bit-flag constants, \c #kXMP_PropArrayIsOrdered, \c #kXMP_PropArrayIsAlternate, or - /// \c #kXMP_PropArrayIsAltText. If the array exists, must match the existing array type or be - /// null (0 or \c #kXMP_NoOptions). - /// - /// @param itemValue The new item value, a null-terminated UTF-8 string, if the array item has a - /// value. - /// - /// @param itemOptions Option flags describing the item type to create; one of the bit-flag - /// constants \c #kXMP_PropValueIsArray or \c #kXMP_PropValueIsStruct to create a complex array - /// item. - - void AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits itemOptions = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c AppendArrayItem() adds an item to an array using a string object value, creating - /// the array if necessary. - /// - /// Overloads the basic form of the function, allowing you to pass a string object in which to - /// return the item value. It is otherwise identical; see details in the canonical form. - - void AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - const tStringObj & itemValue, - XMP_OptionBits itemOptions = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetStructField() creates or sets the value of a field within a nested structure. - /// - /// Use this to set a value within an existing structure, create a new field within an existing - /// structure, or create an empty structure of any depth. If you set a field in a structure that - /// does not exist, the structure is automatically created. - /// - /// Use \c TXMPUtils::ComposeStructFieldPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param structName The name of the struct. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param fieldName The name of the field. Must be a single XML name, must not be null or the - /// empty string. Same namespace and prefix usage as \c GetProperty(). - /// - /// @param fieldValue The new value, a null-terminated UTF-8 string, if the field has a value. - /// Null to create a new, empty struct or empty field in an existing struct. - /// - /// @param options Option flags describing the property, in which the bit-flag - /// \c #kXMP_PropValueIsStruct must be set to create a struct. - - void SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetStructField() creates or sets the value of a field within a nested structure, - /// using a string object. - /// - /// Overloads the basic form of the function, allowing you to pass a string object in which to - /// return the field value. It is otherwise identical; see details in the canonical form. - - void SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - const tStringObj & fieldValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetQualifier() creates or sets a qualifier attached to a property. - /// - /// Use this to set a value for an existing qualifier, or create a new qualifier. <> Use - /// \c TXMPUtils::ComposeQualifierPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property to which the qualifier is attached. Can be a - /// general path expression, must not be null or the empty string; see \c GetProperty() for - /// namespace prefix usage. - /// - /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or - /// the empty string. Same namespace and prefix usage as \c GetProperty(). - /// - /// @param qualValue The new value, a null-terminated UTF-8 string, if the qualifier has a - /// value. Null to create a new, empty qualifier. - /// - /// @param options Option flags describing the <>, a logical OR - /// of property-type bit-flag constants. Use the macro \c #XMP_PropIsQualifier to create a - /// qualifier. <> - - void SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetQualifier() creates or sets a qualifier attached to a property using a string object. - /// - /// Overloads the basic form of the function, allowing you to pass a string object - /// for the qualifier value. It is otherwise identical; see details in the canonical form. - - void SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - const tStringObj & qualValue, - XMP_OptionBits options = 0 ); - - /// @} - - // ============================================================================================= - - // --------------------------------------------------------------------------------------------- - /// \name Detecting and deleting properties. - /// @{ - /// - /// The namespace URI and prefix usage for property specifiers in these functions is the same as - /// for \c TXMPMeta::GetProperty(). - - // --------------------------------------------------------------------------------------------- - /// @brief \c DeleteProperty() deletes an XMP subtree rooted at a given property. - /// - /// It is not an error if the property does not exist. - /// - /// @param schemaNS The namespace URI for the property; see \c GetProperty(). - /// - /// @param propName The name of the property; see \c GetProperty(). - - void DeleteProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DeleteArrayItem() deletes an XMP subtree rooted at a given array item. - /// - /// It is not an error if the array item does not exist. Use - /// \c TXMPUtils::ComposeArrayItemPath() to create a complex path. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem - /// to specify the last existing array item. - - void DeleteArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DeleteStructField() deletes an XMP subtree rooted at a given struct field. - /// - /// It is not an error if the field does not exist. - /// - /// @param schemaNS The namespace URI for the struct; see \c GetProperty(). - /// - /// @param structName The name of the struct. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param fieldName The name of the field. Must be a single XML name, must not be null or the - /// empty string. Same namespace and prefix usage as \c GetProperty(). - - void DeleteStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DeleteQualifier() deletes an XMP subtree rooted at a given qualifier. - /// - /// It is not an error if the qualifier does not exist. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property to which the qualifier is attached. Can be a - /// general path expression, must not be null or the empty string; see \c GetProperty() for - /// namespace prefix usage. - /// - /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or - /// the empty string. Same namespace and prefix usage as \c GetProperty(). - - void DeleteQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DoesPropertyExist() reports whether a property currently exists. - /// - /// @param schemaNS The namespace URI for the property; see \c GetProperty(). - /// - /// @param propName The name of the property; see \c GetProperty(). - /// - /// @return True if the property exists. - - bool DoesPropertyExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c DoesArrayItemExist() reports whether an array item currently exists. - /// - /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem - /// to specify the last existing array item. - /// - /// @return True if the array item exists. - - bool DoesArrayItemExist ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c DoesStructFieldExist() reports whether a struct field currently exists. - /// - /// Use \c TXMPUtils::ComposeStructFieldPath() to create a complex path. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param structName The name of the struct. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param fieldName The name of the field. Must be a single XML name, must not be null or the - /// empty string. Same namespace and prefix usage as \c GetProperty(). - /// - /// @return True if the field exists. - - bool DoesStructFieldExist ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c DoesQualifierExist() reports whether a qualifier currently exists. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property to which the qualifier is attached. Can be a - /// general path expression, must not be null or the empty string; see \c GetProperty() for - /// namespace prefix usage. - /// - /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as - /// \c GetProperty(). - /// - /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or - /// the empty string. Same namespace and prefix usage as \c GetProperty(). - /// - /// @return True if the qualifier exists. - - bool DoesQualifierExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) const; - - /// @} - - // ============================================================================================= - // Specialized Get and Set functions - // ============================================================================================= - - // --------------------------------------------------------------------------------------------- - /// \name Accessing properties as binary values. - /// @{ - /// - /// These are very similar to \c TXMPMeta::GetProperty() and \c TXMPMeta::SetProperty(), except - /// that the value is returned or provided in binary form instead of as a UTF-8 string. - /// \c TXMPUtils provides functions for converting between binary and string values. - /// Use the path composition functions in \c TXMPUtils to compose complex path expressions - /// for fields or items in nested structures or arrays, or for qualifiers. - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty_Bool() retrieves the value of a Boolean property as a C++ bool. - /// - /// Reports whether a property exists, and retrieves its binary value and property type information. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue [out] A buffer in which to return the binary value. Can be null if the - /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have - /// values. - /// - /// @param options [out] A buffer in which to return the option flags describing the property, a - /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can - /// be null if flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty_Int() retrieves the value of an integer property as a C long integer. - /// - /// Reports whether a property exists, and retrieves its binary value and property type information. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue [out] A buffer in which to return the binary value. Can be null if the - /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have - /// values. - /// - /// @param options [out] A buffer in which to return the option flags describing the property, a - /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can - /// be null if flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty_Int64() retrieves the value of an integer property as a C long long integer. - /// - /// Reports whether a property exists, and retrieves its binary value and property type information. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue [out] A buffer in which to return the binary value. Can be null if the - /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have - /// values. - /// - /// @param options [out] A buffer in which to return the option flags describing the property, a - /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can - /// be null if flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long long * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty_Float() retrieves the value of a floating-point property as a C double float. - /// - /// Reports whether a property exists, and retrieves its binary value and property type information. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue [out] A buffer in which to return the binary value. Can be null if the - /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have - /// values. - /// - /// @param options [out] A buffer in which to return the option flags describing the property, a - /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can - /// be null if flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetProperty_Date() retrieves the value of a date-time property as an \c #XMP_DateTime structure. - /// - /// Reports whether a property exists, and retrieves its binary value and property type information. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue [out] A buffer in which to return the binary value. Can be null if the - /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have - /// values. - /// - /// @param options [out] A buffer in which to return the option flags describing the property, a - /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can - /// be null if flags are not wanted. - /// - /// @return True if the property exists. - - bool GetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty_Bool() sets the value of a Boolean property using a C++ bool. - /// - /// Sets a property with a binary value, creating it if necessary. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new binary value. Can be null if creating the property. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty_Int() sets the value of an integer property using a C long integer. - /// - /// Sets a property with a binary value, creating it if necessary. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new binary value. Can be null if creating the property. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty_Int64() sets the value of an integer property using a C long long integer. - /// - /// Sets a property with a binary value, creating it if necessary. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new binary value. Can be null if creating the property. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long long propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty_Float() sets the value of a floating-point property using a C double float. - /// - /// Sets a property with a binary value, creating it if necessary. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new binary value. Can be null if creating the property. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetProperty_Date() sets the value of a date/time property using an \c #XMP_DateTime structure. - /// - /// Sets a property with a binary value, creating it if necessary. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param propValue The new binary value. Can be null if creating the property. Must be null - /// for arrays and non-leaf levels of structs that do not have values. - /// - /// @param options Option flags describing the property; a logical OR of allowed bit-flag - /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property - /// that already exists. - - void SetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options = 0 ); - - /// @} - // ============================================================================================= - /// \name Accessing localized text (alt-text) properties. - /// @{ - /// - /// Localized text properties are stored in alt-text arrays. They allow multiple concurrent - /// localizations of a property value, for example a document title or copyright in several - /// languages. - /// - /// These functions provide convenient support for localized text properties, including a - /// number of special and obscure aspects. The most important aspect of these functions is that - /// they select an appropriate array item based on one or two RFC 3066 language tags. One of - /// these languages, the "specific" language, is preferred and selected if there is an exact - /// match. For many languages it is also possible to define a "generic" language that can be - /// used if there is no specific language match. The generic language must be a valid RFC 3066 - /// primary subtag, or the empty string. - /// - /// For example, a specific language of "en-US" should be used in the US, and a specific - /// language of "en-UK" should be used in England. It is also appropriate to use "en" as the - /// generic language in each case. If a US document goes to England, the "en-US" title is - /// selected by using the "en" generic language and the "en-UK" specific language. - /// - /// It is considered poor practice, but allowed, to pass a specific language that is just an - /// RFC 3066 primary tag. For example "en" is not a good specific language, it should only be - /// used as a generic language. Passing "i" or "x" as the generic language is also considered - /// poor practice but allowed. - /// - /// Advice from the W3C about the use of RFC 3066 language tags can be found at: - /// \li http://www.w3.org/International/articles/language-tags/ - /// - /// \note RFC 3066 language tags must be treated in a case insensitive manner. The XMP toolkit - /// does this by normalizing their capitalization: - /// \li The primary subtag is lower case, the suggested practice of ISO 639. - /// \li All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166. - /// \li All other subtags are lower case. - /// - /// The XMP specification defines an artificial language, "x-default", that is used to - /// explicitly denote a default item in an alt-text array. The XMP toolkit normalizes alt-text - /// arrays such that the x-default item is the first item. The \c SetLocalizedText() function - /// has several special features related to the x-default item, see its description for details. - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetLocalizedText() retrieves information about a selected item in an alt-text array. - /// - /// The array item is selected according to these rules: - /// \li Look for an exact match with the specific language. - /// \li If a generic language is given, look for a partial match. - /// \li Look for an x-default item. - /// \li Choose the first item. - /// - /// A partial match with the generic language is where the start of the item's language matches - /// the generic string and the next character is '-'. An exact match is also recognized as a - /// degenerate case. - /// - /// You can pass "x-default" as the specific language. In this case, selection of an - /// \c x-default item is an exact match by the first rule, not a selection by the 3rd rule. The - /// last 2 rules are fallbacks used when the specific and generic languages fail to produce a - /// match. - /// - /// The return value reports whether a match was successfully made. - /// - /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty(). - /// - /// @param altTextName The name of the alt-text array. Can be a general path expression, must - /// not be null or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be - /// null or the empty string if no generic language is wanted. - /// - /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default". - /// Must not be null or the empty string. - /// - /// @param actualLang [out] A string object in which to return the language of the selected - /// array item, if an appropriate array item is found. Can be null if the language is not wanted. - /// - /// @param itemValue [out] A string object in which to return the value of the array item, if an - /// appropriate array item is found. Can be null if the value is not wanted. - /// - /// @param options A buffer in which to return the option flags that describe the array item, if - /// an appropriate array item is found. Can be null if the flags are not wanted. - /// - /// @return True if an appropriate array item exists. - - bool GetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - tStringObj * actualLang, - tStringObj * itemValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetLocalizedText() modifies the value of a selected item in an alt-text array. - /// - /// Creates an appropriate array item if necessary, and handles special cases for the x-default - /// item. - /// - /// The array item is selected according to these rules: - /// \li Look for an exact match with the specific language. - /// \li If a generic language is given, look for a partial match. - /// \li Look for an x-default item. - /// \li Choose the first item. - /// - /// A partial match with the generic language is where the start of the item's language matches - /// the generic string and the next character is '-'. An exact match is also recognized as a - /// degenerate case. - /// - /// You can pass "x-default" as the specific language. In this case, selection of an - /// \c x-default item is an exact match by the first rule, not a selection by the 3rd rule. The - /// last 2 rules are fallbacks used when the specific and generic languages fail to produce a - /// match. - /// - /// Item values are modified according to these rules: - /// - /// \li If the selected item is from a match with the specific language, the value of that - /// item is modified. If the existing value of that item matches the existing value of the - /// x-default item, the x-default item is also modified. If the array only has 1 existing item - /// (which is not x-default), an x-default item is added with the given value. - /// - /// \li If the selected item is from a match with the generic language and there are no other - /// generic matches, the value of that item is modified. If the existing value of that item - /// matches the existing value of the x-default item, the x-default item is also modified. If - /// the array only has 1 existing item (which is not x-default), an x-default item is added - /// with the given value. - /// - /// \li If the selected item is from a partial match with the generic language and there are - /// other partial matches, a new item is created for the specific language. The x-default item - /// is not modified. - /// - /// \li If the selected item is from the last 2 rules then a new item is created for the - /// specific language. If the array only had an x-default item, the x-default item is also - /// modified. If the array was empty, items are created for the specific language and - /// x-default. - /// - /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty(). - /// - /// @param altTextName The name of the alt-text array. Can be a general path expression, must - /// not be null or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be - /// null or the empty string if no generic language is wanted. - /// - /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default". - /// Must not be null or the empty string. - /// - /// @param itemValue The new value for the matching array item, specified as a null-terminated - /// UTF-8 string. - /// - /// @param options Option flags, none currently defined. - - void SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetLocalizedText() modifies the value of a selected item in an alt-text array using - /// a string object. - /// - /// Creates an appropriate array item if necessary, and handles special cases for the x-default - /// item. - /// - /// The array item is selected according to these rules: - /// \li Look for an exact match with the specific language. - /// \li If a generic language is given, look for a partial match. - /// \li Look for an x-default item. - /// \li Choose the first item. - /// - /// A partial match with the generic language is where the start of the item's language matches - /// the generic string and the next character is '-'. An exact match is also recognized as a - /// degenerate case. - /// - /// You can pass "x-default" as the specific language. In this case, selection of an \c x-default - /// item is an exact match by the first rule, not a selection by the 3rd rule. The last 2 rules - /// are fallbacks used when the specific and generic languages fail to produce a match. - /// - /// Item values are modified according to these rules: - /// - /// \li If the selected item is from a match with the specific language, the value of that - /// item is modified. If the existing value of that item matches the existing value of the - /// x-default item, the x-default item is also modified. If the array only has 1 existing item - /// (which is not x-default), an x-default item is added with the given value. - /// - /// \li If the selected item is from a match with the generic language and there are no other - /// generic matches, the value of that item is modified. If the existing value of that item - /// matches the existing value of the x-default item, the x-default item is also modified. If - /// the array only has 1 existing item (which is not x-default), an x-default item is added - /// with the given value. - /// - /// \li If the selected item is from a partial match with the generic language and there are - /// other partial matches, a new item is created for the specific language. The x-default item - /// is not modified. - /// - /// \li If the selected item is from the last 2 rules then a new item is created for the - /// specific language. If the array only had an x-default item, the x-default item is also - /// modified. If the array was empty, items are created for the specific language and - /// x-default. - /// - /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty(). - /// - /// @param altTextName The name of the alt-text array. Can be a general path expression, must - /// not be null or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be - /// null or the empty string if no generic language is wanted. - /// - /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default". - /// Must not be null or the empty string. - /// - /// @param itemValue The new value for the matching array item, specified as a string object. - /// - /// @param options Option flags, none currently defined. - - void SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - const tStringObj & itemValue, - XMP_OptionBits options = 0 ); - - /// @} - - // ============================================================================================= - /// \name Creating and reading serialized RDF. - /// @{ - /// - /// The metadata contained in an XMP object must be serialized as RDF for storage in an XMP - /// packet and output to a file. Similarly, metadata in the form of serialized RDF (such as - /// metadata read from a file using \c TXMPFiles) must be parsed into an XMP object for - /// manipulation with the XMP Toolkit. - /// - /// These functions support parsing serialized RDF into an XMP object, and serializing an XMP - /// object into RDF. The input for parsing can be any valid Unicode encoding. ISO Latin-1 is - /// also recognized, but its use is strongly discouraged. Serialization is always as UTF-8. - - // --------------------------------------------------------------------------------------------- - /// @brief \c ParseFromBuffer() parses RDF from a series of input buffers into this XMP object. - /// - /// Use this to convert metadata from serialized RDF form (as, for example, read from an XMP - /// packet embedded in a file) into an XMP object that you can manipulate with the XMP Toolkit. - /// If this XMP object is empty and the input buffer contains a complete XMP packet, this is the - /// same as creating a new XMP object from that buffer with the constructor. - /// - /// You can use this function to combine multiple buffers into a single metadata tree. To - /// terminate an input loop conveniently, pass the option \c #kXMP_ParseMoreBuffers for all - /// real input, then make a final call with a zero length and \c #kXMP_NoOptions. The buffers - /// can be any length. The buffer boundaries need not respect XML tokens or even Unicode - /// characters. - /// - /// @param buffer A pointer to a buffer of input. Can be null if \c bufferSize is 0. - /// - /// @param bufferSize The length of the input buffer in bytes. Zero is a valid value. - /// - /// @param options An options flag that controls how the parse operation is performed. A logical - /// OR of these bit-flag constants: - /// \li \c #kXMP_ParseMoreBuffers - This is not the last buffer of input, more calls follow. - /// \li \c #kXMP_RequireXMPMeta - The \c x:xmpmeta XML element is required around \c rdf:RDF. - /// - /// @see \c TXMPFiles::GetXMP() - - void ParseFromBuffer ( XMP_StringPtr buffer, - XMP_StringLen bufferSize, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SerializeToBuffer() serializes metadata in this XMP object into a string as RDF. - /// - /// Use this to prepare metadata for storage as an XMP packet embedded in a file. See \c TXMPFiles::PutXMP(). - /// - /// @param rdfString [out] A string object in which to return the serialized RDF. Must not be null. - /// - /// @param options An options flag that controls how the serialization operation is performed. - /// The specified options must be logically consistent; an exception is thrown if they are not. - /// A logical OR of these bit-flag constants: - /// \li \c kXMP_OmitPacketWrapper - Do not include an XML packet wrapper. This cannot be - /// specified together with \c #kXMP_ReadOnlyPacket, \c #kXMP_IncludeThumbnailPad, or - /// \c #kXMP_ExactPacketLength. - /// \li \c kXMP_ReadOnlyPacket - Create a read-only XML packet wapper. Cannot be specified - /// together with \c kXMP_OmitPacketWrapper. - /// \li \c kXMP_UseCompactFormat - Use a highly compact RDF syntax and layout. - /// \li \c kXMP_WriteAliasComments - Include XML comments for aliases. - /// \li \c kXMP_IncludeThumbnailPad - Include typical space for a JPEG thumbnail in the - /// padding if no \c xmp:Thumbnails property is present. Cannot be specified together with - /// \c kXMP_OmitPacketWrapper. - /// \li \c kXMP_ExactPacketLength - The padding parameter provides the overall packet length. - /// The actual amount of padding is computed. An exception is thrown if the packet exceeds - /// this length with no padding. Cannot be specified together with - /// \c kXMP_OmitPacketWrapper. - /// - /// In addition to the above options, you can include one of the following encoding options: - /// \li \c #kXMP_EncodeUTF8 - Encode as UTF-8, the default. - /// \li \c #kXMP_EncodeUTF16Big - Encode as big-endian UTF-16. - /// \li \c #kXMP_EncodeUTF16Little - Encode as little-endian UTF-16. - /// \li \c #kXMP_EncodeUTF32Big - Encode as big-endian UTF-32. - /// \li \c #kXMP_EncodeUTF32Little - Encode as little-endian UTF-32. - /// - /// @param padding The amount of padding to be added if a writeable XML packet is created. If - /// zero (the default) an appropriate amount of padding is computed. - /// - /// @param newline The string to be used as a line terminator. If empty, defaults to linefeed, - /// U+000A, the standard XML newline. - /// - /// @param indent The string to be used for each level of indentation in the serialized RDF. If - /// empty, defaults to two ASCII spaces, U+0020. - /// - /// @param baseIndent The number of levels of indentation to be used for the outermost XML - /// element in the serialized RDF. This is convenient when embedding the RDF in other text. - - void SerializeToBuffer ( tStringObj * rdfString, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent = "", - XMP_Index baseIndent = 0 ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c SerializeToBuffer() serializes metadata in this XMP object into a string as RDF. - /// - /// This simpler form of the function uses default values for the \c newline, \c indent, and - /// \c baseIndent parameters. - /// - /// @param rdfString [out] A string object in which to return the serialized RDF. Must not be null. - /// - /// @param options An options flag that controls how the serialization operation is performed. - /// The specified options must be logically consistent; an exception is thrown if they are not. - /// A logical OR of these bit-flag constants: - /// \li \c kXMP_OmitPacketWrapper - Do not include an XML packet wrapper. This cannot be - /// specified together with \c #kXMP_ReadOnlyPacket, \c #kXMP_IncludeThumbnailPad, or - /// \c #kXMP_ExactPacketLength. - /// \li \c kXMP_ReadOnlyPacket - Create a read-only XML packet wapper. Cannot be specified - /// together with \c kXMP_OmitPacketWrapper. - /// \li \c kXMP_UseCompactFormat - Use a highly compact RDF syntax and layout. - /// \li \c kXMP_WriteAliasComments - Include XML comments for aliases. - /// \li \c kXMP_IncludeThumbnailPad - Include typical space for a JPEG thumbnail in the - /// padding if no \c xmp:Thumbnails property is present. Cannot be specified together with - /// \c kXMP_OmitPacketWrapper. - /// \li \c kXMP_ExactPacketLength - The padding parameter provides the overall packet length. - /// The actual amount of padding is computed. An exception is thrown if the packet exceeds - /// this length with no padding. Cannot be specified together with - /// \c kXMP_OmitPacketWrapper. - /// - /// In addition to the above options, you can include one of the following encoding options: - /// \li \c #kXMP_EncodeUTF8 - Encode as UTF-8, the default. - /// \li \c #kXMP_EncodeUTF16Big - Encode as big-endian UTF-16. - /// \li \c #kXMP_EncodeUTF16Little - Encode as little-endian UTF-16. - /// \li \c #kXMP_EncodeUTF32Big - Encode as big-endian UTF-32. - /// \li \c #kXMP_EncodeUTF32Little - Encode as little-endian UTF-32. - /// - /// @param padding The amount of padding to be added if a writeable XML packet is created. - /// If zero (the default) an appropriate amount of padding is computed. - - void SerializeToBuffer ( tStringObj * rdfString, - XMP_OptionBits options = 0, - XMP_StringLen padding = 0 ) const; - - /// @} - // ============================================================================================= - // Miscellaneous Member Functions - // ============================== - - // --------------------------------------------------------------------------------------------- - /// \name Helper functions. - /// @{ - - // --------------------------------------------------------------------------------------------- - /// @brief Retrieves an internal reference that can be safely passed across DLL boundaries and - /// reconstructed. - /// - /// The \c TXMPMeta class is a normal C++ template, it is instantiated and local to each client - /// executable, as are the other \c TXMP* classes. Different clients might not use the same - /// string type to instantiate \c TXMPMeta. - /// - /// Because of this you should not pass \c SXMPMeta objects, or pointers to \c SXMPMeta objects, - /// across DLL boundaries. Use this function to obtain a safe internal reference that you can - /// pass, then construct a local object on the callee side. This construction does not create a - /// cloned XMP tree, it is the same underlying XMP object safely wrapped in each client's - /// \c SXMPMeta object. - /// - /// Use this function and the associated constructor like this: - /// \li The callee's header contains: - ///
-    /// CalleeMethod ( XMPMetaRef xmpRef );
-    /// 
- /// - /// \li The caller's code contains: - ///
-    /// SXMPMeta callerXMP;
-    /// CalleeMethod ( callerXMP.GetInternalRef() );
-    /// 
- /// - /// \li The callee's code contains: - ///
-    /// SXMPMeta calleeXMP ( xmpRef );
-    /// 
- /// - /// @return The reference object. - - XMPMetaRef GetInternalRef() const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c GetObjectName() retrieves the client-assigned name of this XMP object. - /// - /// Assign this name with \c SetObjectName(). - /// - /// @param name [out] A string object in which to return the name. - - void GetObjectName ( tStringObj * name ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetObjectName() assigns a name to this XMP object. - /// - /// Retrieve this client-assigned name with \c GetObjectName(). - /// - /// @param name The name as a null-terminated UTF-8 string. - - void SetObjectName ( XMP_StringPtr name ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetObjectName() assigns a name to this XMP object. - /// - /// Retrieve this client-assigned name with \c GetObjectName(). - /// - /// @param name The name as a string object. - - void SetObjectName ( tStringObj name ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Sort() sorts the data model tree of an XMP object. - /// - /// Use this function to sort the data model of an XMP object into a canonical order. This can - /// be convenient when comparing data models, (e.g. by text comparison of DumpObject output). - /// - /// At the top level the namespaces are sorted by their prefixes. Within a namespace, the top - /// level properties are sorted by name. Within a struct, the fields are sorted by their - /// qualified name, i.e. their XML prefix:local form. Unordered arrays of simple items are - /// sorted by value. Language Alternative arrays are sorted by the xml:lang qualifiers, with - /// the "x-default" item placed first. - - void Sort(); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Erase() restores the object to a "just constructed" state. - - void Erase(); - - // --------------------------------------------------------------------------------------------- - /// @brief \c Clone() creates a deep copy of an XMP object. - /// - /// Use this function to copy an entire XMP metadata tree. Assignment and copy constructors only - /// increment a reference count, they do not do a deep copy. This function returns an object, - /// not a pointer. The following shows correct usage: - /// - ///
-    /// SXMPMeta * clone1 = new SXMPMeta ( sourceXMP.Clone() );  // This works.
-    /// SXMPMeta   clone2 ( sourceXMP.Clone );  	// This works also. (Not a pointer.)
-    /// 
- /// The \c clone2 example does not use an explicit pointer. - /// This is good for local usage, protecting against memory leaks. - /// - /// This is an example of incorrect usage: - ///
-    /// SXMPMeta * clone3 = &sourceXMP.Clone();		// ! This does not work!
-    /// 
- /// The assignment to \c clone3 creates a temporary object, initializes it with the clone, - /// assigns the address of the temporary to \c clone3, then deletes the temporary. - /// - /// @param options Option flags, not currently defined.. - /// - /// @return An XMP object cloned from the original. - - TXMPMeta Clone ( XMP_OptionBits options = 0 ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c CountArrayItems() reports the number of items currently defined in an array. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @return The number of items. - - XMP_Index CountArrayItems ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief \c DumpObject() outputs the content of an XMP object to a callback handler for debugging. - /// - /// Invokes a client-defined callback for each line of output. - /// - /// @param outProc The client-defined procedure to handle each line of output. - /// - /// @param clientData A pointer to client-defined data to pass to the handler. - /// - /// @return A success-fail status value, returned from the handler. Zero is success, failure - /// values are client-defined. - /// - /// @see Static functions \c DumpNamespaces() and \c DumpAliases() - - XMP_Status DumpObject ( XMP_TextOutputProc outProc, - void * clientData ) const; - - // --------------------------------------------------------------------------------------------- - /// @brief Not implemented - XMP_OptionBits GetObjectOptions() const; - - // --------------------------------------------------------------------------------------------- - /// \brief Not implemented - void SetObjectOptions ( XMP_OptionBits options ); - - /// @} - - // ============================================================================================= - - XMPMetaRef xmpRef; // *** Should be private, see below. - -private: - -#if 0 // *** VS.Net and gcc seem to not handle the friend declarations properly. - friend class TXMPIterator ; - friend class TXMPUtils ; -#endif - -}; // class TXMPMeta - -#endif // __TXMPMeta_hpp__ diff --git a/xmpsdk/include/TXMPUtils.hpp b/xmpsdk/include/TXMPUtils.hpp deleted file mode 100644 index d7189770db..0000000000 --- a/xmpsdk/include/TXMPUtils.hpp +++ /dev/null @@ -1,965 +0,0 @@ -#ifndef __TXMPUtils_hpp__ -#define __TXMPUtils_hpp__ 1 - -#if ( ! __XMP_hpp__ ) - #error "Do not directly include, use XMPSDK.hpp" -#endif - -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================= -/// \file TXMPUtils.hpp -/// \brief API for access to the XMP Toolkit utility services. -/// -/// \c TXMPUtils is the template class providing utility services for the XMP Toolkit. It must be -/// instantiated with a string class such as \c std::string. See the instructions in XMPSDK.hpp, and -/// the Overview for a discussion of the overall architecture of the XMP API. -// ================================================================================================= - -// ================================================================================================= -/// \class TXMPUtils TXMPUtils.hpp -/// @brief API for access to the XMP Toolkit utility services. -/// -/// \c TXMPUtils is a template class which must be instantiated with a string class such as -/// \c std::string. See the instructions in XMPSDK.hpp, and the Overview for a discussion of the overall -/// architecture of the XMP API. -/// -/// This class defines helper functions that support the basic metadata manipulation provided by -/// \c TXMPMeta. All of the functions are static; that is, you call them directly from the concrete -/// class (\c SXMPUtils), which is never itself instantiated. -/// -/// General categories of utilities include: -/// -/// \li Composing complex path expressions, which you can then pass to the property access -/// functions in \c TXMPMeta -/// \li Converting between binary and string forms of property values -/// \li Manipulating date/time values -/// \li Encoding and decoding base-64 strings -/// \li JPEG file handling -/// \li Editing aids for creating a user interface for the XMP Toolkit -// ================================================================================================= - -template class TXMPUtils { - -public: - - // ============================================================================================= - // No constructors or destructor declared or needed - // ================================================ - - // ============================================================================================ - /// \name Path composition - /// @{ - /// - /// These functions provide support for composing path expressions to deeply nested properties. - /// The functions in \c TXMPMeta such as \c TXMPMeta::GetProperty(), - /// \c TXMPMeta::GetArrayItem(), and \c TXMPMeta::GetStructField() provide easy access to top level - /// simple properties, items in top level arrays, and fields of top level structs. They are - /// not as convenient for more complex things, such as fields several levels deep in a complex - /// struct, or fields within an array of structs, or items of an array that is a field of a - /// struct. You can use these utility functions to compose these paths, which you can then pass - /// to the property access functions. You can also compose paths to top-level array items or - /// struct fields so that you can use the binary accessors such as - /// \c TXMPMeta::GetProperty_Int(). - /// - /// You can use these functions is to compose a complete path expression, or all but the last - /// component. For example, suppose you have a property that is an array of integers within a - /// struct. You can access one of the array items like this: - /// - ///
-    ///   SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
-    ///   SXMPUtils::ComposeArrayItemPath ( schemaNS, path, index, &path );
-    ///   exists = xmpObj.GetProperty_Int ( schemaNS, path, &value, &options );
-    /// 
- /// - /// You could also use this code if you want the string form of the integer: - /// - ///
-    ///   SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
-    ///   xmpObj.GetArrayItem ( schemaNS, path, index, &value, &options );
-    /// 
- /// - /// \note It might look confusing that the \c schemaNS is passed in all of the calls above. This - /// is because the XMP Toolkit keeps the top-level "schema" namespace separate from the rest of - /// the path expression. - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeArrayItemPath() composes the path expression for an item in an array. - /// - /// The returned string is in the form ns:arrayName[i], where "ns" is the prefix for - /// the specified namespace, and "i" is the decimal representation of specified item index. - /// If the last item was specified, the path is ns:arrayName[last()]. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param itemIndex The 1-based index of the desired item. Use the macro - /// \c #kXMP_ArrayLastItem to specify the last existing array item. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeArrayItemPath ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeStructFieldPath() composes the path expression for a field in a struct. - /// - /// The returned string is in the form ns:structName/fNS:fieldName, where "ns" is the - /// prefix for the schema namespace, and "fNS" is the prefix for field namespace. - /// - /// @param schemaNS The namespace URI for the struct; see \c GetProperty(). - /// - /// @param structName The name of the struct. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field. Same URI and prefix usage as the - /// \c schemaNS and \c structName parameters. - /// - /// @param fieldName The name of the field. Must be a single XML name, must not be null or the - /// empty string. Same URI and prefix usage as the \c schemaNS and \c structName parameters. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeStructFieldPath ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeQualifierPath() composes the path expression for a qualifier. - /// - /// The returned string is in the form ns:propName/?qNS:qualName, where "ns" is the - /// prefix for the schema namespace, and "qNS" is the prefix for the qualifier namespace. - /// - /// @param schemaNS The namespace URI; see \c GetProperty(). - /// - /// @param propName The name of the property to which the qualifier is attached. Can be a - /// general path expression, must not be null or the empty string; see \c GetProperty() for - /// namespace prefix usage. - /// - /// @param qualNS The namespace URI for the qualifier. Same URI and prefix usage as the - /// \c schemaNS and \c propName parameters. - /// - /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or the - /// empty string. Same URI and prefix usage as the \c schemaNS and \c propName parameters. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeQualifierPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeLangSelector() composes the path expression to select an alternate item by language. - /// - /// Path syntax allows two forms of "content addressing" to select an item in an array of - /// alternatives. The form used in this function lets you select an item in an alt-text array - /// based on the value of its \c xml:lang qualifier. The other form of content addressing is - /// shown in \c ComposeFieldSelector(). - /// - /// The returned string is in the form ns:arrayName[\@xml:lang='langName'], where - /// "ns" is the prefix for the schema namespace - /// - /// This function provides a path expression that is explicitly and only for a specific - /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText() - /// are preferred, because they provide extra logic to choose the appropriate language and - /// maintain consistency with the 'x-default' value. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param langName The RFC 3066 code for the desired language, as a null-terminated UTF-8 string. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeLangSelector() composes a path expression to select an alternate item by language. - /// - /// Path syntax allows two forms of "content addressing" to select an item in an array of - /// alternatives. The form used in this function lets you select an item in an alt-text array - /// based on the value of its \c xml:lang qualifier. The other form of content addressing is - /// shown in \c ComposeFieldSelector(). - /// - /// The returned string is in the form ns:arrayName[\@xml:lang='langName'], where - /// "ns" is the prefix for the schema namespace - /// - /// This function provides a path expression that is explicitly and only for a specific - /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText() - /// are preferred, because they provide extra logic to choose the appropriate language and - /// maintain consistency with the 'x-default' value. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param langName The RFC 3066 code for the desired language, as a string object. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - const tStringObj & langName, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value. - /// - /// Path syntax allows two forms of "content addressing" to select an item in an array of - /// alternatives. The form used in this function lets you select an item in an array of structs - /// based on the value of one of the fields in the structs. The other form of content addressing - /// is shown in \c ComposeLangSelector(). - /// - /// For example, consider a simple struct that has two fields, the name of a city and the URI of - /// an FTP site in that city. Use this to create an array of download alternatives. You can show - /// the user a popup built from the values of the city fields, then get the corresponding URI as - /// follows: - ///
-    ///   ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
-    ///   exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
-    /// 
- /// - /// The returned string is in the form ns:arrayName[fNS:fieldName='fieldValue'], where - /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix - /// usage as the \c schemaNS and \c arrayName parameters. - /// - /// @param fieldName The name of the field used as the selector. Must be a single XML name, must - /// not be null or the empty string. It must be the name of a field that is itself simple. - /// - /// @param fieldValue The desired value of the field, specified as a null-terminated UTF-8 string. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - tStringObj * fullPath ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value. - /// - /// Path syntax allows two forms of "content addressing" to select an item in an array of - /// alternatives. The form used in this function lets you select an item in an array of structs - /// based on the value of one of the fields in the structs. The other form of content addressing - /// is shown in \c ComposeLangSelector(). - /// - /// For example, consider a simple struct that has two fields, the name of a city and the URI of - /// an FTP site in that city. Use this to create an array of download alternatives. You can show - /// the user a popup built from the values of the city fields, then get the corresponding URI as - /// follows: - ///
-    ///   ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
-    ///   exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
-    /// 
- /// - /// The returned string is in the form ns:arrayName[fNS:fieldName='fieldValue'], where - /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace. - /// - /// @param schemaNS The namespace URI for the array; see \c GetProperty(). - /// - /// @param arrayName The name of the array. Can be a general path expression, must not be null - /// or the empty string; see \c GetProperty() for namespace prefix usage. - /// - /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix - /// usage as the \c schemaNS and \c arrayName parameters. - /// - /// @param fieldName The name of the field used as the selector. Must be a single XML name, must - /// not be null or the empty string. It must be the name of a field that is itself simple. - /// - /// @param fieldValue The desired value of the field, specified as a string object. - /// - /// @param fullPath [out] A string in which to return the composed path. - - static void ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - const tStringObj & fieldValue, - tStringObj * fullPath ); - - /// @} - - // ============================================================================================= - /// \name Conversion between binary types and strings - /// @{ - /// - /// The main accessors in \c TXMPMeta set and retrieve property values as strings. additional - /// functions, such as \c TXMPMeta::SetPropertyInt(), set and retrieve property values as - /// explicit binary data types. Use these functions to convert between binary and string - /// values. - /// - /// Strings can be specified as null-terminated UTF-8 (\c #XMP_StringPtr), or as string - /// objects (\c tStringObj) of the type declared when instantiating the XMP classes; see - /// \c XMPSDK.hpp. Alternate forms of each conversion function allow either type of string. - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertFromBool() converts a Boolean value to a string. - /// - /// The string values of Booleans are returned by the macros \c #kXMP_TrueStr and - /// \c #kXMP_FalseStr in \c XMP_Const.h. - /// - /// @param binValue The Boolean value to be converted. - /// - /// @param strValue [out] A buffer in which to return the string representation of the value. - - static void ConvertFromBool ( bool binValue, - tStringObj * strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertFromInt() converts a 32-bit integer value to a string. - /// - /// @param binValue The integer value to be converted. - /// - /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d". - /// - /// @param strValue [out] A buffer in which to return the string representation of the value. - - static void ConvertFromInt ( long binValue, - XMP_StringPtr format, - tStringObj * strValue ); - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertFromInt64() converts a 64-bit integer value to a string. - /// - /// @param binValue The integer value to be converted. - /// - /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d". - /// - /// @param strValue [out] A buffer in which to return the string representation of the value. - - static void ConvertFromInt64 ( long long binValue, - XMP_StringPtr format, - tStringObj * strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertFromFloat() converts a floating-point value to a string. - /// - /// @param binValue The floating-point value to be converted. - /// - /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d". - /// - /// @param strValue [out] A buffer in which to return the string representation of the value. - - static void ConvertFromFloat ( double binValue, - XMP_StringPtr format, - tStringObj * strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertFromDate() converts a date/time value to a string. - /// - /// Formats a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime: - ///
-    ///   YYYY
-    ///   YYYY-MM
-    ///   YYYY-MM-DD
-    ///   YYYY-MM-DDThh:mmTZD
-    ///   YYYY-MM-DDThh:mm:ssTZD
-    ///   YYYY-MM-DDThh:mm:ss.sTZD
-    /// 
- /// - /// \c YYYY = four-digit year, formatted as "%.4d"
- /// \c MM = two-digit month (01=January)
- /// \c DD = two-digit day of month (01 through 31)
- /// \c hh = two digits of hour (00 through 23)
- /// \c mm = two digits of minute (00 through 59)
- /// \c ss = two digits of second (00 through 59)
- /// \c s = one or more digits representing a decimal fraction of a second
- /// \c TZD = time zone designator (Z or +hh:mm or -hh:mm) - /// - /// Time-only input is allowed where the year, month, and day are all zero. This is output as - /// "0000-00-00...". - /// - /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows - /// any year, even negative ones. - /// - /// @param binValue The date/time value to be converted. - /// - /// @param strValue [out] A buffer in which to return the ISO 8601 string representation of the date/time. - - static void ConvertFromDate ( const XMP_DateTime & binValue, - tStringObj * strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToBool() converts a string to a Boolean value. - /// - /// The preferred strings are those returned by the macros \c #kXMP_TrueStr and \c #kXMP_FalseStr. - /// If these do not match, the function does a case insensitive comparison, then simply 't' or 'f', - /// and finally non-zero and zero integer representations. - /// - /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string. - /// - /// @return The appropriate C++ bool value for the string. - - static bool ConvertToBool ( XMP_StringPtr strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToBool() converts a string to a Boolean value. - /// - /// Overloads the basic form of the function, allowing you to pass a string object, - /// rather than a const * char. It is otherwise identical; see details in the canonical form. - /// - /// @param strValue The string representation of the value, specified as a string object. - /// - /// @return The appropriate C++ bool value for the string. - - static bool ConvertToBool ( const tStringObj & strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToInt() converts a string to a 32-bit integer value. - /// - /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string. - /// - /// @return The 32-bit integer value. - - static long ConvertToInt ( XMP_StringPtr strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToInt() converts a string to a 32-bit integer value. - /// - /// Overloads the basic form of the function, allowing you to pass a string object, - /// rather than a const * char. It is otherwise identical. - /// - /// @param strValue The string representation of the value, specified as a string object. - /// - /// @return The 32-bit integer value. - - static long ConvertToInt ( const tStringObj & strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value. - /// - /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string. - /// - /// @return The 64-bit integer value. - - static long long ConvertToInt64 ( XMP_StringPtr strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value. - /// - /// Overloads the basic form of the function, allowing you to pass a string object, - /// rather than a const * char. It is otherwise identical. - /// - /// @param strValue The string representation of the value, specified as a string object. - /// - /// @return The 64-bit integer value. - - static long long ConvertToInt64 ( const tStringObj & strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToFloat() converts a string to a floating-point value. - /// - /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string. - /// - /// @return The floating-point value. - - static double ConvertToFloat ( XMP_StringPtr strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToFloat() converts a string to a floating-point value. - /// - /// Overloads the basic form of the function, allowing you to pass a string object, - /// rather than a const * char. It is otherwise identical. - /// - /// @param strValue The string representation of the value, specified as a string object. - /// - /// @return The floating-point value. - - static double ConvertToFloat ( const tStringObj & strValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToDate() converts a string to a date/time value. - /// - /// Parses a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime: - ///
-    ///   YYYY
-    ///   YYYY-MM
-    ///   YYYY-MM-DD
-    ///   YYYY-MM-DDThh:mmTZD
-    ///   YYYY-MM-DDThh:mm:ssTZD
-    ///   YYYY-MM-DDThh:mm:ss.sTZD
-    /// 
- /// - /// \c YYYY = four-digit year, formatted as "%.4d"
- /// \c MM = two-digit month (01=January)
- /// \c DD = two-digit day of month (01 through 31)
- /// \c hh = two digits of hour (00 through 23)
- /// \c mm = two digits of minute (00 through 59)
- /// \c ss = two digits of second (00 through 59)
- /// \c s = one or more digits representing a decimal fraction of a second
- /// \c TZD = time zone designator (Z or +hh:mm or -hh:mm) - /// - /// A missing date portion or missing TZD are tolerated. A missing date value can begin with - /// "Thh:" or "hh:"; the year, month, and day are all set to zero in the \c #XMP_DateTime value. - /// A missing TZD is assumed to be UTC. - /// - /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows - /// any year, even negative ones. - /// - /// @param strValue The ISO 8601 string representation of the date/time, specified as a - /// null-terminated UTF-8 string. - /// - /// @param binValue [out] A buffer in which to return the binary date/time value. - - static void ConvertToDate ( XMP_StringPtr strValue, - XMP_DateTime * binValue ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToDate() converts a string to a date/time value. - /// - /// Overloads the basic form of the function, allowing you to pass a string object, - /// rather than a const * char. It is otherwise identical. - /// See details for the canonical form. - /// - /// - /// @param strValue The ISO 8601 string representation of the date/time, specified as a string - /// object. - /// - /// @param binValue [out] A buffer in which to return the binary date/time value. - - static void ConvertToDate ( const tStringObj & strValue, - XMP_DateTime * binValue ); - - /// @} - - // ============================================================================================= - /// \name Date-time manipulation - /// @{ - /// - /// In addition to the type-conversion functions that convert between strings and binary - /// date-time values, these functions create, manipulate, and compare date-time values. - - // --------------------------------------------------------------------------------------------- - /// @brief \c CurrentDateTime() obtains the current date and time. - /// - /// Creates and returns a binary \c #XMP_DateTime value. The returned time is UTC, properly - /// adjusted for the local time zone. The resolution of the time is not guaranteed to be finer - /// than seconds. - /// - /// @param time [out] A buffer in which to return the date/time value. - - static void CurrentDateTime ( XMP_DateTime * time ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SetTimeZone() sets the time zone in a date/time value to the local time zone. - /// - /// Any existing time zone value is replaced. The other date/time fields are not adjusted in any way. - /// - /// @param time A pointer to the date-time value, which is modified in place. - - static void SetTimeZone ( XMP_DateTime * time ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToUTCTime() ensures that a time is UTC. - /// - /// If the time zone is not UTC, the time is adjusted and the time zone set to be UTC. If the - /// time zone is already UTC, the value is not modified. - /// - /// @param time A pointer to the date-time value, which is modified in place. - - static void ConvertToUTCTime ( XMP_DateTime * time ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c ConvertToLocalTime() ensures that a time is local. - /// - /// If the time zone is not the local zone, the time is adjusted and the time zone set to be local. - /// If the time zone is already the local zone, the value is not modified. - /// - /// @param time A pointer to the date-time value, which is modified in place. - - static void ConvertToLocalTime ( XMP_DateTime * time ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c CompareDateTime() compares the order of two date/time values. - /// - /// @param left The left-side date/time value. - /// - /// @param right The right-side date/time value. - /// - /// @return An integer indicating the order: - /// \li -1 if left is earlier than right - /// \li 0 if left matches right - /// \li +1 if left is later than right - - static int CompareDateTime ( const XMP_DateTime & left, - const XMP_DateTime & right ); - - /// @} - - // ============================================================================================= - /// \name Base64 encoding and decoding - /// @{ - /// - /// These functions convert between raw data values and Base64-encoded strings. - - // --------------------------------------------------------------------------------------------- - /// @brief \c EncodeToBase64() converts a raw data value to a Base64-encoded string. - /// - /// @param rawStr An \c #XMP_StringPtr (char *) string containing the raw data to be converted. - /// - /// @param rawLen The number of characters of raw data to be converted. - /// - /// @param encodedStr [out] A string object in which to return the encoded string. - - static void EncodeToBase64 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - tStringObj * encodedStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c EncodeToBase64() converts a raw data value passed in a string object to a Base64-encoded string. - /// - /// Overloads the basic form of the function, allowing you to pass a string object as input. - /// It is otherwise identical. - /// - /// @param rawStr A string object containing the raw data to be converted. - /// - /// @param encodedStr [out] A string object in which to return the encoded string. - - static void EncodeToBase64 ( const tStringObj & rawStr, - tStringObj * encodedStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DecodeFromBase64() Decodes a Base64-encoded string to raw data. - /// - /// @param encodedStr An \c #XMP_StringPtr (char *) string containing the encoded data to be converted. - /// - /// @param encodedLen The number of characters of raw data to be converted. - /// - /// @param rawStr [out] A string object in which to return the decoded data. - - static void DecodeFromBase64 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - tStringObj * rawStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DecodeFromBase64() Decodes a Base64-encoded string, passed as a string object, to raw data. - /// - /// Overloads the basic form of the function, allowing you to pass a string object as input. - /// It is otherwise identical. - /// - /// @param encodedStr An string object containing the encoded data to be converted. - /// - /// @param rawStr [out] A string object in which to return the decoded data. - - static void DecodeFromBase64 ( const tStringObj & encodedStr, - tStringObj * rawStr ); - - /// @} - - // ============================================================================================= - // ============================================================================================= - /// \name JPEG file handling - /// @{ - /// - /// These functions support the partitioning of XMP in JPEG files into standard and extended - /// portions in order to work around the 64KB size limit of JPEG marker segments. - /// - /// @note (Doc note) Add detail about how to write out and read back extended data - - // --------------------------------------------------------------------------------------------- - /// @brief \c PackageForJPEG() creates XMP serializations appropriate for a JPEG file. - /// - /// The standard XMP in a JPEG file is limited to 64K bytes. This function serializes the XMP - /// metadata in an XMP object into a string of RDF (see \c TXMPMeta::SerializeToBuffer()). If - /// the data does not fit into the 64K byte limit, it creates a second packet string with the - /// extended data. - /// - /// @param xmpObj The XMP object containing the metadata. - /// - /// @param standardXMP [out] A string object in which to return the full standard XMP packet. - /// - /// @param extendedXMP [out] A string object in which to return the serialized extended XMP, - /// empty if not needed. - /// - /// @param extendedDigest [out] A string object in which to return an MD5 digest of the serialized - /// extended XMP, empty if not needed. - /// - /// @see \c MergeFromJPEG() - - static void PackageForJPEG ( const TXMPMeta & xmpObj, - tStringObj * standardXMP, - tStringObj * extendedXMP, - tStringObj * extendedDigest ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c MergeFromJPEG() merges standard and extended XMP retrieved from a JPEG file. - /// - /// When an extended partition stores properties that do not fit into the JPEG file limitation - /// of 64K bytes, this function integrates those properties back into the same XMP object with - /// those from the standard XMP packet. - /// - /// @param fullXMP [in, out] An XMP object which the caller has initialized from the standard - /// XMP packet in a JPEG file. The extended XMP is added to this object. - /// - /// @param extendedXMP An XMP object which the caller has initialized from the extended XMP - /// packet in a JPEG file. - /// - /// @see \c PackageForJPEG() - - static void MergeFromJPEG ( TXMPMeta * fullXMP, - const TXMPMeta & extendedXMP ); - - /// @} - - // ============================================================================================= - /// \name Editing utilities - /// @{ - /// - /// These functions are useful in implementing a user interface for editing XMP. They - /// convert sets of property values to and from displayable and manipulable strings, and perform - /// operations on sets of metadata, such as those available from the File Info dialog box. - - // --------------------------------------------------------------------------------------------- - /// @brief \c CatenateArrayItems() creates a single edit string from a set of array item values. - /// - /// Collects the values of all items in an array into a single string, using a specified - /// separation string. Each item in the specified array must be a simple string value. - /// - /// @param xmpObj The XMP object containing the array to be catenated. - /// - /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string. - /// - /// @param arrayName The name of the array. May be a general path expression, must not be null - /// or the empty string. - /// - /// @param separator The string with which to separate the items in the catenated string. - /// Defaults to "; ", ASCII semicolon and space (U+003B, U+0020). - /// - /// @param quotes The character or characters to use as quotes around array items that contain a - /// separator. Defaults to the double-quote character ("), ASCII quote (U+0022). - /// - /// @param options Option flags to control the catenation. <> - /// - /// @param catedStr [out] A string object in which to return the catenated array items. - /// - /// @see \c SeparateArrayItems() - - static void CatenateArrayItems ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - tStringObj * catedStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values. - /// - /// This reverses the action of \c CatenateArrayItems(), separating out individual array items - /// from the edit string and updating the array with the new values. Each item in the array must - /// be a simple string value. - /// - /// @param xmpObj The XMP object containing the array to be updated. - /// - /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string. - /// - /// @param arrayName The name of the array. May be a general path expression, must not be null - /// or the empty string. - /// - /// @param options Option flags to control the separation. <> - /// - /// @param catedStr The concatenated array items, as created by \c CatenateArrayItems(), - /// specified as a null-terminated UTF-8 string. - - static void SeparateArrayItems ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values. - /// - /// Overloads the basic form of the function, allowing you to pass a string object in which - /// to return the concatenated string. It is otherwise identical; see details for the canonical form. - /// - - static void SeparateArrayItems ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - const tStringObj & catedStr ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c RemoveProperties() removes multiple properties from an XMP object. - /// - /// The operation depends on how the namespace and property are specified: - /// - /// \li Non-empty \c schemaNS and \c propName - The named property is removed if it is an - /// external property, or if the \c #kXMPUtil_DoAllProperties option flag is set. It does not - /// matter whether the named property is an actual property or an alias. - /// - /// \li Non-empty \c schemaNS and empty \c propName - All external properties in the named - /// schema are removed. Internal properties are also removed if the - /// \c #kXMPUtil_DoAllProperties option flag is set. In addition, aliases from the named schema - /// are removed if the \c #kXMPUtil_IncludeAliases option flag is set. - /// - /// \li Empty \c schemaNS and empty \c propName - All external properties in all schemas are - /// removed. Internal properties are also removed if the \c #kXMPUtil_DoAllProperties option - /// flag is set. Aliases are handled implicitly, because the associated actuals are removed or - /// not. - /// - /// \li It is an error to pass an empty \c schemaNS and non-empty \c propName. - /// - /// @param xmpObj The XMP object containing the properties to be removed. - /// - /// @param schemaNS Optional schema namespace URI for the properties to be removed. - /// - /// @param propName Optional path expression for the property to be removed. - /// - /// @param options Option flags to control the deletion operation. A logical OR of these - /// bit-flag constants: - /// \li \c #kXMPUtil_DoAllProperties - Delete internal properties in addition to external properties. - /// \li \c #kXMPUtil_IncludeAliases - Include aliases if the schema is explicitly specified. - - static void RemoveProperties ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS = 0, - XMP_StringPtr propName = 0, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c AppendProperties() adds or moves properties from one XMP object to another. - /// - /// The default operation is to append only external properties that do not already exist in the - /// destination. Option flags allow you to add internal properties, and to merge values of - /// properties that exist in both the source and destination. - /// - /// \li \c #kXMPUtil_DoAllProperties: Operate on all top-level properties, external and - /// internal. You can use this flag together with \c #kXMPUtil_ReplaceOldValues to replace the - /// values of existing top-level properties. - /// - /// \li \c #kXMPUtil_ReplaceOldValues: Propagate all top-level properties from the source to - /// the destination, replacing any existing values. The values of properties in the - /// destination that are not in the source are not modified.
- /// The keep-or-replace-old notion also applies within structs and arrays. Top-level - /// properties are added to the destination if they do not already exist. If they do exist but - /// differ in form (simple/struct/array) then the destination is not modified. If the forms - /// match, simple properties are left unchanged, while structs and arrays are merged.
- /// Do not use this option when the processing is more complicated. <> - /// - /// \li \c #kXMPUtil_DeleteEmptyValues: An empty value in the source XMP causes the - /// corresponding destination property to be deleted. By default, empty values are treated in - /// the same way as non-empty values. An empty value is a simple empty string, an array with - /// no items,or a struct with no fields. Qualifiers are ignored. - /// - /// The detailed behavior is defined by the following pseudo-code: - /// - ///
-    /// AppendProperties ( sourceXMP, destXMP, options ):
-    ///    doAll = options & kXMPUtil_DoAllProperties
-    ///    replaceOld = options & kXMPUtil_ReplaceOldValues
-    ///    deleteEmpty = options & kXMPUtil_DeleteEmptyValues
-    ///    for all source schema (top level namespaces):
-    ///    for all top level properties in sourceSchema:
-    ///    if doAll or prop is external:
-    ///       AppendSubtree ( sourceNode, destSchema, replaceOld, deleteEmpty )
-    ///
-    /// AppendSubtree ( sourceNode, destParent, replaceOld, deleteEmpty ):
-    ///    if deleteEmpty and source value is empty:
-    ///       delete the corresponding child from destParent
-    ///    else if sourceNode not in destParent (by name):
-    ///       copy sourceNode's subtree to destParent
-    ///    else if replaceOld:
-    ///       delete subtree from destParent
-    ///       copy sourceNode's subtree to destParent
-    ///    else: // (Already exists in dest and not replacing, merge structs and arrays)
-    ///       if sourceNode and destNode forms differ:
-    ///          return, leave the destNode alone
-    ///       else if form is a struct:
-    ///          for each field in sourceNode:
-    ///             AppendSubtree ( sourceNode.field, destNode, replaceOld )
-    ///       else if form is an alt-text array:
-    ///          copy new items by xml:lang value into the destination
-    ///       else if form is an array:
-    ///          copy new items by value into the destination, ignoring order and duplicates
-    /// 
- /// - /// Array item checking is n-squared; this can be time-intensive if the replace-old options is - /// not specified. Each source item is checked to see if it already exists in the destination, - /// without regard to order or duplicates. Simple items are compared by value and \c xml:lang - /// qualifier; other qualifiers are ignored. Structs are recursively compared by field names, - /// without regard to field order. Arrays are compared by recursively comparing all items. - /// - /// @param source The source XMP object. - /// - /// @param dest The destination XMP object. - /// - /// @param options Option flags to control the copying. A logical OR of these bit-flag constants: - /// \li \c kXMPUtil_DoAllProperties - Operate on internal properties in addition to external properties. - /// \li \c kXMPUtil_ReplaceOldValues - Replace the values of existing properties. - /// \li \c kXMPUtil_DeleteEmptyValues - Delete properties if the new value is empty. - - static void AppendProperties ( const TXMPMeta & source, - TXMPMeta * dest, - XMP_OptionBits options = 0 ); - - // --------------------------------------------------------------------------------------------- - /// @brief \c DuplicateSubtree() replicates a subtree from one XMP object into another. - /// - /// The destination can be a different namespace and root location in the same object, or the - /// same or a different location in another XMP object. - /// - /// @param source The source XMP object. - /// - /// @param dest The destination XMP object. - /// - /// @param sourceNS The schema namespace URI for the source subtree. - /// - /// @param sourceRoot The root location for the source subtree. Can be a general path expression, - /// must not be null or the empty string. - /// - /// @param destNS The schema namespace URI for the destination. Defaults to the source namespace. - /// - /// @param destRoot The root location for the destination. Can be a general path expression. - /// Defaults to the source location. - /// - /// @param options Option flags to control the operation. <> - - static void DuplicateSubtree ( const TXMPMeta & source, - TXMPMeta * dest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS = 0, - XMP_StringPtr destRoot = 0, - XMP_OptionBits options = 0 ); - - /// @} - - // ============================================================================================= - - // ============================================================================================= - -}; // class TXMPUtils - -// ================================================================================================= - -#endif // __TXMPUtils_hpp__ diff --git a/xmpsdk/include/XMP.incl_cpp b/xmpsdk/include/XMP.incl_cpp deleted file mode 100644 index 6501be9c73..0000000000 --- a/xmpsdk/include/XMP.incl_cpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef __XMP_incl_cpp__ -#define __XMP_incl_cpp__ 1 - -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================ -/// \file XMP.incl_cpp -/// \brief Overall client glue file for the XMP toolkit. -/// -/// This is an overall client source file of XMP toolkit glue, the only XMP-specific one that -/// clients should build in projects. This ensures that all of the client-side glue code for the -/// XMP toolkit gets compiled. -/// -/// You cannot compile this file directly, because the template's string type must be declared and -/// only the client can do that. Instead, include this in some other source file. For example, -/// to use std::string you only need these two lines: -/// -/// \code -/// #include -/// #include "XMP.incl_cpp" -/// \endcode - - -#include "XMPSDK.hpp" // ! This must be the first include! - -#define XMP_ClientBuild 1 - -#ifdef _MSC_VER - #if XMP_DebugBuild - #pragma warning ( push, 4 ) - #else - #pragma warning ( push, 3 ) - #endif - #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) -#endif - -#if defined ( TXMP_STRING_TYPE ) && (! TXMP_EXPAND_INLINE) - - // We're using a single out of line instantiation. Do it here. - - #include "client-glue/TXMPMeta.incl_cpp" - #include "client-glue/TXMPIterator.incl_cpp" - #include "client-glue/TXMPUtils.incl_cpp" - template class TXMPMeta ; - template class TXMPIterator ; - template class TXMPUtils ; - -#endif - -#ifdef _MSC_VER - #pragma warning ( pop ) -#endif - -#endif // __XMP_incl_cpp__ diff --git a/xmpsdk/include/XMPSDK.hpp b/xmpsdk/include/XMPSDK.hpp deleted file mode 100644 index 229714f8d8..0000000000 --- a/xmpsdk/include/XMPSDK.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __XMP_hpp__ -#define __XMP_hpp__ 1 - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================ -/// \file XMPSDK.hpp -/// \brief Overall header file for the XMP Toolkit -/// -/// This is an overall header file, the only one that C++ clients should include. -/// -/// The full client API is in the \c TXMPMeta.hpp, \c TXMPIterator.hpp, \c TXMPUtils.hpp headers. -/// Read these for information, but do not include them directly. The \c TXMP... classes are C++ -/// template classes that must be instantiated with a string class such as \c std::string. The -/// string class is used to return text strings for property values, serialized XMP, and so on. -/// Clients must also compile \c XMP.incl_cpp to ensure that all client-side glue code is generated. -/// This should be done by including it in exactly one client source file. -/// -/// There are two C preprocessor macros that simplify use of the templates: -/// -/// \li \c TXMP_STRING_TYPE - Define this as the string class to use with the template. You will get -/// the template headers included and typedefs (\c SXMPMeta, and so on) to use in your code. -/// -/// \li \c TXMP_EXPAND_INLINE - Define this as 1 if you want to have the template functions expanded -/// inline in your code. Leave it undefined, or defined as 0, to use out-of-line instantiations of -/// the template functions. Compiling \c XMP.incl_cpp generates explicit out-of-line -/// instantiations if \c TXMP_EXPAND_INLINE is off. -/// -/// The template parameter, class \c tStringObj, must have the following member functions (which -/// match those for \c std::string): -/// -///
-///  tStringObj& assign ( const char * str, size_t len )
-///  size_t size() const
-///  const char * c_str() const
-/// 
-/// -/// The string class must be suitable for at least UTF-8. This is the encoding used for all general -/// values, and is the default encoding for serialized XMP. The string type must also be suitable -/// for UTF-16 or UTF-32 if those serialization encodings are used. This mainly means tolerating -/// embedded 0 bytes, which \c std::string does. -// ================================================================================================ - -/// /c XMP_Environment.h must be the first included header. -#include "XMP_Environment.h" - -#include "XMP_Version.h" -#include "XMP_Const.h" - -#ifdef _MSC_VER - #if XMP_DebugBuild - #pragma warning ( push, 4 ) - #else - #pragma warning ( push, 3 ) - #endif - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) -#endif - -#if defined ( TXMP_STRING_TYPE ) - - #include "TXMPMeta.hpp" - #include "TXMPIterator.hpp" - #include "TXMPUtils.hpp" - typedef class TXMPMeta SXMPMeta; // For client convenience. - typedef class TXMPIterator SXMPIterator; - typedef class TXMPUtils SXMPUtils; - #if TXMP_EXPAND_INLINE - #error "TXMP_EXPAND_INLINE is not working at present. Please don't use it." - #include "client-glue/TXMPMeta.incl_cpp" - #include "client-glue/TXMPIterator.incl_cpp" - #include "client-glue/TXMPUtils.incl_cpp" - #endif - -#endif // TXMP_STRING_TYPE - -#ifdef _MSC_VER - #pragma warning ( pop ) -#endif - -// ================================================================================================= - -#endif // __XMP_hpp__ diff --git a/xmpsdk/include/XMP_Const.h b/xmpsdk/include/XMP_Const.h deleted file mode 100644 index e84e18fd0d..0000000000 --- a/xmpsdk/include/XMP_Const.h +++ /dev/null @@ -1,1311 +0,0 @@ -#ifndef __XMP_Const_h__ -#define __XMP_Const_h__ 1 - -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" - -#include -#include - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -/// \file XMP_Const.h -/// \brief Common C/C++ types and constants for the XMP toolkit. -// ================================================================================================= - -// ================================================================================================= -// Basic types and constants -// ========================= - -// The XMP_... types are used on the off chance that the ..._t types present a problem. In that -// case only the declarations of the XMP_... types needs to change, not all of the uses. These -// types are used where fixed sizes are required in order to have a known ABI for a DLL build. - -typedef int8_t XMP_Int8; -typedef int16_t XMP_Int16; -typedef int32_t XMP_Int32; -typedef int64_t XMP_Int64; - -typedef uint8_t XMP_Uns8; -typedef uint16_t XMP_Uns16; -typedef uint32_t XMP_Uns32; -typedef uint64_t XMP_Uns64; - -typedef XMP_Uns8 XMP_Bool; - -/// An "ABI safe" pointer to the internal part of an XMP object. Use to pass an XMP object across -/// client DLL boundaries. See \c TXMPMeta::GetInternalRef(). -typedef struct __XMPMeta__ * XMPMetaRef; - -/// An "ABI safe" pointer to the internal part of an XMP iteration object. Use to pass an XMP -/// iteration object across client DLL boundaries. See \c TXMPIterator. -typedef struct __XMPIterator__ * XMPIteratorRef; - -/// An "ABI safe" pointer to the internal part of an XMP document operations object. Use to pass an -/// XMP document operations object across client DLL boundaries. See \c TXMPDocOps. -typedef struct __XMPDocOps__ * XMPDocOpsRef; - -/// An "ABI safe" pointer to the internal part of an XMP file-handling object. Use to pass an XMP -/// file-handling object across client DLL boundaries. See \c TXMPFiles. -typedef struct __XMPFiles__ * XMPFilesRef; - -// ================================================================================================= - -/// \name General scalar types and constants -/// @{ - -/// \typedef XMP_StringPtr -/// \brief The type for input string parameters. A const char *, a null-terminated UTF-8 -/// string. - -/// \typedef XMP_StringLen -/// \brief The type for string length parameters. A 32-bit unsigned integer, as big as will be -/// practically needed. - -/// \typedef XMP_Index -/// \brief The type for offsets and indices. A 32-bit signed integer. It is signed to allow -1 for -/// loop termination. - -/// \typedef XMP_OptionBits -/// \brief The type for a collection of 32 flag bits. Individual flags are defined as enum value bit -/// masks; see \c #kXMP_PropValueIsURI and following. A number of macros provide common set or set -/// operations, such as \c XMP_PropIsSimple. For other tests use an expression like options & -/// kXMP_. When passing multiple option flags use the bitwise-OR operator. '|', -/// not the arithmatic plus, '+'. - -typedef const char * XMP_StringPtr; // Points to a null terminated UTF-8 string. -typedef XMP_Uns32 XMP_StringLen; -typedef XMP_Int32 XMP_Index; // Signed, sometimes -1 is handy. -typedef XMP_Uns32 XMP_OptionBits; // Used as 32 individual bits. - -/// \def kXMP_TrueStr -/// \brief The canonical true string value for Booleans in serialized XMP. -/// -/// Code that converts from string to bool should be case insensitive, and also allow "1". - -/// \def kXMP_FalseStr -/// \brief The canonical false string value for Booleans in serialized XMP. -/// -/// Code that converts from string to bool should be case insensitive, and also allow "0". - -#define kXMP_TrueStr "True" // Serialized XMP spellings, not for the type bool. -#define kXMP_FalseStr "False" - -/// Type for yes/no/maybe answers. The values are picked to allow Boolean-like usage. The yes and -/// values are true (non-zero), the no value is false (zero). -enum { - /// The part or parts have definitely changed. - kXMPTS_Yes = 1, - /// The part or parts have definitely not changed. - kXMPTS_No = 0, - /// The part or parts might, or might not, have changed. - kXMPTS_Maybe = -1 -}; -typedef XMP_Int8 XMP_TriState; - -/// @} - -// ================================================================================================= - -/// \struct XMP_DateTime -/// \brief The expanded type for a date and time. -/// -/// Dates and time in the serialized XMP are ISO 8601 strings. The \c XMP_DateTime struct allows -/// easy conversion with other formats. -/// -/// All of the fields are 32 bit, even though most could be 8 bit. This avoids overflow when doing -/// carries for arithmetic or normalization. All fields have signed values for the same reasons. -/// -/// Date-time values are occasionally used with only a date or only a time component. A date without -/// a time has zeros in the \c XMP_DateTime struct for all time fields. A time without a date has -/// zeros for all date fields (year, month, and day). -/// -/// \c TXMPUtils provides utility functions for manipulating date-time values. -/// -/// @see \c TXMPUtils::ConvertToDate(), \c TXMPUtils::ConvertFromDate(), -/// \c TXMPUtils::CompareDateTime(), \c TXMPUtils::ConvertToLocalTime(), -/// \c TXMPUtils::ConvertToUTCTime(), \c TXMPUtils::CurrentDateTime(), -/// \c TXMPUtils::SetTimeZone() - -struct XMP_DateTime { - - /// The year, can be negative. - XMP_Int32 year; - - /// The month in the range 1..12. - XMP_Int32 month; - - /// The day of the month in the range 1..31. - XMP_Int32 day; - - /// The hour in the range 0..23. - XMP_Int32 hour; - - /// The minute in the range 0..59. - XMP_Int32 minute; - - /// The second in the range 0..59. - XMP_Int32 second; - - /// The "sign" of the time zone, \c #kXMP_TimeIsUTC (0) means UTC, \c #kXMP_TimeWestOfUTC (-1) - /// is west, \c #kXMP_TimeEastOfUTC (+1) is east. - XMP_Int32 tzSign; - - /// The time zone hour in the range 0..23. - XMP_Int32 tzHour; - - /// The time zone minute in the range 0..59. - XMP_Int32 tzMinute; - - /// Nanoseconds within a second, often left as zero. - XMP_Int32 nanoSecond; - -}; - -/// Constant values for \c XMP_DateTime::tzSign field. -enum { - /// Time zone is west of UTC. - kXMP_TimeWestOfUTC = -1, - /// UTC time. - kXMP_TimeIsUTC = 0, - /// Time zone is east of UTC. - kXMP_TimeEastOfUTC = +1 -}; - -// ================================================================================================= -// Standard namespace URI constants -// ================================ - -/// \name XML namespace constants for standard XMP schema. -/// @{ -/// -/// \def kXMP_NS_XMP -/// \brief The XML namespace for the XMP "basic" schema. -/// -/// \def kXMP_NS_XMP_Rights -/// \brief The XML namespace for the XMP copyright schema. -/// -/// \def kXMP_NS_XMP_MM -/// \brief The XML namespace for the XMP digital asset management schema. -/// -/// \def kXMP_NS_XMP_BJ -/// \brief The XML namespace for the job management schema. -/// -/// \def kXMP_NS_XMP_T -/// \brief The XML namespace for the XMP text document schema. -/// -/// \def kXMP_NS_XMP_T_PG -/// \brief The XML namespace for the XMP paged document schema. -/// -/// \def kXMP_NS_PDF -/// \brief The XML namespace for the PDF schema. -/// -/// \def kXMP_NS_Photoshop -/// \brief The XML namespace for the Photoshop custom schema. -/// -/// \def kXMP_NS_EXIF -/// \brief The XML namespace for Adobe's EXIF schema. -/// -/// \def kXMP_NS_TIFF -/// \brief The XML namespace for Adobe's TIFF schema. -/// -/// @} - -#define kXMP_NS_XMP "http://ns.adobe.com/xap/1.0/" - -#define kXMP_NS_XMP_Rights "http://ns.adobe.com/xap/1.0/rights/" -#define kXMP_NS_XMP_MM "http://ns.adobe.com/xap/1.0/mm/" -#define kXMP_NS_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/" - -#define kXMP_NS_PDF "http://ns.adobe.com/pdf/1.3/" -#define kXMP_NS_Photoshop "http://ns.adobe.com/photoshop/1.0/" -#define kXMP_NS_PSAlbum "http://ns.adobe.com/album/1.0/" -#define kXMP_NS_EXIF "http://ns.adobe.com/exif/1.0/" -#define kXMP_NS_EXIF_Aux "http://ns.adobe.com/exif/1.0/aux/" -#define kXMP_NS_TIFF "http://ns.adobe.com/tiff/1.0/" -#define kXMP_NS_PNG "http://ns.adobe.com/png/1.0/" -#define kXMP_NS_SWF "http://ns.adobe.com/swf/1.0/" -#define kXMP_NS_JPEG "http://ns.adobe.com/jpeg/1.0/" -#define kXMP_NS_JP2K "http://ns.adobe.com/jp2k/1.0/" -#define kXMP_NS_CameraRaw "http://ns.adobe.com/camera-raw-settings/1.0/" -#define kXMP_NS_DM "http://ns.adobe.com/xmp/1.0/DynamicMedia/" -#define kXMP_NS_ASF "http://ns.adobe.com/asf/1.0/" -#define kXMP_NS_WAV "http://ns.adobe.com/xmp/wav/1.0/" - -#define kXMP_NS_XMP_Note "http://ns.adobe.com/xmp/note/" - -#define kXMP_NS_AdobeStockPhoto "http://ns.adobe.com/StockPhoto/1.0/" -#define kXMP_NS_CreatorAtom "http://ns.adobe.com/creatorAtom/1.0/" - -/// \name XML namespace constants for qualifiers and structured property fields. -/// @{ -/// -/// \def kXMP_NS_XMP_IdentifierQual -/// \brief The XML namespace for qualifiers of the xmp:Identifier property. -/// -/// \def kXMP_NS_XMP_Dimensions -/// \brief The XML namespace for fields of the Dimensions type. -/// -/// \def kXMP_NS_XMP_Image -/// \brief The XML namespace for fields of a graphical image. Used for the Thumbnail type. -/// -/// \def kXMP_NS_XMP_ResourceEvent -/// \brief The XML namespace for fields of the ResourceEvent type. -/// -/// \def kXMP_NS_XMP_ResourceRef -/// \brief The XML namespace for fields of the ResourceRef type. -/// -/// \def kXMP_NS_XMP_ST_Version -/// \brief The XML namespace for fields of the Version type. -/// -/// \def kXMP_NS_XMP_ST_Job -/// \brief The XML namespace for fields of the JobRef type. -/// -/// @} - -#define kXMP_NS_XMP_IdentifierQual "http://ns.adobe.com/xmp/Identifier/qual/1.0/" -#define kXMP_NS_XMP_Dimensions "http://ns.adobe.com/xap/1.0/sType/Dimensions#" -#define kXMP_NS_XMP_Text "http://ns.adobe.com/xap/1.0/t/" -#define kXMP_NS_XMP_PagedFile "http://ns.adobe.com/xap/1.0/t/pg/" -#define kXMP_NS_XMP_Graphics "http://ns.adobe.com/xap/1.0/g/" -#define kXMP_NS_XMP_Image "http://ns.adobe.com/xap/1.0/g/img/" -#define kXMP_NS_XMP_Font "http://ns.adobe.com/xap/1.0/sType/Font#" -#define kXMP_NS_XMP_ResourceEvent "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" -#define kXMP_NS_XMP_ResourceRef "http://ns.adobe.com/xap/1.0/sType/ResourceRef#" -#define kXMP_NS_XMP_ST_Version "http://ns.adobe.com/xap/1.0/sType/Version#" -#define kXMP_NS_XMP_ST_Job "http://ns.adobe.com/xap/1.0/sType/Job#" -#define kXMP_NS_XMP_ManifestItem "http://ns.adobe.com/xap/1.0/sType/ManifestItem#" - -// Deprecated XML namespace constants -#define kXMP_NS_XMP_T "http://ns.adobe.com/xap/1.0/t/" -#define kXMP_NS_XMP_T_PG "http://ns.adobe.com/xap/1.0/t/pg/" -#define kXMP_NS_XMP_G_IMG "http://ns.adobe.com/xap/1.0/g/img/" - -/// \name XML namespace constants from outside Adobe. -/// @{ -/// -/// \def kXMP_NS_DC -/// \brief The XML namespace for the Dublin Core schema. -/// -/// \def kXMP_NS_IPTCCore -/// \brief The XML namespace for the IPTC Core schema. -/// -/// \def kXMP_NS_RDF -/// \brief The XML namespace for RDF. -/// -/// \def kXMP_NS_XML -/// \brief The XML namespace for XML. -/// -/// @} - -#define kXMP_NS_DC "http://purl.org/dc/elements/1.1/" - -#define kXMP_NS_IPTCCore "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" - -#define kXMP_NS_DICOM "http://ns.adobe.com/DICOM/" - -#define kXMP_NS_PDFA_Schema "http://www.aiim.org/pdfa/ns/schema#" -#define kXMP_NS_PDFA_Property "http://www.aiim.org/pdfa/ns/property#" -#define kXMP_NS_PDFA_Type "http://www.aiim.org/pdfa/ns/type#" -#define kXMP_NS_PDFA_Field "http://www.aiim.org/pdfa/ns/field#" -#define kXMP_NS_PDFA_ID "http://www.aiim.org/pdfa/ns/id/" -#define kXMP_NS_PDFA_Extension "http://www.aiim.org/pdfa/ns/extension/" - -#define kXMP_NS_PDFX "http://ns.adobe.com/pdfx/1.3/" -#define kXMP_NS_PDFX_ID "http://www.npes.org/pdfx/ns/id/" - -#define kXMP_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -#define kXMP_NS_XML "http://www.w3.org/XML/1998/namespace" - -// ================================================================================================= -// Enums and macros used for option bits -// ===================================== - -/// \name Macros for standard option selections. -/// @{ -/// -/// \def kXMP_ArrayLastItem -/// \brief Options macro accesses last array item. -/// -/// \def kXMP_UseNullTermination -/// \brief Options macro sets string style. -/// -/// \def kXMP_NoOptions -/// \brief Options macro clears all property-type bits. -/// -/// @} - -#define kXMP_ArrayLastItem ((XMP_Index)(-1L)) -#define kXMP_UseNullTermination ((XMP_StringLen)(~0UL)) -#define kXMP_NoOptions ((XMP_OptionBits)0UL) - -/// \name Macros for setting and testing general option bits. -/// @{ -/// -/// \def XMP_SetOption -/// \brief Macro sets an option flag bit. -/// \param var A variable storing an options flag. -/// \param opt The bit-flag constant to set. -/// -/// \def XMP_ClearOption -/// \brief Macro clears an option flag bit. -/// \param var A variable storing an options flag. -/// \param opt The bit-flag constant to clear. -/// -/// \def XMP_TestOption -/// \brief Macro reports whether an option flag bit is set. -/// \param var A variable storing an options flag. -/// \param opt The bit-flag constant to test. -/// \return True if the bit is set. -/// -/// \def XMP_OptionIsSet -/// \brief Macro reports whether an option flag bit is set. -/// \param var A variable storing an options flag. -/// \param opt The bit-flag constant to test. -/// \return True if the bit is set. -/// -/// \def XMP_OptionIsClear -/// \brief Macro reports whether an option flag bit is clear. -/// \param var A variable storing an options flag. -/// \param opt The bit-flag constant to test. -/// \return True if the bit is clear. -/// -/// @} - -#define XMP_SetOption(var,opt) var |= (opt) -#define XMP_ClearOption(var,opt) var &= ~(opt) -#define XMP_TestOption(var,opt) (((var) & (opt)) != 0) -#define XMP_OptionIsSet(var,opt) (((var) & (opt)) != 0) -#define XMP_OptionIsClear(var,opt) (((var) & (opt)) == 0) - -/// \name Macros for setting and testing specific option bits. -/// @{ -/// -/// \def XMP_PropIsSimple -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropIsStruct -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropIsArray -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_ArrayIsUnordered -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_ArrayIsOrdered -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_ArrayIsAlternate -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_ArrayIsAltText -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropHasQualifiers -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropIsQualifier -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropHasLang -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_NodeIsSchema -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// \def XMP_PropIsAlias -/// \brief Macro reports the property type specified by an options flag. -/// \param opt The options flag to check. -/// -/// @} - -#define XMP_PropIsSimple(opt) (((opt) & kXMP_PropCompositeMask) == 0) -#define XMP_PropIsStruct(opt) (((opt) & kXMP_PropValueIsStruct) != 0) -#define XMP_PropIsArray(opt) (((opt) & kXMP_PropValueIsArray) != 0) - -#define XMP_ArrayIsUnordered(opt) (((opt) & kXMP_PropArrayIsOrdered) == 0) -#define XMP_ArrayIsOrdered(opt) (((opt) & kXMP_PropArrayIsOrdered) != 0) -#define XMP_ArrayIsAlternate(opt) (((opt) & kXMP_PropArrayIsAlternate) != 0) -#define XMP_ArrayIsAltText(opt) (((opt) & kXMP_PropArrayIsAltText) != 0) - -#define XMP_PropHasQualifiers(opt) (((opt) & kXMP_PropHasQualifiers) != 0) -#define XMP_PropIsQualifier(opt) (((opt) & kXMP_PropIsQualifier) != 0) -#define XMP_PropHasLang(opt) (((opt) & kXMP_PropHasLang) != 0) - -#define XMP_NodeIsSchema(opt) (((opt) & kXMP_SchemaNode) != 0) -#define XMP_PropIsAlias(opt) (((opt) & kXMP_PropIsAlias) != 0) - -// ------------------------------------------------------------------------------------------------- - -/// Option bit flags for the \c TXMPMeta property accessor functions. -enum { - - /// The XML string form of the property value is a URI, use rdf:resource attribute. DISCOURAGED - kXMP_PropValueIsURI = 0x00000002UL, - - // ------------------------------------------------------ - // Options relating to qualifiers attached to a property. - - /// The property has qualifiers, includes \c rdf:type and \c xml:lang. - kXMP_PropHasQualifiers = 0x00000010UL, - - /// This is a qualifier for some other property, includes \c rdf:type and \c xml:lang. - /// Qualifiers can have arbitrary structure, and can themselves have qualifiers. If the - /// qualifier itself has a structured value, this flag is only set for the top node of the - /// qualifier's subtree. - kXMP_PropIsQualifier = 0x00000020UL, - - /// Implies \c #kXMP_PropHasQualifiers, property has \c xml:lang. - kXMP_PropHasLang = 0x00000040UL, - - /// Implies \c #kXMP_PropHasQualifiers, property has \c rdf:type. - kXMP_PropHasType = 0x00000080UL, - - // -------------------------------------------- - // Options relating to the data structure form. - - /// The value is a structure with nested fields. - kXMP_PropValueIsStruct = 0x00000100UL, - - /// The value is an array (RDF alt/bag/seq). The "ArrayIs..." flags identify specific types - /// of array; default is a general unordered array, serialized using an \c rdf:Bag container. - kXMP_PropValueIsArray = 0x00000200UL, - - /// The item order does not matter. - kXMP_PropArrayIsUnordered = kXMP_PropValueIsArray, - - /// Implies \c #kXMP_PropValueIsArray, item order matters. It is serialized using an \c rdf:Seq container. - kXMP_PropArrayIsOrdered = 0x00000400UL, - - /// Implies \c #kXMP_PropArrayIsOrdered, items are alternates. It is serialized using an \c rdf:Alt container. - kXMP_PropArrayIsAlternate = 0x00000800UL, - - // ------------------------------------ - // Additional struct and array options. - - /// Implies \c #kXMP_PropArrayIsAlternate, items are localized text. Each array element is a - /// simple property with an \c xml:lang attribute. - kXMP_PropArrayIsAltText = 0x00001000UL, - - // kXMP_InsertBeforeItem = 0x00004000UL, ! Used by SetXyz functions. - // kXMP_InsertAfterItem = 0x00008000UL, ! Used by SetXyz functions. - - // ---------------------------- - // Other miscellaneous options. - - /// This property is an alias name for another property. This is only returned by - /// \c TXMPMeta::GetProperty() and then only if the property name is simple, not an path expression. - kXMP_PropIsAlias = 0x00010000UL, - - /// This property is the base value (actual) for a set of aliases.This is only returned by - /// \c TXMPMeta::GetProperty() and then only if the property name is simple, not an path expression. - kXMP_PropHasAliases = 0x00020000UL, - - /// The value of this property is "owned" by the application, and should not generally be editable in a UI. - kXMP_PropIsInternal = 0x00040000UL, - - /// The value of this property is not derived from the document content. - kXMP_PropIsStable = 0x00100000UL, - - /// The value of this property is derived from the document content. - kXMP_PropIsDerived = 0x00200000UL, - - // kXMPUtil_AllowCommas = 0x10000000UL, ! Used by TXMPUtils::CatenateArrayItems and ::SeparateArrayItems. - // kXMP_DeleteExisting = 0x20000000UL, ! Used by TXMPMeta::SetXyz functions to delete any pre-existing property. - // kXMP_SchemaNode = 0x80000000UL, ! Returned by iterators - #define to avoid warnings - - // ------------------------------ - // Masks that are multiple flags. - - /// Property type bit-flag mask for all array types - kXMP_PropArrayFormMask = kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText, - - /// Property type bit-flag mask for composite types (array and struct) - kXMP_PropCompositeMask = kXMP_PropValueIsStruct | kXMP_PropArrayFormMask, - - /// Mask for bits that are reserved for transient use by the implementation. - kXMP_ImplReservedMask = 0x70000000L - -}; - -#define kXMP_SchemaNode ((XMP_OptionBits)0x80000000UL) - -/// Option bit flags for the \c TXMPMeta property setting functions. These option bits are shared -/// with the accessor functions: -/// \li \c #kXMP_PropValueIsURI -/// \li \c #kXMP_PropValueIsStruct -/// \li \c #kXMP_PropValueIsArray -/// \li \c #kXMP_PropArrayIsOrdered -/// \li \c #kXMP_PropArrayIsAlternate -/// \li \c #kXMP_PropArrayIsAltText -enum { - - /// Option for array item location: Insert a new item before the given index. - kXMP_InsertBeforeItem = 0x00004000UL, - - /// Option for array item location: Insert a new item after the given index. - kXMP_InsertAfterItem = 0x00008000UL, - - /// Delete any pre-existing property. - kXMP_DeleteExisting = 0x20000000UL, - - /// Bit-flag mask for property-value option bits - kXMP_PropValueOptionsMask = kXMP_PropValueIsURI, - - /// Bit-flag mask for array-item location bits - kXMP_PropArrayLocationMask = kXMP_InsertBeforeItem | kXMP_InsertAfterItem - -}; - -// ------------------------------------------------------------------------------------------------- - -/// Option bit flags for \c TXMPMeta::ParseFromBuffer(). -enum { - - /// Require a surrounding \c x:xmpmeta element. - kXMP_RequireXMPMeta = 0x0001UL, - - /// This is the not last input buffer for this parse stream. - kXMP_ParseMoreBuffers = 0x0002UL, - - /// Do not reconcile alias differences, throw an exception. - kXMP_StrictAliasing = 0x0004UL - -}; - -/// Option bit flags for \c TXMPMeta::SerializeToBuffer(). -enum { - - // *** Option to remove empty struct/array, or leaf with empty value? - - /// Omit the XML packet wrapper. - kXMP_OmitPacketWrapper = 0x0010UL, - - /// Default is a writeable packet. - kXMP_ReadOnlyPacket = 0x0020UL, - - /// Use a compact form of RDF. - kXMP_UseCompactFormat = 0x0040UL, - - /// Include a padding allowance for a thumbnail image. - kXMP_IncludeThumbnailPad = 0x0100UL, - - /// The padding parameter is the overall packet length. - kXMP_ExactPacketLength = 0x0200UL, - - /// Show aliases as XML comments. - kXMP_WriteAliasComments = 0x0400UL, - - /// Omit all formatting whitespace. - kXMP_OmitAllFormatting = 0x0800UL, - - /// Omit the x:xmpmeta element surrounding the rdf:RDF element. - kXMP_OmitXMPMetaElement = 0x1000UL, - - _XMP_LittleEndian_Bit = 0x0001UL, // ! Don't use directly, see the combined values below! - _XMP_UTF16_Bit = 0x0002UL, - _XMP_UTF32_Bit = 0x0004UL, - - /// Bit-flag mask for encoding-type bits - kXMP_EncodingMask = 0x0007UL, - - /// Use UTF8 encoding - kXMP_EncodeUTF8 = 0UL, - - /// Use UTF16 big-endian encoding - kXMP_EncodeUTF16Big = _XMP_UTF16_Bit, - - /// Use UTF16 little-endian encoding - kXMP_EncodeUTF16Little = _XMP_UTF16_Bit | _XMP_LittleEndian_Bit, - - /// Use UTF32 big-endian encoding - kXMP_EncodeUTF32Big = _XMP_UTF32_Bit, - - /// Use UTF13 little-endian encoding - kXMP_EncodeUTF32Little = _XMP_UTF32_Bit | _XMP_LittleEndian_Bit - -}; - -// ------------------------------------------------------------------------------------------------- - -/// Option bit flags for \c TXMPIterator construction. -enum { - - /// The low 8 bits are an enum of what data structure to iterate. - kXMP_IterClassMask = 0x00FFUL, - - /// Iterate the property tree of a TXMPMeta object. - kXMP_IterProperties = 0x0000UL, - - /// Iterate the global alias table. - kXMP_IterAliases = 0x0001UL, - - /// Iterate the global namespace table. - kXMP_IterNamespaces = 0x0002UL, - - /// Just do the immediate children of the root, default is subtree. - kXMP_IterJustChildren = 0x0100UL, - - /// Just do the leaf nodes, default is all nodes in the subtree. - kXMP_IterJustLeafNodes = 0x0200UL, - - /// Return just the leaf part of the path, default is the full path. - kXMP_IterJustLeafName = 0x0400UL, - - /// Include aliases, default is just actual properties. - kXMP_IterIncludeAliases = 0x0800UL, - - /// Omit all qualifiers. - kXMP_IterOmitQualifiers = 0x1000UL - -}; - -/// Option bit flags for \c TXMPIterator::Skip(). -enum { - - /// Skip the subtree below the current node. - kXMP_IterSkipSubtree = 0x0001UL, - - /// Skip the subtree below and remaining siblings of the current node. - kXMP_IterSkipSiblings = 0x0002UL - -}; - -// ------------------------------------------------------------------------------------------------- -/// Option bit flags for \c TXMPUtils::CatenateArrayItems() and \c TXMPUtils::SeparateArrayItems(). -/// These option bits are shared with the accessor functions: -/// \li \c #kXMP_PropValueIsArray, -/// \li \c #kXMP_PropArrayIsOrdered, -/// \li \c #kXMP_PropArrayIsAlternate, -/// \li \c #kXMP_PropArrayIsAltText -enum { - - /// Allow commas in item values, default is separator. - kXMPUtil_AllowCommas = 0x10000000UL - -}; - -/// Option bit flags for \c TXMPUtils::RemoveProperties() and \c TXMPUtils::AppendProperties(). -enum { - - /// Do all properties, default is just external properties. - kXMPUtil_DoAllProperties = 0x0001UL, - - /// Replace existing values, default is to leave them. - kXMPUtil_ReplaceOldValues = 0x0002UL, - - /// Delete properties if the new value is empty. - kXMPUtil_DeleteEmptyValues = 0x0004UL, - - /// Include aliases, default is just actual properties. - kXMPUtil_IncludeAliases = 0x0800UL - -}; - -// ================================================================================================= -// Types and Constants for XMPFiles -// ================================ - -/// File format constants for use with XMPFiles. -enum { - - // ! Hex used to avoid gcc warnings. Leave the constants so the text reads big endian. There - // ! seems to be no decent way on UNIX to determine the target endianness at compile time. - // ! Forcing it on the client isn't acceptable. - - // -------------------- - // Public file formats. - - /// Public file format constant: 'PDF ' - kXMP_PDFFile = 0x50444620UL, - /// Public file format constant: 'PS ', general PostScript following DSC conventions - kXMP_PostScriptFile = 0x50532020UL, - /// Public file format constant: 'EPS ', encapsulated PostScript - kXMP_EPSFile = 0x45505320UL, - - /// Public file format constant: 'JPEG' - kXMP_JPEGFile = 0x4A504547UL, - /// Public file format constant: 'JPX ', JPEG 2000, ISO 15444-1 - kXMP_JPEG2KFile = 0x4A505820UL, - /// Public file format constant: 'TIFF' - kXMP_TIFFFile = 0x54494646UL, - /// Public file format constant: 'GIF ' - kXMP_GIFFile = 0x47494620UL, - /// Public file format constant: 'PNG ' - kXMP_PNGFile = 0x504E4720UL, - - /// Public file format constant: 'SWF ' - kXMP_SWFFile = 0x53574620UL, - /// Public file format constant: 'FLA ' - kXMP_FLAFile = 0x464C4120UL, - /// Public file format constant: 'FLV ' - kXMP_FLVFile = 0x464C5620UL, - - /// Public file format constant: 'MOV ', Quicktime - kXMP_MOVFile = 0x4D4F5620UL, - /// Public file format constant: 'AVI ' - kXMP_AVIFile = 0x41564920UL, - /// Public file format constant: 'CIN ', Cineon - kXMP_CINFile = 0x43494E20UL, - /// Public file format constant: 'WAV ' - kXMP_WAVFile = 0x57415620UL, - /// Public file format constant: 'MP3 ' - kXMP_MP3File = 0x4D503320UL, - /// Public file format constant: 'SES ', Audition session - kXMP_SESFile = 0x53455320UL, - /// Public file format constant: 'CEL ', Audition loop - kXMP_CELFile = 0x43454C20UL, - /// Public file format constant: 'MPEG' - kXMP_MPEGFile = 0x4D504547UL, - /// Public file format constant: 'MP2 ' - kXMP_MPEG2File = 0x4D503220UL, - /// Public file format constant: 'MP4 ', ISO 14494-12 and -14 - kXMP_MPEG4File = 0x4D503420UL, - /// Public file format constant: 'WMAV', Windows Media Audio and Video - kXMP_WMAVFile = 0x574D4156UL, - /// Public file format constant: 'AIFF' - kXMP_AIFFFile = 0x41494646UL, - /// Public file format constant: 'P2 ', a collection not really a single file - kXMP_P2File = 0x50322020UL, - /// Public file format constant: 'XDCF', a collection not really a single file - kXMP_XDCAM_FAMFile = 0x58444346UL, - /// Public file format constant: 'XDCS', a collection not really a single file - kXMP_XDCAM_SAMFile = 0x58444353UL, - /// Public file format constant: 'XDCX', a collection not really a single file - kXMP_XDCAM_EXFile = 0x58444358UL, - /// Public file format constant: 'AVHD', a collection not really a single file - kXMP_AVCHDFile = 0x41564844UL, - /// Public file format constant: 'SHDV', a collection not really a single file - kXMP_SonyHDVFile = 0x53484456UL, - - /// Public file format constant: 'HTML' - kXMP_HTMLFile = 0x48544D4CUL, - /// Public file format constant: 'XML ' - kXMP_XMLFile = 0x584D4C20UL, - /// Public file format constant: 'text' - kXMP_TextFile = 0x74657874UL, - - // ------------------------------- - // Adobe application file formats. - - /// Adobe application file format constant: 'PSD ' - kXMP_PhotoshopFile = 0x50534420UL, - /// Adobe application file format constant: 'AI ' - kXMP_IllustratorFile = 0x41492020UL, - /// Adobe application file format constant: 'INDD' - kXMP_InDesignFile = 0x494E4444UL, - /// Adobe application file format constant: 'AEP ' - kXMP_AEProjectFile = 0x41455020UL, - /// Adobe application file format constant: 'AET ', After Effects Project Template - kXMP_AEProjTemplateFile = 0x41455420UL, - /// Adobe application file format constant: 'FFX ' - kXMP_AEFilterPresetFile = 0x46465820UL, - /// Adobe application file format constant: 'NCOR' - kXMP_EncoreProjectFile = 0x4E434F52UL, - /// Adobe application file format constant: 'PRPJ' - kXMP_PremiereProjectFile = 0x5052504AUL, - /// Adobe application file format constant: 'PRTL' - kXMP_PremiereTitleFile = 0x5052544CUL, - /// Adobe application file format constant: 'UCF ', Universal Container Format - kXMP_UCFFile = 0x55434620UL, - - // ------- - // Others. - - /// Unknown file format constant: ' ' - kXMP_UnknownFile = 0x20202020UL - -}; - -/// Type for file format identification constants. See \c #kXMP_PDFFile and following. -typedef XMP_Uns32 XMP_FileFormat; - -// ------------------------------------------------------------------------------------------------- - -/// Byte-order masks, do not use directly -enum { - kXMP_CharLittleEndianMask = 1, - kXMP_Char16BitMask = 2, - kXMP_Char32BitMask = 4 -}; - -/// Constants to allow easy testing for 16/32 bit and big/little endian. -enum { - /// 8-bit - kXMP_Char8Bit = 0, - /// 16-bit big-endian - kXMP_Char16BitBig = kXMP_Char16BitMask, - /// 16-bit little-endian - kXMP_Char16BitLittle = kXMP_Char16BitMask | kXMP_CharLittleEndianMask, - /// 32-bit big-endian - kXMP_Char32BitBig = kXMP_Char32BitMask, - /// 32-bit little-endian - kXMP_Char32BitLittle = kXMP_Char32BitMask | kXMP_CharLittleEndianMask, - /// Variable or not-yet-known cases - kXMP_CharUnknown = 1 -}; - -/// \name Macros to test components of the character form mask -/// @{ -/// -/// \def XMP_CharFormIs16Bit -/// \brief Macro reports the encoding of a character. -/// \param f The character to check. -/// -/// \def XMP_CharFormIs32Bit -/// \brief Macro reports the encoding of a character. -/// \param f The character to check. -/// -/// \def XMP_CharFormIsBigEndian -/// \brief Macro reports the byte-order of a character. -/// \param f The character to check. -/// -/// \def XMP_CharFormIsLittleEndian -/// \brief Macro reports the byte-order of a character. -/// \param f The character to check. -/// -/// \def XMP_GetCharSize -/// \brief Macro reports the byte-size of a character. -/// \param f The character to check. -/// -/// \def XMP_CharToSerializeForm -/// \brief Macro converts \c XMP_Uns8 to \c XMP_OptionBits. -/// \param cf The character to convert. -/// -/// \def XMP_CharFromSerializeForm -/// \brief Macro converts \c XMP_OptionBits to \c XMP_Uns8. -/// \param sf The character to convert. -/// -/// @} - -#define XMP_CharFormIs16Bit(f) ( ((int)(f) & kXMP_Char16BitMask) != 0 ) -#define XMP_CharFormIs32Bit(f) ( ((int)(f) & kXMP_Char32BitMask) != 0 ) -#define XMP_CharFormIsBigEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) == 0 ) -#define XMP_CharFormIsLittleEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) != 0 ) -#define XMP_GetCharSize(f) ( ((int)(f)&6) == 0 ? 1 : (int)(f)&6 ) -#define XMP_CharToSerializeForm(cf) ( (XMP_OptionBits)(cf) ) -#define XMP_CharFromSerializeForm(sf) ( (XMP_Uns8)(sf) ) - -/// \def kXMPFiles_UnknownOffset -/// \brief Constant for an unknown packet offset within a file. -#define kXMPFiles_UnknownOffset ((XMP_Int64)-1) - -/// \def kXMPFiles_UnknownLength -/// \brief Constant for an unknown packet length within a file. -#define kXMPFiles_UnknownLength ((XMP_Int32)-1) - -/// XMP packet description -struct XMP_PacketInfo { - - /// Packet offset in the file in bytes, -1 if unknown. - XMP_Int64 offset; - /// Packet length in the file in bytes, -1 if unknown. - XMP_Int32 length; - /// Packet padding size in bytes, zero if unknown. - XMP_Int32 padSize; // Zero if unknown. - - /// Character format using the values \c kXMP_Char8Bit, \c kXMP_Char16BitBig, etc. - XMP_Uns8 charForm; - /// True if there is a packet wrapper and the trailer says writeable by dumb packet scanners. - XMP_Bool writeable; - /// True if there is a packet wrapper, the "" XML processing instructions. - XMP_Bool hasWrapper; - - /// Padding to make the struct's size be a multiple 4. - XMP_Uns8 pad; - - /// Default constructor. - XMP_PacketInfo() : offset(kXMPFiles_UnknownOffset), length(kXMPFiles_UnknownLength), - padSize(0), charForm(0), writeable(0), hasWrapper(0), pad(0) {}; - -}; - -/// Version of the XMP_PacketInfo type -enum { - /// Version of the XMP_PacketInfo type - kXMP_PacketInfoVersion = 3 -}; - -// ------------------------------------------------------------------------------------------------- - -/// Values for \c XMP_ThumbnailInfo::tnailFormat. -enum { - /// The thumbnail data has an unknown format. - kXMP_UnknownTNail = 0, - /// The thumbnail data is a JPEG stream, presumably compressed. - kXMP_JPEGTNail = 1, - /// The thumbnail data is a TIFF stream, presumably uncompressed. - kXMP_TIFFTNail = 2, - /// The thumbnail data is in the format of Photoshop Image Resource 1036. - kXMP_PShopTNail = 3 -}; - -/// Thumbnail descriptor -struct XMP_ThumbnailInfo { - - /// The format of the containing file. - XMP_FileFormat fileFormat; - /// Full image size in pixels. - XMP_Uns32 fullWidth, fullHeight; - /// Thumbnail image size in pixels. - XMP_Uns32 tnailWidth, tnailHeight; - /// Orientation of full image and thumbnail, as defined by Exif for tag 274. - - XMP_Uns16 fullOrientation, tnailOrientation; - /// Raw image data from the host file, valid for life of the owning \c XMPFiles object. Do not modify! - const XMP_Uns8 * tnailImage; - /// The size in bytes of the thumbnail image data. - XMP_Uns32 tnailSize; - /// The format of the thumbnail image data. - XMP_Uns8 tnailFormat; - - /// Padding to make the struct's size be a multiple 4. - XMP_Uns8 pad1, pad2, pad3; - - /// Default constructor. - XMP_ThumbnailInfo() : fileFormat(kXMP_UnknownFile), fullWidth(0), fullHeight(0), - tnailWidth(0), tnailHeight(0), fullOrientation(0), tnailOrientation(0), - tnailImage(0), tnailSize(0), tnailFormat(kXMP_UnknownTNail) {}; - -}; - -/// Version of the XMP_ThumbnailInfo type -enum { - /// Version of the XMP_ThumbnailInfo type - kXMP_ThumbnailInfoVersion = 1 -}; - -// ------------------------------------------------------------------------------------------------- - -/// Option bit flags for \c TXMPFiles::Initialize(). -enum { - /// Do not initialize QuickTime, the client will. - kXMPFiles_NoQuickTimeInit = 0x0001 -}; - -/// Option bit flags for \c TXMPFiles::GetFormatInfo(). -enum { - - /// Can inject first-time XMP into an existing file. - kXMPFiles_CanInjectXMP = 0x00000001, - - /// Can expand XMP or other metadata in an existing file. - kXMPFiles_CanExpand = 0x00000002, - - /// Can copy one file to another, writing new metadata. - kXMPFiles_CanRewrite = 0x00000004, - - /// Can expand, but prefers in-place update. - kXMPFiles_PrefersInPlace = 0x00000008, - - /// Supports reconciliation between XMP and other forms. - kXMPFiles_CanReconcile = 0x00000010, - - /// Allows access to just the XMP, ignoring other forms. - kXMPFiles_AllowsOnlyXMP = 0x00000020, - - /// File handler returns raw XMP packet information. - kXMPFiles_ReturnsRawPacket = 0x00000040, - - /// File handler returns native thumbnail. - kXMPFiles_ReturnsTNail = 0x00000080, - - /// The file handler does the file open and close. - kXMPFiles_HandlerOwnsFile = 0x00000100, - - /// The file handler allows crash-safe file updates. - kXMPFiles_AllowsSafeUpdate = 0x00000200, - - /// The file format needs the XMP packet to be read-only. - kXMPFiles_NeedsReadOnlyPacket = 0x00000400, - - /// The file handler uses a "sidecar" file for the XMP. - kXMPFiles_UsesSidecarXMP = 0x00000800, - - /// The format is folder oriented, for example the P2 video format. - kXMPFiles_FolderBasedFormat = 0x00001000 - -}; - -/// Option bit flags for \c TXMPFiles::OpenFile(). -enum { - - /// Open for read-only access. - kXMPFiles_OpenForRead = 0x00000001, - - /// Open for reading and writing. - kXMPFiles_OpenForUpdate = 0x00000002, - - /// Only the XMP is wanted, allows space/time optimizations. - kXMPFiles_OpenOnlyXMP = 0x00000004, - - /// Cache thumbnail if possible, \c TXMPFiles::GetThumbnail() will be called. - kXMPFiles_OpenCacheTNail = 0x00000008, - - /// Be strict about locating XMP and reconciling with other forms. - kXMPFiles_OpenStrictly = 0x00000010, - - /// Require the use of a smart handler. - kXMPFiles_OpenUseSmartHandler = 0x00000020, - - /// Force packet scanning, do not use a smart handler. - kXMPFiles_OpenUsePacketScanning = 0x00000040, - - /// Only packet scan files "known" to need scanning. - kXMPFiles_OpenLimitedScanning = 0x00000080, - - /// Attempt to repair a file opened for update, default is to not open (throw an exception). - kXMPFiles_OpenRepairFile = 0x00000100, - - /// Set if calling from background thread. - kXMPFiles_OpenInBackground = 0x10000000 - -}; - -// A note about kXMPFiles_OpenInBackground. The XMPFiles handler for .mov files currently uses -// QuickTime. On Macintosh, calls to Enter/ExitMovies versus Enter/ExitMoviesOnThread must be made. -// This option is used to signal background use so that the .mov handler can behave appropriately. - -/// Option bit flags for \c TXMPFiles::CloseFile(). -enum { - /// Write into a temporary file and swap for crash safety. - kXMPFiles_UpdateSafely = 0x0001 -}; - -// ================================================================================================= -// Exception codes -// =============== - -/// \name Errors Exception handling -/// @{ -/// -/// XMP Tookit errors result in throwing an \c XMP_Error exception. Any exception thrown within the -/// XMP Toolkit is caught in the toolkit and rethrown as an \c XMP_Error. -/// -/// The \c XMP_Error class contains a numeric code and an English explanation. New numeric codes may -/// be added at any time. There are typically many possible explanations for each numeric code. The -/// explanations try to be precise about the specific circumstances causing the error. -/// -/// \note The explanation string is for debugging use only. It must not be shown to users in a -/// final product. It is written for developers not users, and never localized. -/// - -/// XMP Toolkit error, associates an error code with a descriptive error string. -class XMP_Error { -public: - - /// @brief Constructor for an XMP_Error. - /// - /// @param _id The numeric code. - /// - /// @param _errMsg The descriptive string, for debugging use only. It must not be shown to users - /// in a final product. It is written for developers, not users, and never localized. - XMP_Error ( XMP_Int32 _id, XMP_StringPtr _errMsg ) : id(_id), errMsg(_errMsg) {}; - - /// Retrieves the numeric code from an XMP_Error. - inline XMP_Int32 GetID() const { return id; }; - - /// Retrieves the descriptive string from an XMP_Error. - inline XMP_StringPtr GetErrMsg() const { return errMsg; }; - -private: - /// Exception code. See constants \c #kXMPErr_Unknown and following. - XMP_Int32 id; - /// Descriptive string, for debugging use only. It must not be shown to users in a final - /// product. It is written for developers, not users, and never localized. - XMP_StringPtr errMsg; -}; - -/// Exception code constants -enum { - - // -------------------- - // Generic error codes. - - /// Generic unknown error - kXMPErr_Unknown = 0, - /// Generic undefined error - kXMPErr_TBD = 1, - /// Generic unavailable error - kXMPErr_Unavailable = 2, - /// Generic bad object error - kXMPErr_BadObject = 3, - /// Generic bad parameter error - kXMPErr_BadParam = 4, - /// Generic bad value error - kXMPErr_BadValue = 5, - /// Generic assertion failure - kXMPErr_AssertFailure = 6, - /// Generic enforcement failure - kXMPErr_EnforceFailure = 7, - /// Generic unimplemented error - kXMPErr_Unimplemented = 8, - /// Generic internal failure - kXMPErr_InternalFailure = 9, - /// Generic deprecated error - kXMPErr_Deprecated = 10, - /// Generic external failure - kXMPErr_ExternalFailure = 11, - /// Generic user abort error - kXMPErr_UserAbort = 12, - /// Generic standard exception - kXMPErr_StdException = 13, - /// Generic unknown exception - kXMPErr_UnknownException = 14, - /// Generic out-of-memory error - kXMPErr_NoMemory = 15, - - // ------------------------------------ - // More specific parameter error codes. - - /// Bad schema parameter - kXMPErr_BadSchema = 101, - /// Bad XPath parameter - kXMPErr_BadXPath = 102, - /// Bad options parameter - kXMPErr_BadOptions = 103, - /// Bad index parameter - kXMPErr_BadIndex = 104, - /// Bad iteration position - kXMPErr_BadIterPosition = 105, - /// XML parsing error - kXMPErr_BadParse = 106, - /// Serialization error - kXMPErr_BadSerialize = 107, - /// File format error - kXMPErr_BadFileFormat = 108, - /// No file handler found for format - kXMPErr_NoFileHandler = 109, - /// Data too large for JPEG file format - kXMPErr_TooLargeForJPEG = 110, - - // ----------------------------------------------- - // File format and internal structure error codes. - - /// XML format error - kXMPErr_BadXML = 201, - /// RDF format error - kXMPErr_BadRDF = 202, - /// XMP format error - kXMPErr_BadXMP = 203, - /// Empty iterator - kXMPErr_EmptyIterator = 204, - /// Unicode error - kXMPErr_BadUnicode = 205, - /// TIFF format error - kXMPErr_BadTIFF = 206, - /// JPEG format error - kXMPErr_BadJPEG = 207, - /// PSD format error - kXMPErr_BadPSD = 208, - /// PSIR format error - kXMPErr_BadPSIR = 209, - /// IPTC format error - kXMPErr_BadIPTC = 210, - /// MPEG format error - kXMPErr_BadMPEG = 211 - -}; - -/// @} - -// ================================================================================================= -// Client callbacks -// ================ - -// ------------------------------------------------------------------------------------------------- -/// \name Special purpose callback functions -/// @{ - -/// A signed 32-bit integer used as a status result for the output callback routine, -/// \c XMP_TextOutputProc. Zero means no error, all other values except -1 are private to the callback. -/// The callback is wrapped to prevent exceptions being thrown across DLL boundaries. Any exceptions -/// thrown out of the callback cause a return status of -1. - -typedef XMP_Int32 XMP_Status; - -// ------------------------------------------------------------------------------------------------- -/// The signature of a client-defined callback for text output from XMP Toolkit debugging -/// operations. The callback is invoked one or more times for each line of output. The end of a line -/// is signaled by a '\\n' character at the end of the buffer. Formatting newlines are never present -/// in the middle of a buffer, but values of properties might contain any UTF-8 characters. -/// -/// @param refCon A pointer to client-defined data passed to the TextOutputProc. -/// -/// @param buffer A string containing one line of output. -/// -/// @param bufferSize The number of characters in the output buffer. -/// -/// @return A success/fail status value. Any failure result aborts the output. -/// -/// @see \c TXMPMeta::DumpObject() - -typedef XMP_Status (* XMP_TextOutputProc) ( void * refCon, - XMP_StringPtr buffer, - XMP_StringLen bufferSize ); - -// ------------------------------------------------------------------------------------------------- -/// The signature of a client-defined callback to check for a user request to abort a time-consuming -/// operation within XMPFiles. -/// -/// @param arg A pointer to caller-defined data passed from the registration call. -/// -/// @return True to abort the current operation, which results in an exception being thrown. -/// -/// @see \c TXMPFiles::SetAbortProc() - -typedef bool (* XMP_AbortProc) ( void * arg ); // Used by . - -/// @} - -// ================================================================================================= -// Stuff with no better place to be -// ================================ - -/// XMP Toolkit version information -typedef struct XMP_VersionInfo { - /// The primary release number, the "1" in version "1.2.3". - XMP_Uns8 major; - /// The secondary release number, the "2" in version "1.2.3". - XMP_Uns8 minor; - /// The tertiary release number, the "3" in version "1.2.3". - XMP_Uns8 micro; - /// A 0/1 boolean value, true if this is a debug build. - XMP_Bool isDebug; - /// A rolling build number, monotonically increasing in a release. - XMP_Uns32 build; - /// Individual feature implementation flags. - XMP_Uns32 flags; - /// A comprehensive version information string. - XMP_StringPtr message; -} XMP_VersionInfo; - -// ================================================================================================= - -#if __cplusplus -} // extern "C" -#endif - -#endif // __XMP_Const_h__ diff --git a/xmpsdk/include/XMP_Environment.h b/xmpsdk/include/XMP_Environment.h deleted file mode 100644 index 42635deca5..0000000000 --- a/xmpsdk/include/XMP_Environment.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef __XMP_Environment_h__ -#define __XMP_Environment_h__ 1 - -// ================================================================================================= -// XMP_Environment.h - Build environment flags for the XMP toolkit. -// ================================================================ -// -// This header is just C preprocessor macro definitions to set up the XMP toolkit build environment. -// It must be the first #include in any chain since it might affect things in other #includes. -// -// ================================================================================================= - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================= -// Determine the Platform -// ====================== - -// One of MAC_ENV, WIN_ENV, or UNIX_ENV must be defined by the client. Since some other code -// requires these to be defined without values, they are only used here to define XMP-specific -// macros with 0 or 1 values. - - -#if !defined(_FILE_OFFSET_BITS) -#define _FILE_OFFSET_BITS 64 -#endif - -#if __LP64__ -# ifdef _WIN64 -# undef _WIN64 -# endif -# define _WIN64 1 -#endif - -#if defined _WIN32 -# define WIN_ENV 1 -/* Todo: How to correctly recognize a Mac platform? */ -#elif defined macintosh || defined MACOS_CLASSIC || defined MACOS_X_UNIX || defined MACOS_X || defined MACOS || defined(__APPLE__) -# define MAC_ENV 1 -#else -# define UNIX_ENV 1 -#endif - -// ! Tempting though it might be to have a standard macro for big or little endian, there seems to -// ! be no decent way to do that on our own in UNIX. Forcing it on the client isn't acceptable. - -#if defined ( MAC_ENV ) - - #if 0 // ! maybe someday - ! MAC_ENV - #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true" - #endif - - #if defined ( WIN_ENV ) || defined ( UNIX_ENV ) - #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV" - #endif - - #define XMP_MacBuild 1 - #define XMP_WinBuild 0 - #define XMP_UNIXBuild 0 - -#elif defined ( WIN_ENV ) - - #if 0 // ! maybe someday - ! WIN_ENV - #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true" - #endif - - #if defined ( UNIX_ENV ) - #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV" - #endif - - #define XMP_MacBuild 0 - #define XMP_WinBuild 1 - #define XMP_UNIXBuild 0 - -#elif defined ( UNIX_ENV ) - - #if 0 // ! maybe someday - ! UNIX_ENV - #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true" - #endif - - #define XMP_MacBuild 0 - #define XMP_WinBuild 0 - #define XMP_UNIXBuild 1 - -#else - - #error "XMP environment error - must define one of MAC_ENV, WIN_ENV, or UNIX_ENV" - -#endif - -// ================================================================================================= -// Common Macros -// ============= - -#if defined ( DEBUG ) - #if defined ( NDEBUG ) - #undef NDEBUG - #warning - #warning "XMP environment - DEBUG and NDEBUG defined. NDEBUG has been undefined" - #warning - #endif - #define XMP_DebugBuild 1 -#endif - -#if defined ( NDEBUG ) - #define XMP_DebugBuild 0 -#endif - -#ifndef XMP_DebugBuild - #define XMP_DebugBuild 0 -#endif - -#if XMP_DebugBuild - #include // The assert macro needs printf. -#endif - -#ifndef XMP_64 - #if _WIN64 - #define XMP_64 1 - #else - #define XMP_64 0 - #endif -#endif - -#define UNUSED(x) (void)(x) - -// ================================================================================================= -// Macintosh Specific Settings -// =========================== - -// ================================================================================================= -// Windows Specific Settings -// ========================= - -// ================================================================================================= -// UNIX Specific Settings -// ====================== - -// ================================================================================================= - -#endif // __XMP_Environment_h__ - -/* - If you're using Solaris and the Solaris Studio compiler, then you really - do need to use -library=stdcxx4 along with these inclusions below -*/ -#if defined(OS_SOLARIS) -#include -#include -#include -#include -#include -#if defined(__cplusplus) -#include -#include -#endif -#endif - diff --git a/xmpsdk/include/XMP_Version.h b/xmpsdk/include/XMP_Version.h deleted file mode 100644 index f8b0ea8104..0000000000 --- a/xmpsdk/include/XMP_Version.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __XMP_Version_h__ -#define __XMP_Version_h__ 1 - -/* --------------------------------------------------------------------------------------------- */ -/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */ -/* --------------------------------------------------------------------------------------------- */ - -/* -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= -*/ - -/* ============================================================================================= */ -/** -XMP Toolkit Version Information - -Version information for the XMP toolkit is stored in the executable and available through a runtime -call, SXMPMeta::GetVersionInfo. In addition a static version number is defined in this -header. The information in the executable or returned by SXMPMeta::GetVersionInfo is about -the implementation internals, it is runtime version information. The values defined in this header -describe the version of the API used at client compile time. They do not necessarily relate to the -runtime version. - -Important: Do not display the static values defined here to users as the version of XMP in use. Do -not base runtime decisions on just this static version. It is OK to compare the static and runtime -versions. - -*/ -/* ============================================================================================= */ - -#define XMP_API_VERSION_MAJOR 4 -#define XMP_API_VERSION_MINOR 4 -#define XMP_API_VERSION_MICRO 0 - -#define XMP_API_VERSION 4.4 -#define XMP_API_VERSION_STRING "4.4.0-Exiv2" - -/* ============================================================================================= */ - -#endif /* __XMP_Version_h__ */ diff --git a/xmpsdk/include/client-glue/TXMPIterator.incl_cpp b/xmpsdk/include/client-glue/TXMPIterator.incl_cpp deleted file mode 100644 index 672203e27e..0000000000 --- a/xmpsdk/include/client-glue/TXMPIterator.incl_cpp +++ /dev/null @@ -1,226 +0,0 @@ -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================ -/// \file TXMPIterator.incl_cpp -/// \brief The implementation of the TXMPIterator template class. - -#include "XMPSDK.hpp" -#include "client-glue/WXMP_Common.hpp" -#include "client-glue/WXMPIterator.hpp" - -// ================================================================================================= -// Implementation Guidelines -// ========================= -// -// The implementations of the template functions are very stylized. The jobs done in this code are: -// -// 1. Set up the xmpIter template data member in the constructors. -// 2. Call through to the appropriate WXMPIterator function. -// 3. Copy returned strings and release the threading lock. -// -// The various kinds of functions follow similar patterns, first assuming no returned string: -// -// Constructors - Use an initializer for the xmpIter data member to call the WXMPIterator constructor. -// Destructor - Let the WXMPIterator destructor be implicitly called for the xmpIter data member. -// Static function - Simply call the corresponding WXMPIterator static function. -// Non-static function - Simply call the corresponding WXMPIterator function using xmpIter. -// -// If a member function has returned strings the code looks roughly like this: -// -// <<>> -// <<>> -// if ( <<>> ) { -// if ( outStr != 0 ) outStr->assign ( outPtr, outLen ); -// <<>> -// } -// return result; -// -// The <<>> is the call to the wrapper, and <<>> is the check and throw -// if the wrapper reports failure. The <<>> check is used to determine if the string -// should actually be assigned. For example, GetProperty can't assign the value if the property -// does not exist. There is no <<>> check if it isn't, well, appropriate. Outputs are -// always passed as explicit pointers, and null can be passed if the string is not wanted. The -// inner implementation holds the threading lock if an output string is returned, regardless of -// whether the client wants it or not (which the implementation does not know). -// -// ================================================================================================= - -#ifndef XMP_TraceCTorDTor - #define XMP_TraceCTorDTor 0 -#endif - -#if XMP_TraceCTorDTor - class XIPeek { // Hack to peek at the client ref count in the internal object. - public: - XIPeek(); - virtual ~XIPeek(); - XMP_Int32 clientRefs; - }; -#endif - -// ------------------------------------------------------------------------------------------------- - -#define PropIterCTor(xmpRef,schemaNS,propName,options) \ - WrapCheckIterRef ( newRef, zXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options ) ); \ - this->iterRef = newRef - -// ------------------------------------------------------------------------------------------------- - -#define TableIterCTor(schemaNS,propName,options) \ - WrapCheckIterRef ( newRef, zXMPIterator_TableCTor_1 ( schemaNS, propName, options ) ); \ - this->iterRef = newRef - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator ( const TXMPIterator & original ) : iterRef(original.iterRef) -{ - WXMPIterator_IncrementRefCount_1 ( this->iterRef ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Copy construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPIterator,void):: -operator= ( const TXMPIterator & rhs ) -{ - #if XMP_TraceCTorDTor - XIPeek* xiLHS = (XIPeek*)this->iterRef; - XIPeek* xiRHS = (XIPeek*)rhs.iterRef; - printf ( "Assign TXMPIterator, lhs @ %.8X, rhs @ %.8X\n", this, &rhs ); - printf ( " original lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs ); - printf ( " original rhs ref = %.8X, count = %d\n", xiRHS, xiRHS->clientRefs ); - #endif - XMPIteratorRef oldRef = this->iterRef; // ! Decrement last so errors leave client object OK. - this->iterRef = rhs.iterRef; - WXMPIterator_IncrementRefCount_1 ( this->iterRef ); - WXMPIterator_DecrementRefCount_1 ( oldRef ); - #if XMP_TraceCTorDTor - printf ( " result lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator() : iterRef(0) -{ - throw XMP_Error ( kXMPErr_Unavailable, "No default construction for XMP iterators" ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Default construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options /* = 0 */ ) : iterRef(0) -{ - PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, propName, options ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Construct property TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_OptionBits options /* = 0 */ ) : iterRef(0) -{ - PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, "", options ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Construct schema TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator ( const TXMPMeta & xmpObj, - XMP_OptionBits options /* = 0 */ ) : iterRef(0) -{ - PropIterCTor ( xmpObj.GetInternalRef(), "", "", options ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Construct tree TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -TXMPIterator ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ) : iterRef(0) -{ - TableIterCTor ( schemaNS, propName, options ); - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Construct table TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPIterator):: -~TXMPIterator () throw() -{ - #if XMP_TraceCTorDTor - XIPeek* xiPtr = (XIPeek*)this->iterRef; - printf ( "Destruct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs ); - #endif - WXMPIterator_DecrementRefCount_1 ( this->iterRef ); - this->iterRef = 0; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPIterator,bool):: -Next ( tStringObj * schemaNS /* = 0 */, - tStringObj * propPath /* = 0 */, - tStringObj * propValue /* = 0 */, - XMP_OptionBits * options /* = 0 */ ) -{ - XMP_StringPtr schemaPtr = 0; - XMP_StringLen schemaLen = 0; - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - XMP_StringPtr valuePtr = 0; - XMP_StringLen valueLen = 0; - WrapCheckBool ( found, zXMPIterator_Next_1 ( &schemaPtr, &schemaLen, &pathPtr, &pathLen, &valuePtr, &valueLen, options ) ); - if ( found ) { - if ( schemaNS != 0 ) schemaNS->assign ( schemaPtr, schemaLen ); - if ( propPath != 0 ) propPath->assign ( pathPtr, pathLen ); - if ( propValue != 0 ) propValue->assign ( valuePtr, valueLen ); - WXMPUtils_UnlockIter_1 ( this->iterRef, 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPIterator,void):: -Skip ( XMP_OptionBits options ) -{ - WrapCheckVoid ( zXMPIterator_Skip_1 ( options ) ); -} - -// ================================================================================================= diff --git a/xmpsdk/include/client-glue/TXMPMeta.incl_cpp b/xmpsdk/include/client-glue/TXMPMeta.incl_cpp deleted file mode 100644 index 0131aa50ef..0000000000 --- a/xmpsdk/include/client-glue/TXMPMeta.incl_cpp +++ /dev/null @@ -1,935 +0,0 @@ -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================ -/// \file TXMPMeta.incl_cpp -/// \brief The implementation of the TXMPMeta template class. - -#include "XMPSDK.hpp" -#include "client-glue/WXMP_Common.hpp" -#include "client-glue/WXMPMeta.hpp" - -// ================================================================================================= -// Implementation Guidelines -// ========================= -// -// The implementations of the template functions are very stylized. ... -// -// ================================================================================================= - -#ifndef XMP_TraceCTorDTor - #define XMP_TraceCTorDTor 0 -#endif - -#if XMP_TraceCTorDTor - class XMPeek { // Hack to peek at the client ref count in the internal object. - public: - XMPeek(); - virtual ~XMPeek(); - XMP_Int32 clientRefs; - }; -#endif - -// ================================================================================================= -// Local utilities -// =============== - -// ------------------------------------------------------------------------------------------------- - -class TOPW_Info { -public: - XMP_TextOutputProc clientProc; - void * clientRefCon; - TOPW_Info ( XMP_TextOutputProc proc, void * refCon ) : clientProc(proc), clientRefCon(refCon) {}; -private: - TOPW_Info() {}; // ! Hide default constructor. -}; - -static XMP_Status TextOutputProcWrapper ( void * refCon, - XMP_StringPtr buffer, - XMP_StringLen bufferSize ) -{ - try { // Don't let client callback exceptions propagate across DLL boundaries. - TOPW_Info * info = (TOPW_Info*)refCon; - return info->clientProc ( info->clientRefCon, buffer, bufferSize ); - } catch ( ... ) { - return -1; - } -} - -// ================================================================================================= -// Initialization and termination -// ============================== - -XMP_MethodIntro(TXMPMeta,void):: -GetVersionInfo ( XMP_VersionInfo * info ) -{ - WrapNoCheckVoid ( zXMPMeta_GetVersionInfo_1 ( info ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -Initialize() -{ - WrapCheckBool ( ok, zXMPMeta_Initialize_1() ); - return ok; -} -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -Terminate() -{ - WrapNoCheckVoid ( zXMPMeta_Terminate_1() ); -} - -// ================================================================================================= -// Constuctors, destructor, operators -// ================================== - -static XMPMetaRef DefaultCTor() -{ - WrapCheckMetaRef ( newRef, zXMPMeta_CTor_1() ); - return newRef; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPMeta):: -TXMPMeta() : xmpRef(DefaultCTor()) -{ - #if XMP_TraceCTorDTor - XMPeek* xmPtr = (XMPeek*)this->xmpRef; - printf ( "Default construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPMeta):: -TXMPMeta ( const TXMPMeta & original ) : xmpRef(original.xmpRef) -{ - WXMPMeta_IncrementRefCount_1 ( this->xmpRef ); - #if XMP_TraceCTorDTor - XMPeek* xmPtr = (XMPeek*)this->xmpRef; - printf ( "Copy construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -operator= ( const TXMPMeta & rhs ) -{ - #if XMP_TraceCTorDTor - XMPeek* xmLHS = (XMPeek*)this->xmpRef; - XMPeek* xmRHS = (XMPeek*)rhs.xmpRef; - printf ( "Assign TXMPMeta, lhs @ %.8X, rhs @ %.8X\n", this, &rhs ); - printf ( " original lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs ); - printf ( " original rhs ref = %.8X, count = %d\n", xmRHS, xmRHS->clientRefs ); - #endif - XMPMetaRef oldRef = this->xmpRef; // ! Decrement last so errors leave client object OK. - this->xmpRef = rhs.xmpRef; - WXMPMeta_IncrementRefCount_1 ( this->xmpRef ); // Increment the count on the new ref. - WXMPMeta_DecrementRefCount_1 ( oldRef ); // Decrement the count on the old ref. - #if XMP_TraceCTorDTor - printf ( " result lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPMeta):: -TXMPMeta ( XMPMetaRef _xmpRef ) : xmpRef(_xmpRef) -{ - WXMPMeta_IncrementRefCount_1 ( this->xmpRef ); - #if XMP_TraceCTorDTor - XMPeek* xmPtr = (XMPeek*)this->xmpRef; - printf ( "Ref construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs ); - #endif -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPMeta):: -TXMPMeta ( XMP_StringPtr buffer, - XMP_StringLen xmpSize ) : xmpRef(DefaultCTor()) -{ - #if XMP_TraceCTorDTor - XMPeek* xmPtr = (XMPeek*)this->xmpRef; - printf ( "Parse construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs ); - #endif - try { - this->ParseFromBuffer ( buffer, xmpSize ); - } catch ( ... ) { - WXMPMeta_DecrementRefCount_1 ( this->xmpRef ); - this->xmpRef = 0; - throw; - } -} - -// ------------------------------------------------------------------------------------------------- - -XMP_CTorDTorIntro(TXMPMeta):: -~TXMPMeta() throw() -{ - #if XMP_TraceCTorDTor - XMPeek* xmPtr = (XMPeek*)this->xmpRef; - printf ( "Destruct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs ); - #endif - WXMPMeta_DecrementRefCount_1 ( this->xmpRef ); - this->xmpRef = 0; - -} // ~TXMPMeta () - -// ================================================================================================= -// Global state functions -// ====================== - -XMP_MethodIntro(TXMPMeta,XMP_OptionBits):: -GetGlobalOptions() -{ - WrapCheckOptions ( options, zXMPMeta_GetGlobalOptions_1() ); - return options; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetGlobalOptions ( XMP_OptionBits options ) -{ - WrapCheckVoid ( zXMPMeta_SetGlobalOptions_1 ( options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,XMP_Status):: -DumpNamespaces ( XMP_TextOutputProc outProc, - void * refCon ) -{ - TOPW_Info info ( outProc, refCon ); - WrapCheckStatus ( status, zXMPMeta_DumpNamespaces_1 ( TextOutputProcWrapper, &info ) ); - return status; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,XMP_Status):: -DumpAliases ( XMP_TextOutputProc outProc, - void * refCon ) -{ - TOPW_Info info ( outProc, refCon ); - WrapCheckStatus ( status, zXMPMeta_DumpAliases_1 ( TextOutputProcWrapper, &info ) ); - return status; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -RegisterNamespace ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix ) -{ - WrapCheckVoid ( zXMPMeta_RegisterNamespace_1 ( namespaceURI, prefix ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetNamespacePrefix ( XMP_StringPtr namespaceURI, - tStringObj * namespacePrefix ) -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetNamespacePrefix_1 ( namespaceURI, &resultPtr, &resultLen ) ); - if ( found ) { - if ( namespacePrefix != 0 ) namespacePrefix->assign ( resultPtr, resultLen ); - WXMPMeta_Unlock_1 ( 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetNamespaceURI ( XMP_StringPtr namespacePrefix, - tStringObj * namespaceURI ) -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetNamespaceURI_1 ( namespacePrefix, &resultPtr, &resultLen ) ); - if ( found ) { - if ( namespaceURI != 0 ) namespaceURI->assign ( resultPtr, resultLen ); - WXMPMeta_Unlock_1 ( 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteNamespace ( XMP_StringPtr namespaceURI ) -{ - WrapCheckVoid ( zXMPMeta_DeleteNamespace_1 ( namespaceURI ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm ) -{ - WrapCheckVoid ( zXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - tStringObj * actualNS, - tStringObj * actualProp, - XMP_OptionBits * arrayForm ) -{ - XMP_StringPtr nsPtr = 0; - XMP_StringLen nsLen = 0; - XMP_StringPtr propPtr = 0; - XMP_StringLen propLen = 0; - WrapCheckBool ( found, zXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, &nsPtr, &nsLen, &propPtr, &propLen, arrayForm ) ); - if ( found ) { - if ( actualNS != 0 ) actualNS->assign ( nsPtr, nsLen ); - if ( actualProp != 0 ) actualProp->assign ( propPtr, propLen ); - WXMPMeta_Unlock_1 ( 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp ) -{ - WrapCheckVoid ( zXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -RegisterStandardAliases ( XMP_StringPtr schemaNS ) -{ - WrapCheckVoid ( zXMPMeta_RegisterStandardAliases_1 ( schemaNS ) ); -} - -// ================================================================================================= -// Basic property manipulation functions -// ===================================== - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - tStringObj * propValue, - XMP_OptionBits * options ) const -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetProperty_1 ( schemaNS, propName, &resultPtr, &resultLen, options ) ); - if ( found ) { - if ( propValue != 0 ) propValue->assign ( resultPtr, resultLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - tStringObj * itemValue, - XMP_OptionBits * options ) const -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetArrayItem_1 ( schemaNS, arrayName, itemIndex, &resultPtr, &resultLen, options ) ); - if ( found ) { - if ( itemValue != 0 ) itemValue->assign ( resultPtr, resultLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - tStringObj * fieldValue, - XMP_OptionBits * options ) const -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetStructField_1 ( schemaNS, structName, fieldNS, fieldName, &resultPtr, &resultLen, options ) ); - if ( found ) { - if ( fieldValue != 0 ) fieldValue->assign ( resultPtr, resultLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - tStringObj * qualValue, - XMP_OptionBits * options ) const -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckBool ( found, zXMPMeta_GetQualifier_1 ( schemaNS, propName, qualNS, qualName, &resultPtr, &resultLen, options ) ); - if ( found ) { - if ( qualValue != 0 ) qualValue->assign ( resultPtr, resultLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); - } - return found; -} //GetQualifier () - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_1 ( schemaNS, propName, propValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const tStringObj & propValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->SetProperty ( schemaNS, propName, propValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetArrayItem_1 ( schemaNS, arrayName, itemIndex, itemValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - const tStringObj & itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_AppendArrayItem_1 ( schemaNS, arrayName, arrayOptions, itemValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - const tStringObj & itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetStructField_1 ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - const tStringObj & fieldValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetQualifier_1 ( schemaNS, propName, qualNS, qualName, qualValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - const tStringObj & qualValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) -{ - WrapCheckVoid ( zXMPMeta_DeleteProperty_1 ( schemaNS, propName ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) -{ - WrapCheckVoid ( zXMPMeta_DeleteArrayItem_1 ( schemaNS, arrayName, itemIndex ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) -{ - WrapCheckVoid ( zXMPMeta_DeleteStructField_1 ( schemaNS, structName, fieldNS, fieldName ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -DeleteQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) -{ - WrapCheckVoid ( zXMPMeta_DeleteQualifier_1 ( schemaNS, propName, qualNS, qualName ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -DoesPropertyExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) const -{ - WrapCheckBool ( exists, zXMPMeta_DoesPropertyExist_1 ( schemaNS, propName ) ); - return exists; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -DoesArrayItemExist ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) const -{ - WrapCheckBool ( exists, zXMPMeta_DoesArrayItemExist_1 ( schemaNS, arrayName, itemIndex ) ); - return exists; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -DoesStructFieldExist ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) const -{ - WrapCheckBool ( exists, zXMPMeta_DoesStructFieldExist_1 ( schemaNS, structName, fieldNS, fieldName ) ); - return exists; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -DoesQualifierExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) const -{ - WrapCheckBool ( exists, zXMPMeta_DoesQualifierExist_1 ( schemaNS, propName, qualNS, qualName ) ); - return exists; -} - -// ================================================================================================= -// Specialized Get and Set functions -// ================================= - -XMP_MethodIntro(TXMPMeta,bool):: -GetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - tStringObj * actualLang, - tStringObj * itemValue, - XMP_OptionBits * options ) const -{ - XMP_StringPtr langPtr = 0; - XMP_StringLen langLen = 0; - XMP_StringPtr itemPtr = 0; - XMP_StringLen itemLen = 0; - WrapCheckBool ( found, zXMPMeta_GetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang, - &langPtr, &langLen, &itemPtr, &itemLen, options ) ); - if ( found ) { - if ( actualLang != 0 ) actualLang->assign ( langPtr, langLen ); - if ( itemValue != 0 ) itemValue->assign ( itemPtr, itemLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, kXMP_NoOptions ); - } - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang, itemValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - const tStringObj & itemValue, - XMP_OptionBits options /* = 0 */ ) -{ - this->SetLocalizedText ( schemaNS, altTextName, genericLang, specificLang, itemValue.c_str(), options ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool * propValue, - XMP_OptionBits * options ) const -{ - XMP_Bool binValue; - WrapCheckBool ( found, zXMPMeta_GetProperty_Bool_1 ( schemaNS, propName, &binValue, options ) ); - if ( found && (propValue != 0) ) *propValue = binValue; - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long * propValue, - XMP_OptionBits * options ) const -{ - XMP_Int32 abiValue; - WrapCheckBool ( found, zXMPMeta_GetProperty_Int_1 ( schemaNS, propName, &abiValue, options ) ); - if ( found && (propValue != 0) ) *propValue = abiValue; - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long long * propValue, - XMP_OptionBits * options ) const -{ - XMP_Int64 abiValue; - WrapCheckBool ( found, zXMPMeta_GetProperty_Int64_1 ( schemaNS, propName, &abiValue, options ) ); - if ( found && (propValue != 0) ) *propValue = abiValue; - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options ) const -{ - WrapCheckBool ( found, zXMPMeta_GetProperty_Float_1 ( schemaNS, propName, propValue, options ) ); - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,bool):: -GetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options ) const -{ - WrapCheckBool ( found, zXMPMeta_GetProperty_Date_1 ( schemaNS, propName, propValue, options ) ); - return found; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_Bool_1 ( schemaNS, propName, propValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_Int_1 ( schemaNS, propName, propValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - long long propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_Int64_1 ( schemaNS, propName, propValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_Float_1 ( schemaNS, propName, propValue, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_SetProperty_Date_1 ( schemaNS, propName, propValue, options ) ); -} - -// ================================================================================================= -// Miscellaneous Member Functions -// ============================== - -XMP_MethodIntro(TXMPMeta,XMPMetaRef):: -GetInternalRef() const -{ - return this->xmpRef; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -GetObjectName ( tStringObj * name ) const -{ - XMP_StringPtr namePtr = 0; - XMP_StringLen nameLen = 0; - WrapCheckVoid ( zXMPMeta_GetObjectName_1 ( &namePtr, &nameLen ) ); - if ( name != 0 ) name->assign ( namePtr, nameLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetObjectName ( XMP_StringPtr name ) -{ - WrapCheckVoid ( zXMPMeta_SetObjectName_1 ( name ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetObjectName ( tStringObj name ) -{ - this->SetObjectName ( name.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,XMP_OptionBits):: -GetObjectOptions() const -{ - WrapCheckOptions ( options, zXMPMeta_GetObjectOptions_1() ); - return options; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SetObjectOptions ( XMP_OptionBits options ) -{ - WrapCheckVoid ( zXMPMeta_SetObjectOptions_1 ( options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -Sort() -{ - WrapCheckVoid ( zXMPMeta_Sort_1() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -Erase() -{ - WrapCheckVoid ( zXMPMeta_Erase_1() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,TXMPMeta):: -Clone ( XMP_OptionBits options ) const -{ - WrapCheckMetaRef ( cloneRef, zXMPMeta_Clone_1 ( options ) ); - return TXMPMeta ( cloneRef ); // Ref construct will increment the clientRefs. -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,XMP_Index):: -CountArrayItems ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName ) const -{ - WrapCheckIndex ( count, zXMPMeta_CountArrayItems_1 ( schemaNS, arrayName ) ); - return count; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,XMP_Status):: -DumpObject ( XMP_TextOutputProc outProc, - void * refCon ) const -{ - TOPW_Info info ( outProc, refCon ); - WrapCheckStatus ( status, zXMPMeta_DumpObject_1 ( TextOutputProcWrapper, &info ) ); - return status; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -ParseFromBuffer ( XMP_StringPtr buffer, - XMP_StringLen bufferSize, - XMP_OptionBits options /* = 0 */ ) -{ - WrapCheckVoid ( zXMPMeta_ParseFromBuffer_1 ( buffer, bufferSize, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SerializeToBuffer ( tStringObj * pktString, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent, - XMP_Index baseIndent /* = 0 */ ) const -{ - XMP_StringPtr resultPtr = 0; - XMP_StringLen resultLen = 0; - WrapCheckVoid ( zXMPMeta_SerializeToBuffer_1 ( &resultPtr, &resultLen, options, padding, newline, indent, baseIndent ) ); - if ( pktString != 0 ) pktString->assign ( resultPtr, resultLen ); - WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPMeta,void):: -SerializeToBuffer ( tStringObj * pktString, - XMP_OptionBits options /* = 0 */, - XMP_StringLen padding /* = 0 */ ) const -{ - this->SerializeToBuffer ( pktString, options, padding, "", "", 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -// ================================================================================================= diff --git a/xmpsdk/include/client-glue/TXMPUtils.incl_cpp b/xmpsdk/include/client-glue/TXMPUtils.incl_cpp deleted file mode 100644 index 6898be73bc..0000000000 --- a/xmpsdk/include/client-glue/TXMPUtils.incl_cpp +++ /dev/null @@ -1,493 +0,0 @@ -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// ================================================================================================ -/// \file TXMPUtils.incl_cpp -/// \brief The implementation of the TXMPUtils template class. - -#include "XMPSDK.hpp" -#include "client-glue/WXMP_Common.hpp" -#include "client-glue/WXMPUtils.hpp" - -// ================================================================================================= -// Implementation Guidelines -// ========================= -// -// The implementations of the template functions are very stylized. ... -// -// ================================================================================================= - -XMP_MethodIntro(TXMPUtils,void):: -ComposeArrayItemPath ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - tStringObj * fullPath ) -{ - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - WrapCheckVoid ( zXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, &pathPtr, &pathLen ) ); - if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeStructFieldPath ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - tStringObj * fullPath ) -{ - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - WrapCheckVoid ( zXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, &pathPtr, &pathLen ) ); - if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeQualifierPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - tStringObj * fullPath ) -{ - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - WrapCheckVoid ( zXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, &pathPtr, &pathLen ) ); - if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - tStringObj * fullPath ) -{ - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - WrapCheckVoid ( zXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, &pathPtr, &pathLen ) ); - if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - const tStringObj & langName, - tStringObj * fullPath ) -{ - TXMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName.c_str(), fullPath ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - tStringObj * fullPath ) -{ - XMP_StringPtr pathPtr = 0; - XMP_StringLen pathLen = 0; - WrapCheckVoid ( zXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, - &pathPtr, &pathLen ) ); - if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - const tStringObj & fieldValue, - tStringObj * fullPath ) -{ - TXMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue.c_str(), fullPath ); -} - -// ------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertFromBool ( bool binValue, - tStringObj * strValue ) -{ - XMP_StringPtr strPtr = 0; - XMP_StringLen strLen = 0; - WrapCheckVoid ( zXMPUtils_ConvertFromBool_1 ( binValue, &strPtr, &strLen ) ); - if ( strValue != 0 ) strValue->assign ( strPtr, strLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertFromInt ( long binValue, - XMP_StringPtr format, - tStringObj * strValue ) -{ - XMP_StringPtr strPtr = 0; - XMP_StringLen strLen = 0; - WrapCheckVoid ( zXMPUtils_ConvertFromInt_1 ( binValue, format, &strPtr, &strLen ) ); - if ( strValue != 0 ) strValue->assign ( strPtr, strLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertFromInt64 ( long long binValue, - XMP_StringPtr format, - tStringObj * strValue ) -{ - XMP_StringPtr strPtr = 0; - XMP_StringLen strLen = 0; - WrapCheckVoid ( zXMPUtils_ConvertFromInt64_1 ( binValue, format, &strPtr, &strLen ) ); - if ( strValue != 0 ) strValue->assign ( strPtr, strLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertFromFloat ( double binValue, - XMP_StringPtr format, - tStringObj * strValue ) -{ - XMP_StringPtr strPtr = 0; - XMP_StringLen strLen = 0; - WrapCheckVoid ( zXMPUtils_ConvertFromFloat_1 ( binValue, format, &strPtr, &strLen ) ); - if ( strValue != 0 ) strValue->assign ( strPtr, strLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertFromDate ( const XMP_DateTime & binValue, - tStringObj * strValue ) -{ - XMP_StringPtr strPtr = 0; - XMP_StringLen strLen = 0; - WrapCheckVoid ( zXMPUtils_ConvertFromDate_1 ( binValue, &strPtr, &strLen ) ); - if ( strValue != 0 ) strValue->assign ( strPtr, strLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,bool):: -ConvertToBool ( XMP_StringPtr strValue ) -{ - WrapCheckBool ( value, zXMPUtils_ConvertToBool_1 ( strValue ) ); - return value; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,bool):: -ConvertToBool ( const tStringObj & strValue ) -{ - return TXMPUtils::ConvertToBool ( strValue.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,long):: -ConvertToInt ( XMP_StringPtr strValue ) -{ - WrapCheckInt32 ( value, zXMPUtils_ConvertToInt_1 ( strValue ) ); - return value; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,long):: -ConvertToInt ( const tStringObj & strValue ) -{ - return TXMPUtils::ConvertToInt ( strValue.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,long long):: -ConvertToInt64 ( XMP_StringPtr strValue ) -{ - WrapCheckInt64 ( value, zXMPUtils_ConvertToInt64_1 ( strValue ) ); - return value; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,long long):: -ConvertToInt64 ( const tStringObj & strValue ) -{ - return TXMPUtils::ConvertToInt64 ( strValue.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,double):: -ConvertToFloat ( XMP_StringPtr strValue ) -{ - WrapCheckFloat ( value, zXMPUtils_ConvertToFloat_1 ( strValue ) ); - return value; -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,double):: -ConvertToFloat ( const tStringObj & strValue ) -{ - return TXMPUtils::ConvertToFloat ( strValue.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertToDate ( XMP_StringPtr strValue, - XMP_DateTime * binValue ) -{ - WrapCheckVoid ( zXMPUtils_ConvertToDate_1 ( strValue, binValue ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertToDate ( const tStringObj & strValue, - XMP_DateTime * binValue ) -{ - TXMPUtils::ConvertToDate ( strValue.c_str(), binValue ); -} - -// ------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -CurrentDateTime ( XMP_DateTime * time ) -{ - WrapCheckVoid ( zXMPUtils_CurrentDateTime_1 ( time ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -SetTimeZone ( XMP_DateTime * time ) -{ - WrapCheckVoid ( zXMPUtils_SetTimeZone_1 ( time ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertToUTCTime ( XMP_DateTime * time ) -{ - WrapCheckVoid ( zXMPUtils_ConvertToUTCTime_1 ( time ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -ConvertToLocalTime ( XMP_DateTime * time ) -{ - WrapCheckVoid ( zXMPUtils_ConvertToLocalTime_1 ( time ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,int):: -CompareDateTime ( const XMP_DateTime & left, - const XMP_DateTime & right ) -{ - WrapCheckInt32 ( result, zXMPUtils_CompareDateTime_1 ( left, right ) ); - return result; -} - -// ------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -EncodeToBase64 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - tStringObj * encodedStr ) -{ - XMP_StringPtr encPtr = 0; - XMP_StringLen encLen = 0; - WrapCheckVoid ( zXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, &encPtr, &encLen ) ); - if ( encodedStr != 0 ) encodedStr->assign ( encPtr, encLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -EncodeToBase64 ( const tStringObj & rawStr, - tStringObj * encodedStr ) -{ - TXMPUtils::EncodeToBase64 ( rawStr.c_str(), (XMP_StringLen)rawStr.size(), encodedStr ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -DecodeFromBase64 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - tStringObj * rawStr ) -{ - XMP_StringPtr rawPtr = 0; - XMP_StringLen rawLen = 0; - WrapCheckVoid ( zXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, &rawPtr, &rawLen ) ); - if ( rawStr != 0 ) rawStr->assign ( rawPtr, rawLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -DecodeFromBase64 ( const tStringObj & encodedStr, - tStringObj * rawStr ) -{ - TXMPUtils::DecodeFromBase64 ( encodedStr.c_str(), (XMP_StringLen)encodedStr.size(), rawStr ); -} - -// ------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------- - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -PackageForJPEG ( const TXMPMeta & xmpObj, - tStringObj * standardXMP, - tStringObj * extendedXMP, - tStringObj * extendedDigest ) -{ - XMP_StringPtr stdStr = 0; - XMP_StringLen stdLen = 0; - XMP_StringPtr extStr = 0; - XMP_StringLen extLen = 0; - XMP_StringPtr digestStr = 0; - XMP_StringLen digestLen = 0; - WrapCheckVoid ( zXMPUtils_PackageForJPEG_1 ( xmpObj.GetInternalRef(), - &stdStr, &stdLen, &extStr, &extLen, &digestStr, &digestLen ) ); - if ( standardXMP != 0 ) standardXMP->assign ( stdStr, stdLen ); - if ( extendedXMP != 0 ) extendedXMP->assign ( extStr, extLen ); - if ( extendedDigest != 0 ) extendedDigest->assign ( digestStr, digestLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -MergeFromJPEG ( TXMPMeta * fullXMP, - const TXMPMeta & extendedXMP ) -{ - WrapCheckVoid ( zXMPUtils_MergeFromJPEG_1 ( fullXMP->GetInternalRef(), extendedXMP.GetInternalRef() ) ); -} - -// ------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -CatenateArrayItems ( const TXMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - tStringObj * catedStr ) -{ - XMP_StringPtr catedPtr = 0; - XMP_StringLen catedLen = 0; - WrapCheckVoid ( zXMPUtils_CatenateArrayItems_1 ( xmpObj.GetInternalRef(), schemaNS, arrayName, - separator, quotes, options, &catedPtr, &catedLen ) ); - if ( catedStr != 0 ) catedStr->assign ( catedPtr, catedLen ); - WXMPUtils_Unlock_1 ( 0 ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -SeparateArrayItems ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr ) -{ - if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" ); - WrapCheckVoid ( zXMPUtils_SeparateArrayItems_1 ( xmpObj->GetInternalRef(), schemaNS, arrayName, options, catedStr ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -SeparateArrayItems ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - const tStringObj & catedStr ) -{ - TXMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr.c_str() ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -RemoveProperties ( TXMPMeta * xmpObj, - XMP_StringPtr schemaNS /* = 0 */, - XMP_StringPtr propName /* = 0 */, - XMP_OptionBits options /* = 0 */ ) -{ - if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" ); - WrapCheckVoid ( zXMPUtils_RemoveProperties_1 ( xmpObj->GetInternalRef(), schemaNS, propName, options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -AppendProperties ( const TXMPMeta & source, - TXMPMeta * dest, - XMP_OptionBits options /* = 0 */ ) -{ - if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" ); - WrapCheckVoid ( zXMPUtils_AppendProperties_1 ( source.GetInternalRef(), dest->GetInternalRef(), options ) ); -} - -// ------------------------------------------------------------------------------------------------- - -XMP_MethodIntro(TXMPUtils,void):: -DuplicateSubtree ( const TXMPMeta & source, - TXMPMeta * dest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS /*= 0 */, - XMP_StringPtr destRoot /* = 0 */, - XMP_OptionBits options /* = 0 */ ) -{ - if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" ); - WrapCheckVoid ( zXMPUtils_DuplicateSubtree_1 ( source.GetInternalRef(), dest->GetInternalRef(), - sourceNS, sourceRoot, destNS, destRoot, options ) ); -} - -// ================================================================================================= - -// ================================================================================================= diff --git a/xmpsdk/include/client-glue/WXMPFiles.hpp b/xmpsdk/include/client-glue/WXMPFiles.hpp deleted file mode 100644 index cdc510ce89..0000000000 --- a/xmpsdk/include/client-glue/WXMPFiles.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef __WXMPFiles_hpp__ -#define __WXMPFiles_hpp__ 1 - -// ================================================================================================= -// ADOBE SYSTEMS INCORPORATED -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "client-glue/WXMP_Common.hpp" - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -/// \file WXMPFiles.h -/// \brief High level support to access metadata in files of interest to Adobe applications. -/// -/// This header ... -/// -// ================================================================================================= - -// ================================================================================================= - -#define WrapCheckXMPFilesRef(result,WCallProto) \ - WXMP_Result wResult; \ - WCallProto; \ - PropagateException ( wResult ); \ - XMPFilesRef result = XMPFilesRef(wResult.ptrResult) - -// ================================================================================================= - -#define zXMPFiles_GetVersionInfo_1(versionInfo) \ - WXMPFiles_GetVersionInfo_1 ( versionInfo /* no wResult */ ) - -#define zXMPFiles_Initialize_1() \ - WXMPFiles_Initialize_1 ( &wResult ) - -#define zXMPFiles_Initialize_2(options) \ - WXMPFiles_Initialize_2 ( options, &wResult ) - -#define zXMPFiles_Terminate_1() \ - WXMPFiles_Terminate_1 ( /* no wResult */ ) - -#define zXMPFiles_CTor_1() \ - WXMPFiles_CTor_1 ( &wResult ) - -#define zXMPFiles_GetFormatInfo_1(format,flags) \ - WXMPFiles_GetFormatInfo_1 ( format, flags, &wResult ) - -#define zXMPFiles_CheckFileFormat_1(filePath) \ - WXMPFiles_CheckFileFormat_1 ( filePath, &wResult ) - -#define zXMPFiles_CheckPackageFormat_1(folderPath) \ - WXMPFiles_CheckPackageFormat_1 ( folderPath, &wResult ) - -#define zXMPFiles_OpenFile_1(filePath,format,openFlags) \ - WXMPFiles_OpenFile_1 ( this->xmpFilesRef, filePath, format, openFlags, &wResult ) - -#define zXMPFiles_CloseFile_1(closeFlags) \ - WXMPFiles_CloseFile_1 ( this->xmpFilesRef, closeFlags, &wResult ) - -#define zXMPFiles_GetFileInfo_1(filePath,filePathLen,openFlags,format,handlerFlags) \ - WXMPFiles_GetFileInfo_1 ( this->xmpFilesRef, filePath, filePathLen, openFlags, format, handlerFlags, &wResult ) - -#define zXMPFiles_SetAbortProc_1(abortProc,abortArg) \ - WXMPFiles_SetAbortProc_1 ( this->xmpFilesRef, abortProc, abortArg, &wResult ) - -#define zXMPFiles_GetXMP_1(xmpRef,xmpPacket,xmpPacketLen,packetInfo) \ - WXMPFiles_GetXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, packetInfo, &wResult ) - -#define zXMPFiles_GetThumbnail_1(tnailInfo) \ - WXMPFiles_GetThumbnail_1 ( this->xmpFilesRef, tnailInfo, &wResult ) - -#define zXMPFiles_PutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \ - WXMPFiles_PutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult ) - -#define zXMPFiles_CanPutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \ - WXMPFiles_CanPutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult ) - -// ================================================================================================= - -extern void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo ); - -extern void WXMPFiles_Initialize_1 ( WXMP_Result * result ); - -extern void WXMPFiles_Initialize_2 ( XMP_OptionBits options, WXMP_Result * result ); - -extern void WXMPFiles_Terminate_1(); - -extern void WXMPFiles_CTor_1 ( WXMP_Result * result ); - -extern void WXMPFiles_UnlockLib_1(); - -extern void WXMPFiles_UnlockObj_1 ( XMPFilesRef xmpFilesRef ); - -extern void WXMPFiles_IncrementRefCount_1 ( XMPFilesRef xmpFilesRef ); - -extern void WXMPFiles_DecrementRefCount_1 ( XMPFilesRef xmpFilesRef ); - -extern void WXMPFiles_GetFormatInfo_1 ( XMP_FileFormat format, - XMP_OptionBits * flags, // ! Can be null. - WXMP_Result * result ); - -extern void WXMPFiles_CheckFileFormat_1 ( XMP_StringPtr filePath, - WXMP_Result * result ); - -extern void WXMPFiles_CheckPackageFormat_1 ( XMP_StringPtr folderPath, - WXMP_Result * result ); - -extern void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpFilesRef, - XMP_StringPtr filePath, - XMP_FileFormat format, - XMP_OptionBits openFlags, - WXMP_Result * result ); - -extern void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpFilesRef, - XMP_OptionBits closeFlags, - WXMP_Result * result ); - -extern void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpFilesRef, - XMP_StringPtr * filePath, - XMP_StringLen * filePathLen, - XMP_OptionBits * openFlags, // ! Can be null. - XMP_FileFormat * format, // ! Can be null. - XMP_OptionBits * handlerFlags, // ! Can be null. - WXMP_Result * result ); - -extern void WXMPFiles_SetAbortProc_1 ( XMPFilesRef xmpFilesRef, - XMP_AbortProc abortProc, - void * abortArg, - WXMP_Result * result ); - -extern void WXMPFiles_GetXMP_1 ( XMPFilesRef xmpFilesRef, - XMPMetaRef xmpRef, // ! Can be null. - XMP_StringPtr * xmpPacket, - XMP_StringLen * xmpPacketLen, - XMP_PacketInfo * packetInfo, // ! Can be null. - WXMP_Result * result ); - -extern void WXMPFiles_GetThumbnail_1 ( XMPFilesRef xmpFilesRef, - XMP_ThumbnailInfo * tnailInfo, // ! Can be null. - WXMP_Result * result ); - -extern void WXMPFiles_PutXMP_1 ( XMPFilesRef xmpFilesRef, - XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed. - XMP_StringPtr xmpPacket, - XMP_StringLen xmpPacketLen, - WXMP_Result * result ); - -extern void WXMPFiles_CanPutXMP_1 ( XMPFilesRef xmpFilesRef, - XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed. - XMP_StringPtr xmpPacket, - XMP_StringLen xmpPacketLen, - WXMP_Result * result ); - -// ================================================================================================= - -#if __cplusplus -} -#endif - -#endif // __WXMPFiles_hpp__ diff --git a/xmpsdk/include/client-glue/WXMPIterator.hpp b/xmpsdk/include/client-glue/WXMPIterator.hpp deleted file mode 100644 index c5e9e26d2c..0000000000 --- a/xmpsdk/include/client-glue/WXMPIterator.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#if ! __WXMPIterator_hpp__ -#define __WXMPIterator_hpp__ 1 - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "client-glue/WXMP_Common.hpp" - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= - -#define zXMPIterator_PropCTor_1(xmpRef,schemaNS,propName,options) \ - WXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options, &wResult ); - -#define zXMPIterator_TableCTor_1(schemaNS,propName,options) \ - WXMPIterator_TableCTor_1 ( schemaNS, propName, options, &wResult ); - - -#define zXMPIterator_Next_1(schemaNS,nsSize,propPath,pathSize,propValue,valueSize,options) \ - WXMPIterator_Next_1 ( this->iterRef, schemaNS, nsSize, propPath, pathSize, propValue, valueSize, options, &wResult ); - -#define zXMPIterator_Skip_1(options) \ - WXMPIterator_Skip_1 ( this->iterRef, options, &wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef ); - -extern void -WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef ); - -extern void -WXMPIterator_Unlock_1 ( XMP_OptionBits options ); - -extern void -WXMPIterator_Next_1 ( XMPIteratorRef iterRef, - XMP_StringPtr * schemaNS, - XMP_StringLen * nsSize, - XMP_StringPtr * propPath, - XMP_StringLen * pathSize, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ); - -extern void -WXMPIterator_Skip_1 ( XMPIteratorRef iterRef, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef, - XMP_OptionBits options ); - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif - -#endif // __WXMPIterator_hpp__ diff --git a/xmpsdk/include/client-glue/WXMPMeta.hpp b/xmpsdk/include/client-glue/WXMPMeta.hpp deleted file mode 100644 index ca94374258..0000000000 --- a/xmpsdk/include/client-glue/WXMPMeta.hpp +++ /dev/null @@ -1,622 +0,0 @@ -#if ! __WXMPMeta_hpp__ -#define __WXMPMeta_hpp__ 1 - -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "client-glue/WXMP_Common.hpp" - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -#define zXMPMeta_GetVersionInfo_1(info) \ - WXMPMeta_GetVersionInfo_1 ( info /* no wResult */ ) - -#define zXMPMeta_Initialize_1() \ - WXMPMeta_Initialize_1 ( &wResult ) -#define zXMPMeta_Terminate_1() \ - WXMPMeta_Terminate_1 ( /* no wResult */ ) - -#define zXMPMeta_CTor_1() \ - WXMPMeta_CTor_1 ( &wResult ) - -#define zXMPMeta_GetGlobalOptions_1() \ - WXMPMeta_GetGlobalOptions_1 ( &wResult ) - -#define zXMPMeta_SetGlobalOptions_1(options) \ - WXMPMeta_SetGlobalOptions_1 ( options, &wResult ) - -#define zXMPMeta_DumpNamespaces_1(outProc,refCon) \ - WXMPMeta_DumpNamespaces_1 ( outProc, refCon, &wResult ) - -#define zXMPMeta_DumpAliases_1(outProc,refCon) \ - WXMPMeta_DumpAliases_1 ( outProc, refCon, &wResult ) - -#define zXMPMeta_RegisterNamespace_1(namespaceURI,prefix) \ - WXMPMeta_RegisterNamespace_1 ( namespaceURI, prefix, &wResult ) - -#define zXMPMeta_GetNamespacePrefix_1(namespaceURI,namespacePrefix,prefixSize) \ - WXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, prefixSize, &wResult ) - -#define zXMPMeta_GetNamespaceURI_1(namespacePrefix,namespaceURI,uriSize) \ - WXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, uriSize, &wResult ) - -#define zXMPMeta_DeleteNamespace_1(namespaceURI) \ - WXMPMeta_DeleteNamespace_1 ( namespaceURI, &wResult ) - -#define zXMPMeta_RegisterAlias_1(aliasNS,aliasProp,actualNS,actualProp,arrayForm) \ - WXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm, &wResult ) - -#define zXMPMeta_ResolveAlias_1(aliasNS,aliasProp,actualNS,nsSize,actualProp,propSize,arrayForm) \ - WXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm, &wResult ) - -#define zXMPMeta_DeleteAlias_1(aliasNS,aliasProp) \ - WXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp, &wResult ) - -#define zXMPMeta_RegisterStandardAliases_1(schemaNS) \ - WXMPMeta_RegisterStandardAliases_1 ( schemaNS, &wResult ) - -#define zXMPMeta_GetProperty_1(schemaNS,propName,propValue,valueSize,options) \ - WXMPMeta_GetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, valueSize, options, &wResult ) - -#define zXMPMeta_GetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,valueSize,options) \ - WXMPMeta_GetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, valueSize, options, &wResult ) - -#define zXMPMeta_GetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,valueSize,options) \ - WXMPMeta_GetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options, &wResult ) - -#define zXMPMeta_GetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,valueSize,options) \ - WXMPMeta_GetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, valueSize, options, &wResult ) - -#define zXMPMeta_SetProperty_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,options) \ - WXMPMeta_SetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, options, &wResult ) - -#define zXMPMeta_AppendArrayItem_1(schemaNS,arrayName,arrayOptions,itemValue,options) \ - WXMPMeta_AppendArrayItem_1 ( this->xmpRef, schemaNS, arrayName, arrayOptions, itemValue, options, &wResult ) - -#define zXMPMeta_SetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,options) \ - WXMPMeta_SetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, options, &wResult ) - -#define zXMPMeta_SetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,options) \ - WXMPMeta_SetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, options, &wResult ) - -#define zXMPMeta_DeleteProperty_1(schemaNS,propName) \ - WXMPMeta_DeleteProperty_1 ( this->xmpRef, schemaNS, propName, &wResult ) - -#define zXMPMeta_DeleteArrayItem_1(schemaNS,arrayName,itemIndex) \ - WXMPMeta_DeleteArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult ) - -#define zXMPMeta_DeleteStructField_1(schemaNS,structName,fieldNS,fieldName) \ - WXMPMeta_DeleteStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult ) - -#define zXMPMeta_DeleteQualifier_1(schemaNS,propName,qualNS,qualName) \ - WXMPMeta_DeleteQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult ) - -#define zXMPMeta_DoesPropertyExist_1(schemaNS,propName) \ - WXMPMeta_DoesPropertyExist_1 ( this->xmpRef, schemaNS, propName, &wResult ) - -#define zXMPMeta_DoesArrayItemExist_1(schemaNS,arrayName,itemIndex) \ - WXMPMeta_DoesArrayItemExist_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult ) - -#define zXMPMeta_DoesStructFieldExist_1(schemaNS,structName,fieldNS,fieldName) \ - WXMPMeta_DoesStructFieldExist_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult ) - -#define zXMPMeta_DoesQualifierExist_1(schemaNS,propName,qualNS,qualName) \ - WXMPMeta_DoesQualifierExist_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult ) - -#define zXMPMeta_GetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,actualLang,langSize,itemValue,valueSize,options) \ - WXMPMeta_GetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, actualLang, langSize, itemValue, valueSize, options, &wResult ) - -#define zXMPMeta_SetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,itemValue,options) \ - WXMPMeta_SetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, itemValue, options, &wResult ) - -#define zXMPMeta_GetProperty_Bool_1(schemaNS,propName,propValue,options) \ - WXMPMeta_GetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_GetProperty_Int_1(schemaNS,propName,propValue,options) \ - WXMPMeta_GetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_GetProperty_Int64_1(schemaNS,propName,propValue,options) \ - WXMPMeta_GetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_GetProperty_Float_1(schemaNS,propName,propValue,options) \ - WXMPMeta_GetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_GetProperty_Date_1(schemaNS,propName,propValue,options) \ - WXMPMeta_GetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetProperty_Bool_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetProperty_Int_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetProperty_Int64_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetProperty_Float_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_SetProperty_Date_1(schemaNS,propName,propValue,options) \ - WXMPMeta_SetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult ) - -#define zXMPMeta_GetObjectName_1(namePtr,nameLen) \ - WXMPMeta_GetObjectName_1 ( this->xmpRef, namePtr, nameLen, &wResult ) - -#define zXMPMeta_SetObjectName_1(name) \ - WXMPMeta_SetObjectName_1 ( this->xmpRef, name, &wResult ) - -#define zXMPMeta_GetObjectOptions_1() \ - WXMPMeta_GetObjectOptions_1 ( this->xmpRef, &wResult ) - -#define zXMPMeta_SetObjectOptions_1(options) \ - WXMPMeta_SetObjectOptions_1 ( this->xmpRef, options, &wResult ) - -#define zXMPMeta_Sort_1() \ - WXMPMeta_Sort_1 ( this->xmpRef, &wResult ) - -#define zXMPMeta_Erase_1() \ - WXMPMeta_Erase_1 ( this->xmpRef, &wResult ) - -#define zXMPMeta_Clone_1(options) \ - WXMPMeta_Clone_1 ( this->xmpRef, options, &wResult ) - -#define zXMPMeta_CountArrayItems_1(schemaNS,arrayName) \ - WXMPMeta_CountArrayItems_1 ( this->xmpRef, schemaNS, arrayName, &wResult ) - -#define zXMPMeta_DumpObject_1(outProc,refCon) \ - WXMPMeta_DumpObject_1 ( this->xmpRef, outProc, refCon, &wResult ) - -#define zXMPMeta_ParseFromBuffer_1(buffer,bufferSize,options) \ - WXMPMeta_ParseFromBuffer_1 ( this->xmpRef, buffer, bufferSize, options, &wResult ) - -#define zXMPMeta_SerializeToBuffer_1(pktString,pktSize,options,padding,newline,indent,baseIndent) \ - WXMPMeta_SerializeToBuffer_1 ( this->xmpRef, pktString, pktSize, options, padding, newline, indent, baseIndent, &wResult ) - -// ================================================================================================= - -extern void -WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info ); - -extern void -WXMPMeta_Initialize_1 ( WXMP_Result * wResult ); -extern void -WXMPMeta_Terminate_1(); - -extern void -WXMPMeta_Unlock_1 ( XMP_OptionBits options ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_CTor_1 ( WXMP_Result * wResult ); - -extern void -WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef ); - -extern void -WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult ); - -extern void -WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix, - WXMP_Result * wResult ); - -extern void -WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr * namespacePrefix, - XMP_StringLen * prefixSize, - WXMP_Result * wResult ); - -extern void -WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix, - XMP_StringPtr * namespaceURI, - XMP_StringLen * uriSize, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm, - WXMP_Result * wResult ); - -extern void -WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - WXMP_Result * wResult ); - -extern void -WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fieldValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - WXMP_Result * wResult ); - -extern void -WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - WXMP_Result * wResult ) /* const */ ; - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr * actualLang, - XMP_StringLen * langSize, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Bool * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Bool propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * namePtr, - XMP_StringLen * nameLen, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef, - XMP_StringPtr name, - WXMP_Result * wResult ); - -extern void -WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_Sort_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ); - -extern void -WXMPMeta_Erase_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ); - -extern void -WXMPMeta_Clone_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - WXMP_Result * wResult ) /* const */ ; - -extern void -WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef, - XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ) /* const */ ; - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef, - XMP_StringPtr buffer, - XMP_StringLen bufferSize, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * pktString, - XMP_StringLen * pktSize, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent, - XMP_Index baseIndent, - WXMP_Result * wResult ) /* const */ ; - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif - -#endif // __WXMPMeta_hpp__ diff --git a/xmpsdk/include/client-glue/WXMPUtils.hpp b/xmpsdk/include/client-glue/WXMPUtils.hpp deleted file mode 100644 index 55890fc5d8..0000000000 --- a/xmpsdk/include/client-glue/WXMPUtils.hpp +++ /dev/null @@ -1,322 +0,0 @@ -#if ! __WXMPUtils_hpp__ -#define __WXMPUtils_hpp__ 1 - -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "client-glue/WXMP_Common.hpp" - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= - -#define zXMPUtils_ComposeArrayItemPath_1(schemaNS,arrayName,itemIndex,fullPath,pathSize) \ - WXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, fullPath, pathSize, &wResult ); - -#define zXMPUtils_ComposeStructFieldPath_1(schemaNS,structName,fieldNS,fieldName,fullPath,pathSize) \ - WXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize, &wResult ); - -#define zXMPUtils_ComposeQualifierPath_1(schemaNS,propName,qualNS,qualName,fullPath,pathSize) \ - WXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, fullPath, pathSize, &wResult ); - -#define zXMPUtils_ComposeLangSelector_1(schemaNS,arrayName,langName,fullPath,pathSize) \ - WXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, fullPath, pathSize, &wResult ); - -#define zXMPUtils_ComposeFieldSelector_1(schemaNS,arrayName,fieldNS,fieldName,fieldValue,fullPath,pathSize) \ - WXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize, &wResult ); - -#define zXMPUtils_ConvertFromBool_1(binValue,strValue,strSize) \ - WXMPUtils_ConvertFromBool_1 ( binValue, strValue, strSize, &wResult ); - -#define zXMPUtils_ConvertFromInt_1(binValue,format,strValue,strSize) \ - WXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, strSize, &wResult ); - -#define zXMPUtils_ConvertFromInt64_1(binValue,format,strValue,strSize) \ - WXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, strSize, &wResult ); - -#define zXMPUtils_ConvertFromFloat_1(binValue,format,strValue,strSize) \ - WXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, strSize, &wResult ); - -#define zXMPUtils_ConvertFromDate_1(binValue,strValue,strSize) \ - WXMPUtils_ConvertFromDate_1 ( binValue, strValue, strSize, &wResult ); - -#define zXMPUtils_ConvertToBool_1(strValue) \ - WXMPUtils_ConvertToBool_1 ( strValue, &wResult ); - -#define zXMPUtils_ConvertToInt_1(strValue) \ - WXMPUtils_ConvertToInt_1 ( strValue, &wResult ); - -#define zXMPUtils_ConvertToInt64_1(strValue) \ - WXMPUtils_ConvertToInt64_1 ( strValue, &wResult ); - -#define zXMPUtils_ConvertToFloat_1(strValue) \ - WXMPUtils_ConvertToFloat_1 ( strValue, &wResult ); - -#define zXMPUtils_ConvertToDate_1(strValue,binValue) \ - WXMPUtils_ConvertToDate_1 ( strValue, binValue, &wResult ); - -#define zXMPUtils_CurrentDateTime_1(time) \ - WXMPUtils_CurrentDateTime_1 ( time, &wResult ); - -#define zXMPUtils_SetTimeZone_1(time) \ - WXMPUtils_SetTimeZone_1 ( time, &wResult ); - -#define zXMPUtils_ConvertToUTCTime_1(time) \ - WXMPUtils_ConvertToUTCTime_1 ( time, &wResult ); - -#define zXMPUtils_ConvertToLocalTime_1(time) \ - WXMPUtils_ConvertToLocalTime_1 ( time, &wResult ); - -#define zXMPUtils_CompareDateTime_1(left,right) \ - WXMPUtils_CompareDateTime_1 ( left, right, &wResult ); - -#define zXMPUtils_EncodeToBase64_1(rawStr,rawLen,encodedStr,encodedLen) \ - WXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, encodedLen, &wResult ); - -#define zXMPUtils_DecodeFromBase64_1(encodedStr,encodedLen,rawStr,rawLen) \ - WXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, rawLen, &wResult ); - -#define zXMPUtils_PackageForJPEG_1(xmpObj,stdStr,stdLen,extStr,extLen,digestStr,digestLen) \ - WXMPUtils_PackageForJPEG_1 ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen, &wResult ); - -#define zXMPUtils_MergeFromJPEG_1(fullXMP,extendedXMP) \ - WXMPUtils_MergeFromJPEG_1 ( fullXMP, extendedXMP, &wResult ); - -#define zXMPUtils_CatenateArrayItems_1(xmpObj,schemaNS,arrayName,separator,quotes,options,catedPtr,catedLen) \ - WXMPUtils_CatenateArrayItems_1 ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedPtr, catedLen, &wResult ); - -#define zXMPUtils_SeparateArrayItems_1(xmpObj,schemaNS,arrayName,options,catedStr) \ - WXMPUtils_SeparateArrayItems_1 ( xmpObj, schemaNS, arrayName, options, catedStr, &wResult ); - -#define zXMPUtils_RemoveProperties_1(xmpObj,schemaNS,propName,options) \ - WXMPUtils_RemoveProperties_1 ( xmpObj, schemaNS, propName, options, &wResult ); - -#define zXMPUtils_AppendProperties_1(source,dest,options) \ - WXMPUtils_AppendProperties_1 ( source, dest, options, &wResult ); - -#define zXMPUtils_DuplicateSubtree_1(source,dest,sourceNS,sourceRoot,destNS,destRoot,options) \ - WXMPUtils_DuplicateSubtree_1 ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options, &wResult ); - -// ================================================================================================= - -extern void -WXMPUtils_Unlock_1 ( XMP_OptionBits options ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertFromFloat_1 ( double binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue, - XMP_DateTime * binValue, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ); - -extern void -WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ); - -extern void -WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ); - -extern void -WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left, - const XMP_DateTime & right, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen, - WXMP_Result * wResult ); - -extern void -WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_PackageForJPEG_1 ( XMPMetaRef xmpObj, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen, - WXMP_Result * wResult ); - -extern void -WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef fullXMP, - XMPMetaRef extendedXMP, - WXMP_Result * wResult ); - -// ------------------------------------------------------------------------------------------------- - -extern void -WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen, - WXMP_Result * wResult ); - -extern void -WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr, - WXMP_Result * wResult ); - -extern void -WXMPUtils_RemoveProperties_1 ( XMPMetaRef xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPUtils_AppendProperties_1 ( XMPMetaRef source, - XMPMetaRef dest, - XMP_OptionBits options, - WXMP_Result * wResult ); - -extern void -WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef source, - XMPMetaRef dest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS, - XMP_StringPtr destRoot, - XMP_OptionBits options, - WXMP_Result * wResult ); - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif - -#endif // __WXMPUtils_hpp__ diff --git a/xmpsdk/include/client-glue/WXMP_Common.hpp b/xmpsdk/include/client-glue/WXMP_Common.hpp deleted file mode 100644 index 4d6eaab429..0000000000 --- a/xmpsdk/include/client-glue/WXMP_Common.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#if ! __WXMP_Common_hpp__ -#define __WXMP_Common_hpp__ 1 - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#ifndef XMP_Inline - #if TXMP_EXPAND_INLINE - #define XMP_Inline inline - #else - #define XMP_Inline /* not inline */ - #endif -#endif - -#define XMP_CTorDTorIntro(Class) template XMP_Inline Class -#define XMP_MethodIntro(Class,ResultType) template XMP_Inline ResultType Class - -struct WXMP_Result { - XMP_StringPtr errMessage; - void * ptrResult; - double floatResult; - XMP_Uns64 int64Result; - XMP_Uns32 int32Result; - WXMP_Result() : errMessage(0) {}; -}; - -#if __cplusplus -extern "C" { -#endif - -#define PropagateException(res) \ - if ( res.errMessage != 0 ) throw XMP_Error ( res.int32Result, res.errMessage ); - -#ifndef TraceXMPCalls - #define TraceXMPCalls 0 -#endif - -#if ! TraceXMPCalls - #define InvokeCheck(WCallProto) \ - WXMP_Result wResult; \ - WCallProto; \ - PropagateException ( wResult ) -#else - #define InvokeCheck(WCallProto) \ - WXMP_Result wResult; \ - fprintf ( stderr, "WXMP calling: %s\n", #WCallProto ); fflush ( stderr ); \ - WCallProto; \ - if ( wResult.errMessage == 0 ) { \ - fprintf ( stderr, "WXMP back, no error\n" ); fflush ( stderr ); \ - } else { \ - fprintf ( stderr, "WXMP back, error: %s\n", wResult.errMessage ); fflush ( stderr ); \ - } \ - PropagateException ( wResult ) -#endif - -// ------------------------------------------------------------------------------------------------- - -#define WrapNoCheckVoid(WCallProto) \ - WCallProto; - -#define WrapCheckVoid(WCallProto) \ - InvokeCheck(WCallProto) - -#define WrapCheckMetaRef(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMPMetaRef result = XMPMetaRef(wResult.ptrResult) - -#define WrapCheckIterRef(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMPIteratorRef result = XMPIteratorRef(wResult.ptrResult) - -#define WrapCheckDocOpsRef(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMPDocOpsRef result = XMPDocOpsRef(wResult.ptrResult) - -#define WrapCheckBool(result,WCallProto) \ - InvokeCheck(WCallProto); \ - bool result = bool(wResult.int32Result) - -#define WrapCheckTriState(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_TriState result = XMP_TriState(wResult.int32Result) - -#define WrapCheckOptions(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_OptionBits result = XMP_OptionBits(wResult.int32Result) - -#define WrapCheckStatus(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_Status result = XMP_Status(wResult.int32Result) - -#define WrapCheckIndex(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_Index result = XMP_Index(wResult.int32Result) - -#define WrapCheckInt32(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_Int32 result = wResult.int32Result - -#define WrapCheckInt64(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_Int64 result = wResult.int64Result - -#define WrapCheckFloat(result,WCallProto) \ - InvokeCheck(WCallProto); \ - double result = wResult.floatResult - -#define WrapCheckFormat(result,WCallProto) \ - InvokeCheck(WCallProto); \ - XMP_FileFormat result = wResult.int32Result - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif - -#endif // __WXMP_Common_hpp__ diff --git a/xmpsdk/src/ExpatAdapter.cpp b/xmpsdk/src/ExpatAdapter.cpp deleted file mode 100644 index 09117c7511..0000000000 --- a/xmpsdk/src/ExpatAdapter.cpp +++ /dev/null @@ -1,507 +0,0 @@ -// ================================================================================================= -// Copyright 2005-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! Must be the first #include! -#include "XMPCore_Impl.hpp" - -#include "ExpatAdapter.hpp" -#include "XMPMeta.hpp" - -#include "expat.h" - -#include - -using namespace std; - -#if XMP_WinBuild -# ifdef _MSC_VER - #pragma warning ( disable : 4996 ) // '...' was declared deprecated -# endif -#endif - -// *** Set memory handlers. - -#ifndef DumpXMLParseEvents - #define DumpXMLParseEvents 0 -#endif - -#define FullNameSeparator '@' - -// ================================================================================================= - -static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri ); -static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix ); - -static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs ); -static void EndElementHandler ( void * userData, XMP_StringPtr name ); - -static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len ); -static void StartCdataSectionHandler ( void * userData ); -static void EndCdataSectionHandler ( void * userData ); - -static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data ); -static void CommentHandler ( void * userData, XMP_StringPtr comment ); - -#if BanAllEntityUsage - - // For now we do this by banning DOCTYPE entirely. This is easy and consistent with what is - // available in recent Java XML parsers. Another, somewhat less drastic, approach would be to - // ban all entity declarations. We can't allow declarations and ban references, Expat does not - // call the SkippedEntityHandler for references in attribute values. - - // ! Standard entities (&, <, >, ", ', and numeric character references) are - // ! not banned. Expat handles them transparently no matter what. - - static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName, - XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset ); - -#endif - -// ================================================================================================= - -extern "C" ExpatAdapter * XMP_NewExpatAdapter() -{ - return new ExpatAdapter; -} // XMP_NewExpatAdapter - -// ================================================================================================= - -ExpatAdapter::ExpatAdapter() : parser(0) -{ - - #if XMP_DebugBuild - this->elemNesting = 0; - #if DumpXMLParseEvents - if ( this->parseLog == 0 ) this->parseLog = stdout; - #endif - #endif - - this->parser = XML_ParserCreateNS ( 0, FullNameSeparator ); - if ( this->parser == 0 ) XMP_Throw ( "Failure creating Expat parser", kXMPErr_ExternalFailure ); - - XML_SetUserData ( this->parser, this ); - - XML_SetNamespaceDeclHandler ( this->parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler ); - XML_SetElementHandler ( this->parser, StartElementHandler, EndElementHandler ); - - XML_SetCharacterDataHandler ( this->parser, CharacterDataHandler ); - XML_SetCdataSectionHandler ( this->parser, StartCdataSectionHandler, EndCdataSectionHandler ); - - XML_SetProcessingInstructionHandler ( this->parser, ProcessingInstructionHandler ); - XML_SetCommentHandler ( this->parser, CommentHandler ); - - #if BanAllEntityUsage - XML_SetStartDoctypeDeclHandler ( this->parser, StartDoctypeDeclHandler ); - isAborted = false; - #endif - - this->parseStack.push_back ( &this->tree ); // Push the XML root node. - -} // ExpatAdapter::ExpatAdapter - -// ================================================================================================= - -ExpatAdapter::~ExpatAdapter() -{ - - if ( this->parser != 0 ) XML_ParserFree ( this->parser ); - this->parser = 0; - -} // ExpatAdapter::~ExpatAdapter - -// ================================================================================================= - -#if XMP_DebugBuild - static XMP_VarString sExpatMessage; -#endif - -static const char * kOneSpace = " "; - -void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last /* = true */ ) -{ - enum XML_Status status; - - if ( length == 0 ) { // Expat does not like empty buffers. - if ( ! last ) return; - buffer = kOneSpace; - length = 1; - } - - status = XML_Parse ( this->parser, (const char *)buffer, length, last ); - - #if BanAllEntityUsage - if ( this->isAborted ) XMP_Throw ( "DOCTYPE is not allowed", kXMPErr_BadXML ); - #endif - - if ( status != XML_STATUS_OK ) { - - XMP_StringPtr errMsg = "XML parsing failure"; - - #if 0 // XMP_DebugBuild // Disable for now to make test output uniform. Restore later with thread safety. - - // *** This is a good candidate for a callback error notification mechanism. - // *** This code is not thread safe, the sExpatMessage isn't locked. But that's OK for debug usage. - - enum XML_Error expatErr = XML_GetErrorCode ( this->parser ); - const char * expatMsg = XML_ErrorString ( expatErr ); - int errLine = XML_GetCurrentLineNumber ( this->parser ); - - char msgBuffer[1000]; - // AUDIT: Use of sizeof(msgBuffer) for snprintf length is safe. - snprintf ( msgBuffer, sizeof(msgBuffer), "# Expat error %d at line %d, \"%s\"", expatErr, errLine, expatMsg ); - sExpatMessage = msgBuffer; - errMsg = sExpatMessage.c_str(); - - #if DumpXMLParseEvents - if ( this->parseLog != 0 ) fprintf ( this->parseLog, "%s\n", errMsg, expatErr, errLine, expatMsg ); - #endif - - #endif - - XMP_Throw ( errMsg, kXMPErr_BadXML ); - - } - -} // ExpatAdapter::ParseBuffer - -// ================================================================================================= -// ================================================================================================= - -#if XMP_DebugBuild & DumpXMLParseEvents - - static inline void PrintIndent ( FILE * file, size_t count ) - { - for ( ; count > 0; --count ) fprintf ( file, " " ); - } - -#endif - -// ================================================================================================= - -static void SetQualName ( XMP_StringPtr fullName, XML_Node * node ) -{ - // Expat delivers the full name as a catenation of namespace URI, separator, and local name. - - // As a compatibility hack, an "about" or "ID" attribute of an rdf:Description element is - // changed to "rdf:about" or rdf:ID. Easier done here than in the RDF recognizer. - - // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/. - // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace. - - // ! This code presumes the RDF namespace prefix is "rdf". - - size_t sepPos = strlen(fullName); - for ( --sepPos; sepPos > 0; --sepPos ) { - if ( fullName[sepPos] == FullNameSeparator ) break; - } - - if ( fullName[sepPos] == FullNameSeparator ) { - - XMP_StringPtr prefix; - XMP_StringLen prefixLen; - XMP_StringPtr localPart = fullName + sepPos + 1; - - node->ns.assign ( fullName, sepPos ); - if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/"; - - bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &prefixLen ); - if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure ); - node->nsPrefixLen = prefixLen; // ! Includes the ':'. - - node->name = prefix; - node->name += localPart; - - } else { - - node->name = fullName; // The name is not in a namespace. - - if ( node->parent->name == "rdf:Description" ) { - if ( node->name == "about" ) { - node->ns = kXMP_NS_RDF; - node->name = "rdf:about"; - node->nsPrefixLen = 4; // ! Include the ':'. - } else if ( node->name == "ID" ) { - node->ns = kXMP_NS_RDF; - node->name = "rdf:ID"; - node->nsPrefixLen = 4; // ! Include the ':'. - } - } - - } - -} // SetQualName - -// ================================================================================================= - -static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri ) -{ - IgnoreParam(userData); - - // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/. - // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace. - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif - - if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace. - if ( uri == 0 ) return; // Ignore, have xmlns:pre="", no URI to register. - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "StartNamespace: %s - \"%s\"\n", prefix, uri ); - } - #endif - - if ( XMP_LitMatch ( uri, "http://purl.org/dc/1.1/" ) ) uri = "http://purl.org/dc/elements/1.1/"; - XMPMeta::RegisterNamespace ( uri, prefix ); - -} // StartNamespaceDeclHandler - -// ================================================================================================= - -static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix ) -{ - IgnoreParam(userData); - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif - - if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace. - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "EndNamespace: %s\n", prefix ); - } - #endif - - // ! Nothing to do, Expat has done all of the XML processing. - -} // EndNamespaceDeclHandler - -// ================================================================================================= - -static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs ) -{ - XMP_Assert ( attrs != 0 ); - ExpatAdapter * thiz = (ExpatAdapter*)userData; - - size_t attrCount = 0; - for ( XMP_StringPtr* a = attrs; *a != 0; ++a ) ++attrCount; - if ( (attrCount & 1) != 0 ) XMP_Throw ( "Expat attribute info has odd length", kXMPErr_ExternalFailure ); - attrCount = attrCount/2; // They are name/value pairs. - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "StartElement: %s, %d attrs", name, attrCount ); - for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) { - XMP_StringPtr attrName = *attr; - XMP_StringPtr attrValue = *(attr+1); - fprintf ( thiz->parseLog, ", %s = \"%s\"", attrName, attrValue ); - } - fprintf ( thiz->parseLog, "\n" ); - } - #endif - - XML_Node * parentNode = thiz->parseStack.back(); - XML_Node * elemNode = new XML_Node ( parentNode, "", kElemNode ); - - SetQualName ( name, elemNode ); - - for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) { - - XMP_StringPtr attrName = *attr; - XMP_StringPtr attrValue = *(attr+1); - XML_Node * attrNode = new XML_Node ( elemNode, "", kAttrNode ); - - SetQualName ( attrName, attrNode ); - attrNode->value = attrValue; - if ( attrNode->name == "xml:lang" ) NormalizeLangValue ( &attrNode->value ); - elemNode->attrs.push_back ( attrNode ); - - } - - parentNode->content.push_back ( elemNode ); - thiz->parseStack.push_back ( elemNode ); - - if ( elemNode->name == "rdf:RDF" ) { - thiz->rootNode = elemNode; - ++thiz->rootCount; - } - #if XMP_DebugBuild - ++thiz->elemNesting; - #endif - -} // StartElementHandler - -// ================================================================================================= - -static void EndElementHandler ( void * userData, XMP_StringPtr name ) -{ - IgnoreParam(name); - - ExpatAdapter * thiz = (ExpatAdapter*)userData; - - #if XMP_DebugBuild - --thiz->elemNesting; - #endif - (void) thiz->parseStack.pop_back(); - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "EndElement: %s\n", name ); - } - #endif - -} // EndElementHandler - -// ================================================================================================= - -static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len ) -{ - ExpatAdapter * thiz = (ExpatAdapter*)userData; - - if ( (cData == 0) || (len == 0) ) { cData = ""; len = 0; } - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "CharContent: \"" ); - for ( int i = 0; i < len; ++i ) fprintf ( thiz->parseLog, "%c", cData[i] ); - fprintf ( thiz->parseLog, "\"\n" ); - } - #endif - - XML_Node * parentNode = thiz->parseStack.back(); - XML_Node * cDataNode = new XML_Node ( parentNode, "", kCDataNode ); - - cDataNode->value.assign ( cData, len ); - parentNode->content.push_back ( cDataNode ); - -} // CharacterDataHandler - -// ================================================================================================= - -static void StartCdataSectionHandler ( void * userData ) -{ - IgnoreParam(userData); - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "StartCDATA\n" ); - } - #endif - - // *** Since markup isn't recognized inside CDATA, this affects XMP's double escaping. - -} // StartCdataSectionHandler - -// ================================================================================================= - -static void EndCdataSectionHandler ( void * userData ) -{ - IgnoreParam(userData); - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "EndCDATA\n" ); - } - #endif - -} // EndCdataSectionHandler - -// ================================================================================================= - -static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data ) -{ - XMP_Assert ( target != 0 ); - ExpatAdapter * thiz = (ExpatAdapter*)userData; - - if ( ! XMP_LitMatch ( target, "xpacket" ) ) return; // Ignore all PIs except the XMP packet wrapper. - if ( data == 0 ) data = ""; - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "PI: %s - \"%s\"\n", target, data ); - } - #endif - - XML_Node * parentNode = thiz->parseStack.back(); - XML_Node * piNode = new XML_Node ( parentNode, target, kPINode ); - - piNode->value.assign ( data ); - parentNode->content.push_back ( piNode ); - -} // ProcessingInstructionHandler - -// ================================================================================================= - -static void CommentHandler ( void * userData, XMP_StringPtr comment ) -{ - IgnoreParam(userData); - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif - - if ( comment == 0 ) comment = ""; - - #if XMP_DebugBuild & DumpXMLParseEvents - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "Comment: \"%s\"\n", comment ); - } - #endif - - // ! Comments are ignored. - -} // CommentHandler - -// ================================================================================================= - -#if BanAllEntityUsage -static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName, - XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset ) -{ - IgnoreParam(doctypeName); - IgnoreParam(sysid); - IgnoreParam(pubid); - IgnoreParam(has_internal_subset); - - ExpatAdapter * thiz = (ExpatAdapter*)userData; - - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - if ( thiz->parseLog != 0 ) { - PrintIndent ( thiz->parseLog, thiz->elemNesting ); - fprintf ( thiz->parseLog, "DocType: \"%s\"\n", doctypeName ); - } - #endif - - thiz->isAborted = true; // ! Can't throw an exception across the plain C Expat frames. - (void) XML_StopParser ( thiz->parser, XML_FALSE /* not resumable */ ); - -} // StartDoctypeDeclHandler -#endif - -// ================================================================================================= diff --git a/xmpsdk/src/ExpatAdapter.hpp b/xmpsdk/src/ExpatAdapter.hpp deleted file mode 100644 index 9d6c9ec4be..0000000000 --- a/xmpsdk/src/ExpatAdapter.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __ExpatAdapter_hpp__ -#define __ExpatAdapter_hpp__ - -// ================================================================================================= -// Copyright 2005-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! Must be the first #include! -#include "XMLParserAdapter.hpp" - -// ================================================================================================= -// Derived XML parser adapter for Expat. -// ================================================================================================= - -#ifndef BanAllEntityUsage - #define BanAllEntityUsage 0 -#endif - -struct XML_ParserStruct; // ! Hack to avoid exposing expat.h to all clients. -typedef struct XML_ParserStruct *XML_Parser; - -class ExpatAdapter : public XMLParserAdapter { -public: - - XML_Parser parser; - - #if BanAllEntityUsage - bool isAborted; - #endif - - #if XMP_DebugBuild - size_t elemNesting; - #endif - - ExpatAdapter(); - virtual ~ExpatAdapter(); - - void ParseBuffer ( const void * buffer, size_t length, bool last = true ); - -}; - -extern "C" ExpatAdapter * XMP_NewExpatAdapter(); - -// ================================================================================================= - -#endif // __ExpatAdapter_hpp__ diff --git a/xmpsdk/src/MD5.cpp b/xmpsdk/src/MD5.cpp deleted file mode 100644 index b040bd2c20..0000000000 --- a/xmpsdk/src/MD5.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5_CTX structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' header - * definitions; now uses stuff from dpkg's config.h. - * - Ian Jackson . - * Still in the public domain. - */ - -#include - -#include "MD5.h" - -using namespace std; - -static void -byteSwap(UWORD32 *buf, unsigned words) -{ - const uint32_t byteOrderTest = 0x1; - if (((char *)&byteOrderTest)[0] == 0) { - md5byte *p = (md5byte *)buf; - - do { - *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | - ((unsigned)p[1] << 8 | p[0]); - p += 4; - } while (--words); - } -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void -MD5Init(struct MD5_CTX *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void -MD5Update(struct MD5_CTX *ctx, md5byte const *buf, unsigned len) -{ - UWORD32 t; - - /* Update byte count */ - - t = ctx->bytes[0]; - if ((ctx->bytes[0] = t + len) < t) - ctx->bytes[1]++; /* Carry from low to high */ - - t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ - if (t > len) { - memcpy((md5byte *)ctx->in + 64 - t, buf, len); - return; - } - /* First chunk is an odd size */ - memcpy((md5byte *)ctx->in + 64 - t, buf, t); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - buf += t; - len -= t; - - /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void -MD5Final(md5byte digest[16], struct MD5_CTX *ctx) -{ - int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ - md5byte *p = (md5byte *)ctx->in + count; - - /* Set the first char of padding to 0x80. There is always room. */ - *p++ = 0x80; - - /* Bytes of padding needed to make 56 bytes (-8..55) */ - count = 56 - 1 - count; - - if (count < 0) { /* Padding forces an extra block */ - memset(p, 0, count + 8); - byteSwap(ctx->in, 16); - MD5Transform(ctx->buf, ctx->in); - p = (md5byte *)ctx->in; - count = 56; - } - memset(p, 0, count); - byteSwap(ctx->in, 14); - - /* Append length in bits and transform */ - ctx->in[14] = ctx->bytes[0] << 3; - ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; - MD5Transform(ctx->buf, ctx->in); - - byteSwap(ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f,w,x,y,z,in,s) \ - (w += f(x,y,z) + in, w = (w<>(32-s)) + x) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void -MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) -{ - UWORD32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} diff --git a/xmpsdk/src/ParseRDF.cpp b/xmpsdk/src/ParseRDF.cpp deleted file mode 100644 index a92257c204..0000000000 --- a/xmpsdk/src/ParseRDF.cpp +++ /dev/null @@ -1,1296 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" -#include "ExpatAdapter.hpp" - -#include - -#if DEBUG - #include -#endif - -using namespace std; - -#if XMP_WinBuild -# ifdef _MSC_VER - #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced - #pragma warning ( disable : 4505 ) // unreferenced local function has been removed -# endif -#endif - -// ================================================================================================= - -// *** This might be faster and use less memory as a state machine. A big advantage of building an -// *** XML tree though is easy lookahead during the recursive descent processing. - -// *** It would be nice to give a line number or byte offset in the exception messages. - - -// 7 RDF/XML Grammar (from http://www.w3.org/TR/rdf-syntax-grammar/#section-Infoset-Grammar) -// -// 7.1 Grammar summary -// -// 7.2.2 coreSyntaxTerms -// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype -// -// 7.2.3 syntaxTerms -// coreSyntaxTerms | rdf:Description | rdf:li -// -// 7.2.4 oldTerms -// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID -// -// 7.2.5 nodeElementURIs -// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms ) -// -// 7.2.6 propertyElementURIs -// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms ) -// -// 7.2.7 propertyAttributeURIs -// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms ) -// -// 7.2.8 doc -// root ( document-element == RDF, children == list ( RDF ) ) -// -// 7.2.9 RDF -// start-element ( URI == rdf:RDF, attributes == set() ) -// nodeElementList -// end-element() -// -// 7.2.10 nodeElementList -// ws* ( nodeElement ws* )* -// -// 7.2.11 nodeElement -// start-element ( URI == nodeElementURIs, -// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) ) -// propertyEltList -// end-element() -// -// 7.2.12 ws -// A text event matching white space defined by [XML] definition White Space Rule [3] S in section Common Syntactic Constructs. -// -// 7.2.13 propertyEltList -// ws* ( propertyElt ws* )* -// -// 7.2.14 propertyElt -// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt | -// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt -// -// 7.2.15 resourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) ) -// ws* nodeElement ws* -// end-element() -// -// 7.2.16 literalPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) ) -// text() -// end-element() -// -// 7.2.17 parseTypeLiteralPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) ) -// literal -// end-element() -// -// 7.2.18 parseTypeResourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) ) -// propertyEltList -// end-element() -// -// 7.2.19 parseTypeCollectionPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) ) -// nodeElementList -// end-element() -// -// 7.2.20 parseTypeOtherPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) ) -// propertyEltList -// end-element() -// -// 7.2.21 emptyPropertyElt -// start-element ( URI == propertyElementURIs, -// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) ) -// end-element() -// -// 7.2.22 idAttr -// attribute ( URI == rdf:ID, string-value == rdf-id ) -// -// 7.2.23 nodeIdAttr -// attribute ( URI == rdf:nodeID, string-value == rdf-id ) -// -// 7.2.24 aboutAttr -// attribute ( URI == rdf:about, string-value == URI-reference ) -// -// 7.2.25 propertyAttr -// attribute ( URI == propertyAttributeURIs, string-value == anyString ) -// -// 7.2.26 resourceAttr -// attribute ( URI == rdf:resource, string-value == URI-reference ) -// -// 7.2.27 datatypeAttr -// attribute ( URI == rdf:datatype, string-value == URI-reference ) -// -// 7.2.28 parseLiteral -// attribute ( URI == rdf:parseType, string-value == "Literal") -// -// 7.2.29 parseResource -// attribute ( URI == rdf:parseType, string-value == "Resource") -// -// 7.2.30 parseCollection -// attribute ( URI == rdf:parseType, string-value == "Collection") -// -// 7.2.31 parseOther -// attribute ( URI == rdf:parseType, string-value == anyString - ("Resource" | "Literal" | "Collection") ) -// -// 7.2.32 URI-reference -// An RDF URI Reference. -// -// 7.2.33 literal -// Any XML element content that is allowed according to [XML] definition Content of Elements Rule [43] content -// in section 3.1 Start-Tags, End-Tags, and Empty-Element Tags. -// -// 7.2.34 rdf-id -// An attribute string-value matching any legal [XML-NS] token NCName. - - -// ================================================================================================= -// Primary Parsing Functions -// ========================= -// -// Each of these is responsible for recognizing an RDF syntax production and adding the appropriate -// structure to the XMP tree. They simply return for success, failures will throw an exception. - -static void -RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode ); - -static void -RDF_NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel ); - -static void -RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel ); -enum { kIsTopLevel = true, kNotTopLevel = false }; - -static void -RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - -static void -RDF_EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ); - - -// ================================================================================================= - -typedef XMP_Uns8 RDFTermKind; - -// *** Logic might be safer with just masks. - -enum { - kRDFTerm_Other = 0, - kRDFTerm_RDF = 1, // Start of coreSyntaxTerms. - kRDFTerm_ID = 2, - kRDFTerm_about = 3, - kRDFTerm_parseType = 4, - kRDFTerm_resource = 5, - kRDFTerm_nodeID = 6, - kRDFTerm_datatype = 7, // End of coreSyntaxTerms. - kRDFTerm_Description = 8, // Start of additions for syntaxTerms. - kRDFTerm_li = 9, // End of of additions for syntaxTerms. - kRDFTerm_aboutEach = 10, // Start of oldTerms. - kRDFTerm_aboutEachPrefix = 11, - kRDFTerm_bagID = 12, // End of oldTerms. - - kRDFTerm_FirstCore = kRDFTerm_RDF, - kRDFTerm_LastCore = kRDFTerm_datatype, - kRDFTerm_FirstSyntax = kRDFTerm_FirstCore, // ! Yes, the syntax terms include the core terms. - kRDFTerm_LastSyntax = kRDFTerm_li, - kRDFTerm_FirstOld = kRDFTerm_aboutEach, - kRDFTerm_LastOld = kRDFTerm_bagID -}; - -enum { - kRDFMask_Other = 1 << kRDFTerm_Other, - kRDFMask_RDF = 1 << kRDFTerm_RDF, - kRDFMask_ID = 1 << kRDFTerm_ID, - kRDFMask_about = 1 << kRDFTerm_about, - kRDFMask_parseType = 1 << kRDFTerm_parseType, - kRDFMask_resource = 1 << kRDFTerm_resource, - kRDFMask_nodeID = 1 << kRDFTerm_nodeID, - kRDFMask_datatype = 1 << kRDFTerm_datatype, - kRDFMask_Description = 1 << kRDFTerm_Description, - kRDFMask_li = 1 << kRDFTerm_li, - kRDFMask_aboutEach = 1 << kRDFTerm_aboutEach, - kRDFMask_aboutEachPrefix = 1 << kRDFTerm_aboutEachPrefix, - kRDFMask_bagID = 1 << kRDFTerm_bagID -}; - -enum { - kRDF_HasValueElem = 0x10000000UL // ! Contains rdf:value child. Must fit within kXMP_ImplReservedMask! -}; - -// ------------------------------------------------------------------------------------------------- -// GetRDFTermKind -// -------------- - -static RDFTermKind -GetRDFTermKind ( const XMP_VarString & name ) -{ - RDFTermKind term = kRDFTerm_Other; - - // Arranged to hopefully minimize the parse time for large XMP. - - if ( (name.size() > 4) && (strncmp ( name.c_str(), "rdf:", 4 ) == 0) ) { - - if ( name == "rdf:li" ) { - term = kRDFTerm_li; - } else if ( name == "rdf:parseType" ) { - term = kRDFTerm_parseType; - } else if ( name == "rdf:Description" ) { - term = kRDFTerm_Description; - } else if ( name == "rdf:about" ) { - term = kRDFTerm_about; - } else if ( name == "rdf:resource" ) { - term = kRDFTerm_resource; - } else if ( name == "rdf:RDF" ) { - term = kRDFTerm_RDF; - } else if ( name == "rdf:ID" ) { - term = kRDFTerm_ID; - } else if ( name == "rdf:nodeID" ) { - term = kRDFTerm_nodeID; - } else if ( name == "rdf:datatype" ) { - term = kRDFTerm_datatype; - } else if ( name == "rdf:aboutEach" ) { - term = kRDFTerm_aboutEach; - } else if ( name == "rdf:aboutEachPrefix" ) { - term = kRDFTerm_aboutEachPrefix; - } else if ( name == "rdf:bagID" ) { - term = kRDFTerm_bagID; - } - - } - - return term; - -} // GetRDFTermKind - - -// ================================================================================================= - - -// ------------------------------------------------------------------------------------------------- -// IsCoreSyntaxTerm -// ---------------- -// -// 7.2.2 coreSyntaxTerms -// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype - -static bool -IsCoreSyntaxTerm ( RDFTermKind term ) -{ - - if ( (kRDFTerm_FirstCore <= term) && (term <= kRDFTerm_LastCore) ) return true; - return false; - -} // IsCoreSyntaxTerm - - -// ------------------------------------------------------------------------------------------------- -// IsOldTerm -// --------- -// -// 7.2.4 oldTerms -// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID - -static bool -IsOldTerm ( RDFTermKind term ) -{ - - if ( (kRDFTerm_FirstOld <= term) && (term <= kRDFTerm_LastOld) ) return true; - return false; - -} // IsOldTerm - -// ------------------------------------------------------------------------------------------------- -// IsPropertyElementName -// --------------------- -// -// 7.2.6 propertyElementURIs -// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms ) - -static bool -IsPropertyElementName ( RDFTermKind term ) -{ - - if ( (term == kRDFTerm_Description) || IsOldTerm ( term ) ) return false; - return (! IsCoreSyntaxTerm ( term )); - -} // IsPropertyElementName - -// ================================================================================================= -// AddChildNode -// ============ - -static XMP_Node * -AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel ) -{ - #if 0 - cout << "AddChildNode, parent = " << xmpParent->name << ", child = " << xmlNode.name; - cout << ", value = \"" << value << '"'; - if ( isTopLevel ) cout << ", top level"; - cout << endl; - #endif - - if ( xmlNode.ns.empty() ) { - XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF ); - } - - XMP_StringPtr childName = xmlNode.name.c_str(); - const bool isArrayItem = (xmlNode.name == "rdf:li"); - const bool isValueNode = (xmlNode.name == "rdf:value"); - XMP_OptionBits childOptions = 0; - - if ( isTopLevel ) { - - // Lookup the schema node, adjust the XMP parent pointer. - XMP_Assert ( xmpParent->parent == 0 ); // Incoming parent must be the tree root. - XMP_Node * schemaNode = FindSchemaNode ( xmpParent, xmlNode.ns.c_str(), kXMP_CreateNodes ); - if ( schemaNode->options & kXMP_NewImplicitNode ) schemaNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - // *** Should use "opt &= ~flag" (no conditional), need runtime check for proper 32 bit code. - xmpParent = schemaNode; - - // If this is an alias set the isAlias flag in the node and the hasAliases flag in the tree. - if ( sRegisteredAliasMap->find ( xmlNode.name ) != sRegisteredAliasMap->end() ) { - childOptions |= kXMP_PropIsAlias; - schemaNode->parent->options |= kXMP_PropHasAliases; - } - - } - - // Make sure that this is not a duplicate of a named node. - if ( ! (isArrayItem | isValueNode) ) { - if ( FindChildNode ( xmpParent, childName, kXMP_ExistingOnly ) != 0 ) { - XMP_Throw ( "Duplicate property or field node", kXMPErr_BadXMP ); - } - - } - - // Add the new child to the XMP parent node. - XMP_Node * newChild = new XMP_Node ( xmpParent, childName, value, childOptions ); - if ( (! isValueNode) || xmpParent->children.empty() ) { - xmpParent->children.push_back ( newChild ); - } else { - xmpParent->children.insert ( xmpParent->children.begin(), newChild ); - } - if ( isValueNode ) { - if ( isTopLevel || (! (xmpParent->options & kXMP_PropValueIsStruct)) ) XMP_Throw ( "Misplaced rdf:value element", kXMPErr_BadRDF ); - xmpParent->options |= kRDF_HasValueElem; - } - - if ( isArrayItem ) { - if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) XMP_Throw ( "Misplaced rdf:li element", kXMPErr_BadRDF ); - newChild->name = kXMP_ArrayItemName; - #if 0 // *** XMP_DebugBuild - newChild->_namePtr = newChild->name.c_str(); - #endif - } - - return newChild; - -} // AddChildNode - - -// ================================================================================================= -// AddQualifierNode -// ================ - -static XMP_Node * -AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value ) -{ - - #if 0 - cout << "AddQualifierNode, parent = " << xmpParent->name << ", name = " << name; - cout << ", value = \"" << value << '"' << endl; - #endif - - const bool isLang = (name == "xml:lang"); - const bool isType = (name == "rdf:type"); - - XMP_Node * newQual = 0; - - newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier ); - - if ( ! (isLang | isType) ) { - xmpParent->qualifiers.push_back ( newQual ); - } else if ( isLang ) { - if ( xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( newQual ); - } else { - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual ); - } - xmpParent->options |= kXMP_PropHasLang; - } else { - XMP_Assert ( isType ); - if ( xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( newQual ); - } else { - size_t offset = 0; - if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1; - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual ); - } - xmpParent->options |= kXMP_PropHasType; - } - - xmpParent->options |= kXMP_PropHasQualifiers; - - return newQual; - -} // AddQualifierNode - - -// ================================================================================================= -// AddQualifierNode -// ================ - -static XMP_Node * -AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr ) -{ - if ( attr.ns.empty() ) { - XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF ); - } - - return AddQualifierNode ( xmpParent, attr.name, attr.value ); - -} // AddQualifierNode - - -// ================================================================================================= -// FixupQualifiedNode -// ================== -// -// The parent is an RDF pseudo-struct containing an rdf:value field. Fix the XMP data model. The -// rdf:value node must be the first child, the other children are qualifiers. The form, value, and -// children of the rdf:value node are the real ones. The rdf:value node's qualifiers must be added -// to the others. - -static void -FixupQualifiedNode ( XMP_Node * xmpParent ) -{ - size_t qualNum, qualLim; - size_t childNum, childLim; - - XMP_Enforce ( (xmpParent->options & kXMP_PropValueIsStruct) && (! xmpParent->children.empty()) ); - - XMP_Node * valueNode = xmpParent->children[0]; - XMP_Enforce ( valueNode->name == "rdf:value" ); - - xmpParent->qualifiers.reserve ( xmpParent->qualifiers.size() + xmpParent->children.size() + valueNode->qualifiers.size() ); - - // Move the qualifiers on the value node to the parent. Make sure an xml:lang qualifier stays at - // the front. Check for duplicate names between the value node's qualifiers and the parent's - // children. The parent's children are about to become qualifiers. Check here, between the - // groups. Intra-group duplicates are caught by AddChildNode. - - qualNum = 0; - qualLim = valueNode->qualifiers.size(); - - if ( valueNode->options & kXMP_PropHasLang ) { - - if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Redundant xml:lang for rdf:value element", kXMPErr_BadXMP ); - - XMP_Node * langQual = valueNode->qualifiers[0]; - - XMP_Assert ( langQual->name == "xml:lang" ); - langQual->parent = xmpParent; - xmpParent->options |= kXMP_PropHasLang; - - if ( xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( langQual ); // *** Should use utilities to add qual & set parent. - } else { - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), langQual ); - } - valueNode->qualifiers[0] = 0; // We just moved it to the parent. - - qualNum = 1; // Start the remaining copy after the xml:lang qualifier. - - } - - for ( ; qualNum != qualLim; ++qualNum ) { - - XMP_Node * currQual = valueNode->qualifiers[qualNum]; - if ( FindChildNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly ) != 0 ) { - XMP_Throw ( "Duplicate qualifier node", kXMPErr_BadXMP ); - } - - currQual->parent = xmpParent; - xmpParent->qualifiers.push_back ( currQual ); - valueNode->qualifiers[qualNum] = 0; // We just moved it to the parent. - - } - - valueNode->qualifiers.clear(); // ! There should be nothing but null pointers. - - // Change the parent's other children into qualifiers. This loop starts at 1, child 0 is the - // rdf:value node. Put xml:lang at the front, append all others. - - for ( childNum = 1, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) { - - XMP_Node * currQual = xmpParent->children[childNum]; - - bool isLang = (currQual->name == "xml:lang"); - - currQual->options |= kXMP_PropIsQualifier; - currQual->parent = xmpParent; - - if ( isLang ) { - if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Duplicate xml:lang qualifier", kXMPErr_BadXMP ); - xmpParent->options |= kXMP_PropHasLang; - } else if ( currQual->name == "rdf:type" ) { - xmpParent->options |= kXMP_PropHasType; - } - - if ( (! isLang) || xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( currQual ); - } else { - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual ); - } - xmpParent->children[childNum] = 0; // We just moved it to the qualifers. - - } - - if ( ! xmpParent->qualifiers.empty() ) xmpParent->options |= kXMP_PropHasQualifiers; - - // Move the options and value last, other checks need the parent's original options. Move the - // value node's children to be the parent's children. Delete the now useless value node. - - XMP_Assert ( xmpParent->options & (kXMP_PropValueIsStruct | kRDF_HasValueElem) ); - xmpParent->options &= ~ (static_cast(kXMP_PropValueIsStruct) | static_cast(kRDF_HasValueElem)); - xmpParent->options |= valueNode->options; - - xmpParent->value.swap ( valueNode->value ); - #if 0 // *** XMP_DebugBuild - xmpParent->_valuePtr = xmpParent->value.c_str(); - #endif - - xmpParent->children[0] = 0; // ! Remove the value node itself before the swap. - xmpParent->children.swap ( valueNode->children ); - - for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) { - XMP_Node * currChild = xmpParent->children[childNum]; - currChild->parent = xmpParent; - } - - delete valueNode; - -} // FixupQualifiedNode - - -// ================================================================================================= -// ProcessRDF -// ========== -// -// Parse the XML tree of the RDF and build the corresponding XMP tree. - -// *** Throw an exception if no XMP is found? By option? -// *** Do parsing exceptions cause the partial tree to be deleted? - -void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & rdfNode, XMP_OptionBits options ) -{ - IgnoreParam(options); - - RDF_RDF ( xmpTree, rdfNode ); - -} // ProcessRDF - - -// ================================================================================================= -// RDF_RDF -// ======= -// -// 7.2.9 RDF -// start-element ( URI == rdf:RDF, attributes == set() ) -// nodeElementList -// end-element() -// -// The top level rdf:RDF node. It can only have xmlns attributes, which have already been removed -// during construction of the XML tree. - -static void -RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode ) -{ - - if ( ! xmlNode.attrs.empty() ) XMP_Throw ( "Invalid attributes of rdf:RDF element", kXMPErr_BadRDF ); - RDF_NodeElementList ( xmpTree, xmlNode, kIsTopLevel ); - -} // RDF_RDF - - -// ================================================================================================= -// RDF_NodeElementList -// =================== -// -// 7.2.10 nodeElementList -// ws* ( nodeElement ws* )* - -static void -RDF_NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel ) -{ - XMP_Assert ( isTopLevel ); - - XML_cNodePos currChild = xmlParent.content.begin(); // *** Change these loops to the indexed pattern. - XML_cNodePos endChild = xmlParent.content.end(); - - for ( ; currChild != endChild; ++currChild ) { - if ( (*currChild)->IsWhitespaceNode() ) continue; - RDF_NodeElement ( xmpParent, **currChild, isTopLevel ); - } - -} // RDF_NodeElementList - - -// ================================================================================================= -// RDF_NodeElement -// =============== -// -// 7.2.5 nodeElementURIs -// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms ) -// -// 7.2.11 nodeElement -// start-element ( URI == nodeElementURIs, -// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) ) -// propertyEltList -// end-element() -// -// A node element URI is rdf:Description or anything else that is not an RDF term. - -static void -RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name ); - if ( (nodeTerm != kRDFTerm_Description) && (nodeTerm != kRDFTerm_Other) ) { - XMP_Throw ( "Node element must be rdf:Description or typedNode", kXMPErr_BadRDF ); - } - - if ( isTopLevel && (nodeTerm == kRDFTerm_Other) ) { - XMP_Throw ( "Top level typedNode not allowed", kXMPErr_BadXMP ); - } else { - RDF_NodeElementAttrs ( xmpParent, xmlNode, isTopLevel ); - RDF_PropertyElementList ( xmpParent, xmlNode, isTopLevel ); - } - -} // RDF_NodeElement - - -// ================================================================================================= -// RDF_NodeElementAttrs -// ==================== -// -// 7.2.7 propertyAttributeURIs -// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms ) -// -// 7.2.11 nodeElement -// start-element ( URI == nodeElementURIs, -// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) ) -// propertyEltList -// end-element() -// -// Process the attribute list for an RDF node element. A property attribute URI is anything other -// than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored, as are rdf:about -// attributes on inner nodes. - -static const XMP_OptionBits kExclusiveAttrMask = (kRDFMask_ID | kRDFMask_nodeID | kRDFMask_about); - -static void -RDF_NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - XMP_OptionBits exclusiveAttrs = 0; // Used to detect attributes that are mutually exclusive. - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - - RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name ); - - switch ( attrTerm ) { - - case kRDFTerm_ID : - case kRDFTerm_nodeID : - case kRDFTerm_about : - - if ( exclusiveAttrs & kExclusiveAttrMask ) XMP_Throw ( "Mutally exclusive about, ID, nodeID attributes", kXMPErr_BadRDF ); - exclusiveAttrs |= (1 << attrTerm); - - if ( isTopLevel && (attrTerm == kRDFTerm_about) ) { - // This is the rdf:about attribute on a top level node. Set the XMP tree name if - // it doesn't have a name yet. Make sure this name matches the XMP tree name. - XMP_Assert ( xmpParent->parent == 0 ); // Must be the tree root node. - if ( xmpParent->name.empty() ) { - xmpParent->name = (*currAttr)->value; - } else if ( ! (*currAttr)->value.empty() ) { - if ( xmpParent->name != (*currAttr)->value ) XMP_Throw ( "Mismatched top level rdf:about values", kXMPErr_BadXMP ); - } - } - - break; - - case kRDFTerm_Other : - AddChildNode ( xmpParent, **currAttr, (*currAttr)->value.c_str(), isTopLevel ); - break; - - default : - XMP_Throw ( "Invalid nodeElement attribute", kXMPErr_BadRDF ); - - } - - } - -} // RDF_NodeElementAttrs - - -// ================================================================================================= -// RDF_PropertyElementList -// ======================= -// -// 7.2.13 propertyEltList -// ws* ( propertyElt ws* )* - -static void -RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel ) -{ - XML_cNodePos currChild = xmlParent.content.begin(); - XML_cNodePos endChild = xmlParent.content.end(); - - for ( ; currChild != endChild; ++currChild ) { - if ( (*currChild)->IsWhitespaceNode() ) continue; - if ( (*currChild)->kind != kElemNode ) { - XMP_Throw ( "Expected property element node not found", kXMPErr_BadRDF ); - } - RDF_PropertyElement ( xmpParent, **currChild, isTopLevel ); - } - -} // RDF_PropertyElementList - - -// ================================================================================================= -// RDF_PropertyElement -// =================== -// -// 7.2.14 propertyElt -// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt | -// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt -// -// 7.2.15 resourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) ) -// ws* nodeElement ws* -// end-element() -// -// 7.2.16 literalPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) ) -// text() -// end-element() -// -// 7.2.17 parseTypeLiteralPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) ) -// literal -// end-element() -// -// 7.2.18 parseTypeResourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) ) -// propertyEltList -// end-element() -// -// 7.2.19 parseTypeCollectionPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) ) -// nodeElementList -// end-element() -// -// 7.2.20 parseTypeOtherPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) ) -// propertyEltList -// end-element() -// -// 7.2.21 emptyPropertyElt -// start-element ( URI == propertyElementURIs, -// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) ) -// end-element() -// -// The various property element forms are not distinguished by the XML element name, but by their -// attributes for the most part. The exceptions are resourcePropertyElt and literalPropertyElt. They -// are distinguished by their XML element content. -// -// NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can appear in -// many of these. We have to allow for it in the attribute counts below. - -static void -RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name ); - if ( ! IsPropertyElementName ( nodeTerm ) ) XMP_Throw ( "Invalid property element name", kXMPErr_BadRDF ); - - if ( xmlNode.attrs.size() > 3 ) { - - // Only an emptyPropertyElt can have more than 3 attributes. - RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel ); - - } else { - - // Look through the attributes for one that isn't rdf:ID or xml:lang, it will usually tell - // what we should be dealing with. The called routines must verify their specific syntax! - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - XMP_VarString * attrName = 0; - - for ( ; currAttr != endAttr; ++currAttr ) { - attrName = &((*currAttr)->name); - if ( (*attrName != "xml:lang") && (*attrName != "rdf:ID") ) break; - } - - if ( currAttr != endAttr ) { - - XMP_Assert ( attrName != 0 ); - XMP_VarString& attrValue = (*currAttr)->value; - - if ( *attrName == "rdf:datatype" ) { - RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else if ( *attrName != "rdf:parseType" ) { - RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else if ( attrValue == "Literal" ) { - RDF_ParseTypeLiteralPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else if ( attrValue == "Resource" ) { - RDF_ParseTypeResourcePropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else if ( attrValue == "Collection" ) { - RDF_ParseTypeCollectionPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else { - RDF_ParseTypeOtherPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } - - } else { - - // Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt, or an. - // emptyPropertyElt. Look at the child XML nodes to decide which. - - if ( xmlNode.content.empty() ) { - - RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel ); - - } else { - - XML_cNodePos currChild = xmlNode.content.begin(); - XML_cNodePos endChild = xmlNode.content.end(); - - for ( ; currChild != endChild; ++currChild ) { - if ( (*currChild)->kind != kCDataNode ) break; - } - - if ( currChild == endChild ) { - RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel ); - } else { - RDF_ResourcePropertyElement ( xmpParent, xmlNode, isTopLevel ); - } - - } - - } - - } - -} // RDF_PropertyElement - - -// ================================================================================================= -// RDF_ResourcePropertyElement -// =========================== -// -// 7.2.15 resourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) ) -// ws* nodeElement ws* -// end-element() -// -// This handles structs using an rdf:Description node, arrays using rdf:Bag/Seq/Alt, and typedNodes. -// It also catches and cleans up qualified properties written with rdf:Description and rdf:value. - -static void -RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - if ( isTopLevel && (xmlNode.name == "iX:changes") ) return; // Strip old "punchcard" chaff. - - XMP_Node * newCompound = AddChildNode ( xmpParent, xmlNode, "", isTopLevel ); - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - XMP_VarString & attrName = (*currAttr)->name; - if ( attrName == "xml:lang" ) { - AddQualifierNode ( newCompound, **currAttr ); - } else if ( attrName == "rdf:ID" ) { - continue; // Ignore all rdf:ID attributes. - } else { - XMP_Throw ( "Invalid attribute for resource property element", kXMPErr_BadRDF ); - } - } - - XML_cNodePos currChild = xmlNode.content.begin(); - XML_cNodePos endChild = xmlNode.content.end(); - - for ( ; currChild != endChild; ++currChild ) { - if ( ! (*currChild)->IsWhitespaceNode() ) break; - } - if ( currChild == endChild ) XMP_Throw ( "Missing child of resource property element", kXMPErr_BadRDF ); - if ( (*currChild)->kind != kElemNode ) XMP_Throw ( "Children of resource property element must be XML elements", kXMPErr_BadRDF ); - - if ( (*currChild)->name == "rdf:Bag" ) { - newCompound->options |= kXMP_PropValueIsArray; - } else if ( (*currChild)->name == "rdf:Seq" ) { - newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered; - } else if ( (*currChild)->name == "rdf:Alt" ) { - newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate; - } else { - newCompound->options |= kXMP_PropValueIsStruct; - if ( (*currChild)->name != "rdf:Description" ) { - XMP_VarString typeName ( (*currChild)->ns ); - size_t colonPos = (*currChild)->name.find_first_of(':'); - if ( colonPos == XMP_VarString::npos ) XMP_Throw ( "All XML elements must be in a namespace", kXMPErr_BadXMP ); - typeName.append ( (*currChild)->name, colonPos, XMP_VarString::npos ); - AddQualifierNode ( newCompound, XMP_VarString("rdf:type"), typeName ); - } - } - - RDF_NodeElement ( newCompound, **currChild, kNotTopLevel ); - if ( newCompound->options & kRDF_HasValueElem ) { - FixupQualifiedNode ( newCompound ); - } else if ( newCompound->options & kXMP_PropArrayIsAlternate ) { - DetectAltText ( newCompound ); - } - - for ( ++currChild; currChild != endChild; ++currChild ) { - if ( ! (*currChild)->IsWhitespaceNode() ) XMP_Throw ( "Invalid child of resource property element", kXMPErr_BadRDF ); - } - -} // RDF_ResourcePropertyElement - - -// ================================================================================================= -// RDF_LiteralPropertyElement -// ========================== -// -// 7.2.16 literalPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) ) -// text() -// end-element() -// -// Add a leaf node with the text value and qualifiers for the attributes. - -static void -RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - XMP_Node * newChild = AddChildNode ( xmpParent, xmlNode, "", isTopLevel ); - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - XMP_VarString & attrName = (*currAttr)->name; - if ( attrName == "xml:lang" ) { - AddQualifierNode ( newChild, **currAttr ); - } else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) { - continue; // Ignore all rdf:ID and rdf:datatype attributes. - } else { - XMP_Throw ( "Invalid attribute for literal property element", kXMPErr_BadRDF ); - } - } - - XML_cNodePos currChild = xmlNode.content.begin(); - XML_cNodePos endChild = xmlNode.content.end(); - size_t textSize = 0; - - for ( ; currChild != endChild; ++currChild ) { - if ( (*currChild)->kind != kCDataNode ) XMP_Throw ( "Invalid child of literal property element", kXMPErr_BadRDF ); - textSize += (*currChild)->value.size(); - } - - newChild->value.reserve ( textSize ); - - for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) { - newChild->value += (*currChild)->value; - } - - #if 0 // *** XMP_DebugBuild - newChild->_valuePtr = newChild->value.c_str(); - #endif - -} // RDF_LiteralPropertyElement - - -// ================================================================================================= -// RDF_ParseTypeLiteralPropertyElement -// =================================== -// -// 7.2.17 parseTypeLiteralPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) ) -// literal -// end-element() - -static void -RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel); - - XMP_Throw ( "ParseTypeLiteral property element not allowed", kXMPErr_BadXMP ); - -} // RDF_ParseTypeLiteralPropertyElement - - -// ================================================================================================= -// RDF_ParseTypeResourcePropertyElement -// ==================================== -// -// 7.2.18 parseTypeResourcePropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) ) -// propertyEltList -// end-element() -// -// Add a new struct node with a qualifier for the possible rdf:ID attribute. Then process the XML -// child nodes to get the struct fields. - -static void -RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - - XMP_Node * newStruct = AddChildNode ( xmpParent, xmlNode, "", isTopLevel ); - newStruct->options |= kXMP_PropValueIsStruct; - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - XMP_VarString & attrName = (*currAttr)->name; - if ( attrName == "rdf:parseType" ) { - continue; // ! The caller ensured the value is "Resource". - } else if ( attrName == "xml:lang" ) { - AddQualifierNode ( newStruct, **currAttr ); - } else if ( attrName == "rdf:ID" ) { - continue; // Ignore all rdf:ID attributes. - } else { - XMP_Throw ( "Invalid attribute for ParseTypeResource property element", kXMPErr_BadRDF ); - } - } - - RDF_PropertyElementList ( newStruct, xmlNode, kNotTopLevel ); - - if ( newStruct->options & kRDF_HasValueElem ) FixupQualifiedNode ( newStruct ); - - // *** Need to look for arrays using rdf:Description and rdf:type. - -} // RDF_ParseTypeResourcePropertyElement - - -// ================================================================================================= -// RDF_ParseTypeCollectionPropertyElement -// ====================================== -// -// 7.2.19 parseTypeCollectionPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) ) -// nodeElementList -// end-element() - -static void -RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel); - - XMP_Throw ( "ParseTypeCollection property element not allowed", kXMPErr_BadXMP ); - -} // RDF_ParseTypeCollectionPropertyElement - - -// ================================================================================================= -// RDF_ParseTypeOtherPropertyElement -// ================================= -// -// 7.2.20 parseTypeOtherPropertyElt -// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) ) -// propertyEltList -// end-element() - -static void -RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel); - - XMP_Throw ( "ParseTypeOther property element not allowed", kXMPErr_BadXMP ); - -} // RDF_ParseTypeOtherPropertyElement - - -// ================================================================================================= -// RDF_EmptyPropertyElement -// ======================== -// -// 7.2.21 emptyPropertyElt -// start-element ( URI == propertyElementURIs, -// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) ) -// end-element() -// -// -// -// -// -// -// An emptyPropertyElt is an element with no contained content, just a possibly empty set of -// attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a -// simple property with an empty value (ns:Prop1), a simple property whose value is a URI -// (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3). An emptyPropertyElt can also -// represent an XMP struct whose fields are all simple and unqualified (ns:Prop4). -// -// It is an error to use both rdf:value and rdf:resource - that can lead to invalid RDF in the -// verbose form written using a literalPropertyElt. -// -// The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for -// design reasons and partly for historical reasons. The XMP mapping rules are: -// 1. If there is an rdf:value attribute then this is a simple property with a text value. -// All other attributes are qualifiers. -// 2. If there is an rdf:resource attribute then this is a simple property with a URI value. -// All other attributes are qualifiers. -// 3. If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID then this is a simple -// property with an empty value. -// 4. Otherwise this is a struct, the attributes other than xml:lang, rdf:ID, or rdf:nodeID are fields. - -static void -RDF_EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel ) -{ - bool hasPropertyAttrs = false; - bool hasResourceAttr = false; - bool hasNodeIDAttr = false; - bool hasValueAttr = false; - - const XML_Node * valueNode = 0; // ! Can come from rdf:value or rdf:resource. - - if ( ! xmlNode.content.empty() ) XMP_Throw ( "Nested content not allowed with rdf:resource or property attributes", kXMPErr_BadRDF ); - - // First figure out what XMP this maps to and remember the XML node for a simple value. - - XML_cNodePos currAttr = xmlNode.attrs.begin(); - XML_cNodePos endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - - RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name ); - - switch ( attrTerm ) { - - case kRDFTerm_ID : - // Nothing to do. - break; - - case kRDFTerm_resource : - if ( hasNodeIDAttr ) XMP_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF ); - if ( hasValueAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP ); - hasResourceAttr = true; - if ( ! hasValueAttr ) valueNode = *currAttr; - break; - - case kRDFTerm_nodeID : - if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF ); - hasNodeIDAttr = true; - break; - - case kRDFTerm_Other : - if ( (*currAttr)->name == "rdf:value" ) { - if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP ); - hasValueAttr = true; - valueNode = *currAttr; - } else if ( (*currAttr)->name != "xml:lang" ) { - hasPropertyAttrs = true; - } - break; - - default : - XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF ); - break; - - } - - } - - // Create the right kind of child node and visit the attributes again to add the fields or qualifiers. - // ! Because of implementation vagaries, the xmpParent is the tree root for top level properties. - // ! The schema is found, created if necessary, by AddChildNode. - - XMP_Node * childNode = AddChildNode ( xmpParent, xmlNode, "", isTopLevel ); - bool childIsStruct = false; - - if ( hasValueAttr | hasResourceAttr ) { - childNode->value = valueNode->value; - if ( ! hasValueAttr ) childNode->options |= kXMP_PropValueIsURI; // ! Might have both rdf:value and rdf:resource. - } else if ( hasPropertyAttrs ) { - childNode->options |= kXMP_PropValueIsStruct; - childIsStruct = true; - } - - currAttr = xmlNode.attrs.begin(); - endAttr = xmlNode.attrs.end(); - - for ( ; currAttr != endAttr; ++currAttr ) { - - if ( *currAttr == valueNode ) continue; // Skip the rdf:value or rdf:resource attribute holding the value. - RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name ); - - switch ( attrTerm ) { - - case kRDFTerm_ID : - case kRDFTerm_nodeID : - break; // Ignore all rdf:ID and rdf:nodeID attributes.w - - case kRDFTerm_resource : - AddQualifierNode ( childNode, **currAttr ); - break; - - case kRDFTerm_Other : - if ( (! childIsStruct) || (*currAttr)->name == "xml:lang" ) { - AddQualifierNode ( childNode, **currAttr ); - } else { - AddChildNode ( childNode, **currAttr, (*currAttr)->value.c_str(), false ); - } - break; - - default : - XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF ); - break; - - } - - } - -} // RDF_EmptyPropertyElement - - -// ================================================================================================= diff --git a/xmpsdk/src/UnicodeConversions.cpp b/xmpsdk/src/UnicodeConversions.cpp deleted file mode 100644 index 123c502b00..0000000000 --- a/xmpsdk/src/UnicodeConversions.cpp +++ /dev/null @@ -1,1665 +0,0 @@ -// ================================================================================================= -// Copyright 2004-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Const.h" - -#if UnicodeTestBuild - #include - #include - #define UC_Assert assert - #define UC_Throw(m,k) throw std::logic_error ( m ) -#else - #define UC_Assert(cond) /* Nothing for now, should be XMP_Assert. */ - #define UC_Throw(msg,id) throw XMP_Error ( id, msg ) -#endif - -#include "UnicodeConversions.hpp" - -using namespace std; - -// ================================================================================================= - -// *** Look into using asm inlines, e.g. count-leading bits for multi-byte UTF-8. - -CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE = 0; -CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE = 0; - -CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE = 0; -CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE = 0; - -UTF8_to_UTF16_Proc UTF8_to_UTF16BE = 0; -UTF8_to_UTF16_Proc UTF8_to_UTF16LE = 0; -UTF8_to_UTF32_Proc UTF8_to_UTF32BE = 0; -UTF8_to_UTF32_Proc UTF8_to_UTF32LE = 0; - -UTF16_to_UTF8_Proc UTF16BE_to_UTF8 = 0; -UTF16_to_UTF8_Proc UTF16LE_to_UTF8 = 0; -UTF32_to_UTF8_Proc UTF32BE_to_UTF8 = 0; -UTF32_to_UTF8_Proc UTF32LE_to_UTF8 = 0; - -UTF8_to_UTF16_Proc UTF8_to_UTF16Native = 0; -UTF8_to_UTF32_Proc UTF8_to_UTF32Native = 0; -UTF16_to_UTF8_Proc UTF16Native_to_UTF8 = 0; -UTF32_to_UTF8_Proc UTF32Native_to_UTF8 = 0; - -UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE = 0; -UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE = 0; -UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE = 0; -UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE = 0; - -UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE = 0; -UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE = 0; -UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE = 0; -UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE = 0; - -// ------------------------------------------------------------------------------------------------- - -static size_t swap32to16Offset = 0; // Offset to "convert" a swapped UTF32 pointer into a swapped UTF16 pointer. - -// ------------------------------------------------------------------------------------------------- - -static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ); -static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ); - -static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ); -static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ); - -// ------------------------------------------------------------------------------------------------- - -static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf8Read, size_t * utf16Written ); - -static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf8Read, size_t * utf16Written ); - -static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf8Read, size_t * utf32Written ); - -static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf8Read, size_t * utf32Written ); - -// ------------------------------------------------------------------------------------------------- - -static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf16Read, size_t * utf8Written ); - -static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf16Read, size_t * utf8Written ); - -static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf32Read, size_t * utf8Written ); - -static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf32Read, size_t * utf8Written ); - -// ------------------------------------------------------------------------------------------------- - -static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ); - -static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ); - -static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ); - -static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ); - -// ------------------------------------------------------------------------------------------------- - -static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ); - -static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ); - -static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ); - -static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ); - -// ================================================================================================= - -void InitializeUnicodeConversions() -{ - UC_Assert ( (sizeof(UTF8Unit) == 1) && (sizeof(UTF16Unit) == 2) && (sizeof(UTF32Unit) == 4) ); - - UTF16Unit u16 = 0x00FF; - bool bigEndian = (*((UTF8Unit*)&u16) == 0); - - UTF8_to_UTF16Native = UTF8_to_UTF16Nat; - UTF8_to_UTF32Native = UTF8_to_UTF32Nat; - UTF16Native_to_UTF8 = UTF16Nat_to_UTF8; - UTF32Native_to_UTF8 = UTF32Nat_to_UTF8; - - if ( bigEndian ) { - - swap32to16Offset = 0; - - CodePoint_to_UTF16BE = CodePoint_to_UTF16Nat; - CodePoint_to_UTF16LE = CodePoint_to_UTF16Swp; - - CodePoint_from_UTF16BE = CodePoint_from_UTF16Nat; - CodePoint_from_UTF16LE = CodePoint_from_UTF16Swp; - - UTF8_to_UTF16BE = UTF8_to_UTF16Nat; - UTF8_to_UTF16LE = UTF8_to_UTF16Swp; - UTF8_to_UTF32BE = UTF8_to_UTF32Nat; - UTF8_to_UTF32LE = UTF8_to_UTF32Swp; - - UTF16BE_to_UTF8 = UTF16Nat_to_UTF8; - UTF16LE_to_UTF8 = UTF16Swp_to_UTF8; - UTF32BE_to_UTF8 = UTF32Nat_to_UTF8; - UTF32LE_to_UTF8 = UTF32Swp_to_UTF8; - - UTF16BE_to_UTF32BE = UTF16Nat_to_UTF32Nat; - UTF16BE_to_UTF32LE = UTF16Nat_to_UTF32Swp; - UTF16LE_to_UTF32BE = UTF16Swp_to_UTF32Nat; - UTF16LE_to_UTF32LE = UTF16Swp_to_UTF32Swp; - - UTF32BE_to_UTF16BE = UTF32Nat_to_UTF16Nat; - UTF32BE_to_UTF16LE = UTF32Nat_to_UTF16Swp; - UTF32LE_to_UTF16BE = UTF32Swp_to_UTF16Nat; - UTF32LE_to_UTF16LE = UTF32Swp_to_UTF16Swp; - - } else { - - swap32to16Offset = 1; // ! Offset in UTF16 units! - - CodePoint_to_UTF16BE = CodePoint_to_UTF16Swp; - CodePoint_to_UTF16LE = CodePoint_to_UTF16Nat; - - CodePoint_from_UTF16BE = CodePoint_from_UTF16Swp; - CodePoint_from_UTF16LE = CodePoint_from_UTF16Nat; - - UTF8_to_UTF16BE = UTF8_to_UTF16Swp; - UTF8_to_UTF16LE = UTF8_to_UTF16Nat; - UTF8_to_UTF32BE = UTF8_to_UTF32Swp; - UTF8_to_UTF32LE = UTF8_to_UTF32Nat; - - UTF16BE_to_UTF8 = UTF16Swp_to_UTF8; - UTF16LE_to_UTF8 = UTF16Nat_to_UTF8; - UTF32BE_to_UTF8 = UTF32Swp_to_UTF8; - UTF32LE_to_UTF8 = UTF32Nat_to_UTF8; - - UTF16BE_to_UTF32BE = UTF16Swp_to_UTF32Swp; - UTF16BE_to_UTF32LE = UTF16Swp_to_UTF32Nat; - UTF16LE_to_UTF32BE = UTF16Nat_to_UTF32Swp; - UTF16LE_to_UTF32LE = UTF16Nat_to_UTF32Nat; - - UTF32BE_to_UTF16BE = UTF32Swp_to_UTF16Swp; - UTF32BE_to_UTF16LE = UTF32Swp_to_UTF16Nat; - UTF32LE_to_UTF16BE = UTF32Nat_to_UTF16Swp; - UTF32LE_to_UTF16LE = UTF32Nat_to_UTF16Nat; - - } - -} // InitializeUnicodeConversions - -// ================================================================================================= - -#if XMP_MacBuild && __MWERKS__ - - #define UTF16InSwap(inPtr) UTF16Unit ( __lhbrx ( (void*)(inPtr), 0 ) ) - #define UTF32InSwap(inPtr) UTF32Unit ( __lwbrx ( (void*)(inPtr), 0 ) ) - - #define UTF16OutSwap(outPtr,value) __sthbrx ( value, (void*)(outPtr), 0 ) - #define UTF32OutSwap(outPtr,value) __stwbrx ( value, (void*)(outPtr), 0 ) - -#else - - static inline UTF16Unit UTF16InSwap ( const UTF16Unit * inPtr ) - { - UTF16Unit inUnit = *inPtr; - return (inUnit << 8) | (inUnit >> 8); - } - - static inline UTF32Unit UTF32InSwap ( const UTF32Unit * inPtr ) - { - UTF32Unit inUnit = *inPtr; - return (inUnit << 24) | ((inUnit << 8) & 0x00FF0000) | ((inUnit >> 8) & 0x0000FF00) | (inUnit >> 24); - } - - static inline void UTF16OutSwap ( UTF16Unit * outPtr, const UTF16Unit value ) - { - UTF16Unit outUnit = (value << 8) | (value >> 8); - *outPtr = outUnit; - } - - static inline void UTF32OutSwap ( UTF32Unit * outPtr, const UTF32Unit value ) - { - UTF32Unit outUnit = (value << 24) | ((value << 8) & 0x00FF0000) | ((value >> 8) & 0x0000FF00) | (value >> 24); - *outPtr = outUnit; - } - -#endif - -// ================================================================================================= - -void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len ) -{ - for ( size_t i = 0; i < utf16Len; ++i ) utf16Out[i] = UTF16InSwap(utf16In+i); -} - -void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len ) { - for ( size_t i = 0; i < utf32Len; ++i ) utf32Out[i] = UTF32InSwap(utf32In+i); -} - -// ================================================================================================= - -extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian ) -{ - UTF8_to_UTF16_Proc Converter = UTF8_to_UTF16LE; - if ( bigEndian ) Converter = UTF8_to_UTF16BE; - - enum { kBufferSize = 8*1024 }; - UTF16Unit u16Buffer[kBufferSize]; // 16K bytes - size_t readCount, writeCount; - - utf16Str->erase(); - utf16Str->reserve ( 2*utf8Len ); // As good a guess as any. - - while ( utf8Len > 0 ) { - Converter ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf16Str->append ( (const char *)u16Buffer, writeCount*2 ); - utf8In += readCount; - utf8Len -= readCount; - } - -} // ToUTF16 - -// ================================================================================================= - -extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str ) -{ - enum { kBufferSize = 8*1024 }; - UTF16Unit u16Buffer[kBufferSize]; // 16K bytes - size_t readCount, writeCount; - - utf16Str->erase(); - utf16Str->reserve ( 2*utf8Len ); // As good a guess as any. - - while ( utf8Len > 0 ) { - UTF8_to_UTF16Nat ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf16Str->append ( (const char *)u16Buffer, writeCount*2 ); - utf8In += readCount; - utf8Len -= readCount; - } - -} // ToUTF16Native - -// ================================================================================================= - -extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian ) -{ - UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32LE; - if ( bigEndian ) Converter = UTF8_to_UTF32BE; - - enum { kBufferSize = 4*1024 }; - UTF32Unit u32Buffer[kBufferSize]; // 16K bytes - size_t readCount, writeCount; - - utf32Str->erase(); - utf32Str->reserve ( 4*utf8Len ); // As good a guess as any. - - while ( utf8Len > 0 ) { - Converter ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf32Str->append ( (const char *)u32Buffer, writeCount*4 ); - utf8In += readCount; - utf8Len -= readCount; - } - -} // ToUTF32 - -// ================================================================================================= - -extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str ) -{ - enum { kBufferSize = 4*1024 }; - UTF32Unit u32Buffer[kBufferSize]; // 16K bytes - size_t readCount, writeCount; - - utf32Str->erase(); - utf32Str->reserve ( 4*utf8Len ); // As good a guess as any. - - while ( utf8Len > 0 ) { - UTF8_to_UTF32Nat ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf32Str->append ( (const char *)u32Buffer, writeCount*4 ); - utf8In += readCount; - utf8Len -= readCount; - } - -} // ToUTF32Native - -// ================================================================================================= - -extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian ) -{ - UTF16_to_UTF8_Proc Converter = UTF16LE_to_UTF8; - if ( bigEndian ) Converter = UTF16BE_to_UTF8; - - enum { kBufferSize = 16*1024 }; - UTF8Unit u8Buffer[kBufferSize]; - size_t readCount, writeCount; - - utf8Str->erase(); - utf8Str->reserve ( 2*utf16Len ); // As good a guess as any. - - while ( utf16Len > 0 ) { - Converter ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf8Str->append ( (const char *)u8Buffer, writeCount ); - utf16In += readCount; - utf16Len -= readCount; - } - -} // FromUTF16 - -// ================================================================================================= - -extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str ) -{ - enum { kBufferSize = 16*1024 }; - UTF8Unit u8Buffer[kBufferSize]; - size_t readCount, writeCount; - - utf8Str->erase(); - utf8Str->reserve ( 2*utf16Len ); // As good a guess as any. - - while ( utf16Len > 0 ) { - UTF16Nat_to_UTF8 ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf8Str->append ( (const char *)u8Buffer, writeCount ); - utf16In += readCount; - utf16Len -= readCount; - } - -} // FromUTF16Native - -// ================================================================================================= - -extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian ) -{ - UTF32_to_UTF8_Proc Converter = UTF32LE_to_UTF8; - if ( bigEndian ) Converter = UTF32BE_to_UTF8; - - enum { kBufferSize = 16*1024 }; - UTF8Unit u8Buffer[kBufferSize]; - size_t readCount, writeCount; - - utf8Str->erase(); - utf8Str->reserve ( 2*utf32Len ); // As good a guess as any. - - while ( utf32Len > 0 ) { - Converter ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf8Str->append ( (const char *)u8Buffer, writeCount ); - utf32In += readCount; - utf32Len -= readCount; - } - -} // FromUTF32 - -// ================================================================================================= - -extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str ) -{ - enum { kBufferSize = 16*1024 }; - UTF8Unit u8Buffer[kBufferSize]; - size_t readCount, writeCount; - - utf8Str->erase(); - utf8Str->reserve ( 2*utf32Len ); // As good a guess as any. - - while ( utf32Len > 0 ) { - UTF32Nat_to_UTF8 ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount ); - if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML ); - utf8Str->append ( (const char *)u8Buffer, writeCount ); - utf32In += readCount; - utf32Len -= readCount; - } - -} // FromUTF32Native - -// ================================================================================================= - -static void CodePoint_to_UTF8_Multi ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written ) -{ - size_t unitCount = 0; - - if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam ); - if ( (0xD800 <= cpIn) && (cpIn <= 0xDFFF) ) UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam ); - - // Compute the number of bytes using 6 data bits each. Then see if the highest order bits will - // fit into the leading byte. Write the UTF-8 sequence if there is enough room. - - UTF32Unit temp, mask; - size_t bytesNeeded = 0; - for ( temp = cpIn; temp != 0; temp = temp >> 6 ) ++bytesNeeded; - - temp = cpIn >> ((bytesNeeded-1)*6); // The highest order data bits. - mask = (0x80 >> bytesNeeded) - 1; // Available data bits in the leading byte. - if ( temp > mask ) ++bytesNeeded; - - if ( bytesNeeded > utf8Len ) goto Done; // Not enough room for the output. - unitCount = bytesNeeded; - - temp = cpIn; - for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded ) { - utf8Out[bytesNeeded] = 0x80 | UTF8Unit ( temp & 0x3F ); - temp = temp >> 6; - } - - mask = ~((1 << (8-unitCount)) - 1); - utf8Out[0] = UTF8Unit ( mask | temp ); - -Done: - *utf8Written = unitCount; - return; - -} // CodePoint_to_UTF8_Multi - -// ================================================================================================= - -void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written ) -{ - size_t unitCount = 0; - - UC_Assert ( (utf8Out != 0) && (utf8Written != 0) ); - if ( utf8Len == 0 ) goto Done; - if ( cpIn > 0x7F ) goto MultiByte; // ! Force linear execution path for ASCII. - - if ( utf8Len == 0 ) goto Done; - unitCount = 1; - *utf8Out = UTF8Unit(cpIn); - -Done: - *utf8Written = unitCount; - return; - -MultiByte: - CodePoint_to_UTF8_Multi( cpIn, utf8Out, utf8Len, utf8Written ); - return; - -} // CodePoint_to_UTF8 - -// ================================================================================================= - -static void CodePoint_from_UTF8_Multi ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read ) -{ - UTF8Unit inUnit = *utf8In; - size_t unitCount = 0; - UTF32Unit cp; // ! Avoid gcc complaints about declarations after goto's. - const UTF8Unit * utf8Pos; - - // ------------------------------------------------------------------------------------- - // We've got a multibyte UTF-8 character. The first byte has the number of bytes and the - // highest order data bits. The other bytes each add 6 more data bits. - - #if 0 // This might be a more effcient way to count the bytes. - static XMP_Uns8 kByteCounts[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 }; - size_t bytesNeeded = kByteCounts [ inUnit >> 4 ]; - if ( (bytesNeeded < 2) || ((bytesNeeded == 4) && ((inUnit & 0x08) != 0)) ) { - UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam ); - } - #endif - - size_t bytesNeeded = 0; // Count the leading 1 bits in the first byte. - for ( UTF8Unit temp = inUnit; temp > 0x7F; temp = temp << 1 ) ++bytesNeeded; - // *** Consider CPU-specific assembly inline, e.g. cntlzw on PowerPC. - - if ( (bytesNeeded < 2) || (bytesNeeded > 4) ) UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam ); - if ( bytesNeeded > utf8Len ) goto Done; // Not enough input in this buffer. - unitCount = bytesNeeded; - - cp = inUnit & ((1 << (7-unitCount)) - 1); // Isolate the initial data bits in the bottom of cp. - - utf8Pos = utf8In + 1; // We've absorbed the first byte. - for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded, ++utf8Pos ) { - inUnit = *utf8Pos; - if ( (inUnit & UTF8Unit(0xC0)) != UTF8Unit(0x80) ) UC_Throw ( "Invalid UTF-8 data byte", kXMPErr_BadParam ); - cp = (cp << 6) | (inUnit & 0x3F); - } - - if ( cp >= 0xD800 ) { // Skip the next comparisons most of the time. - if ( (0xD800 <= cp) && (cp <= 0xDFFF) ) UC_Throw ( "Bad UTF-8 - surrogate code point", kXMPErr_BadParam ); - if ( cp > 0x10FFFF ) UC_Throw ( "Bad UTF-8 - out of range", kXMPErr_BadParam ); - } - - *cpOut = cp; // ! Don't put after Done, don't write if no input. - -Done: - *utf8Read = unitCount; - return; - -} // CodePoint_from_UTF8_Multi - -// ================================================================================================= - -void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read ) -{ - UTF8Unit inUnit; // ! Don't read until we know there is input. - size_t unitCount = 0; - - UC_Assert ( (utf8In != 0) && (cpOut != 0) && (utf8Read != 0) ); - if ( utf8Len == 0 ) goto Done; - inUnit = *utf8In; - if ( inUnit >= 0x80 ) goto MultiByte; // ! Force linear execution path for ASCII. - - unitCount = 1; - *cpOut = inUnit; // ! Don't put after Done, don't write if no input. - -Done: - *utf8Read = unitCount; - return; - -MultiByte: - CodePoint_from_UTF8_Multi ( utf8In, utf8Len, cpOut, utf8Read ); - return; - -} // CodePoint_from_UTF8 - -// ================================================================================================= - -static void CodePoint_to_UTF16Nat_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ) -{ - size_t unitCount = 0; - UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's. - - if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam ); - if ( utf16Len < 2 ) goto Done; // Not enough room for the output. - - unitCount = 2; - temp = cpIn - 0x10000; - utf16Out[0] = 0xD800 | UTF16Unit ( temp >> 10 ); - utf16Out[1] = 0xDC00 | UTF16Unit ( temp & 0x3FF ); - -Done: - *utf16Written = unitCount; - return; - -} // CodePoint_to_UTF16Nat_Surrogate - -// ================================================================================================= - -static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ) -{ - size_t unitCount = 0; - - UC_Assert ( (utf16Out != 0) && (utf16Written != 0) ); - if ( utf16Len == 0 ) goto Done; - if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP. - -InBMP: - unitCount = 1; - *utf16Out = UTF16Unit(cpIn); - -Done: - *utf16Written = unitCount; - return; - -CheckSurrogate: - if ( cpIn > 0xFFFF ) goto SurrogatePair; - if ( cpIn > 0xDFFF ) goto InBMP; - UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam ); - -SurrogatePair: - CodePoint_to_UTF16Nat_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written ); - return; - -} // CodePoint_to_UTF16Nat - -// ================================================================================================= - -static void CodePoint_from_UTF16Nat_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ) -{ - UTF16Unit hiUnit = *utf16In; - size_t unitCount = 0; - UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's. - UTF32Unit cp; - - // ---------------------------------- - // We've got a UTF-16 surrogate pair. - - if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam ); - if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer. - - loUnit = *(utf16In+1); - if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam ); - - unitCount = 2; - cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000; - - *cpOut = cp; // ! Don't put after Done, don't write if no input. - -Done: - *utf16Read = unitCount; - return; - -} // CodePoint_from_UTF16Nat_Surrogate - -// ================================================================================================= - -static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ) -{ - UTF16Unit inUnit; // ! Don't read until we know there is input. - size_t unitCount = 0; - - UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) ); - if ( utf16Len == 0 ) goto Done; - inUnit = *utf16In; - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP. - - unitCount = 1; - *cpOut = inUnit; // ! Don't put after Done, don't write if no input. - -Done: - *utf16Read = unitCount; - return; - -SurrogatePair: - CodePoint_from_UTF16Nat_Surrogate ( utf16In, utf16Len, cpOut, utf16Read ); - return; - -} // CodePoint_from_UTF16Nat - -// ================================================================================================= - -static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf8Read, size_t * utf16Written ) -{ - const UTF8Unit * utf8Pos = utf8In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf8Left = utf8Len; - size_t utf16Left = utf16Len; - - UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) ); - - while ( (utf8Left > 0) && (utf16Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf8Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF8Unit inUnit = *utf8Pos; - if ( inUnit > 0x7F ) break; - *utf16Pos = inUnit; - ++utf8Pos; - ++utf16Pos; - } - utf8Left -= i; - utf16Left -= i; - - // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units. - while ( (utf8Left > 0) && (utf16Left > 0) ) { - UTF32Unit cp; - size_t len8, len16; - UTF8Unit inUnit = *utf8Pos; - if ( inUnit <= 0x7F ) break; - CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 ); - if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character. - if ( cp <= 0xFFFF ) { - *utf16Pos = UTF16Unit(cp); - len16 = 1; - } else { - CodePoint_to_UTF16Nat_Surrogate ( cp, utf16Pos, utf16Left, &len16 ); - if ( len16 == 0 ) goto Done; // Not enough room in the output buffer. - } - utf8Left -= len8; - utf8Pos += len8; - utf16Left -= len16; - utf16Pos += len16; - } - - } - -Done: // Set the output lengths. - *utf8Read = utf8Len - utf8Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF8_to_UTF16Nat - -// ================================================================================================= - -static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf8Read, size_t * utf32Written ) -{ - const UTF8Unit * utf8Pos = utf8In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf8Left = utf8Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) ); - - while ( (utf8Left > 0) && (utf32Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf8Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF8Unit inUnit = *utf8Pos; - if ( inUnit > 0x7F ) break; - *utf32Pos = inUnit; - ++utf8Pos; - ++utf32Pos; - } - utf8Left -= i; - utf32Left -= i; - - // Do a run of non-ASCII, it copies variable input into 1 output unit. - while ( (utf8Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF8Unit inUnit = *utf8Pos; - if ( inUnit <= 0x7F ) break; - CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, utf32Pos, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character. - utf8Left -= len; - utf8Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf8Read = utf8Len - utf8Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF8_to_UTF32Nat - -// ================================================================================================= - -static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf16Read, size_t * utf8Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF8Unit * utf8Pos = utf8Out; - - size_t utf16Left = utf16Len; - size_t utf8Left = utf8Len; - - UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) ); - - while ( (utf16Left > 0) && (utf8Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf8Left ) limit = utf8Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = *utf16Pos; - if ( inUnit > 0x7F ) break; - *utf8Pos = UTF8Unit(inUnit); - ++utf16Pos; - ++utf8Pos; - } - utf16Left -= i; - utf8Left -= i; - - // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units. - while ( (utf16Left > 0) && (utf8Left > 0) ) { - size_t len8; - UTF16Unit inUnit = *utf16Pos; - if ( inUnit <= 0x7F ) break; - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 ); - if ( len8 == 0 ) goto Done; // Not enough room in the output buffer. - utf16Left -= 1; - utf16Pos += 1; - utf8Left -= len8; - utf8Pos += len8; - } - - // Do a run of surrogate pairs, it copies 2 input units into multiple output units. - while ( (utf16Left > 0) && (utf8Left > 0) ) { - UTF32Unit cp; - size_t len16, len8; - UTF16Unit inUnit = *utf16Pos; - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len16 ); - if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UC_Assert ( len16 == 2 ); - CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 ); - if ( len8 == 0 ) goto Done; // Not enough room in the output buffer. - utf16Left -= len16; - utf16Pos += len16; - utf8Left -= len8; - utf8Pos += len8; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf8Written = utf8Len - utf8Left; - -} // UTF16Nat_to_UTF8 - -// ================================================================================================= - -static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf32Read, size_t * utf8Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF8Unit * utf8Pos = utf8Out; - - size_t utf32Left = utf32Len; - size_t utf8Left = utf8Len; - - UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) ); - - while ( (utf32Left > 0) && (utf8Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf8Left ) limit = utf8Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit inUnit = *utf32Pos; - if ( inUnit > 0x7F ) break; - *utf8Pos = UTF8Unit(inUnit); - ++utf32Pos; - ++utf8Pos; - } - utf32Left -= i; - utf8Left -= i; - - // Do a run of non-ASCII, it copies 1 input unit into multiple output units. - while ( (utf32Left > 0) && (utf8Left > 0) ) { - size_t len; - UTF32Unit inUnit = *utf32Pos; - if ( inUnit <= 0x7F ) break; - CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - utf32Left -= 1; - utf32Pos += 1; - utf8Left -= len; - utf8Pos += len; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf8Written = utf8Len - utf8Left; - -} // UTF32Nat_to_UTF8 - -// ================================================================================================= - -static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf16Left = utf16Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) ); - - while ( (utf16Left > 0) && (utf32Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = *utf16Pos; - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - *utf32Pos = inUnit; - ++utf16Pos; - ++utf32Pos; - } - utf16Left -= i; - utf32Left -= i; - - // Do a run of surrogate pairs, it copies 2 input units into 1 output unit. - while ( (utf16Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF16Unit inUnit = *utf16Pos; - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UC_Assert ( len == 2 ); - utf16Left -= len; - utf16Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF16Nat_to_UTF32Nat - -// ================================================================================================= - -static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf32Left = utf32Len; - size_t utf16Left = utf16Len; - - UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) ); - - while ( (utf32Left > 0) && (utf16Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit inUnit = *utf32Pos; - if ( inUnit > 0xFFFF ) break; - *utf16Pos = UTF16Unit(inUnit); - ++utf32Pos; - ++utf16Pos; - } - utf32Left -= i; - utf16Left -= i; - - // Do a run of non-BMP, it copies 1 input unit into 2 output units. - while ( (utf32Left > 0) && (utf16Left > 0) ) { - size_t len; - UTF32Unit inUnit = *utf32Pos; - if ( inUnit <= 0xFFFF ) break; - CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - UC_Assert ( len == 2 ); - utf32Left -= 1; - utf32Pos += 1; - utf16Left -= 2; - utf16Pos += 2; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF32Nat_to_UTF16Nat - -// ================================================================================================= - -static void CodePoint_to_UTF16Swp_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ) -{ - size_t unitCount = 0; - UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's. - - if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam ); - if ( utf16Len < 2 ) goto Done; // Not enough room for the output. - - unitCount = 2; - temp = cpIn - 0x10000; - UTF16OutSwap ( &utf16Out[0], (0xD800 | UTF16Unit ( temp >> 10 )) ); - UTF16OutSwap ( &utf16Out[1], (0xDC00 | UTF16Unit ( temp & 0x3FF)) ); - -Done: - *utf16Written = unitCount; - return; - -} // CodePoint_to_UTF16Swp_Surrogate - -// ================================================================================================= - -static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ) -{ - size_t unitCount = 0; - - UC_Assert ( (utf16Out != 0) && (utf16Written != 0) ); - if ( utf16Len == 0 ) goto Done; - if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP. - -InBMP: - unitCount = 1; - UTF16OutSwap ( utf16Out, UTF16Unit(cpIn) ); - -Done: - *utf16Written = unitCount; - return; - -CheckSurrogate: - if ( cpIn > 0xFFFF ) goto SurrogatePair; - if ( cpIn > 0xDFFF ) goto InBMP; - UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam ); - -SurrogatePair: - CodePoint_to_UTF16Swp_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written ); - return; - -} // CodePoint_to_UTF16Swp - -// ================================================================================================= - -static void CodePoint_from_UTF16Swp_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ) -{ - UTF16Unit hiUnit = UTF16InSwap(utf16In); - size_t unitCount = 0; - UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's. - UTF32Unit cp; - - // ---------------------------------- - // We've got a UTF-16 surrogate pair. - - if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam ); - if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer. - - loUnit = UTF16InSwap(utf16In+1); - if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam ); - - unitCount = 2; - cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000; - - *cpOut = cp; // ! Don't put after Done, don't write if no input. - -Done: - *utf16Read = unitCount; - return; - -} // CodePoint_from_UTF16Swp_Surrogate - -// ================================================================================================= - -static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ) -{ - UTF16Unit inUnit; // ! Don't read until we know there is input. - size_t unitCount = 0; - - UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) ); - if ( utf16Len == 0 ) goto Done; - inUnit = UTF16InSwap(utf16In); - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP. - - unitCount = 1; - *cpOut = inUnit; // ! Don't put after Done, don't write if no input. - -Done: - *utf16Read = unitCount; - return; - -SurrogatePair: - CodePoint_from_UTF16Swp_Surrogate ( utf16In, utf16Len, cpOut, utf16Read ); - return; - -} // CodePoint_from_UTF16Swp - -// ================================================================================================= - -static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf8Read, size_t * utf16Written ) -{ - const UTF8Unit * utf8Pos = utf8In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf8Left = utf8Len; - size_t utf16Left = utf16Len; - - UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) ); - - while ( (utf8Left > 0) && (utf16Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf8Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF8Unit inUnit = *utf8Pos; - if ( inUnit > 0x7F ) break; - *utf16Pos = UTF16Unit(inUnit) << 8; // Better than: UTF16OutSwap ( utf16Pos, inUnit ); - ++utf8Pos; - ++utf16Pos; - } - utf8Left -= i; - utf16Left -= i; - - // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units. - while ( (utf8Left > 0) && (utf16Left > 0) ) { - UTF32Unit cp; - size_t len8, len16; - UTF8Unit inUnit = *utf8Pos; - if ( inUnit <= 0x7F ) break; - CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 ); - if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character. - if ( cp <= 0xFFFF ) { - UTF16OutSwap ( utf16Pos, UTF16Unit(cp) ); - len16 = 1; - } else { - CodePoint_to_UTF16Swp_Surrogate ( cp, utf16Pos, utf16Left, &len16 ); - if ( len16 == 0 ) goto Done; // Not enough room in the output buffer. - } - utf8Left -= len8; - utf8Pos += len8; - utf16Left -= len16; - utf16Pos += len16; - } - - } - -Done: // Set the output lengths. - *utf8Read = utf8Len - utf8Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF8_to_UTF16Swp - -// ================================================================================================= - -static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf8Read, size_t * utf32Written ) -{ - const UTF8Unit * utf8Pos = utf8In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf8Left = utf8Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) ); - - while ( (utf8Left > 0) && (utf32Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf8Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF8Unit inUnit = *utf8Pos; - if ( inUnit > 0x7F ) break; - *utf32Pos = UTF32Unit(inUnit) << 24; // Better than: UTF32OutSwap ( utf32Pos, inUnit ); - ++utf8Pos; - ++utf32Pos; - } - utf8Left -= i; - utf32Left -= i; - - // Do a run of non-ASCII, it copies variable input into 1 output unit. - while ( (utf8Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF32Unit cp; - UTF8Unit inUnit = *utf8Pos; - if ( inUnit <= 0x7F ) break; - CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character. - UTF32OutSwap ( utf32Pos, cp ); - utf8Left -= len; - utf8Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf8Read = utf8Len - utf8Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF8_to_UTF32Swp - -// ================================================================================================= - -static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf16Read, size_t * utf8Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF8Unit * utf8Pos = utf8Out; - - size_t utf16Left = utf16Len; - size_t utf8Left = utf8Len; - - UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) ); - - while ( (utf16Left > 0) && (utf8Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf8Left ) limit = utf8Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( inUnit > 0x7F ) break; - *utf8Pos = UTF8Unit(inUnit); - ++utf16Pos; - ++utf8Pos; - } - utf16Left -= i; - utf8Left -= i; - - // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units. - while ( (utf16Left > 0) && (utf8Left > 0) ) { - size_t len8; - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( inUnit <= 0x7F ) break; - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 ); - if ( len8 == 0 ) goto Done; // Not enough room in the output buffer. - utf16Left -= 1; - utf16Pos += 1; - utf8Left -= len8; - utf8Pos += len8; - } - - // Do a run of surrogate pairs, it copies 2 input units into multiple output units. - while ( (utf16Left > 0) && (utf8Left > 0) ) { - UTF32Unit cp; - size_t len16, len8; - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len16 ); - if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UC_Assert ( len16 == 2 ); - CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 ); - if ( len8 == 0 ) goto Done; // Not enough room in the output buffer. - utf16Left -= len16; - utf16Pos += len16; - utf8Left -= len8; - utf8Pos += len8; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf8Written = utf8Len - utf8Left; - -} // UTF16Swp_to_UTF8 - -// ================================================================================================= - -static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf32Read, size_t * utf8Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF8Unit * utf8Pos = utf8Out; - - size_t utf32Left = utf32Len; - size_t utf8Left = utf8Len; - - UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) ); - - while ( (utf32Left > 0) && (utf8Left > 0) ) { - - // Do a run of ASCII, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf8Left ) limit = utf8Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit cp = UTF32InSwap(utf32Pos); - if ( cp > 0x7F ) break; - *utf8Pos = UTF8Unit(cp); - ++utf32Pos; - ++utf8Pos; - } - utf32Left -= i; - utf8Left -= i; - - // Do a run of non-ASCII, it copies 1 input unit into multiple output units. - while ( (utf32Left > 0) && (utf8Left > 0) ) { - size_t len; - UTF32Unit cp = UTF32InSwap(utf32Pos); - if ( cp <= 0x7F ) break; - CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - utf32Left -= 1; - utf32Pos += 1; - utf8Left -= len; - utf8Pos += len; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf8Written = utf8Len - utf8Left; - -} // UTF32Swp_to_UTF8 - -// ================================================================================================= - -static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf16Left = utf16Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) ); - - while ( (utf16Left > 0) && (utf32Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - *utf32Pos = UTF32Unit(*utf16Pos) << 16; // Better than: UTF32OutSwap ( utf32Pos, inUnit ); - ++utf16Pos; - ++utf32Pos; - } - utf16Left -= i; - utf32Left -= i; - - // Do a run of surrogate pairs, it copies 2 input units into 1 output unit. - while ( (utf16Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF32Unit cp; - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UTF32OutSwap ( utf32Pos, cp ); - UC_Assert ( len == 2 ); - utf16Left -= len; - utf16Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF16Swp_to_UTF32Swp - -// ================================================================================================= - -static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf32Left = utf32Len; - size_t utf16Left = utf16Len; - - const size_t k32to16Offset = swap32to16Offset; // ! Make sure compiler treats as an invariant. - - UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) ); - - while ( (utf32Left > 0) && (utf16Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit inUnit = UTF32InSwap(utf32Pos); - if ( inUnit > 0xFFFF ) break; - *utf16Pos = *(((UTF16Unit*)utf32Pos) + k32to16Offset); // Better than: UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) ); - ++utf32Pos; - ++utf16Pos; - } - utf32Left -= i; - utf16Left -= i; - - // Do a run of non-BMP, it copies 1 input unit into 2 output units. - while ( (utf32Left > 0) && (utf16Left > 0) ) { - size_t len; - UTF32Unit inUnit = UTF32InSwap(utf32Pos); - if ( inUnit <= 0xFFFF ) break; - CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - UC_Assert ( len == 2 ); - utf32Left -= 1; - utf32Pos += 1; - utf16Left -= 2; - utf16Pos += 2; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF32Swp_to_UTF16Swp - -// ================================================================================================= - -static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf16Left = utf16Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) ); - - while ( (utf16Left > 0) && (utf32Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = *utf16Pos; - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - UTF32OutSwap ( utf32Pos, inUnit ); - ++utf16Pos; - ++utf32Pos; - } - utf16Left -= i; - utf32Left -= i; - - // Do a run of surrogate pairs, it copies 2 input units into 1 output unit. - while ( (utf16Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF32Unit cp; - UTF16Unit inUnit = *utf16Pos; - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UC_Assert ( len == 2 ); - UTF32OutSwap ( utf32Pos, cp ); - utf16Left -= len; - utf16Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF16Nat_to_UTF32Swp - -// ================================================================================================= - -static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ) -{ - const UTF16Unit * utf16Pos = utf16In; - UTF32Unit * utf32Pos = utf32Out; - - size_t utf16Left = utf16Len; - size_t utf32Left = utf32Len; - - UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) ); - - while ( (utf16Left > 0) && (utf32Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf16Left; - if ( limit > utf32Left ) limit = utf32Left; - for ( i = 0; i < limit; ++i ) { - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break; - *utf32Pos = inUnit; - ++utf16Pos; - ++utf32Pos; - } - utf16Left -= i; - utf32Left -= i; - - // Do a run of surrogate pairs, it copies 2 input units into 1 output unit. - while ( (utf16Left > 0) && (utf32Left > 0) ) { - size_t len; - UTF16Unit inUnit = UTF16InSwap(utf16Pos); - if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break; - CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len ); - if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair. - UC_Assert ( len == 2 ); - utf16Left -= len; - utf16Pos += len; - utf32Left -= 1; - utf32Pos += 1; - } - - } - -Done: // Set the output lengths. - *utf16Read = utf16Len - utf16Left; - *utf32Written = utf32Len - utf32Left; - -} // UTF16Swp_to_UTF32Nat - -// ================================================================================================= - -static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf32Left = utf32Len; - size_t utf16Left = utf16Len; - - UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) ); - - while ( (utf32Left > 0) && (utf16Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit inUnit = *utf32Pos; - if ( inUnit > 0xFFFF ) break; - UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) ); - ++utf32Pos; - ++utf16Pos; - } - utf32Left -= i; - utf16Left -= i; - - // Do a run of non-BMP, it copies 1 input unit into 2 output units. - while ( (utf32Left > 0) && (utf16Left > 0) ) { - size_t len; - UTF32Unit inUnit = *utf32Pos; - if ( inUnit <= 0xFFFF ) break; - CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - UC_Assert ( len == 2 ); - utf32Left -= 1; - utf32Pos += 1; - utf16Left -= 2; - utf16Pos += 2; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF32Nat_to_UTF16Swp - -// ================================================================================================= - -static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ) -{ - const UTF32Unit * utf32Pos = utf32In; - UTF16Unit * utf16Pos = utf16Out; - - size_t utf32Left = utf32Len; - size_t utf16Left = utf16Len; - - UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) ); - - while ( (utf32Left > 0) && (utf16Left > 0) ) { - - // Do a run of BMP, it copies 1 input unit into 1 output unit. - size_t i, limit = utf32Left; - if ( limit > utf16Left ) limit = utf16Left; - for ( i = 0; i < limit; ++i ) { - UTF32Unit inUnit = UTF32InSwap(utf32Pos); - if ( inUnit > 0xFFFF ) break; - *utf16Pos = UTF16Unit(inUnit); - ++utf32Pos; - ++utf16Pos; - } - utf32Left -= i; - utf16Left -= i; - - // Do a run of non-BMP, it copies 1 input unit into 2 output units. - while ( (utf32Left > 0) && (utf16Left > 0) ) { - size_t len; - UTF32Unit inUnit = UTF32InSwap(utf32Pos); - if ( inUnit <= 0xFFFF ) break; - CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len ); - if ( len == 0 ) goto Done; // Not enough room in the output buffer. - UC_Assert ( len == 2 ); - utf32Left -= 1; - utf32Pos += 1; - utf16Left -= 2; - utf16Pos += 2; - } - - } - -Done: // Set the output lengths. - *utf32Read = utf32Len - utf32Left; - *utf16Written = utf16Len - utf16Left; - -} // UTF32Swp_to_UTF16Nat - -// ================================================================================================= diff --git a/xmpsdk/src/UnicodeConversions.hpp b/xmpsdk/src/UnicodeConversions.hpp deleted file mode 100644 index 08883000bc..0000000000 --- a/xmpsdk/src/UnicodeConversions.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef __UnicodeConversions_h__ -#define __UnicodeConversions_h__ - -// ================================================================================================= -// Copyright 2004-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include - -// ================================================================================================= - -#if UnicodeTestBuild - typedef unsigned char UTF8Unit; - typedef unsigned short UTF16Unit; - typedef unsigned long UTF32Unit; -#else - typedef XMP_Uns8 UTF8Unit; - typedef XMP_Uns16 UTF16Unit; - typedef XMP_Uns32 UTF32Unit; -#endif - -// ------------------------------------------------------------------------------------------------- - -// ! The UTF16 and UTF32 counts are in storage units, not bytes! CodePoint values are always native. - -// *** MIght be better to return a status than throw an exception for errors? - -typedef void (*CodePoint_to_UTF16_Proc) ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written ); - -typedef void (*CodePoint_from_UTF16_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read ); - -typedef void (*UTF8_to_UTF16_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf8Read, size_t * utf16Written ); - -typedef void (*UTF8_to_UTF32_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf8Read, size_t * utf32Written ); - -typedef void (*UTF16_to_UTF8_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf16Read, size_t * utf8Written ); - -typedef void (*UTF32_to_UTF8_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF8Unit * utf8Out, const size_t utf8Len, - size_t * utf32Read, size_t * utf8Written ); - -typedef void (*UTF16_to_UTF32_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len, - UTF32Unit * utf32Out, const size_t utf32Len, - size_t * utf16Read, size_t * utf32Written ); - -typedef void (*UTF32_to_UTF16_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len, - UTF16Unit * utf16Out, const size_t utf16Len, - size_t * utf32Read, size_t * utf16Written ); - -// ------------------------------------------------------------------------------------------------- - -extern void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written ); - -extern void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read ); - -extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE; -extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE; - -extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE; -extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE; - -extern UTF8_to_UTF16_Proc UTF8_to_UTF16BE; -extern UTF8_to_UTF16_Proc UTF8_to_UTF16LE; - -extern UTF8_to_UTF32_Proc UTF8_to_UTF32BE; -extern UTF8_to_UTF32_Proc UTF8_to_UTF32LE; - -extern UTF16_to_UTF8_Proc UTF16BE_to_UTF8; -extern UTF16_to_UTF8_Proc UTF16LE_to_UTF8; - -extern UTF32_to_UTF8_Proc UTF32BE_to_UTF8; -extern UTF32_to_UTF8_Proc UTF32LE_to_UTF8; - -extern UTF8_to_UTF16_Proc UTF8_to_UTF16Native; -extern UTF8_to_UTF32_Proc UTF8_to_UTF32Native; - -extern UTF16_to_UTF8_Proc UTF16Native_to_UTF8; -extern UTF32_to_UTF8_Proc UTF32Native_to_UTF8; - -extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE; -extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE; - -extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE; -extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE; - -extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE; -extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE; - -extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE; -extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE; - -extern void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len ); -extern void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len ); - -extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian ); -extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian ); - -extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian ); -extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian ); - -extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str ); -extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str ); - -extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str ); -extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str ); - -extern void InitializeUnicodeConversions(); - -// ================================================================================================= - -#endif // __UnicodeConversions_h__ diff --git a/xmpsdk/src/UnicodeInlines.incl_cpp b/xmpsdk/src/UnicodeInlines.incl_cpp deleted file mode 100644 index 8d55bad319..0000000000 --- a/xmpsdk/src/UnicodeInlines.incl_cpp +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef __UnicodeInlines_incl_cpp__ -#define __UnicodeInlines_incl_cpp__ - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "UnicodeConversions.hpp" - -// ================================================================================================= -// Inner loop utilities that need to be inlined. -// ================================================================================================= - -static inline XMP_Uns32 GetCodePoint ( const XMP_Uns8 ** utf8Str_io ) -{ - const XMP_Uns8 * u8Ptr = *utf8Str_io; - XMP_Uns32 cp; - size_t u8Len; - CodePoint_from_UTF8 ( u8Ptr, 4, &cp, &u8Len ); // Throws an exception for errors. - *utf8Str_io = u8Ptr + u8Len; - return cp; -} - -// ================================================================================================= - -static inline bool IsStartChar_ASCII ( XMP_Uns32 cp ) -{ - // ASCII starting characters for an XML name. - if ( (('a' <= cp) && (cp <= 'z')) || (('A' <= cp) && (cp <= 'Z')) || (cp == '_') ) return true; - return false; -} - -// ------------------------------------------------------------------------------------------------- - -static inline bool IsStartChar_NonASCII ( XMP_Uns32 cp ) -{ - // Non-ASCII starting characters for an XML name. - - if ( ((0xC0 <= cp) && (cp <= 0xD6)) || ((0xD8 <= cp) && (cp <= 0xF6)) ) return true; - if ( ((0xF8 <= cp) && (cp <= 0x2FF)) || ((0x370 <= cp) && (cp <= 0x37D)) ) return true; - - if ( ((0x37F <= cp) && (cp <= 0x1FFF)) || ((0x200C <= cp) && (cp <= 0x200D)) ) return true; - if ( ((0x2070 <= cp) && (cp <= 0x218F)) || ((0x2C00 <= cp) && (cp <= 0x2FEF)) ) return true; - if ( ((0x3001 <= cp) && (cp <= 0xD7FF)) || ((0xF900 <= cp) && (cp <= 0xFDCF)) ) return true; - if ( ((0xFDF0 <= cp) && (cp <= 0xFFFD)) || ((0x10000 <= cp) && (cp <= 0xEFFFF)) ) return true; - - return false; - -} - -// ------------------------------------------------------------------------------------------------- - -static inline bool IsOtherChar_ASCII ( XMP_Uns32 cp ) -{ - // ASCII following characters for an XML name. - if ( (('0' <= cp) && (cp <= '9')) || (cp == '-') || (cp == '.') ) return true; - return false; -} - -// ------------------------------------------------------------------------------------------------- - -static inline bool IsOtherChar_NonASCII ( XMP_Uns32 cp ) -{ - // Non-ASCII following characters for an XML name. - if ( (cp == 0xB7) || ((0x300 <= cp) && (cp <= 0x36F)) || ((0x203F <= cp) && (cp <= 0x2040)) ) return true; - return false; -} - -// ------------------------------------------------------------------------------------------------- - -static inline void VerifyUTF8 ( XMP_StringPtr str ) -{ - const XMP_Uns8 * utf8Str = (XMP_Uns8*)str; - while ( *utf8Str != 0 ) { - while ( (*utf8Str != 0) && (*utf8Str < 0x80) ) ++utf8Str; - if ( *utf8Str >= 0x80 ) (void) GetCodePoint ( &utf8Str ); // Throws for bad UTF-8. - } -} - -// ------------------------------------------------------------------------------------------------- - -static inline void VerifySimpleXMLName ( XMP_StringPtr _nameStart, XMP_StringPtr _nameEnd ) -{ - - const XMP_Uns8 * nameStart = (const XMP_Uns8 *) _nameStart; - const XMP_Uns8 * nameEnd = (const XMP_Uns8 *) _nameEnd; - const XMP_Uns8 * namePos = nameStart; - XMP_Uns32 cp; - - // The first character is more restricted. - - if ( nameStart >= nameEnd ) XMP_Throw ( "Empty XML name", kXMPErr_BadXPath ); - - cp = *namePos; - if ( cp < 0x80 ) { - ++namePos; - if ( ! IsStartChar_ASCII(cp) ) goto NameError; - } else { - cp = GetCodePoint ( &namePos ); - if ( ! IsStartChar_NonASCII(cp) ) goto NameError; - } - - // Check the rest of the name. - - while ( namePos < nameEnd ) { - cp = *namePos; - if ( cp < 0x80 ) { - ++namePos; - if ( (! IsStartChar_ASCII(cp)) && (! IsOtherChar_ASCII(cp)) ) goto NameError; - } else { - cp = GetCodePoint ( &namePos ); - if ( (! IsStartChar_NonASCII(cp)) && (! IsOtherChar_NonASCII(cp)) ) goto NameError; - } - } - - return; - -NameError: - XMP_Throw ( "Bad XML name", kXMPErr_BadXPath ); - -} // VerifySimpleXMLName - -// ================================================================================================= - -#endif // __UnicodeInlines_incl_cpp__ diff --git a/xmpsdk/src/WXMPIterator.cpp b/xmpsdk/src/WXMPIterator.cpp deleted file mode 100644 index 4c47b0d31e..0000000000 --- a/xmpsdk/src/WXMPIterator.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPIterator.hpp" -#include "client-glue/WXMPIterator.hpp" - -#if XMP_WinBuild -# ifdef _MSC_VER - #pragma warning ( disable : 4101 ) // unreferenced local variable - #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #if XMP_DebugBuild - #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does -# endif -# endif -#endif - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -// CTor/DTor Wrappers -// ================== - -void -WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPIterator_PropCTor_1" ) - - if ( schemaNS == 0 ) schemaNS = ""; - if ( propName == 0 ) propName = ""; - - const XMPMeta & xmpObj = WtoXMPMeta_Ref ( xmpRef ); - XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options ); - ++iter->clientRefs; - XMP_Assert ( iter->clientRefs == 1 ); - wResult->ptrResult = XMPIteratorRef ( iter ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPIterator_TableCTor_1" ) - - if ( schemaNS == 0 ) schemaNS = ""; - if ( propName == 0 ) propName = ""; - - XMPIterator * iter = new XMPIterator ( schemaNS, propName, options ); - ++iter->clientRefs; - XMP_Assert ( iter->clientRefs == 1 ); - wResult->ptrResult = XMPIteratorRef ( iter ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPIterator_IncrementRefCount_1" ) - - XMPIterator * thiz = (XMPIterator*)iterRef; - - ++thiz->clientRefs; - XMP_Assert ( thiz->clientRefs > 1 ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPIterator_DecrementRefCount_1" ) - - XMPIterator * thiz = (XMPIterator*)iterRef; - - XMP_Assert ( thiz->clientRefs > 0 ); - --thiz->clientRefs; - if ( thiz->clientRefs <= 0 ) delete ( thiz ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPIterator_Unlock_1" ) - - XMPIterator::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= -// Class Method Wrappers -// ===================== - -void -WXMPIterator_Next_1 ( XMPIteratorRef iterRef, - XMP_StringPtr * schemaNS, - XMP_StringLen * nsSize, - XMP_StringPtr * propPath, - XMP_StringLen * pathSize, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * propOptions, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPIterator_Next_1" ) - - if ( schemaNS == 0 ) schemaNS = &voidStringPtr; - if ( nsSize == 0 ) nsSize = &voidStringLen; - if ( propPath == 0 ) propPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - if ( propValue == 0 ) propValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( propOptions == 0 ) propOptions = &voidOptionBits; - - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - XMP_Bool found = iter->Next ( schemaNS, nsSize, propPath, pathSize, propValue, valueSize, propOptions ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_Skip_1 ( XMPIteratorRef iterRef, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPIterator_Skip_1" ) - - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - iter->Skip ( options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef, - XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_UnlockIter_1" ) - - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - iter->UnlockIter ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif diff --git a/xmpsdk/src/WXMPMeta.cpp b/xmpsdk/src/WXMPMeta.cpp deleted file mode 100644 index 7969233885..0000000000 --- a/xmpsdk/src/WXMPMeta.cpp +++ /dev/null @@ -1,1310 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPMeta.hpp" -#include "client-glue/WXMPMeta.hpp" - -#if XMP_WinBuild - #ifdef _MSC_VER - #pragma warning ( disable : 4101 ) // unreferenced local variable - #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #if XMP_DebugBuild - #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does - #endif - #endif -#endif - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -// Init/Term Wrappers -// ================== - -/* class static */ void -WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_GetVersionInfo_1" ) - - XMPMeta::GetVersionInfo ( info ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_Initialize_1 ( WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Initialize_1" ) - - bool ok = XMPMeta::Initialize(); - wResult->int32Result = ok; - - XMP_EXIT_WRAPPER -} -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_Terminate_1() -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Terminate_1" ) - - XMPMeta::Terminate(); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= -// CTor/DTor Wrappers -// ================== - -void -WXMPMeta_CTor_1 ( WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_CTor_1" ) - - XMPMeta * xmpObj = new XMPMeta(); - ++xmpObj->clientRefs; - XMP_Assert ( xmpObj->clientRefs == 1 ); - wResult->ptrResult = XMPMetaRef ( xmpObj ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPMeta_IncrementRefCount_1" ) - - XMPMeta * thiz = (XMPMeta*)xmpRef; - - ++thiz->clientRefs; - XMP_Assert ( thiz->clientRefs > 0 ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPMeta_DecrementRefCount_1" ) - - XMPMeta * thiz = (XMPMeta*)xmpRef; - - XMP_Assert ( thiz->clientRefs > 0 ); - --thiz->clientRefs; - if ( thiz->clientRefs <= 0 ) delete ( thiz ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= -// Class Static Wrappers -// ===================== -// -// These are DLL-entry wrappers for class-static functions. They all follow a simple pattern: -// -// try -// acquire toolbox lock -// validate parameters -// call through to the implementation -// retain toolbox lock if necessary -// catch anything and return an appropriate XMP_Error object -// return null (no error if we get to here) -// -// The toolbox lock is acquired through a local wrapper object that automatically unlocks when the -// try-block is exited. The lock must be retained if the function is returning a string result. The -// output string is owned by the toolkit, the client must copy the string then release the lock. -// The lock used here is the overall toolkit lock. For simplicity at this time the lock is a simple -// mutual exclusion lock, we do not allow multiple concurrent readers. -// -// The one exception to this model is UnlockToolkit. It does not acquire the toolkit lock since this -// is the function the client calls to release the lock after copying an output string! -// -// ================================================================================================= - -/* class static */ void -WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetGlobalOptions_1" ) - - XMP_OptionBits options = XMPMeta::GetGlobalOptions(); - wResult->int32Result = options; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetGlobalOptions_1" ) - - XMPMeta::SetGlobalOptions ( options ); - - XMP_EXIT_WRAPPER -} -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpNamespaces_1" ) - - if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); - - XMP_Status status = XMPMeta::DumpNamespaces ( outProc, refCon ); - wResult->int32Result = status; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpAliases_1" ) - - if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); - - XMP_Status status = XMPMeta::DumpAliases ( outProc, refCon ); - wResult->int32Result = status; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Unlock_1" ) - - XMPMeta::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterNamespace_1" ) - - if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); - if ( (prefix == 0) || (*prefix == 0) ) XMP_Throw ( "Empty prefix", kXMPErr_BadSchema ); - - XMPMeta::RegisterNamespace ( namespaceURI, prefix ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr * namespacePrefix, - XMP_StringLen * prefixSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespacePrefix_1" ) - - if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); - - if ( namespacePrefix == 0 ) namespacePrefix = &voidStringPtr; - if ( prefixSize == 0 ) prefixSize = &voidStringLen; - - bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, namespacePrefix, prefixSize ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix, - XMP_StringPtr * namespaceURI, - XMP_StringLen * uriSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespaceURI_1" ) - - if ( (namespacePrefix == 0) || (*namespacePrefix == 0) ) XMP_Throw ( "Empty namespace prefix", kXMPErr_BadSchema ); - - if ( namespaceURI == 0 ) namespaceURI = &voidStringPtr; - if ( uriSize == 0 ) uriSize = &voidStringLen; - - bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, namespaceURI, uriSize ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteNamespace_1" ) - - if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); - - XMPMeta::DeleteNamespace ( namespaceURI ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - if ( (actualNS == 0) || (*actualNS == 0) ) XMP_Throw ( "Empty actual namespace URI", kXMPErr_BadSchema ); - if ( (actualProp == 0) || (*actualProp == 0) ) XMP_Throw ( "Empty actual property name", kXMPErr_BadXPath ); - - XMPMeta::RegisterAlias ( aliasNS, aliasProp, actualNS, actualProp, arrayForm ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_ResolveAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - - if ( actualNS == 0 ) actualNS = &voidStringPtr; - if ( nsSize == 0 ) nsSize = &voidStringLen; - if ( actualProp == 0 ) actualProp = &voidStringPtr; - if ( propSize == 0 ) propSize = &voidStringLen; - if ( arrayForm == 0 ) arrayForm = &voidOptionBits; - - bool found = XMPMeta::ResolveAlias ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - - XMPMeta::DeleteAlias ( aliasNS, aliasProp ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterStandardAliases_1" ) - - if ( schemaNS == 0 ) schemaNS = ""; - - XMPMeta::RegisterStandardAliases ( schemaNS ); - - XMP_EXIT_WRAPPER -} - -// ================================================================================================= -// Class Method Wrappers -// ===================== -// -// These are DLL-entry wrappers for the methods. They all follow a simple pattern: -// -// validate parameters -// try -// acquire object lock -// call through to the implementation -// retain object lock if necessary -// catch anything and return an appropriate XMP_Error object -// return null (no error if we get to here) -// -// The object lock is acquired through a local wrapper object that automatically unlocks when the -// try-block is exited. The lock must be retained if the function is returning a string result. The -// output string is owned by the object, the client must copy the string then release the lock. The -// lock used here is the per-object lock. For simplicity at this time the lock is a simple mutual -// exclusion lock, we do not allow multiple concurrent readers. -// -// The one exception to this model is UnlockObject. It does not acquire the object lock since this -// is the function the client calls to release the lock after copying an output string! -// -// ================================================================================================= - -void -WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty ( schemaNS, propName, propValue, valueSize, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetArrayItem_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - if ( itemValue == 0 ) itemValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, valueSize, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fieldValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetStructField_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - if ( fieldValue == 0 ) fieldValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetQualifier_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); - if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - if ( qualValue == 0 ) qualValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, valueSize, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetArrayItem_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_AppendArrayItem_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetStructField_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetQualifier_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); - if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteProperty_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteProperty ( schemaNS, propName ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteArrayItem_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteArrayItem ( schemaNS, arrayName, itemIndex ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteStructField_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteStructField ( schemaNS, structName, fieldNS, fieldName ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteQualifier_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); - if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteQualifier ( schemaNS, propName, qualNS, qualName ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesPropertyExist_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesPropertyExist ( schemaNS, propName ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesArrayItemExist_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesArrayItemExist ( schemaNS, arrayName, itemIndex ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesStructFieldExist_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesQualifierExist_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); - if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesQualifierExist ( schemaNS, propName, qualNS, qualName ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr * actualLang, - XMP_StringLen * langSize, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetLocalizedText_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( genericLang == 0 ) genericLang = ""; - if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam ); - - if ( actualLang == 0 ) actualLang = &voidStringPtr; - if ( langSize == 0 ) langSize = &voidStringLen; - if ( itemValue == 0 ) itemValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, - actualLang, langSize, itemValue, valueSize, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetLocalizedText_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( genericLang == 0 ) genericLang = ""; - if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam ); - if ( itemValue == 0 ) itemValue = ""; - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Bool * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Bool_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidByte; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool value; - bool found = meta.GetProperty_Bool ( schemaNS, propName, &value, options ); - if ( propValue != 0 ) *propValue = value; - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidInt32; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Int ( schemaNS, propName, propValue, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int64_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidInt64; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Int64 ( schemaNS, propName, propValue, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Float_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidDouble; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Float ( schemaNS, propName, propValue, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Date_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - if ( propValue == 0 ) propValue = &voidDateTime; - if ( options == 0 ) options = &voidOptionBits; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Date ( schemaNS, propName, propValue, options ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Bool propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Bool_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Bool ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Int ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int64_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Int64 ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Float_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Float ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Date_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Date ( schemaNS, propName, propValue, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef, - XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpObject_1" ) - - if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_Status status = meta.DumpObject ( outProc, refCon ); - wResult->int32Result = status; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_Sort_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_Sort_1" ) - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->Sort(); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_Erase_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_Erase_1" ) - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->Erase(); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_Clone_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_Clone_1" ) - - const XMPMeta & xOriginal = WtoXMPMeta_Ref ( xmpRef ); - XMPMeta * xClone = new XMPMeta; - xOriginal.Clone ( xClone, options ); - XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone. - wResult->ptrResult = xClone; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_CountArrayItems_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_Index count = meta.CountArrayItems ( schemaNS, arrayName ); - wResult->int32Result = count; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options ) /* const */ -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_UnlockObject_1" ) - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.UnlockObject ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * namePtr, - XMP_StringLen * nameLen, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectName_1" ) - - if ( namePtr == 0 ) namePtr = &voidStringPtr; - if ( nameLen == 0 ) nameLen = &voidStringLen; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.GetObjectName ( namePtr, nameLen ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned! -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef, - XMP_StringPtr name, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectName_1" ) - - if ( name == 0 ) name = ""; - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetObjectName ( name ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectOptions_1" ) - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_OptionBits options = meta.GetObjectOptions(); - wResult->int32Result = options; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectOptions_1" ) - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetObjectOptions ( options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef, - XMP_StringPtr buffer, - XMP_StringLen bufferSize, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_ParseFromBuffer_1" ) - - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->ParseFromBuffer ( buffer, bufferSize, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent, - XMP_Index baseIndent, - WXMP_Result * wResult ) /* const */ -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_SerializeToBuffer_1" ) - - if ( rdfString == 0 ) rdfString = &voidStringPtr; - if ( rdfSize == 0 ) rdfSize = &voidStringLen; - - if ( newline == 0 ) newline = ""; - if ( indent == 0 ) indent = ""; - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.SerializeToBuffer ( rdfString, rdfSize, options, padding, newline, indent, baseIndent ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned! -} - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif diff --git a/xmpsdk/src/WXMPUtils.cpp b/xmpsdk/src/WXMPUtils.cpp deleted file mode 100644 index e3ce4375ba..0000000000 --- a/xmpsdk/src/WXMPUtils.cpp +++ /dev/null @@ -1,626 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -// *** Should change "type * inParam" to "type & inParam" - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPUtils.hpp" -#include "client-glue/WXMPUtils.hpp" - -#if XMP_WinBuild - #ifdef _MSC_VER - #pragma warning ( disable : 4101 ) // unreferenced local variable - #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #if XMP_DebugBuild - #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does - #endif - #endif -#endif - -#if __cplusplus -extern "C" { -#endif - -// ================================================================================================= -// Class Static Wrappers -// ===================== - -void -WXMPUtils_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_Unlock_1" ) - - XMPUtils::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= - -void -WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeArrayItemPath_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, fullPath, pathSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeStructFieldPath_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeQualifierPath_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); - if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, fullPath, pathSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeLangSelector_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( (langName == 0) || (*langName == 0) ) XMP_Throw ( "Empty language name", kXMPErr_BadParam ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - - XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, fullPath, pathSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeFieldSelector_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); - if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - if ( fieldValue == 0 ) fieldValue = ""; - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - - XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ================================================================================================= - -void -WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromBool_1" ) - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - - XMPUtils::ConvertFromBool ( binValue, strValue, strSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt_1" ) - - if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - - XMPUtils::ConvertFromInt ( binValue, format, strValue, strSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt64_1" ) - - if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - - XMPUtils::ConvertFromInt64 ( binValue, format, strValue, strSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertFromFloat_1 ( double binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromFloat_1" ) - - if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - - XMPUtils::ConvertFromFloat ( binValue, format, strValue, strSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromDate_1" ) - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - - XMPUtils::ConvertFromDate( binValue, strValue, strSize ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ================================================================================================= - -void -WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToBool_1" ) - - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); - XMP_Bool result = XMPUtils::ConvertToBool ( strValue ); - wResult->int32Result = result; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt_1" ) - - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); - XMP_Int32 result = XMPUtils::ConvertToInt ( strValue ); - wResult->int32Result = result; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt64_1" ) - - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); - XMP_Int64 result = XMPUtils::ConvertToInt64 ( strValue ); - wResult->int64Result = result; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToFloat_1") - - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); - double result = XMPUtils::ConvertToFloat ( strValue ); - wResult->floatResult = result; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue, - XMP_DateTime * binValue, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToDate_1" ) - - if ( binValue == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); // ! Pointer is from the client. - XMPUtils::ConvertToDate ( strValue, binValue ); - - XMP_EXIT_WRAPPER -} - -// ================================================================================================= - -void -WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CurrentDateTime_1" ) - - if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); - XMPUtils::CurrentDateTime ( time ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_SetTimeZone_1" ) - - if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); - XMPUtils::SetTimeZone ( time ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToUTCTime_1" ) - - if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); - XMPUtils::ConvertToUTCTime ( time ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToLocalTime_1" ) - - if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); - XMPUtils::ConvertToLocalTime ( time ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left, - const XMP_DateTime & right, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CompareDateTime_1" ) - - int result = XMPUtils::CompareDateTime ( left, right ); - wResult->int32Result = result; - - XMP_EXIT_WRAPPER -} - -// ================================================================================================= - -void -WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_EncodeToBase64_1" ) - - if ( encodedStr == 0 ) encodedStr = &voidStringPtr; - if ( encodedLen == 0 ) encodedLen = &voidStringLen; - - XMPUtils::EncodeToBase64 ( rawStr, rawLen, encodedStr, encodedLen ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_DecodeFromBase64_1" ) - - if ( rawStr == 0 ) rawStr = &voidStringPtr; - if ( rawLen == 0 ) rawLen = &voidStringLen; - - XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, rawStr, rawLen ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ================================================================================================= - -void -WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_PackageForJPEG_1" ) - - if ( stdStr == 0 ) stdStr = &voidStringPtr; - if ( stdLen == 0 ) stdLen = &voidStringLen; - if ( extStr == 0 ) extStr = &voidStringPtr; - if ( extLen == 0 ) extLen = &voidStringLen; - if ( digestStr == 0 ) digestStr = &voidStringPtr; - if ( digestLen == 0 ) digestLen = &voidStringLen; - - const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj ); - XMPUtils::PackageForJPEG ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef wfullXMP, - XMPMetaRef wextendedXMP, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_MergeFromJPEG_1" ) - - if ( wfullXMP == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - - XMPMeta * fullXMP = WtoXMPMeta_Ptr ( wfullXMP ); - const XMPMeta & extendedXMP = WtoXMPMeta_Ref ( wextendedXMP ); - XMPUtils::MergeFromJPEG ( fullXMP, extendedXMP ); - - XMP_EXIT_WRAPPER -} - -// ================================================================================================= - -void -WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_CatenateArrayItems_1" ) - - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - if ( separator == 0 ) separator = "; "; - if ( quotes == 0 ) quotes = "\""; - - if ( catedStr == 0 ) catedStr = &voidStringPtr; - if ( catedLen == 0 ) catedLen = &voidStringLen; - - const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj ); - XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr, catedLen ); - - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_SeparateArrayItems_1" ) - - if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); - if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( catedStr == 0 ) catedStr = ""; - - XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj ); - XMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_RemoveProperties_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_RemoveProperties_1" ) - - if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - if ( schemaNS == 0 ) schemaNS = ""; - if ( propName == 0 ) propName = ""; - - XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj ); - XMPUtils::RemoveProperties ( xmpObj, schemaNS, propName, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_AppendProperties_1 ( XMPMetaRef wSource, - XMPMetaRef wDest, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_AppendProperties_1" ) - - if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - - const XMPMeta & source = WtoXMPMeta_Ref ( wSource ); - XMPMeta * dest = WtoXMPMeta_Ptr ( wDest ); - XMPUtils::AppendProperties ( source, dest, options ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef wSource, - XMPMetaRef wDest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS, - XMP_StringPtr destRoot, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_DuplicateSubtree_1" ) - - if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - if ( (sourceNS == 0) || (*sourceNS == 0) ) XMP_Throw ( "Empty source schema URI", kXMPErr_BadSchema ); - if ( (sourceRoot == 0) || (*sourceRoot == 0) ) XMP_Throw ( "Empty source root name", kXMPErr_BadXPath ); - if ( destNS == 0 ) destNS = sourceNS; - if ( destRoot == 0 ) destRoot = sourceRoot; - - const XMPMeta & source = WtoXMPMeta_Ref ( wSource ); - XMPMeta * dest = WtoXMPMeta_Ptr ( wDest ); - XMPUtils::DuplicateSubtree ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options ); - - XMP_EXIT_WRAPPER -} - -// ================================================================================================= - -#if __cplusplus -} /* extern "C" */ -#endif diff --git a/xmpsdk/src/XMLParserAdapter.hpp b/xmpsdk/src/XMLParserAdapter.hpp deleted file mode 100644 index 55d53cadbf..0000000000 --- a/xmpsdk/src/XMLParserAdapter.hpp +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef __XMLParserAdapter_hpp__ -#define __XMLParserAdapter_hpp__ - -// ================================================================================================= -// Copyright 2005-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! Must be the first #include! -#include "XMP_Const.h" - -#include -#include - -// ================================================================================================= -// XML_Node details -// -// The XML_Nodes are used only during the XML/RDF parsing process. This presently uses an XML parser -// to create an XML tree, then a recursive descent RDF recognizer to build the corresponding XMP. -// This makes it easier to swap XML parsers and provides a clean separation of XML and RDF issues. -// The overall parsing would be faster and use less memory if the RDF recognition were done on the -// fly using a state machine. But it was much easier to write the recursive descent version. The -// current implementation is pretty fast in absolute terms, so being faster might not be crucial. -// -// Like the XMP tree, the XML tree contains vectors of pointers for down links, and offspring have -// a pointer to their parent. Unlike the XMP tree, this is an exact XML document tree. There are no -// introduced top level namespace nodes or rearrangement of the nodes.. -// -// The exact state of namespaces can vary during the XML parsing, depending on the parser in use. -// By the time the RDF recognition is done though, the namespaces must be normalized. All of the -// used namespaces must be registered, this is done automatically if necessary. All of the "live" -// namespace prefixes will be unique. The ns field of an XML_Node is the namespace URI, the name -// field contains a qualified name (prefix:local). This includes default namespace mapping, the -// URI and prefix will be missing only for elements and attributes in no namespace. - -class XML_Node; - -typedef XML_Node * XML_NodePtr; // Handy for things like: XML_Node * a, b; - b is XML_Node, not XML_Node*! - -enum { kRootNode = 0, kElemNode = 1, kAttrNode = 2, kCDataNode = 3, kPINode = 4 }; - -#define IsWhitespaceChar(ch) ( ((ch) == ' ') || ((ch) == 0x09) || ((ch) == 0x0A) || ((ch) == 0x0D) ) - -typedef std::vector XML_NodeVector; -typedef XML_NodeVector::iterator XML_NodePos; -typedef XML_NodeVector::const_iterator XML_cNodePos; - -#if 0 // Pattern for iterating over the children or attributes: - for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) { - const XML_NodePtr _curr_ = _node_->_offspring_[xxNum]; - } -#endif - -class XML_Node { -public: - - // Intended for lightweight internal use. Clients are expected to use the data directly. - - XMP_Uns8 kind; - std::string ns, name, value; - size_t nsPrefixLen; - XML_NodePtr parent; - XML_NodeVector attrs; - XML_NodeVector content; - - bool IsWhitespaceNode() const; - bool IsLeafContentNode() const; // An empty element or one with a single character data child node. - bool IsEmptyLeafNode() const; - - XMP_StringPtr GetAttrValue ( XMP_StringPtr attrName ) const; - void SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue ); - - XMP_StringPtr GetLeafContentValue() const; - void SetLeafContentValue ( XMP_StringPtr value ); - - size_t CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const; // Number of child elements with this name. - XML_NodePtr GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which = 0 ); - - void Dump ( std::string * buffer ); - void Serialize ( std::string * buffer ); - - void RemoveAttrs(); - void RemoveContent(); - void ClearNode(); - - XML_Node ( XML_NodePtr _parent, XMP_StringPtr _name, XMP_Uns8 _kind ) - : kind(_kind), name(_name), nsPrefixLen(0), parent(_parent) {}; - - XML_Node ( XML_NodePtr _parent, const std::string & _name, XMP_Uns8 _kind ) - : kind(_kind), name(_name), nsPrefixLen(0), parent(_parent) {}; - - virtual ~XML_Node() { RemoveAttrs(); RemoveContent(); }; - -private: - - XML_Node() : kind(0), parent(0) {}; // ! Hidden to make sure parent pointer is always set. - -}; - -// ================================================================================================= -// Abstract base class for XML parser adapters used by the XMP toolkit. - -enum { kXMLPendingInputMax = 16 }; - -class XMLParserAdapter { -public: - - XMLParserAdapter() - : tree(0,"",kRootNode), rootNode(0), rootCount(0), charEncoding(XMP_OptionBits(-1)), pendingCount(0) - { - #if XMP_DebugBuild - parseLog = 0; - #endif - }; - - virtual ~XMLParserAdapter() {}; - - virtual void ParseBuffer ( const void * buffer, size_t length, bool last ) = 0; - - XML_Node tree; - XML_NodeVector parseStack; - XML_NodePtr rootNode; - size_t rootCount; - - XMP_OptionBits charEncoding; - size_t pendingCount; - unsigned char pendingInput[kXMLPendingInputMax]; // Buffered input for character encoding checks. - - #if XMP_DebugBuild - FILE * parseLog; - #endif - -}; - -// ================================================================================================= - -#endif // __XMLParserAdapter_hpp__ diff --git a/xmpsdk/src/XML_Node.cpp b/xmpsdk/src/XML_Node.cpp deleted file mode 100644 index 5f20358ec7..0000000000 --- a/xmpsdk/src/XML_Node.cpp +++ /dev/null @@ -1,463 +0,0 @@ -// ================================================================================================= -// Copyright 2005-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! Must be the first #include! -#include "XMLParserAdapter.hpp" - -#include -#include -#include - -// ! Can't include XMP..._Impl.hpp - used by both Core and Files. -#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0) - -#if XMP_WinBuild -#ifdef _MSC_VER - #define snprintf _snprintf - #pragma warning ( disable : 4996 ) // snprintf is safe -#endif -#endif - -// ================================================================================================= - -#if 0 // Pattern for iterating over the children or attributes: - for ( size_t xxNum = 0, xxLim = _node_->_offspring_->size(); xxNum < xxLim; ++xxNum ) { - const XML_NodePtr _curr_ = _node_->_offspring_[xxNum]; - } -#endif - -// ================================================================================================= -// XML_Node::IsWhitespaceNode -//=========================== - -bool XML_Node::IsWhitespaceNode() const -{ - if ( this->kind != kCDataNode ) return false; - - for ( size_t i = 0; i < this->value.size(); ++i ) { - unsigned char ch = this->value[i]; - if ( IsWhitespaceChar ( ch ) ) continue; - // *** Add checks for other whitespace characters. - return false; // All the checks failed, this isn't whitespace. - } - - return true; - -} // XML_Node::IsWhitespaceNode - -// ================================================================================================= -// XML_Node::IsLeafContentNode -//============================ - -bool XML_Node::IsLeafContentNode() const -{ - if ( this->kind != kElemNode ) return false; - if ( this->content.size() == 0 ) return true; - if ( this->content.size() > 1 ) return false; - if ( this->content[0]->kind != kCDataNode ) return false; - - return true; - -} // XML_Node::IsLeafContentNode - -// ================================================================================================= -// XML_Node::IsEmptyLeafNode -//========================== - -bool XML_Node::IsEmptyLeafNode() const -{ - - if ( (this->kind != kElemNode) || (this->content.size() != 0) ) return false; - return true; - -} // XML_Node::IsEmptyLeafNode - -// ================================================================================================= -// XML_Node::GetAttrValue -//======================= - -XMP_StringPtr XML_Node::GetAttrValue ( XMP_StringPtr attrName ) const -{ - - for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) { - XML_Node * attrPtr = this->attrs[i]; - if ( ! attrPtr->ns.empty() ) continue; // This form of GetAttrValue is for attrs in no namespace. - if ( attrPtr->name == attrName ) return attrPtr->value.c_str(); - } - - return 0; // Not found. - -} // XML_Node::GetAttrValue - -// ================================================================================================= -// XML_Node::SetAttrValue -//======================= - -void XML_Node::SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue ) -{ - - for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) { - XML_Node * attrPtr = this->attrs[i]; - if ( ! attrPtr->ns.empty() ) continue; // This form of SetAttrValue is for attrs in no namespace. - if ( attrPtr->name == attrName ) { - attrPtr->value = attrValue; - return; - } - } - -} // XML_Node::SetAttrValue - -// ================================================================================================= -// XML_Node::GetLeafContentValue -//============================== - -XMP_StringPtr XML_Node::GetLeafContentValue() const -{ - if ( (! this->IsLeafContentNode()) || this->content.empty() ) return ""; - - return this->content[0]->value.c_str(); - -} // XML_Node::GetLeafContentValue - -// ================================================================================================= -// XML_Node::SetLeafContentValue -//============================== - -void XML_Node::SetLeafContentValue ( XMP_StringPtr newValue ) -{ - XML_Node * valueNode; - - if ( ! this->content.empty() ) { - valueNode = this->content[0]; - } else { - valueNode = new XML_Node ( this, "", kCDataNode ); - this->content.push_back ( valueNode ); - } - - valueNode->value = newValue; - -} // XML_Node::SetLeafContentValue - -// ================================================================================================= -// XML_Node::CountNamedElements -//============================= - -size_t XML_Node::CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const -{ - size_t count = 0; - - for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) { - const XML_Node & child = *this->content[i]; - if ( child.ns != nsURI ) continue; - if ( strcmp ( localName, child.name.c_str()+child.nsPrefixLen ) != 0 ) continue; - ++count; - } - - return count; - -} // XML_Node::CountNamedElements - -// ================================================================================================= -// XML_Node::GetNamedElement -//========================== - -XML_NodePtr XML_Node::GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which /* = 0 */ ) -{ - - for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) { - XML_Node * childPtr = this->content[i]; - if ( childPtr->ns != nsURI ) continue; - if ( strcmp ( localName, childPtr->name.c_str()+childPtr->nsPrefixLen ) != 0 ) continue; - if ( which == 0 ) return childPtr; - --which; - } - - return 0; /// Not found. - -} // XML_Node::GetNamedElement - -// ================================================================================================= -// DumpNodeList -// ============ - -static const char * kNodeKinds[] = { "root", "elem", "attr", "cdata", "pi" }; - -static void DumpNodeList ( std::string * buffer, const XML_NodeVector & list, int indent ) -{ - - for ( size_t i = 0, limit = list.size(); i < limit; ++i ) { - - const XML_Node * node = list[i]; - - for ( int t = indent; t > 0; --t ) *buffer += " "; - if ( node->IsWhitespaceNode() ) { - *buffer += "-- whitespace --\n"; - continue; - } - - *buffer += node->name; - *buffer += " - "; - *buffer += kNodeKinds[node->kind]; - if ( ! node->value.empty() ) { - *buffer += ", value=\""; - *buffer += node->value; - *buffer += "\""; - } - if ( ! node->ns.empty() ) { - *buffer += ", ns=\""; - *buffer += node->ns; - *buffer += "\""; - } - if ( node->nsPrefixLen != 0 ) { - *buffer += ", prefixLen="; - char numBuf [20]; - snprintf ( numBuf, sizeof(numBuf), "%lu", (unsigned long)node->nsPrefixLen ); - *buffer += numBuf; - } - *buffer += "\n"; - - if ( ! node->attrs.empty() ) { - for ( int t = indent+1; t > 0; --t ) *buffer += " "; - *buffer += "attrs:\n"; - DumpNodeList ( buffer, node->attrs, indent+2 ); - } - - if ( ! node->content.empty() ) { - DumpNodeList ( buffer, node->content, indent+1 ); - } - - } - -} // DumpNodeList - -// ================================================================================================= -// XML_Node::Dump -//=============== - -void XML_Node::Dump ( std::string * buffer ) -{ - - *buffer = "Dump of XML_Node tree\n"; - - *buffer += "Root info: name=\""; - *buffer += this->name; - *buffer += "\", value=\""; - *buffer += this->value; - *buffer += "\", ns=\""; - *buffer += this->ns; - *buffer += "\", kind="; - *buffer += kNodeKinds[this->kind]; - *buffer += "\n"; - - if ( ! this->attrs.empty() ) { - *buffer += " attrs:\n"; - DumpNodeList ( buffer, this->attrs, 2 ); - } - *buffer += "\n"; - - DumpNodeList ( buffer, this->content, 0 ); - -} // XML_Node::Dump - -// ================================================================================================= -// SerializeOneNode -// ================ - -static void SerializeOneNode ( std::string * buffer, const XML_Node & node ) -{ - size_t i, limit; - XMP_StringPtr namePtr = node.name.c_str(); - if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces. - - switch ( node.kind ) { - - case kElemNode: - *buffer += '<'; - *buffer += namePtr; - for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) { - SerializeOneNode ( buffer, *node.attrs[i] ); - } - if ( node.content.empty() ) { - *buffer += "/>"; - } else { - *buffer += '>'; - for ( i = 0, limit = node.content.size(); i < limit; ++i ) { - SerializeOneNode ( buffer, *node.content[i] ); - } - *buffer += "'; - } - break; - - case kAttrNode: - *buffer += ' '; - *buffer += namePtr; - *buffer += "=\""; - *buffer += node.value; - *buffer += '"'; - break; - - case kCDataNode: - *buffer += node.value; - break; - - case kPINode: - *buffer += node.value; // *** Note that we're dropping PIs during the Expat parse. - break; - - } - -} // SerializeOneNode - -// ================================================================================================= -// CollectNamespaceDecls -// ===================== - -typedef std::map < std::string, std::string > NamespaceMap; - -static void CollectNamespaceDecls ( NamespaceMap * nsMap, const XML_Node & node ) -{ - size_t i, limit; - - if ( ! node.ns.empty() ) { - size_t nameMid = 0; - while ( node.name[nameMid] != ':' ) ++nameMid; - std::string prefix = node.name.substr ( 0, nameMid ); - (*nsMap)[prefix] = node.ns; - } - - if ( node.kind == kElemNode ) { - - for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) { - CollectNamespaceDecls ( nsMap, *node.attrs[i] ); - } - - for ( i = 0, limit = node.content.size(); i < limit; ++i ) { - const XML_Node & content = *node.content[i]; - if ( content.kind == kElemNode ) CollectNamespaceDecls ( nsMap, content ); - } - - } - -} // CollectNamespaceDecls - -// ================================================================================================= -// XML_Node::Serialize -//==================== - -void XML_Node::Serialize ( std::string * buffer ) -{ - buffer->erase(); - - if ( this->kind != kRootNode ) { - - SerializeOneNode ( buffer, *this ); - - } else { - - // Do the outermost level here, in order to add the XML version and namespace declarations. - - *buffer += "\n"; - - for ( size_t outer = 0, oLimit = this->content.size(); outer < oLimit; ++outer ) { - - const XML_Node & node = *this->content[outer]; - - if ( node.kind != kElemNode ) { - - SerializeOneNode ( buffer, node ); - - } else { - - XMP_StringPtr namePtr = node.name.c_str(); - if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces. - - *buffer += '<'; - *buffer += namePtr; - - NamespaceMap nsMap; - CollectNamespaceDecls ( &nsMap, node ); - NamespaceMap::iterator nsDecl = nsMap.begin(); - NamespaceMap::iterator nsEnd = nsMap.end(); - for ( ; nsDecl != nsEnd; ++nsDecl ) { - const std::string & prefix = nsDecl->first; - *buffer += " xmlns"; - if ( prefix != "_dflt_" ) { *buffer += ':'; *buffer += prefix; } - *buffer += "=\""; - *buffer += nsDecl->second; - *buffer += '"'; - } - - for ( size_t attr = 0, aLimit = node.attrs.size(); attr < aLimit; ++attr ) { - SerializeOneNode ( buffer, *node.attrs[attr] ); - } - - if ( node.content.empty() ) { - *buffer += "/>"; - } else { - *buffer += '>'; - for ( size_t child = 0, cLimit = node.content.size(); child < cLimit; ++child ) { - SerializeOneNode ( buffer, *node.content[child] ); - } - *buffer += "'; - } - - } - - } - - } - - -} // XML_Node::Serialize - -// ================================================================================================= -// XML_Node::RemoveAttrs -//====================== - -void XML_Node::RemoveAttrs() -{ - - for ( size_t i = 0, vLim = this->attrs.size(); i < vLim; ++i ) delete this->attrs[i]; - this->attrs.clear(); - -} // XML_Node::RemoveAttrs - -// ================================================================================================= -// XML_Node::RemoveContent -//======================== - -void XML_Node::RemoveContent() -{ - - for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) delete this->content[i]; - this->content.clear(); - -} // XML_Node::RemoveContent - -// ================================================================================================= -// XML_Node::ClearNode -//==================== - -void XML_Node::ClearNode() -{ - - this->kind = 0; - this->ns.erase(); - this->name.erase(); - this->value.erase(); - - this->RemoveAttrs(); - this->RemoveContent(); - -} // XML_Node::ClearNode - -// ================================================================================================= diff --git a/xmpsdk/src/XMPCore_Impl.cpp b/xmpsdk/src/XMPCore_Impl.cpp deleted file mode 100644 index b810bfe929..0000000000 --- a/xmpsdk/src/XMPCore_Impl.cpp +++ /dev/null @@ -1,1468 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMP_Version.h" -#include "XMPCore_Impl.hpp" -#include "XMPMeta.hpp" // *** For use of GetNamespacePrefix in FindSchemaNode. - -#include "UnicodeInlines.incl_cpp" - -#include - -using namespace std; - -#if XMP_WinBuild - #ifdef _MSC_VER - #pragma warning ( disable : 4290 ) // C++ exception specification ignored except ... not __declspec(nothrow) - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #endif -#endif - -// *** Add debug codegen checks, e.g. that typical masking operations really work -// *** Make option constants 0x...UL. - -// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, or XMP_UNIXBuild. -// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor -// practice of defining the *_ENV macro with an empty value. -#if defined ( MAC_ENV ) - #if ! MAC_ENV - #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true" - #endif -#elif defined ( WIN_ENV ) - #if ! WIN_ENV - #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true" - #endif -#elif defined ( UNIX_ENV ) - #if ! UNIX_ENV - #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true" - #endif -#endif - -// ================================================================================================= -// Static Variables -// ================ - -XMP_Int32 sXMP_InitCount = 0; - -XMP_StringMap * sNamespaceURIToPrefixMap = 0; -XMP_StringMap * sNamespacePrefixToURIMap = 0; - -XMP_AliasMap * sRegisteredAliasMap = 0; // Needed by XMPIterator. - -XMP_VarString * sOutputNS = 0; -XMP_VarString * sOutputStr = 0; -XMP_VarString * sExceptionMessage = 0; - -XMP_Mutex sXMPCoreLock; -int sLockCount = 0; - -#if TraceXMPCalls - FILE * xmpOut = stderr; -#endif - -void * voidVoidPtr = 0; // Used to backfill null output parameters. -XMP_StringPtr voidStringPtr = 0; -XMP_StringLen voidStringLen = 0; -XMP_OptionBits voidOptionBits = 0; -XMP_Uns8 voidByte = 0; -bool voidBool = 0; -XMP_Int32 voidInt32 = 0; -XMP_Int64 voidInt64 = 0; -double voidDouble = 0.0; -XMP_DateTime voidDateTime; -WXMP_Result void_wResult; - -// ================================================================================================= -// Mutex Utilities -// =============== - -// ! Note that the mutex need not be "recursive", allowing the same thread to acquire it multiple -// ! times. There is a single XMP lock which is acquired in the wrapper classes. Internal calls -// ! never go back out to the wrappers. - -#if XMP_WinBuild - - bool XMP_InitMutex ( XMP_Mutex * mutex ) { - InitializeCriticalSection ( mutex ); - return true; - } - - void XMP_TermMutex ( XMP_Mutex & mutex ) { - DeleteCriticalSection ( &mutex ); - } - - void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) { - EnterCriticalSection ( &mutex ); - } - - void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) { - LeaveCriticalSection ( &mutex ); - } - -#else - - // Use pthread for both Mac and generic UNIX. - // ! Would be nice to specify PTHREAD_MUTEX_ERRORCHECK, but the POSIX documentation is useless. - // ! Would be OK but overkill to specify PTHREAD_MUTEX_RECURSIVE. - - bool XMP_InitMutex ( XMP_Mutex * mutex ) { - int err = pthread_mutex_init ( mutex, 0 ); - return (err == 0 ); - } - - void XMP_TermMutex ( XMP_Mutex & mutex ) { - (void) pthread_mutex_destroy ( &mutex ); - } - - void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) { - int err = pthread_mutex_lock ( &mutex ); - if ( err != 0 ) XMP_Throw ( "XMP_EnterCriticalRegion - pthread_mutex_lock failure", kXMPErr_ExternalFailure ); - } - - void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) { - int err = pthread_mutex_unlock ( &mutex ); - if ( err != 0 ) XMP_Throw ( "XMP_ExitCriticalRegion - pthread_mutex_unlock failure", kXMPErr_ExternalFailure ); - } - -#endif - -// ================================================================================================= -// Local Utilities -// =============== - -// ------------------------------------------------------------------------------------------------- -// VerifyXPathRoot -// --------------- -// -// Set up the first 2 components of the expanded XPath. Normalizes the various cases of using the -// full schema URI and/or a qualified root property name. Returns true for normal processing. If -// allowUnknownSchemaNS is true and the schema namespace is not registered, false is returned. If -// allowUnknownSchemaNS is false and the schema namespace is not registered, an exception is thrown. - -// *** Should someday check the full syntax. - -static void -VerifyXPathRoot ( XMP_StringPtr schemaURI, - XMP_StringPtr propName, - XMP_ExpandedXPath * expandedXPath ) -{ - // Do some basic checks on the URI and name. Try to lookup the URI. See if the name is qualified. - - XMP_Assert ( (schemaURI != 0) && (propName != 0) && (*propName != 0) ); - XMP_Assert ( (expandedXPath != 0) && (expandedXPath->empty()) ); - - if ( *schemaURI == 0 ) XMP_Throw ( "Schema namespace URI is required", kXMPErr_BadSchema ); - - if ( (*propName == '?') || (*propName == '@') ) { - XMP_Throw ( "Top level name must not be a qualifier", kXMPErr_BadXPath ); - } - for ( XMP_StringPtr ch = propName; *ch != 0; ++ch ) { - if ( (*ch == '/') || (*ch == '[') ) { - XMP_Throw ( "Top level name must be simple", kXMPErr_BadXPath ); - } - } - - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( XMP_VarString ( schemaURI ) ); - if ( uriPos == sNamespaceURIToPrefixMap->end() ) { - XMP_Throw ( "Unregistered schema namespace URI", kXMPErr_BadSchema ); - } - - XMP_StringPtr colonPos = propName; - while ( (*colonPos != 0) && (*colonPos != ':') ) ++colonPos; - VerifySimpleXMLName ( propName, colonPos ); // Verify the part before any colon. - - // Verify the various URI and prefix combinations. Initialize the expanded XPath. - - if ( *colonPos == 0 ) { - - // The propName is unqualified, use the schemaURI and associated prefix. - - expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) ); - expandedXPath->push_back ( XPathStepInfo ( uriPos->second, 0 ) ); - (*expandedXPath)[kRootPropStep].step += propName; - - } else { - - // The propName is qualified. Make sure the prefix is legit. Use the associated URI and qualified name. - - size_t prefixLen = colonPos - propName + 1; // ! Include the colon. - VerifySimpleXMLName ( colonPos+1, colonPos+strlen(colonPos) ); - - XMP_VarString prefix ( propName, prefixLen ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix ); - if ( prefixPos == sNamespacePrefixToURIMap->end() ) { - XMP_Throw ( "Unknown schema namespace prefix", kXMPErr_BadSchema ); - } - if ( prefix != uriPos->second ) { - XMP_Throw ( "Schema namespace URI and prefix mismatch", kXMPErr_BadSchema ); - } - - expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) ); - expandedXPath->push_back ( XPathStepInfo ( propName, 0 ) ); - - } - -} // VerifyXPathRoot - -// ------------------------------------------------------------------------------------------------- -// VerifyQualName -// -------------- - -static void -VerifyQualName ( XMP_StringPtr qualName, XMP_StringPtr nameEnd ) -{ - if ( qualName >= nameEnd ) XMP_Throw ( "Empty qualified name", kXMPErr_BadXPath ); - - XMP_StringPtr colonPos = qualName; - while ( (colonPos < nameEnd) && (*colonPos != ':') ) ++colonPos; - if ( (colonPos == qualName) || (colonPos >= nameEnd) ) XMP_Throw ( "Ill-formed qualified name", kXMPErr_BadXPath ); - - VerifySimpleXMLName ( qualName, colonPos ); - VerifySimpleXMLName ( colonPos+1, nameEnd ); - - size_t prefixLen = colonPos - qualName + 1; // ! Include the colon. - XMP_VarString prefix ( qualName, prefixLen ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix ); - if ( prefixPos == sNamespacePrefixToURIMap->end() ) { - XMP_Throw ( "Unknown namespace prefix for qualified name", kXMPErr_BadXPath ); - } - -} // VerifyQualName - -// ------------------------------------------------------------------------------------------------- -// FindIndexedItem -// --------------- -// -// [index] An element of an array. -// -// Support the implicit creation of a new last item. - -static XMP_Index -FindIndexedItem ( XMP_Node * arrayNode, const XMP_VarString & indexStep, bool createNodes ) -{ - XMP_Index index = 0; - size_t chLim = indexStep.size() - 1; - - XMP_Assert ( (chLim >= 2) && (indexStep[0] == '[') && (indexStep[chLim] == ']') ); - - for ( size_t chNum = 1; chNum != chLim; ++chNum ) { - XMP_Assert ( ('0' <= indexStep[chNum]) && (indexStep[chNum] <= '9') ); - index = (index * 10) + (indexStep[chNum] - '0'); - if ( index < 0 ) { - XMP_Throw ( "Array index overflow", kXMPErr_BadXPath ); // ! Overflow, not truly negative. - } - } - - --index; // Change to a C-style, zero based index. - if ( index < 0 ) XMP_Throw ( "Array index must be larger than zero", kXMPErr_BadXPath ); - - if ( (index == (XMP_Index)arrayNode->children.size()) && createNodes ) { // Append a new last+1 node. - XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, kXMP_NewImplicitNode ); - arrayNode->children.push_back ( newItem ); - } - - // ! Don't throw here for a too large index. SetProperty will throw, GetProperty will not. - if ( index >= (XMP_Index)arrayNode->children.size() ) index = -1; - return index; - -} // FindIndexedItem - -// ------------------------------------------------------------------------------------------------- -// SplitNameAndValue -// ----------------- -// -// Split the name and value parts for field and qualifier selectors: -// -// [qualName="value"] An element in an array of structs, chosen by a field value. -// [?qualName="value"] An element in an array, chosen by a qualifier value. -// -// The value portion is a string quoted by ''' or '"'. The value may contain any character including -// a doubled quoting character. The value may be empty. - -static void -SplitNameAndValue ( const XMP_VarString & selStep, XMP_VarString * nameStr, XMP_VarString * valueStr ) -{ - XMP_StringPtr partBegin = selStep.c_str(); - XMP_StringPtr partEnd; - - const XMP_StringPtr valueEnd = partBegin + (selStep.size() - 2); - const char quote = *valueEnd; - - XMP_Assert ( (*partBegin == '[') && (*(valueEnd+1) == ']') ); - XMP_Assert ( (selStep.size() >= 6) && ((quote == '"') || (quote == '\'')) ); - - // Extract the name part. - - ++partBegin; // Skip the opening '['. - if ( *partBegin == '?' ) ++partBegin; - for ( partEnd = partBegin+1; *partEnd != '='; ++partEnd ) {}; - - nameStr->assign ( partBegin, (partEnd - partBegin) ); - - // Extract the value part, reducing doubled quotes. - - XMP_Assert ( *(partEnd+1) == quote ); - - partBegin = partEnd + 2; - valueStr->erase(); - valueStr->reserve ( valueEnd - partBegin ); // Maximum length, don't optimize doubled quotes. - - for ( partEnd = partBegin; partEnd < valueEnd; ++partEnd ) { - if ( (*partEnd == quote) && (*(partEnd+1) == quote) ) { - ++partEnd; - valueStr->append ( partBegin, (partEnd - partBegin) ); - partBegin = partEnd+1; // ! Loop will increment partEnd again. - } - } - - valueStr->append ( partBegin, (partEnd - partBegin) ); // ! The loop does not add the last part. - -} // SplitNameAndValue - -// ------------------------------------------------------------------------------------------------- -// LookupQualSelector -// ------------------ -// -// [?qualName="value"] An element in an array, chosen by a qualifier value. -// -// Note that we don't create implicit nodes for qualifier selectors, so no CreateNodes parameter. - -static XMP_Index -LookupQualSelector ( XMP_Node * arrayNode, const XMP_VarString & qualName, XMP_VarString & qualValue ) -{ - XMP_Index index; - - if ( qualName == "xml:lang" ) { - - // *** Should check that the value is legit RFC 1766/3066. - NormalizeLangValue ( &qualValue ); - index = LookupLangItem ( arrayNode, qualValue ) ; - - } else { - - XMP_Index itemLim; - for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) { - - const XMP_Node * currItem = arrayNode->children[index]; - XMP_Assert ( currItem->parent == arrayNode ); - - size_t q, qualLim; - for ( q = 0, qualLim = currItem->qualifiers.size(); q != qualLim; ++q ) { - const XMP_Node * currQual = currItem->qualifiers[q]; - XMP_Assert ( currQual->parent == currItem ); - if ( currQual->name != qualName ) continue; - if ( currQual->value == qualValue ) break; // Exit qual loop. - } - if ( q != qualLim ) break; // Exit child loop, found an item with a matching qualifier. - - } - if ( index == itemLim ) index = -1; - - } - - return index; - -} // LookupQualSelector - -// ------------------------------------------------------------------------------------------------- -// FollowXPathStep -// --------------- -// -// After processing by ExpandXPath, a step can be of these forms: -// qualName A top level property or struct field. -// [index] An element of an array. -// [last()] The last element of an array. -// [qualName="value"] An element in an array of structs, chosen by a field value. -// [?qualName="value"] An element in an array, chosen by a qualifier value. -// ?qualName A general qualifier. -// -// Find the appropriate child node, resolving aliases, and optionally creating nodes. - -static XMP_Node * -FollowXPathStep ( XMP_Node * parentNode, - const XMP_ExpandedXPath & fullPath, - size_t stepNum, - bool createNodes, - XMP_NodePtrPos * ptrPos, - bool aliasedArrayItem = false ) -{ - XMP_Node * nextNode = 0; - const XPathStepInfo & nextStep = fullPath[stepNum]; - XMP_Index index = 0; - XMP_OptionBits stepKind = nextStep.options & kXMP_StepKindMask; - - XMP_Assert ( (kXMP_StructFieldStep <= stepKind) && (stepKind <= kXMP_FieldSelectorStep) ); - - if ( stepKind == kXMP_StructFieldStep ) { - - nextNode = FindChildNode ( parentNode, nextStep.step.c_str(), createNodes, ptrPos ); - - } else if ( stepKind == kXMP_QualifierStep ) { - - XMP_StringPtr qualStep = nextStep.step.c_str(); - XMP_Assert ( *qualStep == '?' ); - ++qualStep; - nextNode = FindQualifierNode ( parentNode, qualStep, createNodes, ptrPos ); - - } else { - - // This is an array indexing step. First get the index, then get the node. - - if ( ! (parentNode->options & kXMP_PropValueIsArray) ) { - XMP_Throw ( "Indexing applied to non-array", kXMPErr_BadXPath ); - } - - if ( stepKind == kXMP_ArrayIndexStep ) { - index = FindIndexedItem ( parentNode, nextStep.step, createNodes ); - } else if ( stepKind == kXMP_ArrayLastStep ) { - index = parentNode->children.size() - 1; - } else if ( stepKind == kXMP_FieldSelectorStep ) { - XMP_VarString fieldName, fieldValue; - SplitNameAndValue ( nextStep.step, &fieldName, &fieldValue ); - index = LookupFieldSelector ( parentNode, fieldName.c_str(), fieldValue.c_str() ); - } else if ( stepKind == kXMP_QualSelectorStep ) { - XMP_VarString qualName, qualValue; - SplitNameAndValue ( nextStep.step, &qualName, &qualValue ); - index = LookupQualSelector ( parentNode, qualName, qualValue ); - } else { - XMP_Throw ( "Unknown array indexing step in FollowXPathStep", kXMPErr_InternalFailure ); - } - - if ( (0 <= index) && (index <= (XMP_Index)parentNode->children.size()) ) nextNode = parentNode->children[index]; - - if ( (index == -1) && createNodes && aliasedArrayItem && (stepKind == kXMP_QualSelectorStep) ) { - - // An ugly special case without an obvious better place to be. We have an alias to the - // x-default item of an alt-text array. A simple reference via SetProperty must create - // the x-default item if it does not yet exist. - - XMP_Assert ( parentNode->options & kXMP_PropArrayIsAltText ); - XMP_Assert ( (stepNum == 2) && (nextStep.step == "[?xml:lang=\"x-default\"]") ); - - nextNode = new XMP_Node ( parentNode, kXMP_ArrayItemName, - (kXMP_PropHasQualifiers | kXMP_PropHasLang | kXMP_NewImplicitNode) ); - - XMP_Node * langQual = new XMP_Node ( nextNode, "xml:lang", "x-default", kXMP_PropIsQualifier ); - nextNode->qualifiers.push_back ( langQual ); - - if ( parentNode->children.empty() ) { - parentNode->children.push_back ( nextNode ); - } else { - parentNode->children.insert ( parentNode->children.begin(), nextNode ); - } - - index = 0; // ! C-style index! The x-default item is always first. - - } - - if ( (nextNode != 0) && (ptrPos != 0) ) *ptrPos = parentNode->children.begin() + index; - - } - - if ( (nextNode != 0) && (nextNode->options & kXMP_NewImplicitNode) ) { - nextNode->options |= (nextStep.options & kXMP_PropArrayFormMask); - } - - XMP_Assert ( (ptrPos == 0) || (nextNode == 0) || (nextNode == **ptrPos) ); - XMP_Assert ( (nextNode != 0) || (! createNodes) ); - return nextNode; - -} // FollowXPathStep - -// ------------------------------------------------------------------------------------------------- -// CheckImplicitStruct -// ------------------- - -static inline void -CheckImplicitStruct ( XMP_Node * node, - const XMP_ExpandedXPath & expandedXPath, - size_t stepNum, - size_t stepLim ) -{ - - if ( (stepNum < stepLim) && - ((node->options & kXMP_PropCompositeMask) == 0) && - (GetStepKind ( expandedXPath[stepNum].options ) == kXMP_StructFieldStep) ) { - - node->options |= kXMP_PropValueIsStruct; - - } - -} // CheckImplicitStruct - -// ------------------------------------------------------------------------------------------------- -// DeleteSubtree -// ------------- - -// *** Might be useful elsewhere? - -static void -DeleteSubtree ( XMP_NodePtrPos rootNodePos ) -{ - XMP_Node * rootNode = *rootNodePos; - XMP_Node * rootParent = rootNode->parent; - - if ( ! (rootNode->options & kXMP_PropIsQualifier) ) { - - rootParent->children.erase ( rootNodePos ); - - } else { - - rootParent->qualifiers.erase ( rootNodePos ); - - XMP_Assert ( rootParent->options & kXMP_PropHasQualifiers); - if ( rootParent->qualifiers.empty() ) rootParent->options ^= kXMP_PropHasQualifiers; - - if ( rootNode->name == "xml:lang" ) { - XMP_Assert ( rootParent->options & kXMP_PropHasLang); - rootParent->options ^= kXMP_PropHasLang; - } else if ( rootNode->name == "rdf:type" ) { - XMP_Assert ( rootParent->options & kXMP_PropHasType); - rootParent->options ^= kXMP_PropHasType; - } - - } - - delete rootNode; - -} // DeleteSubtree - -// ================================================================================================= -// ================================================================================================= - -// ================================================================================================= -// VerifySetOptions -// ================ -// -// Normalize and verify the option flags for SetProperty and similar functions. The allowed options -// here are just those that apply to the property, that would be kept in the XMP_Node. Others that -// affect the selection of the node or other processing must be removed by now. These are: -// kXMP_InsertBeforeItem -// kXMP_InsertAfterItem -// kXMP_KeepQualifiers -// kXMPUtil_AllowCommas - -enum { - kXMP_AllSetOptionsMask = (kXMP_PropValueIsURI | - kXMP_PropValueIsStruct | - kXMP_PropValueIsArray | - kXMP_PropArrayIsOrdered | - kXMP_PropArrayIsAlternate | - kXMP_PropArrayIsAltText | - kXMP_DeleteExisting) -}; - -XMP_OptionBits -VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue ) -{ - - if ( options & kXMP_PropArrayIsAltText ) options |= kXMP_PropArrayIsAlternate; - if ( options & kXMP_PropArrayIsAlternate ) options |= kXMP_PropArrayIsOrdered; - if ( options & kXMP_PropArrayIsOrdered ) options |= kXMP_PropValueIsArray; - - if ( options & ~kXMP_AllSetOptionsMask ) { - XMP_Throw ( "Unrecognized option flags", kXMPErr_BadOptions ); - } - - if ( (options & kXMP_PropValueIsStruct) && (options & kXMP_PropValueIsArray) ) { - XMP_Throw ( "IsStruct and IsArray options are mutually exclusive", kXMPErr_BadOptions ); - } - - if ( (options & kXMP_PropValueOptionsMask) && (options & kXMP_PropCompositeMask) ) { - XMP_Throw ( "Structs and arrays can't have \"value\" options", kXMPErr_BadOptions ); - } - - if ( (propValue != 0) && (options & kXMP_PropCompositeMask) ) { - XMP_Throw ( "Structs and arrays can't have string values", kXMPErr_BadOptions ); - } - - return options; - -} // VerifySetOptions - -// ================================================================================================= -// ComposeXPath -// ============ -// -// Compose the canonical string form of an expanded XPath expression. - -extern void -ComposeXPath ( const XMP_ExpandedXPath & expandedXPath, - XMP_VarString * stringXPath ) -{ - *stringXPath = expandedXPath[kRootPropStep].step; - - for ( size_t index = kRootPropStep+1; index < expandedXPath.size(); ++index ) { - const XPathStepInfo & currStep = expandedXPath[index]; - - switch ( currStep.options & kXMP_StepKindMask ) { - - case kXMP_StructFieldStep : - case kXMP_QualifierStep : - *stringXPath += '/'; - *stringXPath += currStep.step; - break; - - case kXMP_ArrayIndexStep : - case kXMP_ArrayLastStep : - case kXMP_QualSelectorStep : - case kXMP_FieldSelectorStep : - *stringXPath += currStep.step; - break; - - default: - XMP_Throw ( "Unexpected", kXMPErr_InternalFailure ); - - } - - } - -} // ComposeXPath - -// ================================================================================================= -// ExpandXPath -// =========== -// -// Split an XPath expression apart at the conceptual steps, adding the root namespace prefix to the -// first property component. The schema URI is put in the first (0th) slot in the expanded XPath. -// Check if the top level component is an alias, but don't resolve it. -// -// In the most verbose case steps are separated by '/', and each step can be of these forms: -// -// qualName A top level property or struct field. -// *[index] An element of an array. -// *[last()] The last element of an array. -// *[fieldName="value"] An element in an array of structs, chosen by a field value. -// *[@xml:lang="value"] An element in an alt-text array, chosen by the xml:lang qualifier. -// *[?qualName="value"] An element in an array, chosen by a qualifier value. -// @xml:lang An xml:lang qualifier. -// ?qualName A general qualifier. -// -// The logic is complicated though by shorthand for arrays, the separating '/' and leading '*' -// are optional. These are all equivalent: array/*[2] array/[2] array*[2] array[2] -// All of these are broken into the 2 steps "array" and "[2]". -// -// The value portion in the array selector forms is a string quoted by ''' or '"'. The value -// may contain any character including a doubled quoting character. The value may be empty. -// -// The syntax isn't checked, but an XML name begins with a letter or '_', and contains letters, -// digits, '.', '-', '_', and a bunch of special non-ASCII Unicode characters. An XML qualified -// name is a pair of names separated by a colon. - -void -ExpandXPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propPath, - XMP_ExpandedXPath * expandedXPath ) -{ - XMP_Assert ( (schemaNS != 0) && (propPath != 0) && (*propPath != 0) && (expandedXPath != 0) ); - - XMP_StringPtr stepBegin, stepEnd; - XMP_StringPtr qualName, nameEnd; - XMP_VarString currStep; - - qualName = nameEnd = NULL; - size_t resCount = 2; // Guess at the number of steps. At least 2, plus 1 for each '/' or '['. - for ( stepEnd = propPath; *stepEnd != 0; ++stepEnd ) { - if ( (*stepEnd == '/') || (*stepEnd == '[') ) ++resCount; - } - - expandedXPath->clear(); - expandedXPath->reserve ( resCount ); - - // ------------------------------------------------------------------------------------------- - // Pull out the first component and do some special processing on it: add the schema namespace - // prefix and see if it is an alias. The start must be a qualName. - - stepBegin = propPath; - stepEnd = stepBegin; - while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd; - if ( stepEnd == stepBegin ) XMP_Throw ( "Empty initial XPath step", kXMPErr_BadXPath ); - currStep.assign ( stepBegin, (stepEnd - stepBegin) ); - - VerifyXPathRoot ( schemaNS, currStep.c_str(), expandedXPath ); - - XMP_OptionBits stepFlags = kXMP_StructFieldStep; - if ( sRegisteredAliasMap->find ( (*expandedXPath)[kRootPropStep].step ) != sRegisteredAliasMap->end() ) { - stepFlags |= kXMP_StepIsAlias; - } - (*expandedXPath)[kRootPropStep].options |= stepFlags; - - // ----------------------------------------------------- - // Now continue to process the rest of the XPath string. - - while ( *stepEnd != 0 ) { - - stepBegin = stepEnd; - if ( *stepBegin == '/' ) ++stepBegin; - if ( *stepBegin == '*' ) { - ++stepBegin; - if ( *stepBegin != '[' ) XMP_Throw ( "Missing '[' after '*'", kXMPErr_BadXPath ); - } - stepEnd = stepBegin; - - if ( *stepBegin != '[' ) { - - // A struct field or qualifier. - qualName = stepBegin; - while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd; - nameEnd = stepEnd; - stepFlags = kXMP_StructFieldStep; // ! Touch up later, also changing '@' to '?'. - - } else { - - // One of the array forms. - - ++stepEnd; // Look at the character after the leading '['. - - if ( ('0' <= *stepEnd) && (*stepEnd <= '9') ) { - - // A numeric (decimal integer) array index. - while ( (*stepEnd != 0) && ('0' <= *stepEnd) && (*stepEnd <= '9') ) ++stepEnd; - if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for integer array index", kXMPErr_BadXPath ); - stepFlags = kXMP_ArrayIndexStep; - - } else { - - // Could be "[last()]" or one of the selector forms. Find the ']' or '='. - - while ( (*stepEnd != 0) && (*stepEnd != ']') && (*stepEnd != '=') ) ++stepEnd; - if ( *stepEnd == 0 ) XMP_Throw ( "Missing ']' or '=' for array index", kXMPErr_BadXPath ); - - if ( *stepEnd == ']' ) { - - if ( strncmp ( "[last()", stepBegin, (stepEnd - stepBegin) ) != 0 ) { - XMP_Throw ( "Invalid non-numeric array index", kXMPErr_BadXPath ); - } - stepFlags = kXMP_ArrayLastStep; - - } else { - - qualName = stepBegin+1; - nameEnd = stepEnd; - ++stepEnd; // Absorb the '=', remember the quote. - const char quote = *stepEnd; - if ( (quote != '\'') && (quote != '"') ) { - XMP_Throw ( "Invalid quote in array selector", kXMPErr_BadXPath ); - } - - ++stepEnd; // Absorb the leading quote. - while ( *stepEnd != 0 ) { - if ( *stepEnd == quote ) { - if ( *(stepEnd+1) != quote ) break; - ++stepEnd; - } - ++stepEnd; - } - if ( *stepEnd == 0 ) { - XMP_Throw ( "No terminating quote for array selector", kXMPErr_BadXPath ); - } - ++stepEnd; // Absorb the trailing quote. - - stepFlags = kXMP_FieldSelectorStep; // ! Touch up later, also changing '@' to '?'. - - } - - } - - if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for array index", kXMPErr_BadXPath ); - ++stepEnd; - - } - - if ( stepEnd == stepBegin ) XMP_Throw ( "Empty XPath step", kXMPErr_BadXPath ); - currStep.assign ( stepBegin, (stepEnd - stepBegin) ); - - if ( GetStepKind ( stepFlags ) == kXMP_StructFieldStep ) { - - if ( currStep[0] == '@' ) { - currStep[0] = '?'; - if ( currStep != "?xml:lang" ) XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath ); - } - if ( currStep[0] == '?' ) { - ++qualName; - stepFlags = kXMP_QualifierStep; - } - VerifyQualName ( qualName, nameEnd ); - - } else if ( GetStepKind ( stepFlags ) == kXMP_FieldSelectorStep ) { - - if ( currStep[1] == '@' ) { - currStep[1] = '?'; - if ( strncmp ( currStep.c_str(), "[?xml:lang=", 11 ) != 0 ) { - XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath ); - } - } - if ( currStep[1] == '?' ) { - ++qualName; - stepFlags = kXMP_QualSelectorStep; - } - VerifyQualName ( qualName, nameEnd ); - - } - - expandedXPath->push_back ( XPathStepInfo ( currStep, stepFlags ) ); - - } - -} // ExpandXPath - -// ================================================================================================= -// FindSchemaNode -// ============== -// -// Find or create a schema node. Returns a pointer to the node, and optionally an iterator for the -// node's position in the top level vector of schema nodes. The iterator is unchanged if no schema -// node (null) is returned. - -XMP_Node * -FindSchemaNode ( XMP_Node * xmpTree, - XMP_StringPtr nsURI, - bool createNodes, - XMP_NodePtrPos * ptrPos /* = 0 */ ) -{ - XMP_Node * schemaNode = 0; - - XMP_Assert ( xmpTree->parent == 0 ); - - for ( size_t schemaNum = 0, schemaLim = xmpTree->children.size(); schemaNum != schemaLim; ++schemaNum ) { - XMP_Node * currSchema = xmpTree->children[schemaNum]; - XMP_Assert ( currSchema->parent == xmpTree ); - if ( currSchema->name == nsURI ) { - schemaNode = currSchema; - if ( ptrPos != 0 ) *ptrPos = xmpTree->children.begin() + schemaNum; - break; - } - } - - if ( (schemaNode == 0) && createNodes ) { - - schemaNode = new XMP_Node ( xmpTree, nsURI, (kXMP_SchemaNode | kXMP_NewImplicitNode) ); - XMP_StringPtr prefixPtr; - XMP_StringLen prefixLen; - bool found = XMPMeta::GetNamespacePrefix ( nsURI, &prefixPtr, &prefixLen ); // *** Use map directly? - XMP_Assert ( found ); - UNUSED(found); - - schemaNode->value.assign ( prefixPtr, prefixLen ); - xmpTree->children.push_back ( schemaNode ); - if ( ptrPos != 0 ) *ptrPos = xmpTree->children.end() - 1; - - #if 0 // *** XMP_DebugBuild - schemaNode->_valuePtr = schemaNode->value.c_str(); - #endif - - } - - XMP_Assert ( (ptrPos == 0) || (schemaNode == 0) || (schemaNode == **ptrPos) ); - XMP_Assert ( (schemaNode != 0) || (! createNodes) ); - return schemaNode; - -} // FindSchemaNode - -// ================================================================================================= -// FindChildNode -// ============= -// -// Find or create a child node under a given parent node. Returns a pointer to the child node, and -// optionally an iterator for the node's position in the parent's vector of children. The iterator -// is unchanged if no child node (null) is returned. - -XMP_Node * -FindChildNode ( XMP_Node * parent, - XMP_StringPtr childName, - bool createNodes, - XMP_NodePtrPos * ptrPos /* = 0 */ ) -{ - XMP_Node * childNode = 0; - - if ( ! (parent->options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) { - if ( ! (parent->options & kXMP_NewImplicitNode) ) { - XMP_Throw ( "Named children only allowed for schemas and structs", kXMPErr_BadXPath ); - } - if ( parent->options & kXMP_PropValueIsArray ) { - XMP_Throw ( "Named children not allowed for arrays", kXMPErr_BadXPath ); - } - if ( ! createNodes ) { // *** Should be assert? If !createNodes, why is the parent a new implicit node? - XMP_Throw ( "Parent is new implicit node, but createNodes is false", kXMPErr_InternalFailure ); - } - parent->options |= kXMP_PropValueIsStruct; - } - - for ( size_t childNum = 0, childLim = parent->children.size(); childNum != childLim; ++childNum ) { - XMP_Node * currChild = parent->children[childNum]; - XMP_Assert ( currChild->parent == parent ); - if ( currChild->name == childName ) { - childNode = currChild; - if ( ptrPos != 0 ) *ptrPos = parent->children.begin() + childNum; - break; - } - } - - if ( (childNode == 0) && createNodes ) { - childNode = new XMP_Node ( parent, childName, kXMP_NewImplicitNode ); - parent->children.push_back ( childNode ); - if ( ptrPos != 0 ) *ptrPos = parent->children.end() - 1; - } - - XMP_Assert ( (ptrPos == 0) || (childNode == 0) || (childNode == **ptrPos) ); - XMP_Assert ( (childNode != 0) || (! createNodes) ); - return childNode; - -} // FindChildNode - -// ================================================================================================= -// FindQualifierNode -// ================= -// -// Find or create a qualifier node under a given parent node. Returns a pointer to the qualifier node, -// and optionally an iterator for the node's position in the parent's vector of qualifiers. The iterator -// is unchanged if no qualifier node (null) is returned. -// -// ! On entry, the qualName parameter must not have the leading '?' from the XPath step. - -XMP_Node * -FindQualifierNode ( XMP_Node * parent, - XMP_StringPtr qualName, - bool createNodes, - XMP_NodePtrPos * ptrPos /* = 0 */ ) // *** Require ptrPos internally & remove checks? -{ - XMP_Node * qualNode = 0; - - XMP_Assert ( *qualName != '?' ); - - for ( size_t qualNum = 0, qualLim = parent->qualifiers.size(); qualNum != qualLim; ++qualNum ) { - XMP_Node * currQual = parent->qualifiers[qualNum]; - XMP_Assert ( currQual->parent == parent ); - if ( currQual->name == qualName ) { - qualNode = currQual; - if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.begin() + qualNum; - break; - } - } - - if ( (qualNode == 0) && createNodes ) { - - qualNode = new XMP_Node ( parent, qualName, (static_cast(kXMP_PropIsQualifier) | static_cast(kXMP_NewImplicitNode)) ); - parent->options |= kXMP_PropHasQualifiers; - - const bool isLang = XMP_LitMatch ( qualName, "xml:lang" ); - const bool isType = XMP_LitMatch ( qualName, "rdf:type" ); - const bool isSpecial = isLang | isType; - - if ( isLang ) { - parent->options |= kXMP_PropHasLang; - } else if ( isType ) { - parent->options |= kXMP_PropHasType; - } - - if ( parent->qualifiers.empty() || (! isSpecial) ) { - parent->qualifiers.push_back ( qualNode ); - if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.end() - 1; - } else { - XMP_NodePtrPos insertPos = parent->qualifiers.begin(); // ! Lang goes first, type after. - if ( isType && (parent->options & kXMP_PropHasLang) ) ++insertPos; // *** Does insert at end() work? - insertPos = parent->qualifiers.insert ( insertPos, qualNode ); - if ( ptrPos != 0 ) *ptrPos = insertPos; - } - - } - - XMP_Assert ( (ptrPos == 0) || (qualNode == 0) || (qualNode == **ptrPos) ); - XMP_Assert ( (qualNode != 0) || (! createNodes) ); - return qualNode; - -} // FindQualifierNode - -// ================================================================================================= -// LookupFieldSelector -// =================== -// -// [fieldName="value"] An element in an array of structs, chosen by a field value. -// -// Note that we don't create implicit nodes for field selectors, so no CreateNodes parameter. - -XMP_Index -LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue ) -{ - XMP_Index index, itemLim; - - for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) { - - const XMP_Node * currItem = arrayNode->children[index]; - XMP_Assert ( currItem->parent == arrayNode ); - - if ( ! (currItem->options & kXMP_PropValueIsStruct) ) { - XMP_Throw ( "Field selector must be used on array of struct", kXMPErr_BadXPath ); - } - - size_t f, fieldLim; - for ( f = 0, fieldLim = currItem->children.size(); f != fieldLim; ++f ) { - const XMP_Node * currField = currItem->children[f]; - XMP_Assert ( currField->parent == currItem ); - if ( currField->name != fieldName ) continue; - if ( currField->value == fieldValue ) break; // Exit qual loop. - } - if ( f != fieldLim ) break; // Exit child loop, found an item with a matching qualifier. - - } - - if ( index == itemLim ) index = -1; - return index; - -} // LookupFieldSelector - -// ================================================================================================= -// LookupLangItem -// ============== -// -// ! Assumes that the language value is already normalized. - -XMP_Index -LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang ) -{ - if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) { // *** Check for alt-text? - XMP_Throw ( "Language item must be used on array", kXMPErr_BadXPath ); - } - - XMP_Index index = 0; - XMP_Index itemLim = arrayNode->children.size(); - - for ( ; index != itemLim; ++index ) { - const XMP_Node * currItem = arrayNode->children[index]; - XMP_Assert ( currItem->parent == arrayNode ); - if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) continue; - if ( currItem->qualifiers[0]->value == lang ) break; - } - - if ( index == itemLim ) index = -1; - return index; - -} // LookupLangItem - -// ================================================================================================= -// FindNode -// ======== -// -// Follow an expanded path expression to find or create a node. Returns a pointer to the node, and -// optionally an iterator for the node's position in the parent's vector of children or qualifiers. -// The iterator is unchanged if no child node (null) is returned. - -XMP_Node * -FindNode ( XMP_Node * xmpTree, - const XMP_ExpandedXPath & expandedXPath, - bool createNodes, - XMP_OptionBits leafOptions /* = 0 */, - XMP_NodePtrPos * ptrPos /* = 0 */ ) -{ - XMP_Node * currNode = 0; - XMP_NodePtrPos currPos; - XMP_NodePtrPos newSubPos; // Root of implicitly created subtree. Valid only if leaf is new. - bool leafIsNew = false; - - XMP_Assert ( (leafOptions == 0) || createNodes ); - - if ( expandedXPath.empty() ) XMP_Throw ( "Empty XPath", kXMPErr_BadXPath ); - - size_t stepNum = 1; // By default start calling FollowXPathStep for the top level property step. - size_t stepLim = expandedXPath.size(); - - // The start of processing deals with the schema node and top level alias. If the top level step - // is not an alias, lookup the expanded path's schema URI. Otherwise, lookup the expanded path - // for the actual. While tempting, don't substitute the actual's path into the local one, don't - // risk messing with the caller's use of that. Also don't call FindNode recursively, we need to - // keep track of the root of the implicitly created subtree as we move down the path. - - if ( ! (expandedXPath[kRootPropStep].options & kXMP_StepIsAlias) ) { - - currNode = FindSchemaNode ( xmpTree, expandedXPath[kSchemaStep].step.c_str(), createNodes, &currPos ); - if ( currNode == 0 ) return 0; - - if ( currNode->options & kXMP_NewImplicitNode ) { - currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node. - leafIsNew = true; // If any parent is new, the leaf will be new also. - } - - } else { - - stepNum = 2; // ! Continue processing the original path at the second level step. - - XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( expandedXPath[kRootPropStep].step ); - XMP_Assert ( aliasPos != sRegisteredAliasMap->end() ); - - currNode = FindSchemaNode ( xmpTree, aliasPos->second[kSchemaStep].step.c_str(), createNodes, &currPos ); - if ( currNode == 0 ) goto EXIT; - if ( currNode->options & kXMP_NewImplicitNode ) { - currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node. - leafIsNew = true; // If any parent is new, the leaf will be new also. - } - - currNode = FollowXPathStep ( currNode, aliasPos->second, 1, createNodes, &currPos ); - if ( currNode == 0 ) goto EXIT; - if ( currNode->options & kXMP_NewImplicitNode ) { - currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim ); - if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node. - leafIsNew = true; // If any parent is new, the leaf will be new also. - } - - XMP_OptionBits arrayForm = aliasPos->second[kRootPropStep].options & kXMP_PropArrayFormMask; - XMP_Assert ( (arrayForm == 0) || (arrayForm & kXMP_PropValueIsArray) ); - XMP_Assert ( (arrayForm == 0) ? (aliasPos->second.size() == 2) : (aliasPos->second.size() == 3) ); - - if ( arrayForm != 0 ) { - currNode = FollowXPathStep ( currNode, aliasPos->second, 2, createNodes, &currPos, true ); - if ( currNode == 0 ) goto EXIT; - if ( currNode->options & kXMP_NewImplicitNode ) { - currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim ); - if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node. - leafIsNew = true; // If any parent is new, the leaf will be new also. - } - } - - } - - // Now follow the remaining steps of the original XPath. - - // *** ??? Change all the num/lim loops back to numoptions & kXMP_NewImplicitNode ) { - currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit. - CheckImplicitStruct ( currNode, expandedXPath, stepNum+1, stepLim ); - if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node. - leafIsNew = true; // If any parent is new, the leaf will be new also. - } - } - } catch ( ... ) { - if ( leafIsNew ) DeleteSubtree ( newSubPos ); - throw; - } - - // Done. Delete the implicitly created subtree if the eventual node was not found. - -EXIT: - - XMP_Assert ( (currNode == 0) || (currNode == *currPos) ); - XMP_Assert ( (currNode != 0) || (! createNodes) ); - - if ( leafIsNew ) { - if ( currNode != 0 ) { - currNode->options |= leafOptions; - } else { - DeleteSubtree ( newSubPos ); - } - } - - if ( (currNode != 0) && (ptrPos != 0) ) *ptrPos = currPos; - return currNode; - -} // FindNode - -// ================================================================================================= -// CloneOffspring -// ============== - -void -CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ) -{ - size_t qualCount = origParent->qualifiers.size(); - size_t childCount = origParent->children.size(); - - if ( qualCount > 0 ) { - - cloneParent->qualifiers.reserve ( qualCount ); - - for ( size_t qualNum = 0, qualLim = qualCount; qualNum != qualLim; ++qualNum ) { - const XMP_Node * origQual = origParent->qualifiers[qualNum]; - XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options ); - CloneOffspring ( origQual, cloneQual ); - cloneParent->qualifiers.push_back ( cloneQual ); - } - - } - - if ( childCount > 0 ) { - - cloneParent->children.reserve ( childCount ); - - for ( size_t childNum = 0, childLim = childCount; childNum != childLim; ++childNum ) { - const XMP_Node * origChild = origParent->children[childNum]; - XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options ); - CloneOffspring ( origChild, cloneChild ); - cloneParent->children.push_back ( cloneChild ); - } - - } - -} // CloneOffspring - -// ================================================================================================= -// CloneSubtree -// ============ - -XMP_Node * -CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent ) -{ - #if XMP_DebugBuild - if ( cloneParent->parent == 0 ) { - XMP_Assert ( origRoot->options & kXMP_SchemaNode ); - XMP_Assert ( FindConstSchema ( cloneParent, origRoot->name.c_str() ) == 0 ); - } else { - XMP_Assert ( ! (origRoot->options & kXMP_SchemaNode) ); - if ( cloneParent->options & kXMP_PropValueIsStruct ) { // Might be an array. - XMP_Assert ( FindConstChild ( cloneParent, origRoot->name.c_str() ) == 0 ); - } - } - #endif - - XMP_Node * cloneRoot = new XMP_Node ( cloneParent, origRoot->name, origRoot->value, origRoot->options ); - CloneOffspring ( origRoot, cloneRoot ) ; - cloneParent->children.push_back ( cloneRoot ); - - return cloneRoot; - -} // CloneSubtree - -// ================================================================================================= -// CompareSubtrees -// =============== -// -// Compare 2 subtrees for semantic equality. The comparison includes value, qualifiers, and form. -// Schemas, top level properties, struct fields, and qualifiers are allowed to have differing order, -// the appropriate right node is found from the left node's name. Alt-text arrays are allowed to be -// in differing language order, other arrays are compared in order. - -// *** Might someday consider sorting unordered arrays. -// *** Should expose this through XMPUtils. - -bool -CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode ) -{ - // Don't compare the names here, we want to allow the outermost roots to have different names. - if ( (leftNode.value != rightNode.value) || - (leftNode.options != rightNode.options) || - (leftNode.children.size() != rightNode.children.size()) || - (leftNode.qualifiers.size() != rightNode.qualifiers.size()) ) return false; - - // Compare the qualifiers, allowing them to be out of order. - for ( size_t qualNum = 0, qualLim = leftNode.qualifiers.size(); qualNum != qualLim; ++qualNum ) { - const XMP_Node * leftQual = leftNode.qualifiers[qualNum]; - const XMP_Node * rightQual = FindConstQualifier ( &rightNode, leftQual->name.c_str() ); - if ( (rightQual == 0) || (! CompareSubtrees ( *leftQual, *rightQual )) ) return false; - } - - if ( (leftNode.parent == 0) || (leftNode.options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) { - - // The parent node is a tree root, a schema, or a struct. - for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) { - const XMP_Node * leftChild = leftNode.children[childNum]; - const XMP_Node * rightChild = FindConstChild ( &rightNode, leftChild->name.c_str() ); - if ( (rightChild == 0) || (! CompareSubtrees ( *leftChild, *rightChild )) ) return false; - } - - } else if ( leftNode.options & kXMP_PropArrayIsAltText ) { - - // The parent node is an alt-text array. - for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) { - const XMP_Node * leftChild = leftNode.children[childNum]; - XMP_Assert ( (! leftChild->qualifiers.empty()) && (leftChild->qualifiers[0]->name == "xml:lang") ); - XMP_Index rightIndex = LookupLangItem ( &rightNode, leftChild->qualifiers[0]->value ); - if ( rightIndex == -1 ) return false; - const XMP_Node * rightChild = rightNode.children[rightIndex]; - if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false; - } - - } else { - - // The parent must be simple or some other (not alt-text) kind of array. - XMP_Assert ( (! (leftNode.options & kXMP_PropCompositeMask)) || (leftNode.options & kXMP_PropValueIsArray) ); - for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) { - const XMP_Node * leftChild = leftNode.children[childNum]; - const XMP_Node * rightChild = rightNode.children[childNum]; - if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false; - } - - } - - return true; - -} // CompareSubtrees - -// ================================================================================================= -// DeleteEmptySchema -// ================= - -void -DeleteEmptySchema ( XMP_Node * schemaNode ) -{ - - if ( XMP_NodeIsSchema ( schemaNode->options ) && schemaNode->children.empty() ) { - - XMP_Node * xmpTree = schemaNode->parent; - - size_t schemaNum = 0; - size_t schemaLim = xmpTree->children.size(); - while ( (schemaNum < schemaLim) && (xmpTree->children[schemaNum] != schemaNode) ) ++schemaNum; - XMP_Assert ( schemaNum < schemaLim ); - - XMP_NodePtrPos schemaPos = xmpTree->children.begin() + schemaNum; - XMP_Assert ( *schemaPos == schemaNode ); - - xmpTree->children.erase ( schemaPos ); - delete schemaNode; - - } - -} // DeleteEmptySchema - -// ================================================================================================= -// NormalizeLangValue -// ================== -// -// Normalize an xml:lang value so that comparisons are effectively case insensitive as required by -// RFC 3066 (which superceeds RFC 1766). The normalization rules: -// -// - The primary subtag is lower case, the suggested practice of ISO 639. -// - All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166. -// - All other subtags are lower case. - -void -NormalizeLangValue ( XMP_VarString * value ) -{ - char * tagStart; - char * tagEnd; - - // Find and process the primary subtag. - - tagStart = (char*) value->c_str(); - for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) { - if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20; - } - - // Find and process the secondary subtag. - - tagStart = tagEnd; - if ( *tagStart == '-' ) ++tagStart; - for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) { - if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20; - } - if ( tagEnd == tagStart+2 ) { - if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20; - ++tagStart; - if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20; - } - - // Find and process the remaining subtags. - - while ( true ) { - tagStart = tagEnd; - if ( *tagStart == '-' ) ++tagStart; - if ( *tagStart == 0 ) break; - for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) { - if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20; - } - } - -} // NormalizeLangValue - -// ================================================================================================= -// NormalizeLangArray -// ================== -// -// Make sure the x-default item is first. Touch up "single value" arrays that have a default plus -// one real language. This case should have the same value for both items. Older Adobe apps were -// hardwired to only use the 'x-default' item, so we copy that value to the other item. - -void -NormalizeLangArray ( XMP_Node * array ) -{ - XMP_Assert ( XMP_ArrayIsAltText(array->options) ); - - size_t itemNum; - size_t itemLim = array->children.size(); - bool hasDefault = false; - - for ( itemNum = 0; itemNum < itemLim; ++itemNum ) { - - if ( array->children[itemNum]->qualifiers.empty() || - (array->children[itemNum]->qualifiers[0]->name != "xml:lang") ) { - XMP_Throw ( "AltText array items must have an xml:lang qualifier", kXMPErr_BadXMP ); - } - - if ( array->children[itemNum]->qualifiers[0]->value == "x-default" ) { - hasDefault = true; - break; - } - - } - - if ( hasDefault ) { - - if ( itemNum != 0 ) { - XMP_Node * temp = array->children[0]; - array->children[0] = array->children[itemNum]; - array->children[itemNum] = temp; - } - -// 09-Oct-07, ahu: disabled to avoid unexpected behaviour -// if ( itemLim == 2 ) array->children[1]->value = array->children[0]->value; - - } - -} // NormalizeLangArray - -// ================================================================================================= -// DetectAltText -// ============= -// -// See if an array is an alt-text array. If so, make sure the x-default item is first. - -void -DetectAltText ( XMP_Node * xmpParent ) -{ - XMP_Assert ( XMP_ArrayIsAlternate(xmpParent->options) ); - - size_t itemNum, itemLim; - - for ( itemNum = 0, itemLim = xmpParent->children.size(); itemNum < itemLim; ++itemNum ) { - XMP_OptionBits currOptions = xmpParent->children[itemNum]->options; - if ( (currOptions & kXMP_PropCompositeMask) || (! (currOptions & kXMP_PropHasLang)) ) break; - } - - if ( (itemLim != 0) && (itemNum == itemLim) ) { - xmpParent->options |= kXMP_PropArrayIsAltText; - NormalizeLangArray ( xmpParent ); - } - -} // DetectAltText - -// ================================================================================================= -// SortNamedNodes -// ============== -// -// Sort the pointers in an XMP_NodeOffspring vector by name. - -static inline bool Compare ( const XMP_Node * left, const XMP_Node * right ) -{ - return (left->name < right->name); -} - -void -SortNamedNodes ( XMP_NodeOffspring & nodeVector ) -{ - sort ( nodeVector.begin(), nodeVector.end(), Compare ); -} // SortNamedNodes - -// ================================================================================================= diff --git a/xmpsdk/src/XMPCore_Impl.hpp b/xmpsdk/src/XMPCore_Impl.hpp deleted file mode 100644 index 3473c5dbc2..0000000000 --- a/xmpsdk/src/XMPCore_Impl.hpp +++ /dev/null @@ -1,534 +0,0 @@ -#ifndef __XMPCore_Impl_hpp__ -#define __XMPCore_Impl_hpp__ - -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! Must be the first #include! -#include "XMP_Const.h" -#include "XMP_BuildInfo.h" - -#include "client-glue/WXMPMeta.hpp" - -#include -#include -#include - -#include -#include - -#if XMP_WinBuild - #include -#else - // Use pthread for both Mac and generic UNIX. - #include -#endif - -#if XMP_WinBuild -# ifdef _MSC_VER - #pragma warning ( disable : 4244 ) // possible loss of data (temporary for 64 bit builds) - #pragma warning ( disable : 4267 ) // possible loss of data (temporary for 64 bit builds) -# endif -#endif - -// ================================================================================================= -// Primary internal types - -class XMP_Node; -class XML_Node; -class XPathStepInfo; - -typedef XMP_Node * XMP_NodePtr; - -typedef std::vector XMP_NodeOffspring; -typedef XMP_NodeOffspring::iterator XMP_NodePtrPos; - -typedef std::string XMP_VarString; -typedef XMP_VarString::iterator XMP_VarStringPos; -typedef XMP_VarString::const_iterator XMP_cVarStringPos; - -typedef std::pair < XMP_VarString, XMP_VarString > XMP_StringPair; - -typedef std::map < XMP_VarString, XMP_VarString > XMP_StringMap; -typedef XMP_StringMap::iterator XMP_StringMapPos; -typedef XMP_StringMap::const_iterator XMP_cStringMapPos; - -typedef std::vector < XPathStepInfo > XMP_ExpandedXPath; -typedef XMP_ExpandedXPath::iterator XMP_ExpandedXPathPos; -typedef XMP_ExpandedXPath::const_iterator XMP_cExpandedXPathPos; - -typedef std::map < XMP_VarString, XMP_ExpandedXPath > XMP_AliasMap; // Alias name to actual path. -typedef XMP_AliasMap::iterator XMP_AliasMapPos; -typedef XMP_AliasMap::const_iterator XMP_cAliasMapPos; - -// ================================================================================================= -// General global variables and macros - -extern XMP_Int32 sXMP_InitCount; - -extern XMP_AliasMap * sRegisteredAliasMap; - -extern XMP_StringMap * sNamespaceURIToPrefixMap; -extern XMP_StringMap * sNamespacePrefixToURIMap; - -extern XMP_VarString * sOutputNS; -extern XMP_VarString * sOutputStr; - -extern void * voidVoidPtr; // Used to backfill null output parameters. -extern XMP_StringPtr voidStringPtr; -extern XMP_StringLen voidStringLen; -extern XMP_OptionBits voidOptionBits; -extern XMP_Bool voidByte; -extern bool voidBool; -extern XMP_Int32 voidInt32; -extern XMP_Int64 voidInt64; -extern double voidDouble; -extern XMP_DateTime voidDateTime; -extern WXMP_Result void_wResult; - -#define kHexDigits "0123456789ABCDEF" - -#define XMP_LitMatch(s,l) (std::strcmp((s),(l)) == 0) -#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0) - // *** Use the above macros! - -#define kTab ((char)0x09) -#define kLF ((char)0x0A) -#define kCR ((char)0x0D) - -#if XMP_WinBuild - #define snprintf _snprintf -#endif - -#define WtoXMPMeta_Ref(xmpRef) *((const XMPMeta *)(xmpRef)) -#define WtoXMPMeta_Ptr(xmpRef) (((xmpRef) == 0) ? 0 : (XMPMeta *)(xmpRef)) - -#define WtoXMPIterator_Ref(iterRef) *((const XMPIterator *)(iterRef)) -#define WtoXMPIterator_Ptr(iterRef) (((iterRef) == 0) ? 0 : (XMPIterator *)(iterRef)) - -#define WtoXMPDocOps_Ref(docRef) *((const XMPDocOps *)(docRef)) -#define WtoXMPDocOps_Ptr(docRef) (((docRef) == 0) ? 0 : (XMPDocOps *)(docRef)) - -#define IgnoreParam(p) (void)p - -// ================================================================================================= -// Version info - -#if XMP_DebugBuild - #define kXMPCore_DebugFlag 1 -#else - #define kXMPCore_DebugFlag 0 -#endif - -#define kXMPCore_VersionNumber ( (kXMPCore_DebugFlag << 31) | \ - (XMP_API_VERSION_MAJOR << 24) | \ - (XMP_API_VERSION_MINOR << 16) | \ - (XMP_API_VERSION_MICRO << 8) ) - - #define kXMPCoreName "XMP Core" - #define kXMPCore_VersionMessage kXMPCoreName " " XMP_API_VERSION_STRING -// ================================================================================================= -// Support for asserts - -#define _MakeStr(p) #p -#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l) - -#if ! XMP_DebugBuild - #define XMP_Assert(c) ((void) 0) -#else - #define XMP_Assert(c) assert ( c ) -#endif - - #define XMP_Enforce(c) \ - if ( ! (c) ) { \ - const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \ - XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \ - } -// ================================================================================================= -// Support for exceptions and thread locking - -#ifndef TraceXMPCalls - #define TraceXMPCalls 0 -#endif - -#if ! TraceXMPCalls - - #define AnnounceThrow(msg) /* Do nothing. */ - #define AnnounceCatch(msg) /* Do nothing. */ - - #define AnnounceEntry(proc) /* Do nothing. */ - #define AnnounceNoLock(proc) /* Do nothing. */ - #define AnnounceExit() /* Do nothing. */ - - #define ReportLock() ++sLockCount - #define ReportUnlock() --sLockCount - #define ReportKeepLock() /* Do nothing. */ - -#else - - extern FILE * xmpCoreOut; - - #define AnnounceThrow(msg) \ - fprintf ( xmpCoreOut, "XMP_Throw: %s\n", msg ); fflush ( xmpOut ) - #define AnnounceCatch(msg) \ - fprintf ( xmpCoreOut, "Catch in %s: %s\n", procName, msg ); fflush ( xmpOut ) - - #define AnnounceEntry(proc) \ - const char * procName = proc; \ - fprintf ( xmpCoreOut, "Entering %s\n", procName ); fflush ( xmpOut ) - #define AnnounceNoLock(proc) \ - const char * procName = proc; \ - fprintf ( xmpCoreOut, "Entering %s (no lock)\n", procName ); fflush ( xmpOut ) - #define AnnounceExit() \ - fprintf ( xmpCoreOut, "Exiting %s\n", procName ); fflush ( xmpOut ) - - #define ReportLock() \ - ++sLockCount; fprintf ( xmpCoreOut, " Auto lock, count = %d\n", sLockCount ); fflush ( xmpOut ) - #define ReportUnlock() \ - --sLockCount; fprintf ( xmpCoreOut, " Auto unlock, count = %d\n", sLockCount ); fflush ( xmpOut ) - #define ReportKeepLock() \ - fprintf ( xmpCoreOut, " Keeping lock, count = %d\n", sLockCount ); fflush ( xmpOut ) - -#endif - -#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); } - -// ------------------------------------------------------------------------------------------------- - -#if XMP_WinBuild - typedef CRITICAL_SECTION XMP_Mutex; -#else - // Use pthread for both Mac and generic UNIX. - typedef pthread_mutex_t XMP_Mutex; -#endif - -extern XMP_Mutex sXMPCoreLock; -extern int sLockCount; // Keep signed to catch unlock errors. -extern XMP_VarString * sExceptionMessage; - -extern bool XMP_InitMutex ( XMP_Mutex * mutex ); -extern void XMP_TermMutex ( XMP_Mutex & mutex ); - -extern void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ); -extern void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ); - -class XMP_AutoMutex { -public: - XMP_AutoMutex() : mutex(&sXMPCoreLock) { XMP_EnterCriticalRegion ( *mutex ); ReportLock(); }; - ~XMP_AutoMutex() { if ( mutex != 0 ) { ReportUnlock(); XMP_ExitCriticalRegion ( *mutex ); mutex = 0; } }; - void KeepLock() { ReportKeepLock(); mutex = 0; }; -private: - XMP_Mutex * mutex; -}; - -// *** Switch to XMPEnterObjectWrapper & XMPEnterStaticWrapper, to allow for per-object locks. - -// ! Don't do the initialization check (sXMP_InitCount > 0) for the no-lock case. That macro is used -// ! by WXMPMeta_Initialize_1. - -#define XMP_ENTER_WRAPPER_NO_LOCK(proc) \ - AnnounceNoLock ( proc ); \ - XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \ - try { \ - wResult->errMessage = 0; - -#define XMP_ENTER_WRAPPER(proc) \ - AnnounceEntry ( proc ); \ - XMP_Assert ( sXMP_InitCount > 0 ); \ - XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \ - try { \ - XMP_AutoMutex mutex; \ - wResult->errMessage = 0; - -#define XMP_EXIT_WRAPPER \ - XMP_CATCH_EXCEPTIONS \ - AnnounceExit(); - -#define XMP_EXIT_WRAPPER_KEEP_LOCK(keep) \ - if ( keep ) mutex.KeepLock(); \ - XMP_CATCH_EXCEPTIONS \ - AnnounceExit(); - -#define XMP_EXIT_WRAPPER_NO_THROW \ - } catch ( ... ) { \ - AnnounceCatch ( "no-throw catch-all" ); \ - /* Do nothing. */ \ - } \ - AnnounceExit(); - -#define XMP_CATCH_EXCEPTIONS \ - } catch ( XMP_Error & xmpErr ) { \ - wResult->int32Result = xmpErr.GetID(); \ - wResult->ptrResult = (void*)"XMP"; \ - wResult->errMessage = xmpErr.GetErrMsg(); \ - if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \ - AnnounceCatch ( wResult->errMessage ); \ - } catch ( std::exception & stdErr ) { \ - wResult->int32Result = kXMPErr_StdException; \ - wResult->errMessage = stdErr.what(); \ - if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \ - AnnounceCatch ( wResult->errMessage ); \ - } catch ( ... ) { \ - wResult->int32Result = kXMPErr_UnknownException; \ - wResult->errMessage = "Caught unknown exception"; \ - AnnounceCatch ( wResult->errMessage ); \ - } - -#if XMP_DebugBuild - #define RELEASE_NO_THROW /* empty */ -#else - #define RELEASE_NO_THROW throw() -#endif - -// ================================================================================================= -// ExpandXPath, FindNode, and related support - -// *** Normalize the use of "const xx &" for input params - -#define kXMP_ArrayItemName "[]" - -#define kXMP_CreateNodes true -#define kXMP_ExistingOnly false - -#define FindConstSchema(t,u) FindSchemaNode ( const_cast(t), u, kXMP_ExistingOnly, 0 ) -#define FindConstChild(p,c) FindChildNode ( const_cast(p), c, kXMP_ExistingOnly, 0 ) -#define FindConstQualifier(p,c) FindQualifierNode ( const_cast(p), c, kXMP_ExistingOnly, 0 ) -#define FindConstNode(t,p) FindNode ( const_cast(t), p, kXMP_ExistingOnly, 0 ) - -extern XMP_OptionBits -VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue ); - -extern void -ComposeXPath ( const XMP_ExpandedXPath & expandedXPath, - XMP_VarString * stringXPath ); - -extern void -ExpandXPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propPath, - XMP_ExpandedXPath * expandedXPath ); - -extern XMP_Node * -FindSchemaNode ( XMP_Node * xmpTree, - XMP_StringPtr nsURI, - bool createNodes, - XMP_NodePtrPos * ptrPos = 0 ); - -extern XMP_Node * -FindChildNode ( XMP_Node * parent, - XMP_StringPtr childName, - bool createNodes, - XMP_NodePtrPos * ptrPos = 0 ); - -extern XMP_Node * -FindQualifierNode ( XMP_Node * parent, - XMP_StringPtr qualName, - bool createNodes, - XMP_NodePtrPos * ptrPos = 0 ); - -extern XMP_Node * -FindNode ( XMP_Node * xmpTree, - const XMP_ExpandedXPath & expandedXPath, - bool createNodes, - XMP_OptionBits leafOptions = 0, - XMP_NodePtrPos * ptrPos = 0 ); - -extern XMP_Index -LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang ); // ! Lang must be normalized! - -extern XMP_Index -LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue ); - -extern void -CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ); - -extern XMP_Node * -CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent ); - -extern bool -CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode ); - -extern void -DeleteEmptySchema ( XMP_Node * schemaNode ); - -extern void -NormalizeLangValue ( XMP_VarString * value ); - -extern void -NormalizeLangArray ( XMP_Node * array ); - -extern void -DetectAltText ( XMP_Node * xmpParent ); - -extern void -SortNamedNodes ( XMP_NodeOffspring & nodeVector ); - -static inline bool -IsPathPrefix ( XMP_StringPtr fullPath, XMP_StringPtr prefix ) -{ - bool isPrefix = false; - XMP_StringLen prefixLen = std::strlen(prefix); - if ( XMP_LitNMatch ( prefix, fullPath, prefixLen ) ) { - char separator = fullPath[prefixLen]; - if ( (separator == 0) || (separator == '/') || - (separator == '[') || (separator == '*') ) isPrefix = true; - } - return isPrefix; -} - -// ------------------------------------------------------------------------------------------------- - -class XPathStepInfo { -public: - XMP_VarString step; - XMP_OptionBits options; - XPathStepInfo ( XMP_StringPtr _step, XMP_OptionBits _options ) : step(_step), options(_options) {}; - XPathStepInfo ( XMP_VarString _step, XMP_OptionBits _options ) : step(_step), options(_options) {}; -private: - XPathStepInfo() : options(0) {}; // ! Hide the default constructor. -}; - -enum { kSchemaStep = 0, kRootPropStep = 1, kAliasIndexStep = 2 }; - -enum { // Bits for XPathStepInfo options. // *** Add mask check to init code. - kXMP_StepKindMask = 0x0F, // ! The step kinds are mutually exclusive numbers. - kXMP_StructFieldStep = 0x01, // Also for top level nodes (schema "fields"). - kXMP_QualifierStep = 0x02, // ! Order is significant to separate struct/qual from array kinds! - kXMP_ArrayIndexStep = 0x03, // ! The kinds must not overlay array form bits! - kXMP_ArrayLastStep = 0x04, - kXMP_QualSelectorStep = 0x05, - kXMP_FieldSelectorStep = 0x06, - kXMP_StepIsAlias = 0x10 -}; - -#define GetStepKind(f) ((f) & kXMP_StepKindMask) - -#define kXMP_NewImplicitNode kXMP_InsertAfterItem - -// ================================================================================================= -// XMP_Node details - -#if 0 // Pattern for iterating over the children or qualifiers: - for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) { - const XMP_Node * _curr_ = _node_->_offspring_[xxNum]; - } -#endif - -class XMP_Node { -public: - - XMP_OptionBits options; - XMP_VarString name, value; - XMP_Node * parent; - XMP_NodeOffspring children; - XMP_NodeOffspring qualifiers; - #if XMP_DebugBuild - // *** XMP_StringPtr _namePtr, _valuePtr; // *** Not working, need operator=? - #endif - - XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options ) - : options(_options), name(_name), parent(_parent) - { - #if XMP_DebugBuild - XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) || - (options & kXMP_SchemaNode) || (parent == 0) ); - // *** _namePtr = name.c_str(); - // *** _valuePtr = value.c_str(); - #endif - }; - - XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options ) - : options(_options), name(_name), parent(_parent) - { - #if XMP_DebugBuild - XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) || - (options & kXMP_SchemaNode) || (parent == 0) ); - // *** _namePtr = name.c_str(); - // *** _valuePtr = value.c_str(); - #endif - }; - - XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options ) - : options(_options), name(_name), value(_value), parent(_parent) - { - #if XMP_DebugBuild - XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) || - (options & kXMP_SchemaNode) || (parent == 0) ); - // *** _namePtr = name.c_str(); - // *** _valuePtr = value.c_str(); - #endif - }; - - XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options ) - : options(_options), name(_name), value(_value), parent(_parent) - { - #if XMP_DebugBuild - XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) || - (options & kXMP_SchemaNode) || (parent == 0) ); - // *** _namePtr = name.c_str(); - // *** _valuePtr = value.c_str(); - #endif - }; - - void RemoveChildren() - { - for ( size_t i = 0, vLim = children.size(); i < vLim; ++i ) { - if ( children[i] != 0 ) delete children[i]; - } - children.clear(); - } - - void RemoveQualifiers() - { - for ( size_t i = 0, vLim = qualifiers.size(); i < vLim; ++i ) { - if ( qualifiers[i] != 0 ) delete qualifiers[i]; - } - qualifiers.clear(); - } - - void ClearNode() - { - options = 0; - name.erase(); - value.erase(); - this->RemoveChildren(); - this->RemoveQualifiers(); - } - - virtual ~XMP_Node() { RemoveChildren(); RemoveQualifiers(); }; - -private: - XMP_Node() : options(0), parent(0) // ! Make sure parent pointer is always set. - { - #if XMP_DebugBuild - // *** _namePtr = name.c_str(); - // *** _valuePtr = value.c_str(); - #endif - }; - -}; - -class XMP_AutoNode { // Used to hold a child during subtree construction. -public: - XMP_Node * nodePtr; - XMP_AutoNode() : nodePtr(0) {}; - ~XMP_AutoNode() { if ( nodePtr != 0 ) delete ( nodePtr ); nodePtr = 0; }; - XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options ) - : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {}; - XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options ) - : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {}; - XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options ) - : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {}; - XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options ) - : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {}; -}; - -extern void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & xmlTree, XMP_OptionBits options ); - -// ================================================================================================= - -#endif // __XMPCore_Impl_hpp__ diff --git a/xmpsdk/src/XMPIterator.cpp b/xmpsdk/src/XMPIterator.cpp deleted file mode 100644 index ea39602a5c..0000000000 --- a/xmpsdk/src/XMPIterator.cpp +++ /dev/null @@ -1,736 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPIterator.hpp" - -#include -#include // For snprintf. - -#if XMP_WinBuild - #ifdef _MSC_VER - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #pragma warning ( disable : 4996 ) // '...' was declared deprecated - #endif -#endif - -// ================================================================================================= -// Support Routines -// ================================================================================================= - - -#ifndef TraceIterators - #define TraceIterators 0 -#endif - -#if TraceIterators - static const char * sStageNames[] = { "before", "self", "qualifiers", "children" }; -#endif - -static XMP_Node * sDummySchema = 0; // ! Used for some ugliness with aliases. - -// ------------------------------------------------------------------------------------------------- -// AddSchemaProps -// -------------- -// -// Add the top level properties to the IterNode for a schema. - -static void -AddSchemaProps ( IterInfo & info, IterNode & iterSchema, const XMP_Node * xmpSchema ) -{ - UNUSED(info); - #if TraceIterators - printf ( " Adding properties of %s\n", xmpSchema->name.c_str() ); - #endif - - for ( size_t propNum = 0, propLim = xmpSchema->children.size(); propNum != propLim; ++propNum ) { - const XMP_Node * xmpProp = xmpSchema->children[propNum]; - // *** set the has-aliases bit when appropriate - iterSchema.children.push_back ( IterNode ( xmpProp->options, xmpProp->name, 0 ) ); - #if TraceIterators - printf ( " %s\n", xmpProp->name.c_str() ); - #endif - } - -} // AddSchemaProps - -// ------------------------------------------------------------------------------------------------- -// AddSchemaAliases -// ---------------- -// -// Add the aliases to the IterNode for a schema, if the corresponding actual exists. - -static void -AddSchemaAliases ( IterInfo & info, IterNode & iterSchema, XMP_StringPtr schemaURI ) -{ - - // We're showing the aliases also. Look them up by their namespace prefix. Yes, the alias map is - // sorted so we could process just that portion. But that takes more code and the extra speed - // isn't worth it. (Plus this way we avoid a dependence on the map implementation.) Lookup the - // XMP node from the alias, to make sure the actual exists. - - #if TraceIterators - printf ( " Adding aliases\n", schemaURI ); - #endif - - XMP_StringPtr nsPrefix; - XMP_StringLen nsLen; - bool found = XMPMeta::GetNamespacePrefix ( schemaURI, &nsPrefix, &nsLen ); - if ( ! found ) XMP_Throw ( "Unknown iteration namespace", kXMPErr_BadSchema ); - - XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin(); - XMP_AliasMapPos endAlias = sRegisteredAliasMap->end(); - - for ( ; currAlias != endAlias; ++currAlias ) { - if ( XMP_LitNMatch ( currAlias->first.c_str(), nsPrefix, nsLen ) ) { - const XMP_Node * actualProp = FindConstNode ( &info.xmpObj->tree, currAlias->second ); - if ( actualProp != 0 ) { - iterSchema.children.push_back ( IterNode ( (actualProp->options | kXMP_PropIsAlias), currAlias->first, 0 ) ); - #if TraceIterators - printf ( " %s => %s\n", currAlias->first.c_str(), actualProp->name.c_str() ); - #endif - } - } - } - -} // AddSchemaAliases - -// ------------------------------------------------------------------------------------------------- -// AddNodeOffspring -// ---------------- -// -// Add the immediate children and qualifiers to an IterNode. - -static void -AddNodeOffspring ( IterInfo & info, IterNode & iterParent, const XMP_Node * xmpParent ) -{ - XMP_VarString currPath ( iterParent.fullPath ); - size_t leafOffset = iterParent.fullPath.size(); - - if ( (! xmpParent->qualifiers.empty()) && (! (info.options & kXMP_IterOmitQualifiers)) ) { - - #if TraceIterators - printf ( " Adding qualifiers of %s\n", currPath.c_str() ); - #endif - - currPath += "/?"; // All qualifiers are named and use paths like "Prop/?Qual". - leafOffset += 2; - - for ( size_t qualNum = 0, qualLim = xmpParent->qualifiers.size(); qualNum != qualLim; ++qualNum ) { - const XMP_Node * xmpQual = xmpParent->qualifiers[qualNum]; - currPath += xmpQual->name; - iterParent.qualifiers.push_back ( IterNode ( xmpQual->options, currPath, leafOffset ) ); - currPath.erase ( leafOffset ); - #if TraceIterators - printf ( " %s\n", xmpQual->name.c_str() ); - #endif - } - - leafOffset -= 2; - currPath.erase ( leafOffset ); - - } - - if ( ! xmpParent->children.empty() ) { - - #if TraceIterators - printf ( " Adding children of %s\n", currPath.c_str() ); - #endif - - XMP_Assert ( xmpParent->options & kXMP_PropCompositeMask ); - - if ( xmpParent->options & kXMP_PropValueIsStruct ) { - currPath += '/'; - leafOffset += 1; - } - - for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) { - const XMP_Node * xmpChild = xmpParent->children[childNum]; - if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) { - currPath += xmpChild->name; - } else { - char buffer [32]; // AUDIT: Using sizeof(buffer) below for snprintf length is safe. - snprintf ( buffer, sizeof(buffer), "[%lu]", static_cast(childNum+1) ); // ! XPath indices are one-based. - currPath += buffer; - } - iterParent.children.push_back ( IterNode ( xmpChild->options, currPath, leafOffset ) ); - currPath.erase ( leafOffset ); - #if TraceIterators - printf ( " %s\n", (iterParent.children.back().fullPath.c_str() + leafOffset) ); - #endif - } - - } - -} // AddNodeOffspring - -// ------------------------------------------------------------------------------------------------- -// SetCurrSchema -// ------------- - -static inline void -SetCurrSchema ( IterInfo & info, XMP_StringPtr schemaName ) -{ - - info.currSchema = schemaName; - #if 0 // *** XMP_DebugBuild - info._schemaPtr = info.currSchema.c_str(); - #endif - -} // SetCurrSchema - -static inline void -SetCurrSchema ( IterInfo & info, XMP_VarString & schemaName ) -{ - - info.currSchema = schemaName; - #if 0 // *** XMP_DebugBuild - info._schemaPtr = info.currSchema.c_str(); - #endif - -} // SetCurrSchema - -// ------------------------------------------------------------------------------------------------- -// AdvanceIterPos -// -------------- -// -// Adjust currPos and possibly endPos for the next step in a pre-order depth-first traversal. The -// current node has just been visited, move on to its qualifiers, children, then siblings, or back -// up to an ancestor. AdvanceIterPos either moves to a property or qualifier node that can be -// visited, or to the end of the entire iteration. - -static void -AdvanceIterPos ( IterInfo & info ) -{ - // ------------------------------------------------------------------------------------------- - // Keep looking until we find a node to visit or the end of everything. The first time through - // the current node will exist, we just visited it. But we have to keep looking if the current - // node was the last of its siblings or is an empty schema. - - // ! It is possible that info.currPos == info.endPos on entry. Don't dereference info.currPos yet! - - while ( true ) { - - if ( info.currPos == info.endPos ) { - - // ------------------------------------------------------------------------------------ - // At the end of a set of siblings, move up to an ancestor. We've either just finished - // the qualifiers and will move to the children, or have just finished the children and - // will move on to the next sibling. - - if ( info.ancestors.empty() ) break; // We're at the end of the schema list. - - IterPosPair & parent = info.ancestors.back(); - info.currPos = parent.first; - info.endPos = parent.second; - info.ancestors.pop_back(); - - #if TraceIterators - printf ( " Moved up to %s, stage = %s\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] ); - #endif - - } else { - - // ------------------------------------------------------------------------------------------- - // Decide what to do with this iteration node based on its state. Don't use a switch statement, - // some of the cases want to break from the loop. A break in a switch just exits the case. - - #if TraceIterators - printf ( " Moving from %s, stage = %s\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] ); - #endif - - if ( info.currPos->visitStage == kIter_BeforeVisit ) { // Visit this node now. - if ( info.currPos->options & kXMP_SchemaNode ) SetCurrSchema ( info, info.currPos->fullPath ); - break; - } - - if ( info.currPos->visitStage == kIter_VisitSelf ) { // Just finished visiting the value portion. - info.currPos->visitStage = kIter_VisitQualifiers; // Start visiting the qualifiers. - if ( ! info.currPos->qualifiers.empty() ) { - info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) ); - info.endPos = info.currPos->qualifiers.end(); // ! Set the parent's endPos before changing currPos! - info.currPos = info.currPos->qualifiers.begin(); - break; - } - } - - if ( info.currPos->visitStage == kIter_VisitQualifiers ) { // Just finished visiting the qualifiers. - info.currPos->qualifiers.clear(); - info.currPos->visitStage = kIter_VisitChildren; // Start visiting the children. - if ( ! info.currPos->children.empty() ) { - info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) ); - info.endPos = info.currPos->children.end(); // ! Set the parent's endPos before changing currPos! - info.currPos = info.currPos->children.begin(); - break; - } - } - - if ( info.currPos->visitStage == kIter_VisitChildren ) { // Just finished visiting the children. - info.currPos->children.clear(); - ++info.currPos; // Move to the next sibling. - continue; - } - - #if TraceIterators - if ( info.currPos != info.endPos ) { - printf ( " Moved to %s, stage = %s\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] ); - } - #endif - - } - - } // Loop to find the next node. - - XMP_Assert ( (info.currPos == info.endPos) || (info.currPos->visitStage == kIter_BeforeVisit) ); - -} // AdvanceIterPos - -// ------------------------------------------------------------------------------------------------- -// GetNextXMPNode -// -------------- -// -// Used by XMPIterator::Next to obtain the next XMP node, ignoring the kXMP_IterJustLeafNodes flag. -// This isolates some messy code, allowing a clean loop in Next if kXMP_IterJustLeafNodes is set. - -static const XMP_Node * -GetNextXMPNode ( IterInfo & info ) -{ - const XMP_Node * xmpNode = 0; - - // ---------------------------------------------------------------------------------------------- - // On entry currPos points to an iteration node whose state is either before-visit or visit-self. - // If it is before-visit then we will return that node's value part now. If it is visit-self it - // means the previous iteration returned the value portion of that node, so we can advance to the - // next node in the iteration tree. Then we find the corresponding XMP node, allowing for the XMP - // tree to have been modified since that part of the iteration tree was constructed. - - // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP - // ! node for the schema, but we still have to visit it because of possible aliases. The static - // ! sDummySchema is returned if there is no real schema node. - - if ( info.currPos->visitStage != kIter_BeforeVisit ) AdvanceIterPos ( info ); - - bool isSchemaNode = false; - XMP_ExpandedXPath expPath; // Keep outside the loop to avoid constant construct/destruct. - - while ( info.currPos != info.endPos ) { - - isSchemaNode = XMP_NodeIsSchema ( info.currPos->options ); - if ( isSchemaNode ) { - SetCurrSchema ( info, info.currPos->fullPath ); - xmpNode = FindConstSchema ( &info.xmpObj->tree, info.currPos->fullPath.c_str() ); - if ( xmpNode == 0 ) xmpNode = sDummySchema; - } else { - ExpandXPath ( info.currSchema.c_str(), info.currPos->fullPath.c_str(), &expPath ); - xmpNode = FindConstNode ( &info.xmpObj->tree, expPath ); - } - if ( xmpNode != 0 ) break; // Exit the loop, we found a live XMP node. - - info.currPos->visitStage = kIter_VisitChildren; // Make AdvanceIterPos move to the next sibling. - info.currPos->children.clear(); - info.currPos->qualifiers.clear(); - AdvanceIterPos ( info ); - - } - - if ( info.currPos == info.endPos ) return 0; - - // ------------------------------------------------------------------------------------------- - // Now we've got the iteration node and corresponding XMP node. Add the iteration children for - // structs and arrays. The children of schema were added when the iterator was constructed. - - XMP_Assert ( info.currPos->visitStage == kIter_BeforeVisit ); - - if ( info.currPos->visitStage == kIter_BeforeVisit ) { - if ( (! isSchemaNode) && (! (info.options & kXMP_IterJustChildren)) ) { - AddNodeOffspring ( info, *info.currPos, xmpNode ); - } - info.currPos->visitStage = kIter_VisitSelf; - } - - return xmpNode; - -} // GetNextXMPNode - -// ================================================================================================= -// Init/Term -// ================================================================================================= - -// ------------------------------------------------------------------------------------------------- -// Initialize -// ---------- - -/* class static */ bool -XMPIterator::Initialize() -{ - sDummySchema = new XMP_Node ( 0, "dummy:schema/", kXMP_SchemaNode); - return true; - -} // Initialize - -// ------------------------------------------------------------------------------------------------- -// Terminate -// ---------- - -/* class static */ void -XMPIterator::Terminate() RELEASE_NO_THROW -{ - delete ( sDummySchema ); - sDummySchema = 0; - return; - -} // Terminate - -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ - -void -XMPIterator::Unlock ( XMP_OptionBits options ) -{ - UNUSED(options); - - XMPMeta::Unlock ( 0 ); - -} // Unlock - -// ================================================================================================= -// Constructors -// ================================================================================================= - -// ------------------------------------------------------------------------------------------------- -// XMPIterator -// ----------- -// -// Constructor for iterations over the nodes in an XMPMeta object. This builds a tree of iteration -// nodes that caches the existing node names of the XMPMeta object. The iteration tree is a partial -// replica of the XMPMeta tree. The initial iteration tree normally has just the root node, all of -// the schema nodes for a full object iteration. Lower level nodes (children and qualifiers) are -// added when the parent is visited. If the kXMP_IterJustChildren option is passed then the initial -// iterator includes the children and the parent is marked as done. The iteration tree nodes are -// pruned when they are no longer needed. - -XMPIterator::XMPIterator ( const XMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ) : clientRefs(0), info(IterInfo(options,&xmpObj)) -{ - if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) { - XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions ); - } - - // *** Lock the XMPMeta object if we ever stop using a full DLL lock. - - if ( *propName != 0 ) { - - // An iterator rooted at a specific node. - - #if TraceIterators - printf ( "\nNew XMP property iterator for \"%s\", options = %X\n Schema = %s, root = %s\n", - xmpObj.tree.name.c_str(), options, schemaNS, propName ); - #endif - - XMP_ExpandedXPath propPath; - ExpandXPath ( schemaNS, propName, &propPath ); - XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath ); // If not found get empty iteration. - - if ( propNode != 0 ) { - - XMP_VarString rootName ( propPath[1].step ); // The schema is [0]. - for ( size_t i = 2; i < propPath.size(); ++i ) { - XMP_OptionBits stepKind = GetStepKind ( propPath[i].options ); - if ( stepKind <= kXMP_QualifierStep ) rootName += '/'; - rootName += propPath[i].step; - } - - propName = rootName.c_str(); - size_t leafOffset = rootName.size(); - while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset; - if ( propName[leafOffset] == '/' ) ++leafOffset; - - info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) ); - SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() ); - if ( info.options & kXMP_IterJustChildren ) { - AddNodeOffspring ( info, info.tree.children.back(), propNode ); - } - - } - - } else if ( *schemaNS != 0 ) { - - // An iterator for all properties in one schema. - - #if TraceIterators - printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n Schema = %s\n", - xmpObj.tree.name.c_str(), options, schemaNS ); - #endif - - info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) ); - IterNode & iterSchema = info.tree.children.back(); - - XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS ); - if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema ); - - if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS ); - - if ( iterSchema.children.empty() ) { - info.tree.children.pop_back(); // No properties, remove the schema node. - } else { - SetCurrSchema ( info, schemaNS ); - } - - } else { - - // An iterator for all properties in all schema. First add schema that exist (have children), - // adding aliases from them if appropriate. Then add schema that have no actual properties - // but do have aliases to existing properties, if we're including aliases in the iteration. - - #if TraceIterators - printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n", - xmpObj.tree.name.c_str(), options ); - #endif - - // First pick up the schema that exist. - - for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) { - - const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum]; - info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) ); - IterNode & iterSchema = info.tree.children.back(); - - if ( ! (info.options & kXMP_IterJustChildren) ) { - AddSchemaProps ( info, iterSchema, xmpSchema ); - if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() ); - if ( iterSchema.children.empty() ) info.tree.children.pop_back(); // No properties, remove the schema node. - } - - } - - if ( info.options & kXMP_IterIncludeAliases ) { - - // Add the schema that only have aliases. The most convenient, and safest way, is to go - // through the registered namespaces, see if it exists, and let AddSchemaAliases do its - // thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff - // be in storage order (not subject to the namespace map order). - - // ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The - // ! existing schema (presumably) have actual children. We need to call AddSchemaAliases - // ! here to determine if the namespace has any aliases to existing properties. We then - // ! strip the children if necessary. - - XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin(); - XMP_cStringMapPos endNS = sNamespaceURIToPrefixMap->end(); - for ( ; currNS != endNS; ++currNS ) { - XMP_StringPtr schemaName = currNS->first.c_str(); - if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue; - info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) ); - IterNode & iterSchema = info.tree.children.back(); - AddSchemaAliases ( info, iterSchema, schemaName ); - if ( iterSchema.children.empty() ) { - info.tree.children.pop_back(); // No aliases, remove the schema node. - } else if ( info.options & kXMP_IterJustChildren ) { - iterSchema.children.clear(); // Get rid of the children. - } - } - - } - - } - - // Set the current iteration position to the first node to be visited. - - info.currPos = info.tree.children.begin(); - info.endPos = info.tree.children.end(); - - if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) { - info.currPos->visitStage = kIter_VisitSelf; - } - - #if TraceIterators - if ( info.currPos == info.endPos ) { - printf ( " ** Empty iteration **\n" ); - } else { - printf ( " Initial node %s, stage = %s, iterator @ %.8X\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this ); - } - #endif - -} // XMPIterator for XMPMeta objects - -// ------------------------------------------------------------------------------------------------- -// XMPIterator -// ----------- -// -// Constructor for iterations over global tables such as registered namespaces or aliases. - -XMPIterator::XMPIterator ( XMP_StringPtr /*schemaNS*/, - XMP_StringPtr /*propName*/, - XMP_OptionBits options ) : clientRefs(0), info(IterInfo(options,0)) -{ - - XMP_Throw ( "Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented ); - -} // XMPIterator for global tables - -// ------------------------------------------------------------------------------------------------- -// ~XMPIterator -// ----------- - -XMPIterator::~XMPIterator() RELEASE_NO_THROW -{ - XMP_Assert ( this->clientRefs <= 0 ); - // Let everything else default. - -} // ~XMPIterator - -// ================================================================================================= -// Iteration Methods -// ================================================================================================= - -// ------------------------------------------------------------------------------------------------- -// Next -// ---- -// -// Do a preorder traversal of the cached nodes. - -// *** Need to document the relationships between currPos, endPos, and visitStage. - -bool -XMPIterator::Next ( XMP_StringPtr * schemaNS, - XMP_StringLen * nsSize, - XMP_StringPtr * propPath, - XMP_StringLen * pathSize, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * propOptions ) -{ - // *** Lock the XMPMeta object if we ever stop using a full DLL lock. - - // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP - // ! node for the schema, but we still have to visit it because of possible aliases. - - if ( info.currPos == info.endPos ) return false; // Happens at the start of an empty iteration. - - #if TraceIterators - printf ( "Next iteration from %s, stage = %s, iterator @ %.8X\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this ); - #endif - - const XMP_Node * xmpNode = GetNextXMPNode ( info ); - if ( xmpNode == 0 ) return false; - bool isSchemaNode = XMP_NodeIsSchema ( info.currPos->options ); - - if ( info.options & kXMP_IterJustLeafNodes ) { - while ( isSchemaNode || (! xmpNode->children.empty()) ) { - info.currPos->visitStage = kIter_VisitQualifiers; // Skip to this node's children. - xmpNode = GetNextXMPNode ( info ); - if ( xmpNode == 0 ) return false; - isSchemaNode = XMP_NodeIsSchema ( info.currPos->options ); - } - } - - *schemaNS = info.currSchema.c_str(); - *nsSize = info.currSchema.size(); - - *propOptions = info.currPos->options; - - *propPath = ""; - *pathSize = 0; - *propValue = ""; - *valueSize = 0; - - if ( ! (*propOptions & kXMP_SchemaNode) ) { - - *propPath = info.currPos->fullPath.c_str(); - *pathSize = info.currPos->fullPath.size(); - if ( info.options & kXMP_IterJustLeafName ) { - *propPath += info.currPos->leafOffset; - *pathSize -= info.currPos->leafOffset; - } - - if ( ! (*propOptions & kXMP_PropCompositeMask) ) { - *propValue = xmpNode->value.c_str(); - *valueSize = xmpNode->value.size(); - } - - } - - #if TraceIterators - printf ( " Next node %s, stage = %s\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] ); - #endif - - return true; - -} // Next - -// ------------------------------------------------------------------------------------------------- -// Skip -// ---- -// -// Skip some portion of the traversal related to the last visited node. We skip either that node's -// children, or those children and the previous node's siblings. The implementation might look a bit -// awkward because info.currNode always points to the next node to be visited. We might already have -// moved past the things to skip, e.g. if the previous node was simple and the last of its siblings. - -enum { - kXMP_ValidIterSkipOptions = kXMP_IterSkipSubtree | kXMP_IterSkipSiblings -}; - -void -XMPIterator::Skip ( XMP_OptionBits iterOptions ) -{ -// if ( (info.currPos == kIter_NullPos) ) XMP_Throw ( "No prior postion to skip from", kXMPErr_BadIterPosition ); - if ( iterOptions == 0 ) XMP_Throw ( "Must specify what to skip", kXMPErr_BadOptions ); - if ( (iterOptions & ~kXMP_ValidIterSkipOptions) != 0 ) XMP_Throw ( "Undefined options", kXMPErr_BadOptions ); - - #if TraceIterators - printf ( "Skipping from %s, stage = %s, iterator @ %.8X", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this ); - #endif - - if ( iterOptions & kXMP_IterSkipSubtree ) { - #if TraceIterators - printf ( ", mode = subtree\n" ); - #endif - info.currPos->visitStage = kIter_VisitChildren; - } else if ( iterOptions & kXMP_IterSkipSiblings ) { - #if TraceIterators - printf ( ", mode = siblings\n" ); - #endif - info.currPos = info.endPos; - AdvanceIterPos ( info ); - } - #if TraceIterators - printf ( " Skipped to %s, stage = %s\n", - info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] ); - #endif - - -} // Skip - -// ------------------------------------------------------------------------------------------------- -// UnlockIter -// ---------- - -void -XMPIterator::UnlockIter ( XMP_OptionBits options ) -{ - UNUSED(options); - - XMPMeta::Unlock ( 0 ); - -} // UnlockIter - -// ================================================================================================= diff --git a/xmpsdk/src/XMPIterator.hpp b/xmpsdk/src/XMPIterator.hpp deleted file mode 100644 index b72b975350..0000000000 --- a/xmpsdk/src/XMPIterator.hpp +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef __XMPIterator_hpp__ -#define __XMPIterator_hpp__ - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" -#include "XMP_Const.h" -#include "XMPMeta.hpp" - -// ================================================================================================= - -struct IterNode; -typedef std::vector < IterNode > IterOffspring; -typedef IterOffspring::iterator IterPos; - -typedef std::pair < IterPos, IterPos > IterPosPair; -typedef std::vector < IterPosPair > IterPosStack; - -enum { // Values for the visitStage field, used to decide how to proceed past a node. - kIter_BeforeVisit = 0, // Have not visited this node at all. - kIter_VisitSelf = 1, // Have visited this node and returned its value/options portion. - kIter_VisitQualifiers = 2, // In the midst of visiting this node's qualifiers. - kIter_VisitChildren = 3 // In the midst of visiting this node's children. -}; - -struct IterNode { - - XMP_OptionBits options; - XMP_VarString fullPath; - size_t leafOffset; - IterOffspring children, qualifiers; - XMP_Uns8 visitStage; - #if 0 // *** XMP_DebugBuild - XMP_StringPtr _pathPtr, _leafPtr; // *** Not working, need operator=? - #endif - - IterNode() : options(0), leafOffset(0), visitStage(kIter_BeforeVisit) - { - #if 0 // *** XMP_DebugBuild - _pathPtr = _leafPtr = 0; - #endif - }; - - IterNode ( XMP_OptionBits _options, const XMP_VarString& _fullPath, size_t _leafOffset ) - : options(_options), fullPath(_fullPath), leafOffset(_leafOffset), visitStage(kIter_BeforeVisit) - { - #if 0 // *** XMP_DebugBuild - _pathPtr = fullPath.c_str(); - _leafPtr = _pathPtr + leafOffset; - #endif - }; - -}; - -struct IterInfo { - - XMP_OptionBits options; - const XMPMeta * xmpObj; - XMP_VarString currSchema; - IterPos currPos, endPos; - IterPosStack ancestors; - IterNode tree; - #if 0 // *** XMP_DebugBuild - XMP_StringPtr _schemaPtr; // *** Not working, need operator=? - #endif - - IterInfo() : options(0), xmpObj(0) - { - #if 0 // *** XMP_DebugBuild - _schemaPtr = 0; - #endif - }; - - IterInfo ( XMP_OptionBits _options, const XMPMeta * _xmpObj ) : options(_options), xmpObj(_xmpObj) - { - #if 0 // *** XMP_DebugBuild - _schemaPtr = 0; - #endif - }; - -}; - -// ================================================================================================= - -class XMPIterator { -public: - - static bool - Initialize(); // ! For internal use only! - - static void - Terminate() RELEASE_NO_THROW; // ! For internal use only! - - static void - Unlock ( XMP_OptionBits options ); - - XMPIterator ( const XMPMeta & xmpObj, // Construct a property iterator. - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ); - - XMPIterator ( XMP_StringPtr schemaNS, // Construct a table iterator. - XMP_StringPtr propName, - XMP_OptionBits options ); - - virtual ~XMPIterator() RELEASE_NO_THROW; - - bool - Next ( XMP_StringPtr * schemaNS, - XMP_StringLen * nsSize, - XMP_StringPtr * propPath, - XMP_StringLen * pathSize, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * propOptions ); - - void - Skip ( XMP_OptionBits options ); - - void - UnlockIter ( XMP_OptionBits options ); - - // ! Expose so that wrappers and file static functions can see the data. - - XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0. - IterInfo info; - -private: - - // ! These are hidden on purpose: - XMPIterator() : clientRefs(0) - { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); }; - XMPIterator ( const XMPIterator & /* original */ ) : clientRefs(0) - { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); }; - void operator= ( const XMPIterator & /* rhs */ ) - { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); }; - -}; - -// ================================================================================================= - -#endif // __XMPIterator_hpp__ diff --git a/xmpsdk/src/XMPMeta-GetSet.cpp b/xmpsdk/src/XMPMeta-GetSet.cpp deleted file mode 100644 index 9972f9e6e6..0000000000 --- a/xmpsdk/src/XMPMeta-GetSet.cpp +++ /dev/null @@ -1,1212 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// -// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of -// one format in a file with a different format', inventors: Sean Parent, Greg Gilley. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPMeta.hpp" -#include "XMPIterator.hpp" -#include "XMPUtils.hpp" - -#include "XMP_Version.h" -#include "UnicodeInlines.incl_cpp" -#include "UnicodeConversions.hpp" -#include "ExpatAdapter.hpp" - -#if XMP_DebugBuild - #include -#endif - -using namespace std; - -#if XMP_WinBuild - #ifdef _MSC_VER - #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...' - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #endif -#endif - - -// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros -// *** Add debug codegen checks, e.g. that typical masking operations really work -// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch - - -// ================================================================================================= -// Local Types and Constants -// ========================= - -typedef unsigned char XMP_CLTMatch; - -enum { // Values for XMP_CLTMatch. - kXMP_CLT_NoValues, - kXMP_CLT_SpecificMatch, - kXMP_CLT_SingleGeneric, - kXMP_CLT_MultipleGeneric, - kXMP_CLT_XDefault, - kXMP_CLT_FirstItem -}; - - -// ================================================================================================= -// Static Variables -// ================ - - -// ================================================================================================= -// Local Utilities -// =============== - - -// ------------------------------------------------------------------------------------------------- -// SetNodeValue -// ------------ - -static inline void -SetNodeValue ( XMP_Node * node, XMP_StringPtr value ) -{ - - #if XMP_DebugBuild // ! Hack to force an assert. - if ( (node->name == "xmp:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) { - XMP_Assert ( node->name != "xmp:TestAssertNotify" ); - } - #endif - - node->value = value; - - XMP_Uns8* chPtr = (XMP_Uns8*) node->value.c_str(); // Check for valid UTF-8, replace ASCII controls with a space. - while ( *chPtr != 0 ) { - while ( (*chPtr != 0) && (*chPtr < 0x80) ) { - if ( *chPtr < 0x20 ) { - if ( (*chPtr != kTab) && (*chPtr != kLF) && (*chPtr != kCR) ) *chPtr = 0x20; - } else if (*chPtr == 0x7F ) { - *chPtr = 0x20; - } - ++chPtr; - } - XMP_Assert ( (*chPtr == 0) || (*chPtr >= 0x80) ); - if ( *chPtr != 0 ) (void) GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8. - } - - if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &node->value ); - - #if 0 // *** XMP_DebugBuild - node->_valuePtr = node->value.c_str(); - #endif - -} // SetNodeValue - - -// ------------------------------------------------------------------------------------------------- -// SetNode -// ------- -// -// The internals for SetProperty and related calls, used after the node is found or created. - -static void -SetNode ( XMP_Node * node, XMP_StringPtr value, XMP_OptionBits options ) -{ - if ( options & kXMP_DeleteExisting ) { - XMP_ClearOption ( options, kXMP_DeleteExisting ); - node->options = options; - node->value.erase(); - node->RemoveChildren(); - node->RemoveQualifiers(); - } - - node->options |= options; // Keep options set by FindNode when creating a new node. - - if ( value != 0 ) { - - // This is setting the value of a leaf node. - if ( node->options & kXMP_PropCompositeMask ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath ); - XMP_Assert ( node->children.empty() ); - SetNodeValue ( node, value ); - - } else { - - // This is setting up an array or struct. - if ( ! node->value.empty() ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath ); - if ( node->options & kXMP_PropCompositeMask ) { // Can't change an array to a struct, or vice versa. - if ( (options & kXMP_PropCompositeMask) != (node->options & kXMP_PropCompositeMask) ) { - XMP_Throw ( "Requested and existing composite form mismatch", kXMPErr_BadXPath ); - } - } - node->RemoveChildren(); - - } - -} // SetNode - - -// ------------------------------------------------------------------------------------------------- -// DoSetArrayItem -// -------------- - -static void -DoSetArrayItem ( XMP_Node * arrayNode, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options ) -{ - XMP_OptionBits itemLoc = options & kXMP_PropArrayLocationMask; - XMP_Index arraySize = arrayNode->children.size(); - - options &= ~kXMP_PropArrayLocationMask; - options = VerifySetOptions ( options, itemValue ); - - // Now locate or create the item node and set the value. Note the index parameter is one-based! - // The index can be in the range [0..size+1] or "last", normalize it and check the insert flags. - // The order of the normalization checks is important. If the array is empty we end up with an - // index and location to set item size+1. - - XMP_Node * itemNode = 0; - - if ( itemIndex == kXMP_ArrayLastItem ) itemIndex = arraySize; - if ( (itemIndex == 0) && (itemLoc == kXMP_InsertAfterItem) ) { - itemIndex = 1; - itemLoc = kXMP_InsertBeforeItem; - } - if ( (itemIndex == arraySize) && (itemLoc == kXMP_InsertAfterItem) ) { - itemIndex += 1; - itemLoc = 0; - } - if ( (itemIndex == arraySize+1) && (itemLoc == kXMP_InsertBeforeItem) ) itemLoc = 0; - - if ( itemIndex == arraySize+1 ) { - - if ( itemLoc != 0 ) XMP_Throw ( "Can't insert before or after implicit new item", kXMPErr_BadIndex ); - itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 ); - arrayNode->children.push_back ( itemNode ); - - } else { - - if ( (itemIndex < 1) || (itemIndex > arraySize) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadIndex ); - --itemIndex; // ! Convert the index to a C zero-based value! - if ( itemLoc == 0 ) { - itemNode = arrayNode->children[itemIndex]; - } else { - XMP_NodePtrPos itemPos = arrayNode->children.begin() + itemIndex; - if ( itemLoc == kXMP_InsertAfterItem ) ++itemPos; - itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 ); - itemPos = arrayNode->children.insert ( itemPos, itemNode ); - } - - } - - SetNode ( itemNode, itemValue, options ); - -} // DoSetArrayItem - - -// ------------------------------------------------------------------------------------------------- -// ChooseLocalizedText -// ------------------- -// -// 1. Look for an exact match with the specific language. -// 2. If a generic language is given, look for partial matches. -// 3. Look for an "x-default" item. -// 4. Choose the first item. - -static XMP_CLTMatch -ChooseLocalizedText ( const XMP_Node * arrayNode, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - const XMP_Node * * itemNode ) -{ - const XMP_Node * currItem = 0; - const size_t itemLim = arrayNode->children.size(); - size_t itemNum; - - // See if the array has the right form. Allow empty alt arrays, that is what parsing returns. - // *** Should check alt-text bit when that is reliably maintained. - - if ( ! ( XMP_ArrayIsAltText(arrayNode->options) || - (arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options)) ) ) { - XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath ); - } - if ( arrayNode->children.empty() ) { - *itemNode = 0; - return kXMP_CLT_NoValues; - } - - for ( itemNum = 0; itemNum < itemLim; ++itemNum ) { - currItem = arrayNode->children[itemNum]; - if ( currItem->options & kXMP_PropCompositeMask ) { - XMP_Throw ( "Alt-text array item is not simple", kXMPErr_BadXPath ); - } - if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) { - XMP_Throw ( "Alt-text array item has no language qualifier", kXMPErr_BadXPath ); - } - } - - // Look for an exact match with the specific language. - for ( itemNum = 0; itemNum < itemLim; ++itemNum ) { - currItem = arrayNode->children[itemNum]; - if ( currItem->qualifiers[0]->value == specificLang ) { - *itemNode = currItem; - return kXMP_CLT_SpecificMatch; - } - } - - if ( *genericLang != 0 ) { - - // Look for the first partial match with the generic language. - const size_t genericLen = strlen ( genericLang ); - for ( itemNum = 0; itemNum < itemLim; ++itemNum ) { - currItem = arrayNode->children[itemNum]; - XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str(); - const size_t currLangSize = currItem->qualifiers[0]->value.size(); - if ( (currLangSize >= genericLen) && - XMP_LitNMatch ( currLang, genericLang, genericLen ) && - ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) { - *itemNode = currItem; - break; // ! Don't return, need to look for other matches. - } - } - - if ( itemNum < itemLim ) { - - // Look for a second partial match with the generic language. - for ( ++itemNum; itemNum < itemLim; ++itemNum ) { - currItem = arrayNode->children[itemNum]; - XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str(); - const size_t currLangSize = currItem->qualifiers[0]->value.size(); - if ( (currLangSize >= genericLen) && - XMP_LitNMatch ( currLang, genericLang, genericLen ) && - ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) { - return kXMP_CLT_MultipleGeneric; // ! Leave itemNode with the first partial match. - } - } - return kXMP_CLT_SingleGeneric; // No second partial match was found. - - } - - } - - // Look for an 'x-default' item. - for ( itemNum = 0; itemNum < itemLim; ++itemNum ) { - currItem = arrayNode->children[itemNum]; - if ( currItem->qualifiers[0]->value == "x-default" ) { - *itemNode = currItem; - return kXMP_CLT_XDefault; - } - } - - // Everything failed, choose the first item. - *itemNode = arrayNode->children[0]; - return kXMP_CLT_FirstItem; - -} // ChooseLocalizedText - - -// ------------------------------------------------------------------------------------------------- -// AppendLangItem -// -------------- - -static void -AppendLangItem ( XMP_Node * arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue ) -{ - XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue, (kXMP_PropHasQualifiers | kXMP_PropHasLang) ); - XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", itemLang, kXMP_PropIsQualifier ); - newItem->qualifiers.push_back ( langQual ); - - if ( (arrayNode->children.empty()) || (langQual->value != "x-default") ) { - arrayNode->children.push_back ( newItem ); - } else { - arrayNode->children.insert ( arrayNode->children.begin(), newItem ); - } - -} // AppendLangItem - - -// ================================================================================================= -// Class Methods -// ============= -// -// -// ================================================================================================= - - -// ------------------------------------------------------------------------------------------------- -// GetProperty -// ----------- - -bool -XMPMeta::GetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_Node * propNode = FindConstNode ( &tree, expPath ); - if ( propNode == 0 ) return false; - - *propValue = propNode->value.c_str(); - *valueSize = propNode->value.size(); - *options = propNode->options; - - return true; - -} // GetProperty - - -// ------------------------------------------------------------------------------------------------- -// GetArrayItem -// ------------ - -bool -XMPMeta::GetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr itemPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - return GetProperty ( schemaNS, itemPath, itemValue, valueSize, options ); - -} // GetArrayItem - - -// ------------------------------------------------------------------------------------------------- -// GetStructField -// -------------- - -bool -XMPMeta::GetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fieldValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fieldValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - return GetProperty ( schemaNS, fieldPath, fieldValue, valueSize, options ); - -} // GetStructField - - -// ------------------------------------------------------------------------------------------------- -// GetQualifier -// ------------ - -bool -XMPMeta::GetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - XMP_Assert ( (qualValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - return GetProperty ( schemaNS, qualPath, qualValue, valueSize, options ); - -} // GetQualifier - - -// ------------------------------------------------------------------------------------------------- -// SetProperty -// ----------- - -// *** Should handle array items specially, calling SetArrayItem. - -void -XMPMeta::SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - options = VerifySetOptions ( options, propValue ); - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_CreateNodes, options ); - if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath ); - - SetNode ( propNode, propValue, options ); - -} // SetProperty - - -// ------------------------------------------------------------------------------------------------- -// SetArrayItem -// ------------ - -void -XMPMeta::SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create. - if ( arrayNode == 0 ) XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath ); - - DoSetArrayItem ( arrayNode, itemIndex, itemValue, options ); - -} // SetArrayItem - - -// ------------------------------------------------------------------------------------------------- -// AppendArrayItem -// --------------- - -void -XMPMeta::AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - - arrayOptions = VerifySetOptions ( arrayOptions, 0 ); - if ( (arrayOptions & ~kXMP_PropArrayFormMask) != 0 ) { - XMP_Throw ( "Only array form flags allowed for arrayOptions", kXMPErr_BadOptions ); - } - - // Locate or create the array. If it already exists, make sure the array form from the options - // parameter is compatible with the current state. - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create. - - if ( arrayNode != 0 ) { - // The array exists, make sure the form is compatible. Zero arrayForm means take what exists. - if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) { - XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath ); - } - #if 0 - // *** Disable for now. Need to do some general rethinking of semantic checks. - if ( (arrayOptions != 0) && (arrayOptions != (arrayNode->options & kXMP_PropArrayFormMask)) ) { - XMP_Throw ( "Mismatch of existing and specified array form", kXMPErr_BadOptions ); - } - #endif - } else { - // The array does not exist, try to create it. - if ( arrayOptions == 0 ) XMP_Throw ( "Explicit arrayOptions required to create new array", kXMPErr_BadOptions ); - arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes, arrayOptions ); - if ( arrayNode == 0 ) XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath ); - } - - DoSetArrayItem ( arrayNode, kXMP_ArrayLastItem, itemValue, (options | kXMP_InsertAfterItem) ); - -} // AppendArrayItem - - -// ------------------------------------------------------------------------------------------------- -// SetStructField -// -------------- - -void -XMPMeta::SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - SetProperty ( schemaNS, fieldPath, fieldValue, options ); - -} // SetStructField - - -// ------------------------------------------------------------------------------------------------- -// SetQualifier -// ------------ - -void -XMPMeta::SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly ); - if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath ); - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - SetProperty ( schemaNS, qualPath, qualValue, options ); - -} // SetQualifier - - -// ------------------------------------------------------------------------------------------------- -// DeleteProperty -// -------------- - -void -XMPMeta::DeleteProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_NodePtrPos ptrPos; - XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly, kXMP_NoOptions, &ptrPos ); - if ( propNode == 0 ) return; - XMP_Node * parentNode = propNode->parent; - - // Erase the pointer from the parent's vector, then delete the node and all below it. - - if ( ! (propNode->options & kXMP_PropIsQualifier) ) { - - parentNode->children.erase ( ptrPos ); - DeleteEmptySchema ( parentNode ); - - } else { - - if ( propNode->name == "xml:lang" ) { - XMP_Assert ( parentNode->options & kXMP_PropHasLang ); // *** &= ~flag would be safer - parentNode->options ^= kXMP_PropHasLang; - } else if ( propNode->name == "rdf:type" ) { - XMP_Assert ( parentNode->options & kXMP_PropHasType ); - parentNode->options ^= kXMP_PropHasType; - } - - parentNode->qualifiers.erase ( ptrPos ); - XMP_Assert ( parentNode->options & kXMP_PropHasQualifiers ); - if ( parentNode->qualifiers.empty() ) parentNode->options ^= kXMP_PropHasQualifiers; - - } - - delete propNode; // ! The destructor takes care of the whole subtree. - -} // DeleteProperty - - -// ------------------------------------------------------------------------------------------------- -// DeleteArrayItem -// --------------- - -void -XMPMeta::DeleteArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - - XMP_StringPtr itemPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - DeleteProperty ( schemaNS, itemPath ); - -} // DeleteArrayItem - - -// ------------------------------------------------------------------------------------------------- -// DeleteStructField -// ----------------- - -void -XMPMeta::DeleteStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) -{ - XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - DeleteProperty ( schemaNS, fieldPath ); - -} // DeleteStructField - - -// ------------------------------------------------------------------------------------------------- -// DeleteQualifier -// --------------- - -void -XMPMeta::DeleteQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - DeleteProperty ( schemaNS, qualPath ); - -} // DeleteQualifier - - -// ------------------------------------------------------------------------------------------------- -// DoesPropertyExist -// ----------------- - -bool -XMPMeta::DoesPropertyExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_Node * propNode = FindConstNode ( &tree, expPath ); - return (propNode != 0); - -} // DoesPropertyExist - - -// ------------------------------------------------------------------------------------------------- -// DoesArrayItemExist -// ------------------ - -bool -XMPMeta::DoesArrayItemExist ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) const -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - - XMP_StringPtr itemPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - return DoesPropertyExist ( schemaNS, itemPath ); - -} // DoesArrayItemExist - - -// ------------------------------------------------------------------------------------------------- -// DoesStructFieldExist -// -------------------- - -bool -XMPMeta::DoesStructFieldExist ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) const -{ - XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - return DoesPropertyExist ( schemaNS, fieldPath ); - -} // DoesStructFieldExist - - -// ------------------------------------------------------------------------------------------------- -// DoesQualifierExist -// ------------------ - -bool -XMPMeta::DoesQualifierExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - return DoesPropertyExist ( schemaNS, qualPath ); - -} // DoesQualifierExist - - -// ------------------------------------------------------------------------------------------------- -// GetLocalizedText -// ---------------- - -bool -XMPMeta::GetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr _genericLang, - XMP_StringPtr _specificLang, - XMP_StringPtr * actualLang, - XMP_StringLen * langSize, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper. - XMP_Assert ( (actualLang != 0) && (langSize != 0) ); // Enforced by wrapper. - XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_VarString zGenericLang ( _genericLang ); - XMP_VarString zSpecificLang ( _specificLang ); - NormalizeLangValue ( &zGenericLang ); - NormalizeLangValue ( &zSpecificLang ); - - XMP_StringPtr genericLang = zGenericLang.c_str(); - XMP_StringPtr specificLang = zSpecificLang.c_str(); - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - - const XMP_Node * arrayNode = FindConstNode ( &tree, arrayPath ); // *** This expand/find idiom is used in 3 Getters. - if ( arrayNode == 0 ) return false; // *** Should extract it into a local utility. - - XMP_CLTMatch match; - const XMP_Node * itemNode; - - match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &itemNode ); - if ( match == kXMP_CLT_NoValues ) return false; - - *actualLang = itemNode->qualifiers[0]->value.c_str(); - *langSize = itemNode->qualifiers[0]->value.size(); - *itemValue = itemNode->value.c_str(); - *valueSize = itemNode->value.size(); - *options = itemNode->options; - - return true; - -} // GetLocalizedText - - -// ------------------------------------------------------------------------------------------------- -// SetLocalizedText -// ---------------- - -void -XMPMeta::SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr _genericLang, - XMP_StringPtr _specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options ) -{ - UNUSED(options); // Avoid unused parameter warning. - - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper. - - XMP_VarString zGenericLang ( _genericLang ); - XMP_VarString zSpecificLang ( _specificLang ); - NormalizeLangValue ( &zGenericLang ); - NormalizeLangValue ( &zSpecificLang ); - - XMP_StringPtr genericLang = zGenericLang.c_str(); - XMP_StringPtr specificLang = zSpecificLang.c_str(); - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - - // Find the array node and set the options if it was just created. - XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes, - (kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate) ); - if ( arrayNode == 0 ) XMP_Throw ( "Failed to find or create array node", kXMPErr_BadXPath ); - if ( ! XMP_ArrayIsAltText(arrayNode->options) ) { - if ( arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options) ) { - arrayNode->options |= kXMP_PropArrayIsAltText; - } else { - XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath ); - } - } - - // Make sure the x-default item, if any, is first. - - size_t itemNum, itemLim; - XMP_Node * xdItem = 0; - bool haveXDefault = false; - - for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) { - XMP_Node * currItem = arrayNode->children[itemNum]; - XMP_Assert ( XMP_PropHasLang(currItem->options) ); - if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) { - XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath ); - } - if ( currItem->qualifiers[0]->value == "x-default" ) { - xdItem = currItem; - haveXDefault = true; - break; - } - } - - if ( haveXDefault && (itemNum != 0) ) { - XMP_Assert ( arrayNode->children[itemNum]->qualifiers[0]->value == "x-default" ); - XMP_Node * temp = arrayNode->children[0]; - arrayNode->children[0] = arrayNode->children[itemNum]; - arrayNode->children[itemNum] = temp; - } - - // Find the appropriate item. ChooseLocalizedText will make sure the array is a language alternative. - - const XMP_Node * cItemNode; // ! ChooseLocalizedText returns a pointer to a const node. - XMP_CLTMatch match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &cItemNode ); - XMP_Node * itemNode = const_cast ( cItemNode ); - - const bool specificXDefault = XMP_LitMatch ( specificLang, "x-default" ); - - switch ( match ) { - - case kXMP_CLT_NoValues : - - // Create the array items for the specificLang and x-default, with x-default first. - AppendLangItem ( arrayNode, "x-default", itemValue ); - haveXDefault = true; - if ( ! specificXDefault ) AppendLangItem ( arrayNode, specificLang, itemValue ); - break; - - case kXMP_CLT_SpecificMatch : - - if ( ! specificXDefault ) { - // Update the specific item, update x-default if it matches the old value. - if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) { - SetNodeValue ( xdItem, itemValue ); - } - SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check! - } else { - // Update all items whose values match the old x-default value. - XMP_Assert ( haveXDefault && (xdItem == itemNode) ); - for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) { - XMP_Node * currItem = arrayNode->children[itemNum]; - if ( (currItem == xdItem) || (currItem->value != xdItem->value) ) continue; - SetNodeValue ( currItem, itemValue ); - } - SetNodeValue ( xdItem, itemValue ); // And finally do the x-default item. - } - break; - - case kXMP_CLT_SingleGeneric : - - // Update the generic item, update x-default if it matches the old value. - if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) { - SetNodeValue ( xdItem, itemValue ); - } - SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check! - break; - - case kXMP_CLT_MultipleGeneric : - - // Create the specific language, ignore x-default. - AppendLangItem ( arrayNode, specificLang, itemValue ); - if ( specificXDefault ) haveXDefault = true; - break; - - case kXMP_CLT_XDefault : - - // Create the specific language, update x-default if it was the only item. - if ( arrayNode->children.size() == 1 ) SetNodeValue ( xdItem, itemValue ); - AppendLangItem ( arrayNode, specificLang, itemValue ); - break; - - case kXMP_CLT_FirstItem : - - // Create the specific language, don't add an x-default item. - AppendLangItem ( arrayNode, specificLang, itemValue ); - if ( specificXDefault ) haveXDefault = true; - break; - - default : - XMP_Throw ( "Unexpected result from ChooseLocalizedText", kXMPErr_InternalFailure ); - - } - - // Add an x-default at the front if needed. - if ( (! haveXDefault) && (arrayNode->children.size() == 1) ) { - AppendLangItem ( arrayNode, "x-default", itemValue ); - } - -} // SetLocalizedText - - -// ------------------------------------------------------------------------------------------------- -// GetProperty_Bool -// ---------------- - -bool -XMPMeta::GetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool * propValue, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options ); - if ( found ) { - if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath ); - *propValue = XMPUtils::ConvertToBool ( valueStr ); - } - return found; - -} // GetProperty_Bool - - -// ------------------------------------------------------------------------------------------------- -// GetProperty_Int -// --------------- - -bool -XMPMeta::GetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 * propValue, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options ); - if ( found ) { - if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath ); - *propValue = XMPUtils::ConvertToInt ( valueStr ); - } - return found; - -} // GetProperty_Int - - -// ------------------------------------------------------------------------------------------------- -// GetProperty_Int64 -// ----------------- - -bool -XMPMeta::GetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 * propValue, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options ); - if ( found ) { - if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath ); - *propValue = XMPUtils::ConvertToInt64 ( valueStr ); - } - return found; - -} // GetProperty_Int64 - - -// ------------------------------------------------------------------------------------------------- -// GetProperty_Float -// ----------------- - -bool -XMPMeta::GetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options ); - if ( found ) { - if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath ); - *propValue = XMPUtils::ConvertToFloat ( valueStr ); - } - return found; - -} // GetProperty_Float - - -// ------------------------------------------------------------------------------------------------- -// GetProperty_Date -// ---------------- - -bool -XMPMeta::GetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options ) const -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options ); - if ( found ) { - if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath ); - XMPUtils::ConvertToDate ( valueStr, propValue ); - } - return found; - -} // GetProperty_Date - - -// ------------------------------------------------------------------------------------------------- -// SetProperty_Bool -// ---------------- - -void -XMPMeta::SetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromBool ( propValue, &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); - -} // SetProperty_Bool - - -// ------------------------------------------------------------------------------------------------- -// SetProperty_Int -// --------------- - -void -XMPMeta::SetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromInt ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); - -} // SetProperty_Int - - -// ------------------------------------------------------------------------------------------------- -// SetProperty_Int64 -// ----------------- - -void -XMPMeta::SetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); - -} // SetProperty_Int64 - - -// ------------------------------------------------------------------------------------------------- -// SetProperty_Float -// ----------------- - -void -XMPMeta::SetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromFloat ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); - -} // SetProperty_Float - - -// ------------------------------------------------------------------------------------------------- -// SetProperty_Date -// ---------------- - -void -XMPMeta::SetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromDate ( propValue, &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); - -} // SetProperty_Date - -// ================================================================================================= - diff --git a/xmpsdk/src/XMPMeta-Parse.cpp b/xmpsdk/src/XMPMeta-Parse.cpp deleted file mode 100644 index 69596934ea..0000000000 --- a/xmpsdk/src/XMPMeta-Parse.cpp +++ /dev/null @@ -1,1306 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// -// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of -// one format in a file with a different format', inventors: Sean Parent, Greg Gilley. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPMeta.hpp" -#include "XMPUtils.hpp" - -#include "UnicodeInlines.incl_cpp" -#include "UnicodeConversions.hpp" -#include "ExpatAdapter.hpp" - -#if XMP_DebugBuild - #include -#endif - -using namespace std; - -#if XMP_WinBuild -#ifdef _MSC_VER - #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...' - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #pragma warning ( disable : 4996 ) // '...' was declared deprecated -#endif -#endif - - -// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros -// *** Add debug codegen checks, e.g. that typical masking operations really work -// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch - - -// ================================================================================================= -// Local Types and Constants -// ========================= - - -// ================================================================================================= -// Static Variables -// ================ - -#ifndef Trace_ParsingHackery - #define Trace_ParsingHackery 0 -#endif - -static const char * kReplaceLatin1[128] = - { - - // The 0x80..0x9F range is undefined in Latin-1, but is defined in Windows code page 1252. - // The bytes 0x81, 0x8D, 0x8F, 0x90, and 0x9D are formally undefined by Windows 1252, but - // their conversion API maps them to U+0081, etc. These are in XML's RestrictedChar set, so - // we map them to a space. - - "\xE2\x82\xAC", " ", "\xE2\x80\x9A", "\xC6\x92", // 0x80 .. 0x83 - "\xE2\x80\x9E", "\xE2\x80\xA6", "\xE2\x80\xA0", "\xE2\x80\xA1", // 0x84 .. 0x87 - "\xCB\x86", "\xE2\x80\xB0", "\xC5\xA0", "\xE2\x80\xB9", // 0x88 .. 0x8B - "\xC5\x92", " ", "\xC5\xBD", " ", // 0x8C .. 0x8F - - " ", "\xE2\x80\x98", "\xE2\x80\x99", "\xE2\x80\x9C", // 0x90 .. 0x93 - "\xE2\x80\x9D", "\xE2\x80\xA2", "\xE2\x80\x93", "\xE2\x80\x94", // 0x94 .. 0x97 - "\xCB\x9C", "\xE2\x84\xA2", "\xC5\xA1", "\xE2\x80\xBA", // 0x98 .. 0x9B - "\xC5\x93", " ", "\xC5\xBE", "\xC5\xB8", // 0x9C .. 0x9F - - // These are the UTF-8 forms of the official Latin-1 characters in the range 0xA0..0xFF. Not - // too surprisingly these map to U+00A0, etc. Which is the Unicode Latin Supplement range. - - "\xC2\xA0", "\xC2\xA1", "\xC2\xA2", "\xC2\xA3", "\xC2\xA4", "\xC2\xA5", "\xC2\xA6", "\xC2\xA7", // 0xA0 .. 0xA7 - "\xC2\xA8", "\xC2\xA9", "\xC2\xAA", "\xC2\xAB", "\xC2\xAC", "\xC2\xAD", "\xC2\xAE", "\xC2\xAF", // 0xA8 .. 0xAF - - "\xC2\xB0", "\xC2\xB1", "\xC2\xB2", "\xC2\xB3", "\xC2\xB4", "\xC2\xB5", "\xC2\xB6", "\xC2\xB7", // 0xB0 .. 0xB7 - "\xC2\xB8", "\xC2\xB9", "\xC2\xBA", "\xC2\xBB", "\xC2\xBC", "\xC2\xBD", "\xC2\xBE", "\xC2\xBF", // 0xB8 .. 0xBF - - "\xC3\x80", "\xC3\x81", "\xC3\x82", "\xC3\x83", "\xC3\x84", "\xC3\x85", "\xC3\x86", "\xC3\x87", // 0xC0 .. 0xC7 - "\xC3\x88", "\xC3\x89", "\xC3\x8A", "\xC3\x8B", "\xC3\x8C", "\xC3\x8D", "\xC3\x8E", "\xC3\x8F", // 0xC8 .. 0xCF - - "\xC3\x90", "\xC3\x91", "\xC3\x92", "\xC3\x93", "\xC3\x94", "\xC3\x95", "\xC3\x96", "\xC3\x97", // 0xD0 .. 0xD7 - "\xC3\x98", "\xC3\x99", "\xC3\x9A", "\xC3\x9B", "\xC3\x9C", "\xC3\x9D", "\xC3\x9E", "\xC3\x9F", // 0xD8 .. 0xDF - - "\xC3\xA0", "\xC3\xA1", "\xC3\xA2", "\xC3\xA3", "\xC3\xA4", "\xC3\xA5", "\xC3\xA6", "\xC3\xA7", // 0xE0 .. 0xE7 - "\xC3\xA8", "\xC3\xA9", "\xC3\xAA", "\xC3\xAB", "\xC3\xAC", "\xC3\xAD", "\xC3\xAE", "\xC3\xAF", // 0xE8 .. 0xEF - - "\xC3\xB0", "\xC3\xB1", "\xC3\xB2", "\xC3\xB3", "\xC3\xB4", "\xC3\xB5", "\xC3\xB6", "\xC3\xB7", // 0xF0 .. 0xF7 - "\xC3\xB8", "\xC3\xB9", "\xC3\xBA", "\xC3\xBB", "\xC3\xBC", "\xC3\xBD", "\xC3\xBE", "\xC3\xBF", // 0xF8 .. 0xFF - - }; - - -// ================================================================================================= -// Local Utilities -// =============== - - -#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) ) -#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) ) - - -// ------------------------------------------------------------------------------------------------- -// PickBestRoot -// ------------ -static const XML_Node * PickBestRoot ( const XML_Node & xmlParent, XMP_OptionBits options ) -{ - - // Look among this parent's content for x:xmpmeta. The recursion for x:xmpmeta is broader than - // the strictly defined choice, but gives us smaller code. - for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) { - const XML_Node * childNode = xmlParent.content[childNum]; - if ( childNode->kind != kElemNode ) continue; - if ( (childNode->name == "x:xmpmeta") || (childNode->name == "x:xapmeta") ) return PickBestRoot ( *childNode, 0 ); - } - // Look among this parent's content for a bare rdf:RDF if that is allowed. - if ( ! (options & kXMP_RequireXMPMeta) ) { - for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) { - const XML_Node * childNode = xmlParent.content[childNum]; - if ( childNode->kind != kElemNode ) continue; - if ( childNode->name == "rdf:RDF" ) return childNode; - } - } - - // Recurse into the content. - for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) { - const XML_Node * foundRoot = PickBestRoot ( *xmlParent.content[childNum], options ); - if ( foundRoot != 0 ) return foundRoot; - } - - return 0; - -} // PickBestRoot - -// ------------------------------------------------------------------------------------------------- -// FindRootNode -// ------------ -// -// Find the XML node that is the root of the XMP data tree. Generally this will be an outer node, -// but it could be anywhere if a general XML document is parsed (e.g. SVG). The XML parser counted -// all possible root nodes, and kept a pointer to the last one. If there is more than one possible -// root use PickBestRoot to choose among them. -// -// If there is a root node, try to extract the version of the previous XMP toolkit. - -static const XML_Node * FindRootNode ( XMPMeta * thiz, const XMLParserAdapter & xmlParser, XMP_OptionBits options ) -{ - const XML_Node * rootNode = xmlParser.rootNode; - - if ( xmlParser.rootCount > 1 ) rootNode = PickBestRoot ( xmlParser.tree, options ); - if ( rootNode == 0 ) return 0; - - // We have a root node. Try to extract previous toolkit version number. - - XMP_StringPtr verStr = ""; - - XMP_Assert ( rootNode->name == "rdf:RDF" ); - - if ( (options & kXMP_RequireXMPMeta) && - ((rootNode->parent == 0) || - ((rootNode->parent->name != "x:xmpmeta") && (rootNode->parent->name != "x:xapmeta"))) ) return 0; - - for ( size_t attrNum = 0, attrLim = rootNode->parent->attrs.size(); attrNum < attrLim; ++attrNum ) { - const XML_Node * currAttr =rootNode->parent->attrs[attrNum]; - if ( (currAttr->name == "x:xmptk") || (currAttr->name == "x:xaptk") ) { - verStr = currAttr->value.c_str(); - break; - } - } - - // Decode the version number into MMmmuubbb digits. If any part is too big, peg it at 99 or 999. - - unsigned long part; - while ( (*verStr != 0) && ((*verStr < '0') || (*verStr > '9')) ) ++verStr; - - part = 0; - while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) { - part = (part * 10) + (*verStr - '0'); - ++verStr; - } - if ( part > 99 ) part = 99; - thiz->prevTkVer = part * 100*100*1000; - - part = 0; - if ( *verStr == '.' ) ++verStr; - while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) { - part = (part * 10) + (*verStr - '0'); - ++verStr; - } - if ( part > 99 ) part = 99; - thiz->prevTkVer += part * 100*1000; - - part = 0; - if ( *verStr == '.' ) ++verStr; - while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) { - part = (part * 10) + (*verStr - '0'); - ++verStr; - } - if ( part > 99 ) part = 99; - thiz->prevTkVer += part * 1000; - - part = 0; - if ( *verStr == '-' ) ++verStr; - while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) { - part = (part * 10) + (*verStr - '0'); - ++verStr; - } - if ( part > 999 ) part = 999; - thiz->prevTkVer += part; - - return rootNode; - -} // FindRootNode - -// ------------------------------------------------------------------------------------------------- -// NormalizeDCArrays -// ----------------- -// -// Undo the denormalization performed by the XMP used in Acrobat 5. If a Dublin Core array had only -// one item, it was serialized as a simple property. The xml:lang attribute was dropped from an -// alt-text item if the language was x-default. - -// *** This depends on the dc: namespace prefix. - -static void -NormalizeDCArrays ( XMP_Node * xmpTree ) -{ - XMP_Node * dcSchema = FindSchemaNode ( xmpTree, kXMP_NS_DC, kXMP_ExistingOnly ); - if ( dcSchema == 0 ) return; - - for ( size_t propNum = 0, propLimit = dcSchema->children.size(); propNum < propLimit; ++propNum ) { - XMP_Node * currProp = dcSchema->children[propNum]; - XMP_OptionBits arrayForm = 0; - - if ( ! XMP_PropIsSimple ( currProp->options ) ) continue; // Nothing to do if not simple. - - if ( (currProp->name == "dc:creator" ) || // See if it is supposed to be an array. - (currProp->name == "dc:date" ) ) { // *** Think about an array of char* and a loop. - arrayForm = kXMP_PropArrayIsOrdered; - } else if ( - (currProp->name == "dc:description" ) || - (currProp->name == "dc:rights" ) || - (currProp->name == "dc:title" ) ) { - arrayForm = kXMP_PropArrayIsAltText; - } else if ( - (currProp->name == "dc:contributor" ) || - (currProp->name == "dc:language" ) || - (currProp->name == "dc:publisher" ) || - (currProp->name == "dc:relation" ) || - (currProp->name == "dc:subject" ) || - (currProp->name == "dc:type" ) ) { - arrayForm = kXMP_PropValueIsArray; - } - if ( arrayForm == 0 ) continue; // Nothing to do if it isn't supposed to be an array. - - arrayForm = VerifySetOptions ( arrayForm, 0 ); // Set the implicit array bits. - XMP_Node * newArray = new XMP_Node ( dcSchema, currProp->name.c_str(), arrayForm ); - dcSchema->children[propNum] = newArray; - newArray->children.push_back ( currProp ); - currProp->parent = newArray; - currProp->name = kXMP_ArrayItemName; - - if ( XMP_ArrayIsAltText ( arrayForm ) && (! (currProp->options & kXMP_PropHasLang)) ) { - XMP_Node * newLang = new XMP_Node ( currProp, "xml:lang", "x-default", kXMP_PropIsQualifier ); - currProp->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); - if ( currProp->qualifiers.empty() ) { // *** Need a util? - currProp->qualifiers.push_back ( newLang ); - } else { - currProp->qualifiers.insert ( currProp->qualifiers.begin(), newLang ); - } - } - - } - -} // NormalizeDCArrays - - -// ------------------------------------------------------------------------------------------------- -// CompareAliasedSubtrees -// ---------------------- - -// *** Change to do some alias-specific setup, then use CompareSubtrees. One special case for -// *** aliases is a simple to x-default alias, the options and qualifiers obviously differ. - -static void -CompareAliasedSubtrees ( XMP_Node * aliasNode, XMP_Node * baseNode, bool outerCall = true ) -{ - // ! The outermost call is special. The names almost certainly differ. The qualifiers (and - // ! hence options) will differ for an alias to the x-default item of a langAlt array. - if ( (aliasNode->value != baseNode->value) || - (aliasNode->children.size() != baseNode->children.size()) ) { - XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP ); - } - if ( ! outerCall ) { - if ( (aliasNode->name != baseNode->name) || - (aliasNode->options != baseNode->options) || - (aliasNode->qualifiers.size() != baseNode->qualifiers.size()) ) { - XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP ); - } - } - - for ( size_t childNum = 0, childLim = aliasNode->children.size(); childNum < childLim; ++childNum ) { - XMP_Node * aliasChild = aliasNode->children[childNum]; - XMP_Node * baseChild = baseNode->children[childNum]; - CompareAliasedSubtrees ( aliasChild, baseChild, false ); - } - - for ( size_t qualNum = 0, qualLim = aliasNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - XMP_Node * aliasQual = aliasNode->qualifiers[qualNum]; - XMP_Node * baseQual = baseNode->qualifiers[qualNum]; - CompareAliasedSubtrees ( aliasQual, baseQual, false ); - } - -} // CompareAliasedSubtrees - - -// ------------------------------------------------------------------------------------------------- -// TransplantArrayItemAlias -// ------------------------ - -static void -TransplantArrayItemAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent ) -{ - XMP_Node * childNode = oldParent->children[oldNum]; - - if ( newParent->options & kXMP_PropArrayIsAltText ) { - if ( childNode->options & kXMP_PropHasLang ) { - XMP_Throw ( "Alias to x-default already has a language qualifier", kXMPErr_BadXMP ); // *** Allow x-default. - } - childNode->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); - XMP_Node * langQual = new XMP_Node ( childNode, "xml:lang", "x-default", kXMP_PropIsQualifier ); // *** AddLangQual util? - if ( childNode->qualifiers.empty() ) { - childNode->qualifiers.push_back ( langQual ); - } else { - childNode->qualifiers.insert ( childNode->qualifiers.begin(), langQual ); - } - } - - oldParent->children.erase ( oldParent->children.begin() + oldNum ); - childNode->name = kXMP_ArrayItemName; - childNode->parent = newParent; - if ( newParent->children.empty() ) { - newParent->children.push_back ( childNode ); - } else { - newParent->children.insert ( newParent->children.begin(), childNode ); - } - -} // TransplantArrayItemAlias - - -// ------------------------------------------------------------------------------------------------- -// TransplantNamedAlias -// -------------------- - -static void -TransplantNamedAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent, XMP_VarString & newName ) -{ - XMP_Node * childNode = oldParent->children[oldNum]; - - oldParent->children.erase ( oldParent->children.begin() + oldNum ); - childNode->name = newName; - childNode->parent = newParent; - newParent->children.push_back ( childNode ); - -} // TransplantNamedAlias - - -// ------------------------------------------------------------------------------------------------- -// MoveExplicitAliases -// ------------------- - -static void -MoveExplicitAliases ( XMP_Node * tree, XMP_OptionBits parseOptions ) -{ - tree->options ^= kXMP_PropHasAliases; - const bool strictAliasing = ((parseOptions & kXMP_StrictAliasing) != 0); - - // Visit all of the top level nodes looking for aliases. If there is no base, transplant the - // alias subtree. If there is a base and strict aliasing is on, make sure the alias and base - // subtrees match. - - // ! Use "while" loops not "for" loops since both the schema and property loops can remove the - // ! current item from the vector being traversed. And don't increment the counter for a delete. - - size_t schemaNum = 0; - while ( schemaNum < tree->children.size() ) { - XMP_Node * currSchema = tree->children[schemaNum]; - - size_t propNum = 0; - while ( propNum < currSchema->children.size() ) { - XMP_Node * currProp = currSchema->children[propNum]; - if ( ! (currProp->options & kXMP_PropIsAlias) ) { - ++propNum; - continue; - } - currProp->options ^= kXMP_PropIsAlias; - - // Find the base path, look for the base schema and root node. - - XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( currProp->name ); - XMP_Assert ( aliasPos != sRegisteredAliasMap->end() ); - XMP_ExpandedXPath & basePath = aliasPos->second; - XMP_OptionBits arrayOptions = (basePath[kRootPropStep].options & kXMP_PropArrayFormMask); - - XMP_Node * baseSchema = FindSchemaNode ( tree, basePath[kSchemaStep].step.c_str(), kXMP_CreateNodes ); - if ( baseSchema->options & kXMP_NewImplicitNode ) baseSchema->options ^= kXMP_NewImplicitNode; - XMP_Node * baseNode = FindChildNode ( baseSchema, basePath[kRootPropStep].step.c_str(), kXMP_ExistingOnly ); - - if ( baseNode == 0 ) { - - if ( basePath.size() == 2 ) { - // A top-to-top alias, transplant the property. - TransplantNamedAlias ( currSchema, propNum, baseSchema, basePath[kRootPropStep].step ); - } else { - // An alias to an array item, create the array and transplant the property. - baseNode = new XMP_Node ( baseSchema, basePath[kRootPropStep].step.c_str(), arrayOptions ); - baseSchema->children.push_back ( baseNode ); - TransplantArrayItemAlias ( currSchema, propNum, baseNode ); - } - - } else if ( basePath.size() == 2 ) { - - // The base node does exist and this is a top-to-top alias. Check for conflicts if - // strict aliasing is on. Remove and delete the alias subtree. - if ( strictAliasing ) CompareAliasedSubtrees ( currProp, baseNode ); - currSchema->children.erase ( currSchema->children.begin() + propNum ); - delete currProp; - - } else { - - // This is an alias to an array item and the array exists. Look for the aliased item. - // Then transplant or check & delete as appropriate. - - XMP_Node * itemNode = 0; - if ( arrayOptions & kXMP_PropArrayIsAltText ) { - XMP_Index xdIndex = LookupLangItem ( baseNode, *xdefaultName ); - if ( xdIndex != -1 ) itemNode = baseNode->children[xdIndex]; - } else if ( ! baseNode->children.empty() ) { - itemNode = baseNode->children[0]; - } - - if ( itemNode == 0 ) { - TransplantArrayItemAlias ( currSchema, propNum, baseNode ); - } else { - if ( strictAliasing ) CompareAliasedSubtrees ( currProp, itemNode ); - currSchema->children.erase ( currSchema->children.begin() + propNum ); - delete currProp; - } - - } - - } // Property loop - - // Increment the counter or remove an empty schema node. - if ( currSchema->children.size() > 0 ) { - ++schemaNum; - } else { - delete tree->children[schemaNum]; // ! Delete the schema node itself. - tree->children.erase ( tree->children.begin() + schemaNum ); - } - - } // Schema loop - -} // MoveExplicitAliases - - -// ------------------------------------------------------------------------------------------------- -// FixGPSTimeStamp -// --------------- - -static void -FixGPSTimeStamp ( XMP_Node * exifSchema, XMP_Node * gpsDateTime ) -{ - XMP_DateTime binGPSStamp; - try { - XMPUtils::ConvertToDate ( gpsDateTime->value.c_str(), &binGPSStamp ); - } catch ( ... ) { - return; // Don't let a bad date stop other things. - } - if ( (binGPSStamp.year != 0) || (binGPSStamp.month != 0) || (binGPSStamp.day != 0) ) return; - - XMP_Node * otherDate = FindChildNode ( exifSchema, "exif:DateTimeOriginal", kXMP_ExistingOnly ); - if ( otherDate == 0 ) otherDate = FindChildNode ( exifSchema, "exif:DateTimeDigitized", kXMP_ExistingOnly ); - if ( otherDate == 0 ) return; - - XMP_DateTime binOtherDate; - try { - XMPUtils::ConvertToDate ( otherDate->value.c_str(), &binOtherDate ); - } catch ( ... ) { - return; // Don't let a bad date stop other things. - } - - binGPSStamp.year = binOtherDate.year; - binGPSStamp.month = binOtherDate.month; - binGPSStamp.day = binOtherDate.day; - - XMP_StringPtr goodStr; - XMP_StringLen goodLen; - XMPUtils::ConvertFromDate ( binGPSStamp, &goodStr, &goodLen ); - - gpsDateTime->value.assign ( goodStr, goodLen ); - -} // FixGPSTimeStamp - - -// ------------------------------------------------------------------------------------------------- -// MigrateAudioCopyright -// --------------------- -// -// The initial support for WAV files mapped a legacy ID3 audio copyright into a new xmpDM:copyright -// property. This is special case code to migrate that into dc:rights['x-default']. The rules: -// -// 1. If there is no dc:rights array, or an empty array - -// Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright. -// -// 2. If there is a dc:rights array but it has no x-default item - -// Create an x-default item as a copy of the first item then apply rule #3. -// -// 3. If there is a dc:rights array with an x-default item, look for a double linefeed in the value. -// A. If no double linefeed, compare the x-default value to the xmpDM:copyright value. -// A1. If they match then leave the x-default value alone. -// A2. Otherwise, append a double linefeed and the xmpDM:copyright value to the x-default value. -// B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value. -// B1. If they match then leave the x-default value alone. -// B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value. -// -// 4. In all cases, delete the xmpDM:copyright property. - -static void -MigrateAudioCopyright ( XMPMeta * xmp, XMP_Node * dmCopyright ) -{ - - try { - - std::string & dmValue = dmCopyright->value; - static const char * kDoubleLF = "\xA\xA"; - - XMP_Node * dcSchema = FindSchemaNode ( &xmp->tree, kXMP_NS_DC, kXMP_CreateNodes ); - XMP_Node * dcRightsArray = FindChildNode ( dcSchema, "dc:rights", kXMP_ExistingOnly ); - - if ( (dcRightsArray == 0) || dcRightsArray->children.empty() ) { - - // 1. No dc:rights array, create from double linefeed and xmpDM:copyright. - dmValue.insert ( 0, kDoubleLF ); - xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", dmValue.c_str(), 0 ); - - } else { - - std::string xdefaultStr ( "x-default" ); - - XMP_Index xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr ); - - if ( xdIndex < 0 ) { - // 2. No x-default item, create from the first item. - XMP_StringPtr firstValue = dcRightsArray->children[0]->value.c_str(); - xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", firstValue, 0 ); - xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr ); - } - - // 3. Look for a double linefeed in the x-default value. - XMP_Assert ( xdIndex == 0 ); - std::string & defaultValue = dcRightsArray->children[xdIndex]->value; - XMP_Index lfPos = defaultValue.find ( kDoubleLF ); - - if ( lfPos < 0 ) { - - // 3A. No double LF, compare whole values. - if ( dmValue != defaultValue ) { - // 3A2. Append the xmpDM:copyright to the x-default item. - defaultValue += kDoubleLF; - defaultValue += dmValue; - } - - } else { - - // 3B. Has double LF, compare the tail. - if ( defaultValue.compare ( lfPos+2, std::string::npos, dmValue ) != 0 ) { - // 3B2. Replace the x-default tail. - defaultValue.replace ( lfPos+2, std::string::npos, dmValue ); - } - - } - - } - - // 4. Get rid of the xmpDM:copyright. - xmp->DeleteProperty ( kXMP_NS_DM, "copyright" ); - - } catch ( ... ) { - // Don't let failures (like a bad dc:rights form) stop other cleanup. - } - -} // MigrateAudioCopyright - - -// ------------------------------------------------------------------------------------------------- -// RepairAltText -// ------------- -// -// Make sure that the array is well-formed AltText. Each item must be simple and have an xml:lang -// qualifier. If repairs are needed, keep simple non-empty items by adding the xml:lang. - -static void -RepairAltText ( XMP_Node & tree, XMP_StringPtr schemaNS, XMP_StringPtr arrayName ) -{ - XMP_Node * schemaNode = FindSchemaNode ( &tree, schemaNS, kXMP_ExistingOnly ); - if ( schemaNode == 0 ) return; - - XMP_Node * arrayNode = FindChildNode ( schemaNode, arrayName, kXMP_ExistingOnly ); - if ( (arrayNode == 0) || XMP_ArrayIsAltText ( arrayNode->options ) ) return; // Already OK. - - if ( ! XMP_PropIsArray ( arrayNode->options ) ) return; // ! Not even an array, leave it alone. - // *** Should probably change simple values to LangAlt with 'x-default' item. - - arrayNode->options |= (kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText); - - for ( int i = arrayNode->children.size()-1; i >= 0; --i ) { // ! Need a signed index type. - - XMP_Node * currChild = arrayNode->children[i]; - - if ( ! XMP_PropIsSimple ( currChild->options ) ) { - - // Delete non-simple children. - delete ( currChild ); - arrayNode->children.erase ( arrayNode->children.begin() + i ); - - } else if ( ! XMP_PropHasLang ( currChild->options ) ) { - - if ( currChild->value.empty() ) { - - // Delete empty valued children that have no xml:lang. - delete ( currChild ); - arrayNode->children.erase ( arrayNode->children.begin() + i ); - - } else { - - // Add an xml:lang qualifier with the value "x-repair". - XMP_Node * repairLang = new XMP_Node ( currChild, "xml:lang", "x-repair", kXMP_PropIsQualifier ); - if ( currChild->qualifiers.empty() ) { - currChild->qualifiers.push_back ( repairLang ); - } else { - currChild->qualifiers.insert ( currChild->qualifiers.begin(), repairLang ); - } - currChild->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); - - } - - } - - } - -} // RepairAltText - - -// ------------------------------------------------------------------------------------------------- -// TouchUpDataModel -// ---------------- - -static void -TouchUpDataModel ( XMPMeta * xmp ) -{ - XMP_Node & tree = xmp->tree; - - // Do special case touch ups for certain schema. - - XMP_Node * currSchema = 0; - - currSchema = FindSchemaNode ( &tree, kXMP_NS_EXIF, kXMP_ExistingOnly ); - if ( currSchema != 0 ) { - - // Do a special case fix for exif:GPSTimeStamp. - XMP_Node * gpsDateTime = FindChildNode ( currSchema, "exif:GPSTimeStamp", kXMP_ExistingOnly ); - if ( gpsDateTime != 0 ) FixGPSTimeStamp ( currSchema, gpsDateTime ); - - // *** Should probably have RepairAltText change simple values to LangAlt with 'x-default' item. - // *** For now just do this for exif:UserComment, the one case we know about, late in cycle fix. - XMP_Node * userComment = FindChildNode ( currSchema, "exif:UserComment", kXMP_ExistingOnly ); - if ( (userComment != 0) && XMP_PropIsSimple ( userComment->options ) ) { - XMP_Node * newChild = new XMP_Node ( userComment, kXMP_ArrayItemName, - userComment->value.c_str(), userComment->options ); - newChild->qualifiers.swap ( userComment->qualifiers ); - if ( ! XMP_PropHasLang ( newChild->options ) ) { - XMP_Node * langQual = new XMP_Node ( newChild, "xml:lang", "x-default", kXMP_PropIsQualifier ); - newChild->qualifiers.insert ( newChild->qualifiers.begin(), langQual ); - newChild->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); - } - userComment->value.erase(); - userComment->options = kXMP_PropArrayFormMask; // ! Happens to have all the right bits. - userComment->children.push_back ( newChild ); - } - - } - - currSchema = FindSchemaNode ( &tree, kXMP_NS_DM, kXMP_ExistingOnly ); - if ( currSchema != 0 ) { - // Do a special case migration of xmpDM:copyright to dc:rights['x-default']. Do this before - // the dc: touch up since it can affect the dc: schema. - XMP_Node * dmCopyright = FindChildNode ( currSchema, "xmpDM:copyright", kXMP_ExistingOnly ); - if ( dmCopyright != 0 ) MigrateAudioCopyright ( xmp, dmCopyright ); - } - - currSchema = FindSchemaNode ( &tree, kXMP_NS_DC, kXMP_ExistingOnly ); - if ( currSchema != 0 ) { - // Do a special case fix for dc:subject, make sure it is an unordered array. - XMP_Node * dcSubject = FindChildNode ( currSchema, "dc:subject", kXMP_ExistingOnly ); - if ( dcSubject != 0 ) { - XMP_OptionBits keepMask = static_cast(~(kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText)); - dcSubject->options &= keepMask; // Make sure any ordered array bits are clear. - } - } - - // Fix any broken AltText arrays that we know about. - - RepairAltText ( tree, kXMP_NS_DC, "dc:description" ); // ! Note inclusion of prefixes for direct node lookup! - RepairAltText ( tree, kXMP_NS_DC, "dc:rights" ); - RepairAltText ( tree, kXMP_NS_DC, "dc:title" ); - RepairAltText ( tree, kXMP_NS_XMP_Rights, "xmpRights:UsageTerms" ); - RepairAltText ( tree, kXMP_NS_EXIF, "exif:UserComment" ); - - // Tweak old XMP: Move an instance ID from rdf:about to the xmpMM:InstanceID property. An old - // instance ID usually looks like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign - // 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If the name looks like a UUID - // simply move it to xmpMM:InstanceID, don't worry about any existing xmpMM:InstanceID. Both - // will only be present when a newer file with the xmpMM:InstanceID property is updated by an - // old app that uses rdf:about. - - if ( ! tree.name.empty() ) { - - bool nameIsUUID = false; - XMP_StringPtr nameStr = tree.name.c_str(); - - if ( XMP_LitNMatch ( nameStr, "uuid:", 5 ) ) { - - nameIsUUID = true; - - } else if ( tree.name.size() == 36 ) { - - nameIsUUID = true; // ! Assume true, we'll set it to false below if not. - for ( int i = 0; i < 36; ++i ) { - char ch = nameStr[i]; - if ( ch == '-' ) { - if ( (i == 8) || (i == 13) || (i == 18) || (i == 23) ) continue; - nameIsUUID = false; - break; - } else { - if ( (('0' <= ch) && (ch <= '9')) || (('a' <= ch) && (ch <= 'z')) ) continue; - nameIsUUID = false; - break; - } - } - - } - - if ( nameIsUUID ) { - - XMP_ExpandedXPath expPath; - ExpandXPath ( kXMP_NS_XMP_MM, "InstanceID", &expPath ); - XMP_Node * idNode = FindNode ( &tree, expPath, kXMP_CreateNodes, 0 ); - if ( idNode == 0 ) XMP_Throw ( "Failure creating xmpMM:InstanceID", kXMPErr_InternalFailure ); - - idNode->options = 0; // Clobber any existing xmpMM:InstanceID. - idNode->value = tree.name; - idNode->RemoveChildren(); - idNode->RemoveQualifiers(); - - tree.name.erase(); - - } - - } - -} // TouchUpDataModel - - -// ------------------------------------------------------------------------------------------------- -// DetermineInputEncoding -// ---------------------- -// -// Try to determine the character encoding, making a guess if the input is too short. We make some -// simplifying assumtions: the first character must be U+FEFF or ASCII, U+0000 is not allowed. The -// XML 1.1 spec is even more strict, UTF-16 XML documents must begin with U+FEFF, and the first -// "real" character must be '<'. Ignoring the XML declaration, the first XML character could be '<', -// space, tab, CR, or LF. -// -// The possible input sequences are: -// -// Cases with U+FEFF -// EF BB BF -- - UTF-8 -// FE FF -- -- - Big endian UTF-16 -// 00 00 FE FF - Big endian UTF 32 -// FF FE 00 00 - Little endian UTF-32 -// FF FE -- -- - Little endian UTF-16 -// -// Cases with ASCII -// nn mm -- -- - UTF-8 - -// 00 00 00 nn - Big endian UTF-32 -// 00 nn -- -- - Big endian UTF-16 -// nn 00 00 00 - Little endian UTF-32 -// nn 00 -- -- - Little endian UTF-16 -// -// ! We don't check for full patterns, or for errors. We just check enough to determine what the -// ! only possible (or reasonable) case would be. - -static XMP_OptionBits -DetermineInputEncoding ( const XMP_Uns8 * buffer, size_t length ) -{ - if ( length < 2 ) return kXMP_EncodeUTF8; - - XMP_Uns8 * uniChar = (XMP_Uns8*)buffer; // ! Make sure comparisons are unsigned. - - if ( uniChar[0] == 0 ) { - - // These cases are: - // 00 nn -- -- - Big endian UTF-16 - // 00 00 00 nn - Big endian UTF-32 - // 00 00 FE FF - Big endian UTF 32 - - if ( (length < 4) || (uniChar[1] != 0) ) return kXMP_EncodeUTF16Big; - return kXMP_EncodeUTF32Big; - - } else if ( uniChar[0] < 0x80 ) { - - // These cases are: - // nn mm -- -- - UTF-8, includes EF BB BF case - // nn 00 00 00 - Little endian UTF-32 - // nn 00 -- -- - Little endian UTF-16 - - if ( uniChar[1] != 0 ) return kXMP_EncodeUTF8; - if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little; - return kXMP_EncodeUTF32Little; - - } else { - - // These cases are: - // EF BB BF -- - UTF-8 - // FE FF -- -- - Big endian UTF-16 - // FF FE 00 00 - Little endian UTF-32 - // FF FE -- -- - Little endian UTF-16 - - if ( uniChar[0] == 0xEF ) return kXMP_EncodeUTF8; - if ( uniChar[0] == 0xFE ) return kXMP_EncodeUTF16Big; - if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little; - return kXMP_EncodeUTF32Little; - - } - -} // DetermineInputEncoding - - -// ------------------------------------------------------------------------------------------------- -// CountUTF8 -// --------- -// -// Look for a valid multi-byte UTF-8 sequence and return its length. Returns 0 for an invalid UTF-8 -// sequence. Returns a negative value for a partial valid sequence at the end of the buffer. -// -// The checking is not strict. We simply count the number of high order 1 bits in the first byte, -// then look for n-1 following bytes whose high order 2 bits are 1 and 0. We do not check for a -// minimal length representation of the codepoint, or that the codepoint is defined by Unicode. - -static int -CountUTF8 ( const XMP_Uns8 * charStart, const XMP_Uns8 * bufEnd ) -{ - XMP_Assert ( charStart < bufEnd ); // Catch this in debug builds. - if ( charStart >= bufEnd ) return 0; // Don't run-on in release builds. - if ( (*charStart & 0xC0) != 0xC0 ) return 0; // Must have at least 2 high bits set. - - int byteCount = 2; - XMP_Uns8 firstByte = *charStart; - for ( firstByte = firstByte << 2; (firstByte & 0x80) != 0; firstByte = firstByte << 1 ) ++byteCount; - - if ( (charStart + byteCount) > bufEnd ) return -byteCount; - - for ( int i = 1; i < byteCount; ++i ) { - if ( (charStart[i] & 0xC0) != 0x80 ) return 0; - } - - return byteCount; - -} // CountUTF8 - - -// ------------------------------------------------------------------------------------------------- -// CountControlEscape -// ------------------ -// -// Look for a numeric escape sequence for a "prohibited" ASCII control character. These are 0x7F, -// and the range 0x00..0x1F except for tab/LF/CR. Return 0 if this is definitely not a numeric -// escape, the length of the escape if found, or a negative value for a partial escape. - -static int -CountControlEscape ( const XMP_Uns8 * escStart, const XMP_Uns8 * bufEnd ) -{ - XMP_Assert ( escStart < bufEnd ); // Catch this in debug builds. - if ( escStart >= bufEnd ) return 0; // Don't run-on in release builds. - XMP_Assert ( *escStart == '&' ); - - size_t tailLen = bufEnd - escStart; - if ( tailLen < 5 ) return -1; // Don't need a more thorough check, we'll catch it on the next pass. - - if ( strncmp ( (char*)escStart, "&#x", 3 ) != 0 ) return 0; - - XMP_Uns8 escValue = 0; - const XMP_Uns8 * escPos = escStart + 3; - - if ( ('0' <= *escPos) && (*escPos <= '9') ) { - escValue = *escPos - '0'; - ++escPos; - } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) { - escValue = *escPos - 'A' + 10; - ++escPos; - } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) { - escValue = *escPos - 'a' + 10; - ++escPos; - } - - if ( ('0' <= *escPos) && (*escPos <= '9') ) { - escValue = (escValue << 4) + (*escPos - '0'); - ++escPos; - } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) { - escValue = (escValue << 4) + (*escPos - 'A' + 10); - ++escPos; - } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) { - escValue = (escValue << 4) + (*escPos - 'a' + 10); - ++escPos; - } - - if ( escPos == bufEnd ) return -1; // Partial escape. - if ( *escPos != ';' ) return 0; - - size_t escLen = escPos - escStart + 1; - if ( escLen < 5 ) return 0; // ! Catch "&#x;". - - if ( (escValue == kTab) || (escValue == kLF) || (escValue == kCR) ) return 0; // An allowed escape. - - return escLen; // Found a full "prohibited" numeric escape. - -} // CountControlEscape - - -// ------------------------------------------------------------------------------------------------- -// ProcessUTF8Portion -// ------------------ -// -// Early versions of the XMP spec mentioned allowing ISO Latin-1 input. There are also problems with -// some clients placing ASCII control characters within XMP values. This is an XML problem, the XML -// spec only allows tab (0x09), LF (0x0A), and CR (0x0D) from the 0x00..0x1F range. As a concession -// to this we scan 8-bit input for byte sequences that are not valid UTF-8 or in the 0x00..0x1F -// range and replace each byte as follows: -// 0x00..0x1F - Replace with a space, except for tab, CR, and LF. -// 0x7F - Replace with a space. This is ASCII Delete, not allowed by ISO Latin-1. -// 0x80..0x9F - Replace with the UTF-8 for a corresponding Unicode character. -// 0xA0..0XFF - Replace with the UTF-8 for a corresponding Unicode character. -// -// The 0x80..0x9F range is not defined by Latin-1. But the Windows 1252 code page defines these and -// is otherwise the same as Latin-1. -// -// For at least historical compatibility reasons we also find and replace singly escaped ASCII -// control characters. The Expat parser we're using does not allow numeric escapes like "". -// The XML spec is clear that raw controls are not allowed (in the RestrictedChar set), but it isn't -// as clear about numeric escapes for them. At any rate, Expat complains, so we treat the numeric -// escapes like raw characters and replace them with a space. -// -// We check for 1 or 2 hex digits (" " or " ") and upper or lower case (" " or " "). -// The full escape sequence is 5 or 6 bytes. - -static size_t -ProcessUTF8Portion ( XMLParserAdapter * xmlParser, - const XMP_Uns8 * buffer, - size_t length, - bool last ) -{ - const XMP_Uns8 * bufEnd = buffer + length; - - const XMP_Uns8 * spanEnd; - - // `buffer` is copied into this std::string. If `buffer` only - // contains valid UTF-8 and no escape characters, then the copy - // will be identical to the original, but invalid characters are - // replaced - usually with a space character. This std::string was - // added as a performance fix for: - // https://github.com/Exiv2/exiv2/security/advisories/GHSA-w8mv-g8qq-36mj - // Previously, the code was repeatedly calling - // `xmlParser->ParseBuffer()`, which turned out to have quadratic - // complexity, because expat kept reparsing the entire string from - // the beginning. - std::string copy; - - for ( spanEnd = buffer; spanEnd < bufEnd; ++spanEnd ) { - - if ( (0x20 <= *spanEnd) && (*spanEnd <= 0x7E) && (*spanEnd != '&') ) { - copy.push_back(*spanEnd); - continue; // A regular ASCII character. - } - - if ( *spanEnd >= 0x80 ) { - - // See if this is a multi-byte UTF-8 sequence, or a Latin-1 character to replace. - - int uniLen = CountUTF8 ( spanEnd, bufEnd ); - - if ( uniLen > 0 ) { - - // A valid UTF-8 character, keep it as-is. - copy.append((const char*)spanEnd, uniLen); - spanEnd += uniLen - 1; // ! The loop increment will put back the +1. - - } else if ( (uniLen < 0) && (! last) ) { - - // Have a partial UTF-8 character at the end of the buffer and more input coming. - xmlParser->ParseBuffer ( copy.c_str(), copy.size(), false ); - return (spanEnd - buffer); - - } else { - - // Not a valid UTF-8 sequence. Replace the first byte with the Latin-1 equivalent. - const char * replacement = kReplaceLatin1 [ *spanEnd - 0x80 ]; - copy.append ( replacement ); - - } - - } else if ( (*spanEnd < 0x20) || (*spanEnd == 0x7F) ) { - - // Replace ASCII controls other than tab, LF, and CR with a space. - - if ( (*spanEnd == kTab) || (*spanEnd == kLF) || (*spanEnd == kCR) ) { - copy.push_back(*spanEnd); - continue; - } - - copy.push_back(' '); - - } else { - - // See if this is a numeric escape sequence for a prohibited ASCII control. - - XMP_Assert ( *spanEnd == '&' ); - int escLen = CountControlEscape ( spanEnd, bufEnd ); - - if ( escLen < 0 ) { - - // Have a partial numeric escape in this buffer, wait for more input. - if ( last ) { - copy.push_back('&'); - continue; // No more buffers, not an escape, absorb as normal input. - } - xmlParser->ParseBuffer ( copy.c_str(), copy.size(), false ); - return (spanEnd - buffer); - - } else if ( escLen > 0 ) { - - // Have a complete numeric escape to replace. - copy.push_back(' '); - spanEnd = spanEnd + escLen - 1; // ! The loop continuation will increment spanEnd! - - } else { - copy.push_back('&'); - } - - } - - } - - XMP_Assert ( spanEnd == bufEnd ); - copy.push_back(' '); - xmlParser->ParseBuffer ( copy.c_str(), copy.size(), true ); - return length; - -} // ProcessUTF8Portion - - -// ------------------------------------------------------------------------------------------------- -// ParseFromBuffer -// --------------- -// -// Although most clients will probably parse everything in one call, we have a buffered API model -// and need to support even the extreme case of 1 byte at a time parsing. This is considerably -// complicated by some special cases for 8-bit input. Because of this, the first thing we do is -// determine whether the input is 8-bit, UTF-16, or UTF-32. -// -// Both the 8-bit special cases and the encoding determination are easier to do with 8 bytes or more -// of input. The XMLParserAdapter class has a pending-input buffer for this. At the start of parsing -// we (moght) try to fill this buffer before determining the input character encoding. After that, -// we (might) use this buffer with the current input to simplify the logic in Process8BitInput. The -// "(might)" part means that we don't actually use the pending-input buffer unless we have to. In -// particular, the common case of single-buffer parsing won't use it. - -void -XMPMeta::ParseFromBuffer ( XMP_StringPtr buffer, - XMP_StringLen xmpSize, - XMP_OptionBits options ) -{ - if ( (buffer == 0) && (xmpSize != 0) ) XMP_Throw ( "Null parse buffer", kXMPErr_BadParam ); - if ( xmpSize == kXMP_UseNullTermination ) xmpSize = strlen ( buffer ); - - const bool lastClientCall = ((options & kXMP_ParseMoreBuffers) == 0); // *** Could use FlagIsSet & FlagIsClear macros. - - this->tree.ClearNode(); // Make sure the target XMP object is totally empty. - - if ( this->xmlParser == 0 ) { - if ( (xmpSize == 0) && lastClientCall ) return; // Tolerate empty parse. Expat complains if there are no XML elements. - this->xmlParser = XMP_NewExpatAdapter(); - } - - XMLParserAdapter& parser = *this->xmlParser; - - #if 0 // XMP_DebugBuild - if ( parser.parseLog != 0 ) { - char message [200]; // AUDIT: Using sizeof(message) below for snprintf length is safe. - snprintf ( message, sizeof(message), "", // AUDIT: See above. - xmpSize, options, (lastClientCall ? " (last)" : "") ); - fwrite ( message, 1, strlen(message), parser.parseLog ); - fflush ( parser.parseLog ); - } - #endif - - try { // Cleanup the tree and xmlParser if anything fails. - - // Determine the character encoding before doing any real parsing. This is needed to do the - // 8-bit special processing. - - if ( parser.charEncoding == XMP_OptionBits(-1) ) { - - if ( (parser.pendingCount == 0) && (xmpSize >= kXMLPendingInputMax) ) { - - // This ought to be the common case, the first buffer is big enough. - parser.charEncoding = DetermineInputEncoding ( (XMP_Uns8*)buffer, xmpSize ); - - } else { - - // Try to fill the pendingInput buffer before calling DetermineInputEncoding. - - size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount; - if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize; - - memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe. - buffer += pendingOverlap; - xmpSize -= pendingOverlap; - parser.pendingCount += pendingOverlap; - - if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return; - parser.charEncoding = DetermineInputEncoding ( parser.pendingInput, parser.pendingCount ); - - #if Trace_ParsingHackery - fprintf ( stderr, "XMP Character encoding is %d\n", parser.charEncoding ); - #endif - - } - - } - - // We have the character encoding. Process UTF-16 and UTF-32 as is. UTF-8 needs special - // handling to take care of things like ISO Latin-1 or unescaped ASCII controls. - - XMP_Assert ( parser.charEncoding != XMP_OptionBits(-1) ); - - if ( parser.charEncoding != kXMP_EncodeUTF8 ) { - - if ( parser.pendingCount > 0 ) { - // Might have pendingInput from the above portion to determine the character encoding. - parser.ParseBuffer ( parser.pendingInput, parser.pendingCount, false ); - } - parser.ParseBuffer ( buffer, xmpSize, lastClientCall ); - - } else { - - #if Trace_ParsingHackery - fprintf ( stderr, "Parsing %d bytes @ %.8X, %s, %d pending, context: %.8s\n", - xmpSize, buffer, (lastClientCall ? "last" : "not last"), parser.pendingCount, buffer ); - #endif - - // The UTF-8 processing is a bit complex due to the need to tolerate ISO Latin-1 input. - // This is done by scanning the input for byte sequences that are not valid UTF-8, - // assuming they are Latin-1 characters in the range 0x80..0xFF. This requires saving a - // pending input buffer to handle partial UTF-8 sequences at the end of a buffer. - - while ( parser.pendingCount > 0 ) { - - // We've got some leftover input, process it first then continue with the current - // buffer. Try to fill the pendingInput buffer before parsing further. We use a loop - // for weird edge cases like a 2 byte input buffer, using 1 byte for pendingInput, - // then having a partial UTF-8 end and need to absorb more. - - size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount; - if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize; - - memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe. - parser.pendingCount += pendingOverlap; - buffer += pendingOverlap; - xmpSize -= pendingOverlap; - - if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return; - size_t bytesDone = ProcessUTF8Portion ( &parser, parser.pendingInput, parser.pendingCount, lastClientCall ); - size_t bytesLeft = parser.pendingCount - bytesDone; - - #if Trace_ParsingHackery - fprintf ( stderr, " ProcessUTF8Portion handled %d pending bytes\n", bytesDone ); - #endif - - if ( bytesDone == parser.pendingCount ) { - - // Done with all of the pending input, move on to the current buffer. - parser.pendingCount = 0; - - } else if ( bytesLeft <= pendingOverlap ) { - - // The leftover pending input all came from the current buffer. Exit this loop. - buffer -= bytesLeft; - xmpSize += bytesLeft; - parser.pendingCount = 0; - - } else if ( xmpSize > 0 ) { - - // Pull more of the current buffer into the pending input and try again. - // Backup by this pass's overlap so the loop entry code runs OK. - parser.pendingCount -= pendingOverlap; - buffer -= pendingOverlap; - xmpSize += pendingOverlap; - - } else { - - // There is no more of the current buffer. Wait for more. Partial sequences at - // the end of the last buffer should be treated as Latin-1 by ProcessUTF8Portion. - XMP_Assert ( ! lastClientCall ); - parser.pendingCount = bytesLeft; - memcpy ( &parser.pendingInput[0], &parser.pendingInput[bytesDone], bytesLeft ); // AUDIT: Count is safe. - return; - - } - - } - - // Done with the pending input, process the current buffer. - - size_t bytesDone = ProcessUTF8Portion ( &parser, (XMP_Uns8*)buffer, xmpSize, lastClientCall ); - - #if Trace_ParsingHackery - fprintf ( stderr, " ProcessUTF8Portion handled %d additional bytes\n", bytesDone ); - #endif - - if ( bytesDone < xmpSize ) { - - XMP_Assert ( ! lastClientCall ); - size_t bytesLeft = xmpSize - bytesDone; - if ( bytesLeft > kXMLPendingInputMax ) XMP_Throw ( "Parser bytesLeft too large", kXMPErr_InternalFailure ); - - memcpy ( parser.pendingInput, &buffer[bytesDone], bytesLeft ); // AUDIT: Count is safe. - parser.pendingCount = bytesLeft; - return; // Wait for the next buffer. - - } - - } - - if ( lastClientCall ) { - - #if XMP_DebugBuild && DumpXMLParseTree - if ( parser.parseLog == 0 ) parser.parseLog = stdout; - DumpXMLTree ( parser.parseLog, parser.tree, 0 ); - #endif - - const XML_Node * xmlRoot = FindRootNode ( this, *this->xmlParser, options ); - - if ( xmlRoot != 0 ) { - - ProcessRDF ( &this->tree, *xmlRoot, options ); - NormalizeDCArrays ( &this->tree ); - if ( this->tree.options & kXMP_PropHasAliases ) MoveExplicitAliases ( &this->tree, options ); - TouchUpDataModel ( this ); - - // Delete empty schema nodes. Do this last, other cleanup can make empty schema. - size_t schemaNum = 0; - while ( schemaNum < this->tree.children.size() ) { - XMP_Node * currSchema = this->tree.children[schemaNum]; - if ( currSchema->children.size() > 0 ) { - ++schemaNum; - } else { - delete this->tree.children[schemaNum]; // ! Delete the schema node itself. - this->tree.children.erase ( this->tree.children.begin() + schemaNum ); - } - } - - } - - delete this->xmlParser; - this->xmlParser = 0; - - } - - } catch ( ... ) { - - delete this->xmlParser; - this->xmlParser = 0; - prevTkVer = 0; - this->tree.ClearNode(); - throw; - - } - -} // ParseFromBuffer - -// ================================================================================================= diff --git a/xmpsdk/src/XMPMeta-Serialize.cpp b/xmpsdk/src/XMPMeta-Serialize.cpp deleted file mode 100644 index 70a7b02093..0000000000 --- a/xmpsdk/src/XMPMeta-Serialize.cpp +++ /dev/null @@ -1,1342 +0,0 @@ -// ================================================================================================= // Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// -// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of -// one format in a file with a different format', inventors: Sean Parent, Greg Gilley. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPMeta.hpp" - -#include "XMP_Version.h" -#include "UnicodeInlines.incl_cpp" -#include "UnicodeConversions.hpp" - -#if XMP_DebugBuild - #include -#endif - -using namespace std; - -#if XMP_WinBuild -#ifdef _MSC_VER - #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...' - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) -#endif -#endif - -// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros -// *** Add debug codegen checks, e.g. that typical masking operations really work -// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch - - -// ================================================================================================= -// Local Types and Constants -// ========================= - -static const char * kPacketHeader = ""; -static const char * kPacketTrailer = ""; // ! The w/r is at [size-4]. - -static const char * kRDF_XMPMetaStart = ""; -static const char * kRDF_RDFEnd = ""; - -static const char * kRDF_SchemaStart = ""; - -static const char * kRDF_StructStart = ""; -static const char * kRDF_StructEnd = ""; - -static const char * kRDF_BagStart = ""; - -static const char * kRDF_ItemStart = ""; - -static const char * kRDF_ValueStart = ""; - - -// ================================================================================================= -// Static Variables -// ================ - - -// ================================================================================================= -// Local Utilities -// =============== - - -// ------------------------------------------------------------------------------------------------- -// EstimateRDFSize -// --------------- - -// *** Pull the strlen(kXyz) calls into constants. - -static size_t -EstimateRDFSize ( const XMP_Node * currNode, XMP_Index indent, size_t indentLen ) -{ - size_t outputLen = 2 * (indent*indentLen + currNode->name.size() + 4); // The property element tags. - - if ( ! currNode->qualifiers.empty() ) { - // This node has qualifiers, assume it is written using rdf:value and estimate the qualifiers. - - indent += 2; // Everything else is indented inside the rdf:Description element. - outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags. - outputLen += 2 * (indent*indentLen + strlen(kRDF_ValueStart) + 2); // The rdf:value tags. - - for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = currNode->qualifiers[qualNum]; - outputLen += EstimateRDFSize ( currQual, indent, indentLen ); - } - - } - - if ( currNode->options & kXMP_PropValueIsStruct ) { - indent += 1; - outputLen += 2 * (indent*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags. - } else if ( currNode->options & kXMP_PropValueIsArray ) { - indent += 2; - outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_BagStart) + 2); // The rdf:Bag/Seq/Alt tags. - outputLen += 2 * currNode->children.size() * (strlen(kRDF_ItemStart) + 2); // The rdf:li tags, indent counted in children. - } else if ( ! (currNode->options & kXMP_SchemaNode) ) { - outputLen += currNode->value.size(); // This is a leaf value node. - } - - for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) { - const XMP_Node * currChild = currNode->children[childNum]; - outputLen += EstimateRDFSize ( currChild, indent+1, indentLen ); - } - - return outputLen; - -} // EstimateRDFSize - - -// ------------------------------------------------------------------------------------------------- -// DeclareOneNamespace -// ------------------- - -static void -DeclareOneNamespace ( const XMP_VarString & nsPrefix, - const XMP_VarString & nsURI, - XMP_VarString & usedNS, // ! A catenation of the prefixes with colons. - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) -{ - size_t nsPos = usedNS.find ( nsPrefix ); - - if ( nsPos == XMP_VarString::npos ) { - - outputStr += newline; - for ( ; indent > 0; --indent ) outputStr += indentStr; - outputStr += "xmlns:"; - outputStr += nsPrefix; - outputStr[outputStr.size()-1] = '='; // Change the colon to =. - outputStr += '"'; - outputStr += nsURI; - outputStr += '"'; - - usedNS += nsPrefix; - - } - -} // DeclareOneNamespace - - -// ------------------------------------------------------------------------------------------------- -// DeclareElemNamespace -// -------------------- - -static void -DeclareElemNamespace ( const XMP_VarString & elemName, - XMP_VarString & usedNS, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) -{ - size_t colonPos = elemName.find ( ':' ); - - if ( colonPos != XMP_VarString::npos ) { - XMP_VarString nsPrefix ( elemName.substr ( 0, colonPos+1 ) ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix ); - XMP_Enforce ( prefixPos != sNamespacePrefixToURIMap->end() ); - DeclareOneNamespace ( nsPrefix, prefixPos->second, usedNS, outputStr, newline, indentStr, indent ); - } - -} // DeclareElemNamespace - - -// ------------------------------------------------------------------------------------------------- -// DeclareUsedNamespaces -// --------------------- - -// ??? Should iterators be passed by reference to avoid temp copies? - -static void -DeclareUsedNamespaces ( const XMP_Node * currNode, - XMP_VarString & usedNS, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) -{ - - if ( currNode->options & kXMP_SchemaNode ) { - // The schema node name is the URI, the value is the prefix. - DeclareOneNamespace ( currNode->value, currNode->name, usedNS, outputStr, newline, indentStr, indent ); - } else if ( currNode->options & kXMP_PropValueIsStruct ) { - for ( size_t fieldNum = 0, fieldLim = currNode->children.size(); fieldNum < fieldLim; ++fieldNum ) { - const XMP_Node * currField = currNode->children[fieldNum]; - DeclareElemNamespace ( currField->name, usedNS, outputStr, newline, indentStr, indent ); - } - } - - for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) { - const XMP_Node * currChild = currNode->children[childNum]; - DeclareUsedNamespaces ( currChild, usedNS, outputStr, newline, indentStr, indent ); - } - - for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = currNode->qualifiers[qualNum]; - DeclareElemNamespace ( currQual->name, usedNS, outputStr, newline, indentStr, indent ); - DeclareUsedNamespaces ( currQual, usedNS, outputStr, newline, indentStr, indent ); - } - -} // DeclareUsedNamespaces - -// ------------------------------------------------------------------------------------------------- -// EmitRDFArrayTag -// --------------- - -// ??? Should iterators be passed by reference to avoid temp copies? - -enum { - kIsStartTag = true, - kIsEndTag = false -}; - -static void -EmitRDFArrayTag ( XMP_OptionBits arrayForm, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent, - XMP_Index arraySize, - bool isStartTag ) -{ - if ( (! isStartTag) && (arraySize == 0) ) return; - - for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr; - if ( isStartTag ) { - outputStr += "', and ASCII controls (tab, LF, CR). In -// addition, '"' is escaped for attributes. For efficiency, this is done in a double loop. The outer -// loop makes sure the whole value is processed. The inner loop does a contiguous unescaped run -// followed by one escaped character (if we're not at the end). -// -// We depend on parsing and SetProperty logic to make sure there are no invalid ASCII controls in -// the XMP values. The XML spec only allows tab, LF, and CR. Others are not even allowed as -// numeric escape sequences. - -enum { - kForAttribute = true, - kForElement = false -}; - -static void -AppendNodeValue ( XMP_VarString & outputStr, const XMP_VarString & value, bool forAttribute ) -{ - - unsigned char * runStart = (unsigned char *) value.c_str(); - unsigned char * runLimit = runStart + value.size(); - unsigned char * runEnd; - unsigned char ch=0; - - while ( runStart < runLimit ) { - - for ( runEnd = runStart; runEnd < runLimit; ++runEnd ) { - ch = *runEnd; - if ( forAttribute && (ch == '"') ) break; - if ( (ch < 0x20) || (ch == '&') || (ch == '<') || (ch == '>') ) break; - } - - outputStr.append ( (char *) runStart, (runEnd - runStart) ); - - if ( runEnd < runLimit ) { - - if ( ch < 0x20 ) { - - XMP_Assert ( (ch == kTab) || (ch == kLF) || (ch == kCR) ); - - char hexBuf[16]; - memcpy ( hexBuf, "&#xn;", 5 ); - hexBuf[3] = kHexDigits[ch&0xF]; - outputStr.append ( hexBuf, 5 ); - - } else { - - if ( ch == '"' ) { - outputStr += """; - } else if ( ch == '<' ) { - outputStr += "<"; - } else if ( ch == '>' ) { - outputStr += ">"; - } else { - XMP_Assert ( ch == '&' ); - outputStr += "&"; - } - - } - - ++runEnd; - - } - - runStart = runEnd; - - } - -} // AppendNodeValue - - -// ------------------------------------------------------------------------------------------------- -// CanBeRDFAttrProp -// ---------------- - -static bool -CanBeRDFAttrProp ( const XMP_Node * propNode ) -{ - - if ( propNode->name[0] == '[' ) return false; - if ( ! propNode->qualifiers.empty() ) return false; - if ( propNode->options & kXMP_PropValueIsURI ) return false; - if ( propNode->options & kXMP_PropCompositeMask ) return false; - - return true; - -} // CanBeRDFAttrProp - - -// ------------------------------------------------------------------------------------------------- -// IsRDFAttrQualifier -// ------------------ - -static XMP_StringPtr sAttrQualifiers[] = { "xml:lang", "rdf:resource", "rdf:ID", "rdf:bagID", "rdf:nodeID", "" }; - -static bool -IsRDFAttrQualifier ( XMP_VarString qualName ) -{ - - for ( size_t i = 0; *sAttrQualifiers[i] != 0; ++i ) { - if ( qualName == sAttrQualifiers[i] ) return true; - } - - return false; - -} // IsRDFAttrQualifier - - -// ------------------------------------------------------------------------------------------------- -// SerializePrettyRDFProperty -// -------------------------- -// -// Recursively handles the "value" for a node. It does not matter if it is a top level property, a -// field of a struct, or an item of an array. The indent is that for the property element. An -// xml:lang qualifier is written as an attribute of the property start tag, not by itself forcing -// the qualified property form. The patterns below mostly ignore attribute qualifiers like xml:lang. -// Except for the one struct case, attribute qualifiers don't affect the output form. -// -// value -// -// (If no rdf:resource qualifier) -// ... Fields, same forms as top level properties -// -// -// -// -// -// or Seq or Alt -// ... Array items as rdf:li elements, same forms as top level properties -// -// -// -// -// ... Property "value" following the unqualified forms ... -// ... Qualifiers looking like named struct fields -// - -static void -SerializePrettyRDFProperty ( const XMP_Node * propNode, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent, - bool emitAsRDFValue = false ) -{ - XMP_Index level; - bool emitEndTag = true; - bool indentEndTag = true; - - XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask; - - // ------------------------------------------------------------------------------------------ - // Determine the XML element name. Open the start tag with the name and attribute qualifiers. - - XMP_StringPtr elemName = propNode->name.c_str(); - if ( emitAsRDFValue ) { - elemName= "rdf:value"; - } else if ( *elemName == '[' ) { - elemName = "rdf:li"; - } - - for ( level = indent; level > 0; --level ) outputStr += indentStr; - outputStr += '<'; - outputStr += elemName; - - #define isCompact false - bool hasGeneralQualifiers = isCompact; // Might also become true later. - bool hasRDFResourceQual = false; - - for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = propNode->qualifiers[qualNum]; - if ( ! IsRDFAttrQualifier ( currQual->name ) ) { - hasGeneralQualifiers = true; - } else { - if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true; - if ( ! emitAsRDFValue ) { - outputStr += ' '; - outputStr += currQual->name; - outputStr += "=\""; - AppendNodeValue ( outputStr, currQual->value, kForAttribute ); - outputStr += '"'; - } - } - } - - // -------------------------------------------------------- - // Process the property according to the standard patterns. - - if ( hasGeneralQualifiers && (! emitAsRDFValue) ) { - - // ----------------------------------------------------------------------------------------- - // This node has general, non-attribute, qualifiers. Emit using the qualified property form. - // ! The value is output by a recursive call ON THE SAME NODE with emitAsRDFValue set. - - if ( hasRDFResourceQual ) { - XMP_Throw ( "Can't mix rdf:resource and general qualifiers", kXMPErr_BadRDF ); - } - - outputStr += " rdf:parseType=\"Resource\">"; - outputStr += newline; - - SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true ); - - for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = propNode->qualifiers[qualNum]; - if ( IsRDFAttrQualifier ( currQual->name ) ) continue; - SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, indent+1 ); - } - - } else { - - // -------------------------------------------------------------------- - // This node has no general qualifiers. Emit using an unqualified form. - - if ( propForm == 0 ) { - - // -------------------------- - // This is a simple property. - - if ( propNode->options & kXMP_PropValueIsURI ) { - outputStr += " rdf:resource=\""; - AppendNodeValue ( outputStr, propNode->value, kForAttribute ); - outputStr += "\"/>"; - outputStr += newline; - emitEndTag = false; - } else if ( propNode->value.empty() ) { - outputStr += "/>"; - outputStr += newline; - emitEndTag = false; - } else { - outputStr += '>'; - AppendNodeValue ( outputStr, propNode->value, kForElement ); - indentEndTag = false; - } - - } else if ( propForm & kXMP_PropValueIsArray ) { - - // This is an array. - outputStr += '>'; - outputStr += newline; - EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag ); - if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode ); - for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) { - const XMP_Node * currChild = propNode->children[childNum]; - SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, indent+2 ); - } - EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag ); - - - } else if ( ! hasRDFResourceQual ) { - - // This is a "normal" struct, use the rdf:parseType="Resource" form. - XMP_Assert ( propForm & kXMP_PropValueIsStruct ); - if ( propNode->children.size() == 0 ) { - outputStr += " rdf:parseType=\"Resource\"/>"; - outputStr += newline; - emitEndTag = false; - } else { - outputStr += " rdf:parseType=\"Resource\">"; - outputStr += newline; - for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) { - const XMP_Node * currChild = propNode->children[childNum]; - SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, indent+1 ); - } - } - - } else { - - // This is a struct with an rdf:resource attribute, use the "empty property element" form. - XMP_Assert ( propForm & kXMP_PropValueIsStruct ); - for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) { - const XMP_Node * currChild = propNode->children[childNum]; - if ( ! CanBeRDFAttrProp ( currChild ) ) { - XMP_Throw ( "Can't mix rdf:resource and complex fields", kXMPErr_BadRDF ); - } - outputStr += newline; - for ( level = indent+1; level > 0; --level ) outputStr += indentStr; - outputStr += ' '; - outputStr += currChild->name; - outputStr += "=\""; - outputStr += currChild->value; - outputStr += '"'; - } - outputStr += "/>"; - outputStr += newline; - emitEndTag = false; - - } - - } - - // ---------------------------------- - // Emit the property element end tag. - - if ( emitEndTag ) { - if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr; - outputStr += "'; - outputStr += newline; - } - -} // SerializePrettyRDFProperty - - -// ------------------------------------------------------------------------------------------------- -// SerializePrettyRDFSchema -// ------------------------ -// -// Each schema's properties are written in a separate rdf:Description element. All of the necessary -// namespaces are declared in the rdf:Description element. The baseIndent is the base level for the -// entire serialization, that of the x:xmpmeta element. An xml:lang qualifier is written as an -// attribute of the property start tag, not by itself forcing the qualified property form. -// -// -// -// ... The actual properties of the schema, see SerializePrettyRDFProperty -// -// ... If alias comments are wanted -// -// - -static void -SerializePrettyRDFSchema ( const XMP_VarString & treeName, - const XMP_Node * schemaNode, - XMP_VarString & outputStr, - XMP_OptionBits options, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index baseIndent ) -{ - XMP_Assert ( schemaNode->options & kXMP_SchemaNode ); - XMP_Assert ( schemaNode->qualifiers.empty() ); - - // Write the rdf:Description start tag with the namespace declarations. - - XMP_Index level; - for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; - outputStr += kRDF_SchemaStart; - outputStr += '"'; - outputStr += treeName; - outputStr += '"'; - - size_t totalLen = 8; // Start at 8 for "xml:rdf:". - XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); - XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); - for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); - - XMP_VarString usedNS; - usedNS.reserve ( totalLen ); - usedNS = "xml:rdf:"; - DeclareUsedNamespaces ( schemaNode, usedNS, outputStr, newline, indentStr, baseIndent+4 ); - - outputStr += ">"; - outputStr += newline; - - // Write alias comments, if wanted. - - if ( options & kXMP_WriteAliasComments ) { // *** Hoist into a routine, used for Plain XMP also. - - #if 0 // *** Buggy, disable for now. - - XMP_cAliasMapPos aliasPos = sRegisteredAliasMap->begin(); - XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end(); - - for ( ; aliasPos != aliasEnd; ++aliasPos ) { - - size_t nsPos = aliasPos->first.find ( schemaNode->value ); - if ( nsPos == XMP_VarString::npos ) continue; - XMP_Assert ( nsPos == 0 ); - - for ( level = baseIndent+3; level > 0; --level ) outputStr += indentStr; - - outputStr += ""; - outputStr += newline; - - } - - #endif - - } - - // Write each of the schema's actual properties. - for ( size_t propNum = 0, propLim = schemaNode->children.size(); propNum < propLim; ++propNum ) { - const XMP_Node * currProp = schemaNode->children[propNum]; - SerializePrettyRDFProperty ( currProp, outputStr, newline, indentStr, baseIndent+3 ); - } - - // Write the rdf:Description end tag. - for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; - outputStr += kRDF_SchemaEnd; - outputStr += newline; - -} // SerializePrettyRDFSchema - - -// ------------------------------------------------------------------------------------------------- -// SerializeCompactRDFAttrProps -// ---------------------------- -// -// Write each of the parent's simple unqualified properties as an attribute. Returns true if all -// of the properties are written as attributes. - -static bool -SerializeCompactRDFAttrProps ( const XMP_Node * parentNode, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) -{ - size_t prop, propLim; - bool allAreAttrs = true; - - for ( prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) { - - const XMP_Node * currProp = parentNode->children[prop]; - if ( ! CanBeRDFAttrProp ( currProp ) ) { - allAreAttrs = false; - continue; - } - - outputStr += newline; - for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr; - outputStr += currProp->name; - outputStr += "=\""; - AppendNodeValue ( outputStr, currProp->value, kForAttribute ); - outputStr += '"'; - - } - - return allAreAttrs; - -} // SerializeCompactRDFAttrProps - - -// ------------------------------------------------------------------------------------------------- -// SerializeCompactRDFElemProps -// ---------------------------- -// -// Recursively handles the "value" for a node that must be written as an RDF property element. It -// does not matter if it is a top level property, a field of a struct, or an item of an array. The -// indent is that for the property element. The patterns bwlow ignore attribute qualifiers such as -// xml:lang, they don't affect the output form. -// -// -// -// -// ... The fields as elements, if none are simple and unqualified -// -// -// -// -// ... The compound or qualified fields as elements -// -// -// -// -// or Seq or Alt -// ... Array items as rdf:li elements, same forms as top level properties -// -// -// -// -// ... Property "value" following the unqualified forms ... -// ... Qualifiers looking like named struct fields -// - -// *** Consider numbered array items, but has compatibility problems. -// *** Consider qualified form with rdf:Description and attributes. - -static void -SerializeCompactRDFElemProps ( const XMP_Node * parentNode, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) -{ - XMP_Index level; - - for ( size_t prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) { - - const XMP_Node * propNode = parentNode->children[prop]; - if ( CanBeRDFAttrProp ( propNode ) ) continue; - - bool emitEndTag = true; - bool indentEndTag = true; - - XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask; - - // ----------------------------------------------------------------------------------- - // Determine the XML element name, write the name part of the start tag. Look over the - // qualifiers to decide on "normal" versus "rdf:value" form. Emit the attribute - // qualifiers at the same time. - - XMP_StringPtr elemName = propNode->name.c_str(); - if ( *elemName == '[' ) elemName = "rdf:li"; - - for ( level = indent; level > 0; --level ) outputStr += indentStr; - outputStr += '<'; - outputStr += elemName; - - #define isCompact false - bool hasGeneralQualifiers = isCompact; // Might also become true later. - bool hasRDFResourceQual = false; - - for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = propNode->qualifiers[qualNum]; - if ( ! IsRDFAttrQualifier ( currQual->name ) ) { - hasGeneralQualifiers = true; - } else { - if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true; - outputStr += ' '; - outputStr += currQual->name; - outputStr += "=\""; - AppendNodeValue ( outputStr, currQual->value, kForAttribute ); - outputStr += '"'; - } - } - - // -------------------------------------------------------- - // Process the property according to the standard patterns. - - if ( hasGeneralQualifiers ) { - - // ------------------------------------------------------------------------------------- - // The node has general qualifiers, ones that can't be attributes on a property element. - // Emit using the qualified property pseudo-struct form. The value is output by a call - // to SerializePrettyRDFProperty with emitAsRDFValue set. - - // *** We're losing compactness in the calls to SerializePrettyRDFProperty. - // *** Should refactor to have SerializeCompactRDFProperty that does one node. - - outputStr += " rdf:parseType=\"Resource\">"; - outputStr += newline; - - SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true ); - - size_t qualNum = 0; - size_t qualLim = propNode->qualifiers.size(); - if ( propNode->options & kXMP_PropHasLang ) ++qualNum; - - for ( ; qualNum < qualLim; ++qualNum ) { - const XMP_Node * currQual = propNode->qualifiers[qualNum]; - SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, indent+1 ); - } - - } else { - - // -------------------------------------------------------------------- - // This node has only attribute qualifiers. Emit as a property element. - - if ( propForm == 0 ) { - - // -------------------------- - // This is a simple property. - - if ( propNode->options & kXMP_PropValueIsURI ) { - outputStr += " rdf:resource=\""; - AppendNodeValue ( outputStr, propNode->value, kForAttribute ); - outputStr += "\"/>"; - outputStr += newline; - emitEndTag = false; - } else if ( propNode->value.empty() ) { - outputStr += "/>"; - outputStr += newline; - emitEndTag = false; - } else { - outputStr += '>'; - AppendNodeValue ( outputStr, propNode->value, kForElement ); - indentEndTag = false; - } - - } else if ( propForm & kXMP_PropValueIsArray ) { - - // ----------------- - // This is an array. - - outputStr += '>'; - outputStr += newline; - EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag ); - - if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode ); - SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+2 ); - - EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag ); - - } else { - - // ---------------------- - // This must be a struct. - - XMP_Assert ( propForm & kXMP_PropValueIsStruct ); - - bool hasAttrFields = false; - bool hasElemFields = false; - - size_t field, fieldLim; - for ( field = 0, fieldLim = propNode->children.size(); field != fieldLim; ++field ) { - XMP_Node * currField = propNode->children[field]; - if ( CanBeRDFAttrProp ( currField ) ) { - hasAttrFields = true; - if ( hasElemFields ) break; // No sense looking further. - } else { - hasElemFields = true; - if ( hasAttrFields ) break; // No sense looking further. - } - } - - if ( hasRDFResourceQual && hasElemFields ) { - XMP_Throw ( "Can't mix rdf:resource qualifier and element fields", kXMPErr_BadRDF ); - } - - if ( propNode->children.size() == 0 ) { - - // Catch an empty struct as a special case. The case below would emit an empty - // XML element, which gets reparsed as a simple property with an empty value. - outputStr += " rdf:parseType=\"Resource\"/>"; - outputStr += newline; - emitEndTag = false; - - } else if ( ! hasElemFields ) { - - // All fields can be attributes, use the emptyPropertyElt form. - SerializeCompactRDFAttrProps ( propNode, outputStr, newline, indentStr, indent+1 ); - outputStr += "/>"; - outputStr += newline; - emitEndTag = false; - - } else if ( ! hasAttrFields ) { - - // All fields must be elements, use the parseTypeResourcePropertyElt form. - outputStr += " rdf:parseType=\"Resource\">"; - outputStr += newline; - SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+1 ); - - } else { - - // Have a mix of attributes and elements, use an inner rdf:Description. - outputStr += '>'; - outputStr += newline; - for ( level = indent+1; level > 0; --level ) outputStr += indentStr; - outputStr += " 0; --level ) outputStr += indentStr; - outputStr += kRDF_StructEnd; - outputStr += newline; - - } - - } - - } - - // ---------------------------------- - // Emit the property element end tag. - - if ( emitEndTag ) { - if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr; - outputStr += "'; - outputStr += newline; - } - - } - -} // SerializeCompactRDFElemProps - - -// ------------------------------------------------------------------------------------------------- -// SerializeCompactRDFSchemas -// -------------------------- -// -// All properties from all schema are written in a single rdf:Description element, as are all of the -// necessary namespace declarations. The baseIndent is the base level for the entire serialization, -// that of the x:xmpmeta element. The x:xmpmeta and rdf:RDF elements have already been written. -// -// Top level simple unqualified properties are written as attributes of the (only) rdf:Description -// element. Structs, arrays, and qualified properties are written by SerializeCompactRDFElemProp. An -// xml:lang qualifier on a simple property prevents the attribute form. -// -// -// ... The remaining properties of the schema, see SerializeCompactRDFElemProps -// - -static void -SerializeCompactRDFSchemas ( const XMP_Node & xmpTree, - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index baseIndent ) -{ - XMP_Index level; - size_t schema, schemaLim; - - // Begin the rdf:Description start tag. - for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; - outputStr += kRDF_SchemaStart; - outputStr += '"'; - outputStr += xmpTree.name; - outputStr += '"'; - - // Write all necessary xmlns attributes. - - size_t totalLen = 8; // Start at 8 for "xml:rdf:". - XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); - XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); - for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); - - XMP_VarString usedNS; - usedNS.reserve ( totalLen ); - usedNS = "xml:rdf:"; - - for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { - const XMP_Node * currSchema = xmpTree.children[schema]; - DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 ); - } - - // Write the top level "attrProps" and close the rdf:Description start tag. - bool allAreAttrs = true; - for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { - const XMP_Node * currSchema = xmpTree.children[schema]; - allAreAttrs &= SerializeCompactRDFAttrProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 ); - } - if ( ! allAreAttrs ) { - outputStr += ">"; - outputStr += newline; - } else { - outputStr += "/>"; - outputStr += newline; - return; // ! Done if all properties in all schema are written as attributes. - } - - // Write the remaining properties for each schema. - for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { - const XMP_Node * currSchema = xmpTree.children[schema]; - SerializeCompactRDFElemProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 ); - } - - // Write the rdf:Description end tag. - // *** Elide the end tag if everything (all props in all schema) is an attr. - for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; - outputStr += kRDF_SchemaEnd; - outputStr += newline; - -} // SerializeCompactRDFSchemas - - -// ------------------------------------------------------------------------------------------------- -// SerializeAsRDF -// -------------- -// -// -// -// -// -// ... The properties, see SerializePrettyRDFSchema or SerializeCompactRDFSchemas -// -// -// -// - -// *** Need to strip empty arrays? -// *** Option to strip/keep empty structs? -// *** Need to verify handling of rdf:type qualifiers in pretty and compact. -// *** Need to verify round tripping of rdf:ID and similar qualifiers, see RDF 7.2.21. -// *** Check cases of rdf:resource plus explicit attr qualifiers (like xml:lang). - -static void -SerializeAsRDF ( const XMPMeta & xmpObj, - XMP_VarString & headStr, // Everything up to the padding. - XMP_VarString & tailStr, // Everything after the padding. - XMP_OptionBits options, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index baseIndent ) -{ - const size_t treeNameLen = xmpObj.tree.name.size(); - const size_t indentLen = strlen ( indentStr ); - - // First estimate the worst case space and reserve room in the output string. This optimization - // avoids reallocating and copying the output as it grows. The initial count does not look at - // the values of properties, so it does not account for character entities, e.g. for newline. - // Since there can be a lot of these in things like the base 64 encoding of a large thumbnail, - // inflate the count by 1/4 (easy to do) to accommodate. - - // *** Need to include estimate for alias comments. - - size_t outputLen = 2 * (strlen(kPacketHeader) + strlen(kRDF_XMPMetaStart) + strlen(kRDF_RDFStart) + 3*baseIndent*indentLen); - - for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { - const XMP_Node * currSchema = xmpObj.tree.children[schemaNum]; - outputLen += 2*(baseIndent+2)*indentLen + strlen(kRDF_SchemaStart) + treeNameLen + strlen(kRDF_SchemaEnd) + 2; - outputLen += EstimateRDFSize ( currSchema, baseIndent+2, indentLen ); - } - - outputLen += (outputLen >> 2); // Inflate by 1/4, an empirical fudge factor. - - // Now generate the RDF into the head string as UTF-8. - - XMP_Index level; - - headStr.erase(); - headStr.reserve ( outputLen ); - - // Write the packet header PI. - if ( ! (options & kXMP_OmitPacketWrapper) ) { - for ( level = baseIndent; level > 0; --level ) headStr += indentStr; - headStr += kPacketHeader; - headStr += newline; - } - - // Write the xmpmeta element's start tag. - if ( ! (options & kXMP_OmitXMPMetaElement) ) { - for ( level = baseIndent; level > 0; --level ) headStr += indentStr; - headStr += kRDF_XMPMetaStart; - headStr += kXMPCore_VersionMessage "\">"; - headStr += newline; - } - - // Write the rdf:RDF start tag. - for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr; - headStr += kRDF_RDFStart; - headStr += newline; - - // Write all of the properties. - if ( options & kXMP_UseCompactFormat ) { - SerializeCompactRDFSchemas ( xmpObj.tree, headStr, newline, indentStr, baseIndent ); - } else { - if ( xmpObj.tree.children.size() > 0 ) { - for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { - const XMP_Node * currSchema = xmpObj.tree.children[schemaNum]; - SerializePrettyRDFSchema ( xmpObj.tree.name, currSchema, headStr, options, newline, indentStr, baseIndent ); - } - } else { - for ( XMP_Index level = baseIndent+2; level > 0; --level ) headStr += indentStr; - headStr += kRDF_SchemaStart; // Special case an empty XMP object. - headStr += '"'; - headStr += xmpObj.tree.name; - headStr += "\"/>"; - headStr += newline; - } - } - - // Write the rdf:RDF end tag. - for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr; - headStr += kRDF_RDFEnd; - headStr += newline; - - // Write the xmpmeta end tag. - if ( ! (options & kXMP_OmitXMPMetaElement) ) { - for ( level = baseIndent; level > 0; --level ) headStr += indentStr; - headStr += kRDF_XMPMetaEnd; - headStr += newline; - } - - // Write the packet trailer PI into the tail string as UTF-8. - tailStr.erase(); - if ( ! (options & kXMP_OmitPacketWrapper) ) { - tailStr.reserve ( strlen(kPacketTrailer) + (strlen(indentStr) * baseIndent) ); - for ( level = baseIndent; level > 0; --level ) tailStr += indentStr; - tailStr += kPacketTrailer; - if ( options & kXMP_ReadOnlyPacket ) tailStr[tailStr.size()-4] = 'r'; - } - - // ! This assert is just a performance check, to see if the reserve was enough. - // *** XMP_Assert ( headStr.size() <= outputLen ); - // *** Don't use an assert. Think of some way to track this without risk of aborting the client. - -} // SerializeAsRDF - -// ------------------------------------------------------------------------------------------------- -// SerializeToBuffer -// ----------------- - -void -XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index baseIndent ) const -{ - XMP_Assert ( (rdfString != 0) && (rdfSize != 0) && (newline != 0) && (indentStr != 0) ); - - // Fix up some default parameters. - - enum { kDefaultPad = 2048 }; - size_t unicodeUnitSize = 1; - XMP_OptionBits charEncoding = options & kXMP_EncodingMask; - - if ( charEncoding != kXMP_EncodeUTF8 ) { - if ( options & _XMP_UTF16_Bit ) { - if ( options & _XMP_UTF32_Bit ) XMP_Throw ( "Can't use both _XMP_UTF16_Bit and _XMP_UTF32_Bit", kXMPErr_BadOptions ); - unicodeUnitSize = 2; - } else if ( options & _XMP_UTF32_Bit ) { - unicodeUnitSize = 4; - } else { - XMP_Throw ( "Can't use _XMP_LittleEndian_Bit by itself", kXMPErr_BadOptions ); - } - } - - if ( options & kXMP_OmitAllFormatting ) { - newline = " "; // ! Yes, a space for "newline". This ensures token separation. - indentStr = ""; - } else { - if ( *newline == 0 ) newline = "\xA"; // Linefeed - if ( *indentStr == 0 ) { - indentStr = " "; - if ( ! (options & kXMP_UseCompactFormat) ) indentStr = " "; - } - } - - if ( options & kXMP_ExactPacketLength ) { - if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) { - XMP_Throw ( "Inconsistent options for exact size serialize", kXMPErr_BadOptions ); - } - if ( (padding & (unicodeUnitSize-1)) != 0 ) { - XMP_Throw ( "Exact size must be a multiple of the Unicode element", kXMPErr_BadOptions ); - } - } else if ( options & kXMP_ReadOnlyPacket ) { - if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) { - XMP_Throw ( "Inconsistent options for read-only packet", kXMPErr_BadOptions ); - } - padding = 0; - } else if ( options & kXMP_OmitPacketWrapper ) { - if ( options & kXMP_IncludeThumbnailPad ) { - XMP_Throw ( "Inconsistent options for non-packet serialize", kXMPErr_BadOptions ); - } - padding = 0; - } else { - if ( padding == 0 ) padding = kDefaultPad * unicodeUnitSize; - if ( options & kXMP_IncludeThumbnailPad ) { - if ( ! this->DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) padding += (10000 * unicodeUnitSize); // *** Need a better estimate. - } - } - - // Serialize as UTF-8, then convert to UTF-16 or UTF-32 if necessary, and assemble with the padding and tail. - - std::string tailStr; - - SerializeAsRDF ( *this, *sOutputStr, tailStr, options, newline, indentStr, baseIndent ); - if ( charEncoding == kXMP_EncodeUTF8 ) { - - if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); - if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); - padding -= minSize; // Now the actual amount of padding to add. - } - - size_t newlineLen = strlen ( newline ); - - if ( padding < newlineLen ) { - sOutputStr->append ( padding, ' ' ); - } else { - padding -= newlineLen; // Write this newline last. - while ( padding >= (100 + newlineLen) ) { - sOutputStr->append ( 100, ' ' ); - *sOutputStr += newline; - padding -= (100 + newlineLen); - } - sOutputStr->append ( padding, ' ' ); - *sOutputStr += newline; - } - - *sOutputStr += tailStr; - - } else { - - // Need to convert the encoding. Swap the UTF-8 into a local string and convert back. Assemble everything. - - XMP_VarString utf8Str, newlineStr; - bool bigEndian = ((charEncoding & _XMP_LittleEndian_Bit) == 0); - - if ( charEncoding & _XMP_UTF16_Bit ) { - - std::string padStr ( " " ); padStr[0] = 0; // Assume big endian. - - utf8Str.swap ( *sOutputStr ); - ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian ); - utf8Str.swap ( tailStr ); - ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian ); - - if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); - if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); - padding -= minSize; // Now the actual amount of padding to add (in bytes). - } - - utf8Str.assign ( newline ); - ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian ); - size_t newlineLen = newlineStr.size(); - - if ( padding < newlineLen ) { - for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr; - } else { - padding -= newlineLen; // Write this newline last. - while ( padding >= (200 + newlineLen) ) { - for ( int i = 100; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; - padding -= (200 + newlineLen); - } - for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; - } - - *sOutputStr += tailStr; - - } else { - - std::string padStr ( " " ); padStr[0] = padStr[1] = padStr[2] = 0; // Assume big endian. -// UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32BE; - - if ( charEncoding & _XMP_LittleEndian_Bit ) { - padStr[0] = ' '; padStr[1] = padStr[2] = padStr[3] = 0; -// Converter = UTF8_to_UTF32LE; - } - - utf8Str.swap ( *sOutputStr ); - ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian ); - utf8Str.swap ( tailStr ); - ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian ); - - if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); - if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); - padding -= minSize; // Now the actual amount of padding to add (in bytes). - } - - utf8Str.assign ( newline ); - ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian ); - size_t newlineLen = newlineStr.size(); - - if ( padding < newlineLen ) { - for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr; - } else { - padding -= newlineLen; // Write this newline last. - while ( padding >= (400 + newlineLen) ) { - for ( int i = 100; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; - padding -= (400 + newlineLen); - } - for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; - } - - *sOutputStr += tailStr; - - } - - } - - // Return the finished string. - - *rdfString = sOutputStr->c_str(); - *rdfSize = sOutputStr->size(); - -} // SerializeToBuffer - -// ================================================================================================= diff --git a/xmpsdk/src/XMPMeta.cpp b/xmpsdk/src/XMPMeta.cpp deleted file mode 100644 index 30ff4a5a75..0000000000 --- a/xmpsdk/src/XMPMeta.cpp +++ /dev/null @@ -1,1653 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// -// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of -// one format in a file with a different format', inventors: Sean Parent, Greg Gilley. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include - -#include "XMPMeta.hpp" -#include "XMPIterator.hpp" -#include "XMPUtils.hpp" -#include "XMP_Version.h" -#include "UnicodeInlines.incl_cpp" -#include "UnicodeConversions.hpp" - -#include // For sort and stable_sort. - -#if XMP_DebugBuild - #include -#endif - -using namespace std; - -#if XMP_WinBuild -#ifdef _MSC_VER - #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...' - #pragma warning ( disable : 4702 ) // unreachable code - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #pragma warning ( disable : 4996 ) // '...' was declared deprecated -#endif -#endif - - -// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros -// *** Add debug codegen checks, e.g. that typical masking operations really work -// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch - - -// ================================================================================================= -// Local Types and Constants -// ========================= - - -// ================================================================================================= -// Static Variables -// ================ - -XMP_VarString * xdefaultName = 0; - -// These are embedded version strings. - -const char * kXMPCore_EmbeddedVersion = kXMPCore_VersionMessage; -const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr; - -// ================================================================================================= -// Local Utilities -// =============== - -#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) ) -#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) ) - -static const char * kTenSpaces = " "; -#define OutProcPadding(pad) { size_t padLen = (pad); \ - for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \ - for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); } - - -#define OutProcNewline() { status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) goto EXIT; } - -#define OutProcNChars(p,n) { status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) goto EXIT; } - -#define OutProcLiteral(lit) { status = (*outProc) ( refCon, (lit), strlen(lit) ); if ( status != 0 ) goto EXIT; } - -#define OutProcString(str) { status = (*outProc) ( refCon, (str).c_str(), (str).size() ); if ( status != 0 ) goto EXIT; } - -#define OutProcULong(num) { snprintf ( buffer, sizeof(buffer), "%lu", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } -#ifdef __APPLE__ -#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } -#else -#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%lX", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } -#endif - -#define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } - -static const char * kIndent = " "; -#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); } - - -// ------------------------------------------------------------------------------------------------- -// DumpClearString -// --------------- - -static XMP_Status -DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon ) -{ - - char buffer [20]; - bool prevNormal; - XMP_Status status = 0; - - XMP_StringPtr spanStart, spanEnd; - XMP_StringPtr valueEnd = &value[0] + value.size(); - - spanStart = &value[0]; - while ( spanStart < valueEnd ) { - - // Output the next span of regular characters. - for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) { - if ( (unsigned char)(*spanEnd) > 0x7F ) break; - if ( (*spanEnd < 0x20) && (*spanEnd != kTab) && (*spanEnd != kLF) ) break; - } - if ( spanStart != spanEnd ) status = (*outProc) ( refCon, spanStart, (spanEnd-spanStart) ); - if ( status != 0 ) break; - spanStart = spanEnd; - - // Output the next span of irregular characters. - prevNormal = true; - for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) { - if ( ((0x20 <= *spanEnd) && ((unsigned char)(*spanEnd) <= 0x7F)) || (*spanEnd == kTab) || (*spanEnd == kLF) ) break; - char space = ' '; - if ( prevNormal ) space = '<'; - status = (*outProc) ( refCon, &space, 1 ); - if ( status != 0 ) break; - OutProcHexByte ( *spanEnd ); - prevNormal = false; - } - if ( ! prevNormal ) { - status = (*outProc) ( refCon, ">", 1 ); - if ( status != 0 ) return status; - } - spanStart = spanEnd; - - } - -EXIT: - return status; - -} // DumpClearString - - -// ------------------------------------------------------------------------------------------------- -// DumpStringMap -// ------------- - -static XMP_Status -DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon ) -{ - XMP_Status status; - XMP_cStringMapPos currPos; - XMP_cStringMapPos endPos = map.end(); - - size_t maxLen = 0; - for ( currPos = map.begin(); currPos != endPos; ++currPos ) { - size_t currLen = currPos->first.size(); - if ( currLen > maxLen ) maxLen = currLen; - } - - OutProcNewline(); - OutProcLiteral ( label ); - OutProcNewline(); - - for ( currPos = map.begin(); currPos != endPos; ++currPos ) { - OutProcNChars ( " ", 2 ); - DumpClearString ( currPos->first, outProc, refCon ); - OutProcPadding ( maxLen - currPos->first.size() ); - OutProcNChars ( " => ", 4 ); - DumpClearString ( currPos->second, outProc, refCon ); - OutProcNewline(); - } - -EXIT: - return status; - -} // DumpStringMap - - -// ------------------------------------------------------------------------------------------------- -// DumpNodeOptions -// --------------- - -static XMP_Status -DumpNodeOptions ( XMP_OptionBits options, - XMP_TextOutputProc outProc, - void * refCon ) -{ - XMP_Status status; - char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits. - - static const char * optNames[] = { " schema", // 0x8000_0000 - " ?30", - " ?29", - " -COMMAS-", - " ?27", // 0x0800_0000 - " ?26", - " ?25", - " ?24", - " ?23", // 0x0080_0000 - " isStale", - " isDerived", - " isStable", - " ?19", // 0x0008_0000 - " isInternal", - " hasAliases", - " isAlias", - " -AFTER-", // 0x0000_8000 - " -BEFORE-", - " isCompact", - " isLangAlt", - " isAlt", // 0x0000_0800 - " isOrdered", - " isArray", - " isStruct", - " hasType", // 0x0000_0080 - " hasLang", - " isQual", - " hasQual", - " ?3", // 0x0000_0008 - " ?2", - " URI", - " ?0" }; - - if ( options == 0 ) { - - OutProcNChars ( "(0x0)", 5 ); - - } else { - - OutProcNChars ( "(0x", 3 ); - OutProcHexInt ( options ); - OutProcNChars ( " :", 2 ); - - XMP_OptionBits mask = 0x80000000; - for ( int b = 0; b < 32; ++b ) { - if ( options & mask ) OutProcLiteral ( optNames[b] ); - mask = mask >> 1; - } - OutProcNChars ( ")", 1 ); - - } - -EXIT: - return status; - -} // DumpNodeOptions - - -// ------------------------------------------------------------------------------------------------- -// DumpPropertyTree -// ---------------- - -// *** Extract the validation code into a separate routine to call on exit in debug builds. - -static XMP_Status -DumpPropertyTree ( const XMP_Node * currNode, - int indent, - size_t itemIndex, - XMP_TextOutputProc outProc, - void * refCon ) -{ - XMP_Status status; - char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits. - - OutProcIndent ( (size_t)indent ); - if ( itemIndex == 0 ) { - if ( currNode->options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 ); - DumpClearString ( currNode->name, outProc, refCon ); - } else { - OutProcNChars ( "[", 1 ); - OutProcULong ( static_cast(itemIndex) ); - OutProcNChars ( "]", 1 ); - } - - if ( ! (currNode->options & kXMP_PropCompositeMask) ) { - OutProcNChars ( " = \"", 4 ); - DumpClearString ( currNode->value, outProc, refCon ); - OutProcNChars ( "\"", 1 ); - } - - if ( currNode->options != 0 ) { - OutProcNChars ( " ", 2 ); - status = DumpNodeOptions ( currNode->options, outProc, refCon ); - if ( status != 0 ) goto EXIT; - } - - if ( currNode->options & kXMP_PropHasLang ) { - if ( currNode->qualifiers.empty() || (currNode->qualifiers[0]->name != "xml:lang") ) { - OutProcLiteral ( " ** bad lang flag **" ); - } - } - // *** Check rdf:type also. - - if ( ! (currNode->options & kXMP_PropCompositeMask) ) { - if ( ! currNode->children.empty() ) OutProcLiteral ( " ** bad children **" ); - } else if ( currNode->options & kXMP_PropValueIsArray ) { - if ( currNode->options & kXMP_PropValueIsStruct ) OutProcLiteral ( " ** bad comp flags **" ); - } else if ( (currNode->options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) { - OutProcLiteral ( " ** bad comp flags **" ); - } - - #if 0 // *** XMP_DebugBuild - if ( (currNode->_namePtr != currNode->name.c_str()) || - (currNode->_valuePtr != currNode->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" ); - #endif - - OutProcNewline(); - - for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - - const XMP_Node * currQual = currNode->qualifiers[qualNum]; - - if ( currQual->parent != currNode ) OutProcLiteral ( "** bad parent link => " ); - if ( currQual->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad qual name => " ); - if ( ! (currQual->options & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " ); - if ( currQual->name == "xml:lang" ) { - if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " ); - } - - status = DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon ); - if ( status != 0 ) goto EXIT; - - } - - for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) { - - const XMP_Node * currChild = currNode->children[childNum]; - - if ( currChild->parent != currNode ) OutProcLiteral ( "** bad parent link => " ); - if ( currChild->options & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " ); - - if ( currNode->options & kXMP_PropValueIsArray ) { - itemIndex = childNum+1; - if ( currChild->name != kXMP_ArrayItemName ) OutProcLiteral ( "** bad item name => " ); - } else { - itemIndex = 0; - if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " ); - } - - status = DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon ); - if ( status != 0 ) goto EXIT; - - } - -EXIT: - return status; - -} // DumpPropertyTree - - -// ------------------------------------------------------------------------------------------------- -// DumpXMLTree -// ----------- - -#if DumpXMLParseTree - -static inline void PutHexByte ( FILE * log, unsigned char ch ) -{ - - fprintf ( log, "\\x" ); - if ( ch < 0x10 ) { - fprintf ( log, "%c", kHexDigits[ch] ); - } else { - fprintf ( log, "%c%c", kHexDigits[ch>>4], kHexDigits[ch&0xF] ); - } - -} // PutHexByte - -// ------------------------------------------------------------------------------------------------- - -static void PutClearString ( FILE * log, const std::string & str ) -{ - - for ( size_t i = 0; i != str.size(); ++i ) { - unsigned char ch = str[i]; - if ( (0x20 <= ch) && (ch <= 0x7F) ) { - fprintf ( log, "%c", ch ); - } else { - PutHexByte ( log, ch ); - } - } - -} // PutClearString - -// ------------------------------------------------------------------------------------------------- - -static void DumpXMLTree ( FILE * log, const XML_Node & node, int indent ) -{ - size_t i; - - #if 0 // *** XMP_DebugBuild - if ( (node._namePtr != node.name.c_str()) || - (node._valuePtr != node.value.c_str()) ) fprintf ( log, "*** bad debug string ***\n" ); - #endif - - for ( i = 0; i != (size_t)indent; ++i ) fprintf ( log, " " ); - - switch ( node.kind ) { - - case kRootNode : - fprintf ( log, "\nStart of XML tree dump\n\n" ); - if ( (indent != 0) || (! node.attrs.empty()) || - (! node.ns.empty()) || (! node.name.empty()) || (!node.value.empty()) ) fprintf ( log, " ** invalid root ** \n" ); - for ( i = 0; i < node.children.size(); ++i ) { - XMP_Uns8 kind = node.children[i]->kind; - if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" ); - DumpXMLTree ( log, *node.children[i], indent+1 ); - } - fprintf ( log, "\nEnd of XML tree dump\n" ); - break; - - case kElemNode : - fprintf ( log, "Elem %s", node.name.c_str() ); - if ( indent == 0 ) fprintf ( log, " ** invalid elem ** " ); - if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() ); - fprintf ( log, "\n" ); - for ( i = 0; i < node.attrs.size(); ++i ) { - XMP_Uns8 kind = node.attrs[i]->kind; - if ( kind != kAttrNode ) fprintf ( log, " ** invalid attr ** \n" ); - DumpXMLTree ( log, *node.attrs[i], indent+2 ); - } - for ( i = 0; i < node.children.size(); ++i ) { - XMP_Uns8 kind = node.children[i]->kind; - if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" ); - DumpXMLTree ( log, *node.children[i], indent+1 ); - } - break; - - case kAttrNode : - fprintf ( log, "Attr %s", node.name.c_str() ); - if ( (indent == 0) || node.name.empty() || (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid attr ** " ); - fprintf ( log, " = \"" ); - PutClearString ( log, node.value ); - fprintf ( log, "\"" ); - if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() ); - fprintf ( log, "\n" ); - break; - - case kCDataNode : - if ( (indent == 0) || (! node.ns.empty()) || (! node.name.empty()) || - (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid cdata ** \n" ); - fprintf ( log, "\"" ); - PutClearString ( log, node.value ); - fprintf ( log, "\"\n" ); - break; - - case kPINode : - fprintf ( log, "PI %s", node.name.c_str() ); - if ( (indent == 0) || node.name.empty() || (! node.children.empty()) ) fprintf ( log, " ** invalid pi ** \n" ); - if ( ! node.value.empty() ) { - fprintf ( log, " " ); - } - fprintf ( log, "\n" ); - break; - - } - -} // DumpXMLTree - -#endif // DumpXMLParseTree - - -// ------------------------------------------------------------------------------------------------- -// CompareNodeNames -// ---------------- -// -// Comparison routine for sorting XMP nodes by name. The name "xml:lang" is less than anything else, -// and "rdf:type" is less than anything except "xml:lang". This preserves special rules for qualifiers. - -static bool -CompareNodeNames ( XMP_Node * left, XMP_Node * right ) -{ - - if ( left->name == "xml:lang" ) return true; - if ( right->name == "xml:lang" ) return false; - - if ( left->name == "rdf:type" ) return true; - if ( right->name == "rdf:type" ) return false; - - return ( left->name < right->name ); - -} // CompareNodeNames - - -// ------------------------------------------------------------------------------------------------- -// CompareNodeValues -// ----------------- -// -// Comparison routine for sorting XMP nodes by value. - -static bool -CompareNodeValues ( XMP_Node * left, XMP_Node * right ) -{ - - if ( XMP_PropIsSimple ( left->options ) && XMP_PropIsSimple ( right->options ) ) { - return ( left->value < right->value ); - } - - XMP_OptionBits leftForm = left->options & kXMP_PropCompositeMask; - XMP_OptionBits rightForm = right->options & kXMP_PropCompositeMask; - - return ( leftForm < rightForm ); - -} // CompareNodeValues - - -// ------------------------------------------------------------------------------------------------- -// CompareNodeLangs -// ---------------- -// -// Comparison routine for sorting XMP nodes by xml:lang qualifier. An "x-default" value is less than -// any other language. - -static bool -CompareNodeLangs ( XMP_Node * left, XMP_Node * right ) -{ - - if ( left->qualifiers.empty() || (left->qualifiers[0]->name != "xml:lang") ) return false; - if ( right->qualifiers.empty() || (right->qualifiers[0]->name != "xml:lang") ) return false; - - if ( left->qualifiers[0]->value == "x-default" ) return true; - if ( right->qualifiers[0]->value == "x-default" ) return false; - - return ( left->qualifiers[0]->value < right->qualifiers[0]->value ); - -} // CompareNodeLangs - - -// ------------------------------------------------------------------------------------------------- -// SortWithinOffspring -// ------------------- -// -// Sort one level down, within the elements of a node vector. This sorts the qualifiers of each -// node. If the node is a struct it sorts the fields by names. If the node is an unordered array it -// sorts the elements by value. If the node is an AltText array it sorts the elements by language. - -static void -SortWithinOffspring ( XMP_NodeOffspring & nodeVec ) -{ - - for ( size_t i = 0, limit = nodeVec.size(); i < limit; ++i ) { - - XMP_Node * currPos = nodeVec[i]; - - if ( ! currPos->qualifiers.empty() ) { - sort ( currPos->qualifiers.begin(), currPos->qualifiers.end(), CompareNodeNames ); - SortWithinOffspring ( currPos->qualifiers ); - } - - if ( ! currPos->children.empty() ) { - - if ( XMP_PropIsStruct ( currPos->options ) || XMP_NodeIsSchema ( currPos->options ) ) { - sort ( currPos->children.begin(), currPos->children.end(), CompareNodeNames ); - } else if ( XMP_PropIsArray ( currPos->options ) ) { - if ( XMP_ArrayIsUnordered ( currPos->options ) ) { - stable_sort ( currPos->children.begin(), currPos->children.end(), CompareNodeValues ); - } else if ( XMP_ArrayIsAltText ( currPos->options ) ) { - sort ( currPos->children.begin(), currPos->children.end(), CompareNodeLangs ); - } - } - - SortWithinOffspring ( currPos->children ); - - } - - } - -} // SortWithinOffspring - - -// ================================================================================================= -// Constructors -// ============ - - -XMPMeta::XMPMeta() : clientRefs(0), prevTkVer(0), tree(XMP_Node(0,"",0)), xmlParser(0) -{ - // Nothing more to do, clientRefs is incremented in wrapper. - #if XMP_TraceCTorDTor - printf ( "Default construct XMPMeta @ %.8X\n", this ); - #endif -} // XMPMeta - -// ------------------------------------------------------------------------------------------------- - -XMPMeta::~XMPMeta() RELEASE_NO_THROW -{ - #if XMP_TraceCTorDTor - printf ( "Destruct XMPMeta @ %.8X\n", this ); - #endif - - XMP_Assert ( this->clientRefs <= 0 ); - if ( xmlParser != 0 ) delete ( xmlParser ); - xmlParser = 0; - -} // ~XMPMeta - - -// ================================================================================================= -// Class Static Functions -// ====================== -// -// -// ================================================================================================= - -// ------------------------------------------------------------------------------------------------- -// GetVersionInfo -// -------------- - -/* class-static */ void -XMPMeta::GetVersionInfo ( XMP_VersionInfo * info ) -{ - - memset ( info, 0, sizeof(*info) ); // AUDIT: Safe, using sizeof the destination. - XMP_Assert ( sizeof(*info) == sizeof(XMP_VersionInfo) ); - - info->major = XMP_API_VERSION_MAJOR; - info->minor = XMP_API_VERSION_MINOR; - info->micro = XMP_API_VERSION_MICRO; - info->isDebug = kXMPCore_DebugFlag; - info->flags = 0; // ! None defined yet. - info->message = kXMPCore_VersionMessage; - -} // GetVersionInfo - -// ------------------------------------------------------------------------------------------------- -// Initialize -// ---------- - -/* class-static */ bool -XMPMeta::Initialize() -{ - // Allocate and initialize static objects. - - ++sXMP_InitCount; - if ( sXMP_InitCount > 1 ) return true; - - #if TraceXMPCalls - // xmpOut = fopen ( "xmp.out", "w" ); // Coordinate with client glue in WXMP_Common.hpp - fprintf ( xmpOut, "XMP initializing\n" ); fflush ( xmpOut ); - #endif - - sExceptionMessage = new XMP_VarString(); - XMP_InitMutex ( &sXMPCoreLock ); - sOutputNS = new XMP_VarString; - sOutputStr = new XMP_VarString; - - xdefaultName = new XMP_VarString ( "x-default" ); - - sNamespaceURIToPrefixMap = new XMP_StringMap; - sNamespacePrefixToURIMap = new XMP_StringMap; - sRegisteredAliasMap = new XMP_AliasMap; - - InitializeUnicodeConversions(); - - // Register standard namespaces and aliases. - RegisterNamespace ( kXMP_NS_XML, "xml" ); - RegisterNamespace ( kXMP_NS_RDF, "rdf" ); - RegisterNamespace ( kXMP_NS_DC, "dc" ); - - RegisterNamespace ( kXMP_NS_XMP, "xmp" ); - RegisterNamespace ( kXMP_NS_PDF, "pdf" ); - RegisterNamespace ( kXMP_NS_Photoshop, "photoshop" ); - RegisterNamespace ( kXMP_NS_PSAlbum, "album" ); - RegisterNamespace ( kXMP_NS_EXIF, "exif" ); - RegisterNamespace ( kXMP_NS_EXIF_Aux, "aux" ); - RegisterNamespace ( kXMP_NS_TIFF, "tiff" ); - RegisterNamespace ( kXMP_NS_PNG, "png" ); - RegisterNamespace ( kXMP_NS_JPEG, "jpeg" ); - RegisterNamespace ( kXMP_NS_JP2K, "jp2k" ); - RegisterNamespace ( kXMP_NS_CameraRaw, "crs" ); - RegisterNamespace ( kXMP_NS_ASF, "asf" ); - RegisterNamespace ( kXMP_NS_WAV, "wav" ); - - RegisterNamespace ( kXMP_NS_AdobeStockPhoto, "bmsp" ); - RegisterNamespace ( kXMP_NS_CreatorAtom, "creatorAtom" ); - - RegisterNamespace ( kXMP_NS_XMP_Rights, "xmpRights" ); - RegisterNamespace ( kXMP_NS_XMP_MM, "xmpMM" ); - RegisterNamespace ( kXMP_NS_XMP_BJ, "xmpBJ" ); - RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote" ); - - RegisterNamespace ( kXMP_NS_DM, "xmpDM" ); - RegisterNamespace ( kXMP_NS_XMP_Text, "xmpT" ); - RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xmpTPg" ); - RegisterNamespace ( kXMP_NS_XMP_Graphics, "xmpG" ); - RegisterNamespace ( kXMP_NS_XMP_Image, "xmpGImg" ); - - RegisterNamespace ( kXMP_NS_XMP_Font, "stFnt" ); - RegisterNamespace ( kXMP_NS_XMP_Dimensions, "stDim" ); - RegisterNamespace ( kXMP_NS_XMP_ResourceEvent, "stEvt" ); - RegisterNamespace ( kXMP_NS_XMP_ResourceRef, "stRef" ); - RegisterNamespace ( kXMP_NS_XMP_ST_Version, "stVer" ); - RegisterNamespace ( kXMP_NS_XMP_ST_Job, "stJob" ); - RegisterNamespace ( kXMP_NS_XMP_ManifestItem, "stMfs" ); - - RegisterNamespace ( kXMP_NS_XMP_IdentifierQual, "xmpidq" ); - - RegisterNamespace ( kXMP_NS_IPTCCore, "Iptc4xmpCore" ); - RegisterNamespace ( kXMP_NS_DICOM, "DICOM" ); - - RegisterNamespace ( kXMP_NS_PDFA_Schema, "pdfaSchema" ); - RegisterNamespace ( kXMP_NS_PDFA_Property, "pdfaProperty" ); - RegisterNamespace ( kXMP_NS_PDFA_Type, "pdfaType" ); - RegisterNamespace ( kXMP_NS_PDFA_Field, "pdfaField" ); - RegisterNamespace ( kXMP_NS_PDFA_ID, "pdfaid" ); - RegisterNamespace ( kXMP_NS_PDFA_Extension, "pdfaExtension" ); - - RegisterNamespace ( kXMP_NS_PDFX, "pdfx" ); - RegisterNamespace ( kXMP_NS_PDFX_ID, "pdfxid" ); - - RegisterNamespace ( "adobe:ns:meta/", "x" ); - RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX" ); - -// 06-Oct-07, ahu: Do not use aliases. They result in unexpected behaviour. -// XMPMeta::RegisterStandardAliases ( "" ); - - // Initialize the other core classes. - - if ( ! XMPIterator::Initialize() ) XMP_Throw ( "Failure from XMPIterator::Initialize", kXMPErr_InternalFailure ); - if ( ! XMPUtils::Initialize() ) XMP_Throw ( "Failure from XMPUtils::Initialize", kXMPErr_InternalFailure ); - // Do miscelaneous semantic checks of types and arithmetic. - - XMP_Assert ( sizeof(XMP_Int8) == 1 ); - XMP_Assert ( sizeof(XMP_Int16) == 2 ); - XMP_Assert ( sizeof(XMP_Int32) == 4 ); - XMP_Assert ( sizeof(XMP_Int64) == 8 ); - XMP_Assert ( sizeof(XMP_Uns8) == 1 ); - XMP_Assert ( sizeof(XMP_Uns16) == 2 ); - XMP_Assert ( sizeof(XMP_Uns32) == 4 ); - XMP_Assert ( sizeof(XMP_Uns64) == 8 ); - - XMP_Assert ( sizeof(XMP_OptionBits) == 4 ); // Check that option masking work on all 32 bits. - XMP_OptionBits flag = ~0; - - XMP_Assert ( flag == (XMP_OptionBits)(-1L) ); - XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL ); - XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL ); - - XMP_OptionBits opt1 = 0; // Check the general option bit macros. - XMP_OptionBits opt2 = flag; - XMP_SetOption ( opt1, kXMP_PropValueIsArray ); - XMP_ClearOption ( opt2, kXMP_PropValueIsArray ); - XMP_Assert ( opt1 == ~opt2 ); - XMP_Assert ( XMP_TestOption ( opt1, kXMP_PropValueIsArray ) ); - XMP_Assert ( ! XMP_TestOption ( opt2, kXMP_PropValueIsArray ) ); - - XMP_Assert ( XMP_PropIsSimple ( ~kXMP_PropCompositeMask ) ); // Check the special option bit macros. - XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsStruct ) ); - XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsArray ) ); - - XMP_Assert ( XMP_PropIsStruct ( kXMP_PropValueIsStruct ) ); - XMP_Assert ( XMP_PropIsArray ( kXMP_PropValueIsArray ) ); - XMP_Assert ( ! XMP_PropIsStruct ( ~kXMP_PropValueIsStruct ) ); - XMP_Assert ( ! XMP_PropIsArray ( ~kXMP_PropValueIsArray ) ); - - XMP_Assert ( XMP_ArrayIsUnordered ( ~kXMP_PropArrayIsOrdered ) ); - XMP_Assert ( XMP_ArrayIsOrdered ( kXMP_PropArrayIsOrdered ) ); - XMP_Assert ( XMP_ArrayIsAlternate ( kXMP_PropArrayIsAlternate ) ); - XMP_Assert ( XMP_ArrayIsAltText ( kXMP_PropArrayIsAltText ) ); - XMP_Assert ( ! XMP_ArrayIsUnordered ( kXMP_PropArrayIsOrdered ) ); - XMP_Assert ( ! XMP_ArrayIsOrdered ( ~kXMP_PropArrayIsOrdered ) ); - XMP_Assert ( ! XMP_ArrayIsAlternate ( ~kXMP_PropArrayIsAlternate ) ); - XMP_Assert ( ! XMP_ArrayIsAltText ( ~kXMP_PropArrayIsAltText ) ); - - XMP_Assert ( XMP_PropHasQualifiers ( kXMP_PropHasQualifiers ) ); - XMP_Assert ( XMP_PropIsQualifier ( kXMP_PropIsQualifier ) ); - XMP_Assert ( XMP_PropHasLang ( kXMP_PropHasLang ) ); - XMP_Assert ( ! XMP_PropHasQualifiers ( ~kXMP_PropHasQualifiers ) ); - XMP_Assert ( ! XMP_PropIsQualifier ( ~kXMP_PropIsQualifier ) ); - XMP_Assert ( ! XMP_PropHasLang ( ~kXMP_PropHasLang ) ); - - XMP_Assert ( XMP_NodeIsSchema ( kXMP_SchemaNode ) ); - XMP_Assert ( XMP_PropIsAlias ( kXMP_PropIsAlias ) ); - XMP_Assert ( ! XMP_NodeIsSchema ( ~kXMP_SchemaNode ) ); - XMP_Assert ( ! XMP_PropIsAlias ( ~kXMP_PropIsAlias ) ); - - #if 0 // Generally off, enable to hand check generated code. - extern XMP_OptionBits opt3, opt4; - if ( XMP_TestOption ( opt3, kXMP_PropValueIsArray ) ) opt4 = opt3; - if ( ! XMP_TestOption ( opt3, kXMP_PropValueIsStruct ) ) opt4 = opt3; - static bool ok1 = XMP_TestOption ( opt4, kXMP_PropValueIsArray ); - static bool ok2 = ! XMP_TestOption ( opt4, kXMP_PropValueIsStruct ); - #endif - - // Make sure the embedded info strings are referenced and kept. - if ( (kXMPCore_EmbeddedVersion[0] == 0) || (kXMPCore_EmbeddedCopyright[0] == 0) ) return false; - return true; - -} // Initialize - - -// ------------------------------------------------------------------------------------------------- -// Terminate -// --------- - -#define EliminateGlobal(g) delete ( g ); g = 0 - -/* class-static */ void -XMPMeta::Terminate() RELEASE_NO_THROW -{ - --sXMP_InitCount; - if ( sXMP_InitCount > 0 ) return; - - #if TraceXMPCalls - fprintf ( xmpOut, "XMP terminating\n" ); fflush ( xmpOut ); - // fclose ( xmpOut ); // Coordinate with fopen in XMPMeta::Initialize. - #endif - - XMPIterator::Terminate(); - XMPUtils::Terminate(); - EliminateGlobal ( sNamespaceURIToPrefixMap ); - EliminateGlobal ( sNamespacePrefixToURIMap ); - EliminateGlobal ( sRegisteredAliasMap ); - - EliminateGlobal ( xdefaultName ); - EliminateGlobal ( sOutputNS ); - EliminateGlobal ( sOutputStr ); - EliminateGlobal ( sExceptionMessage ); - - XMP_TermMutex ( sXMPCoreLock ); - -} // Terminate - - -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ - -/* class-static */ void -XMPMeta::Unlock ( XMP_OptionBits options ) -{ - UNUSED(options); - - #if TraceXMPLocking - fprintf ( xmpOut, " Unlocking XMP toolkit, count = %d\n", sLockCount ); fflush ( xmpOut ); - #endif - --sLockCount; - XMP_Assert ( sLockCount == 0 ); - XMP_ExitCriticalRegion ( sXMPCoreLock ); - -} // Unlock - - -// ------------------------------------------------------------------------------------------------- -// UnlockObject -// ------------ - -void -XMPMeta::UnlockObject ( XMP_OptionBits options ) const -{ - UNUSED(options); - - XMPMeta::Unlock ( 0 ); - -} // UnlockObject - - -// ------------------------------------------------------------------------------------------------- -// DumpNamespaces -// -------------- -// -// Dump the prefix to URI map (easier to read) and verify that both are consistent and legit. - -// *** Should put checks in a separate routine for regular calling in debug builds. - -/* class-static */ XMP_Status -XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc, - void * refCon ) -{ - XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; - - XMP_StringMapPos p2uEnd = sNamespacePrefixToURIMap->end(); // ! Move up to avoid gcc complaints. - XMP_StringMapPos u2pEnd = sNamespaceURIToPrefixMap->end(); - - status = DumpStringMap ( *sNamespacePrefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon ); - if ( status != 0 ) goto EXIT; - - if ( sNamespacePrefixToURIMap->size() != sNamespaceURIToPrefixMap->size() ) { - OutProcLiteral ( "** bad namespace map sizes **" ); - XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure ); - } - - for ( XMP_StringMapPos nsLeft = sNamespacePrefixToURIMap->begin(); nsLeft != p2uEnd; ++nsLeft ) { - - XMP_StringMapPos nsOther = sNamespaceURIToPrefixMap->find ( nsLeft->second ); - if ( (nsOther == u2pEnd) || (nsLeft != sNamespacePrefixToURIMap->find ( nsOther->second )) ) { - OutProcLiteral ( " ** bad namespace URI ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - - for ( XMP_StringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) { - if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+! - if ( nsLeft->second == nsRight->second ) { - OutProcLiteral ( " ** duplicate namespace URI ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - } - - } - - for ( XMP_StringMapPos nsLeft = sNamespaceURIToPrefixMap->begin(); nsLeft != u2pEnd; ++nsLeft ) { - - XMP_StringMapPos nsOther = sNamespacePrefixToURIMap->find ( nsLeft->second ); - if ( (nsOther == p2uEnd) || (nsLeft != sNamespaceURIToPrefixMap->find ( nsOther->second )) ) { - OutProcLiteral ( " ** bad namespace prefix ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - - for ( XMP_StringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) { - if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+! - if ( nsLeft->second == nsRight->second ) { - OutProcLiteral ( " ** duplicate namespace prefix ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - } - - } - -EXIT: - return status; - -FAILURE: - OutProcNewline(); - (void) DumpStringMap ( *sNamespaceURIToPrefixMap, "Dumping namespace URI to prefix map", outProc, refCon ); - XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure ); - return 0; - -} // DumpNamespaces - - -// ------------------------------------------------------------------------------------------------- -// DumpAliases -// ----------- - -/* class-static */ XMP_Status -XMPMeta::DumpAliases ( XMP_TextOutputProc outProc, - void * refCon ) -{ - XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; - - XMP_Assert ( sRegisteredAliasMap != 0 ); - - XMP_cAliasMapPos aliasPos; - XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end(); - - size_t maxLen = 0; - for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) { - size_t currLen = aliasPos->first.size(); - if ( currLen > maxLen ) maxLen = currLen; - } - - OutProcLiteral ( "Dumping alias name to actual path map" ); - OutProcNewline(); - - for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) { - - OutProcNChars ( " ", 3 ); - DumpClearString ( aliasPos->first, outProc, refCon ); - OutProcPadding ( maxLen - aliasPos->first.size() ); - OutProcNChars ( " => ", 4 ); - - size_t actualPathSize = aliasPos->second.size(); - for ( size_t stepNum = 1; stepNum < actualPathSize; ++stepNum ) OutProcString ( aliasPos->second[stepNum].step ); - - XMP_OptionBits arrayForm = aliasPos->second[1].options & kXMP_PropArrayFormMask; - - if ( arrayForm == 0 ) { - if ( actualPathSize != 2 ) OutProcLiteral ( " ** bad actual path **" ); - } else { - OutProcNChars ( " ", 2 ); - DumpNodeOptions ( arrayForm, outProc, refCon ); - if ( ! (arrayForm & kXMP_PropValueIsArray) ) OutProcLiteral ( " ** bad array form **" ); - if ( actualPathSize != 3 ) OutProcLiteral ( " ** bad actual path **" ); - } - - if ( aliasPos->second[0].options != kXMP_SchemaNode ) OutProcLiteral ( " ** bad schema form **" ); - - OutProcNewline(); - - } - -EXIT: - return status; - -} // DumpAliases - - -// ------------------------------------------------------------------------------------------------- -// GetGlobalOptions -// ---------------- - -/* class-static */ XMP_OptionBits -XMPMeta::GetGlobalOptions() -{ - XMP_OptionBits options = 0; - - return options; - -} // GetGlobalOptions - - -// ------------------------------------------------------------------------------------------------- -// SetGlobalOptions -// ---------------- - -/* class-static */ void -XMPMeta::SetGlobalOptions ( XMP_OptionBits /*options*/ ) -{ - - XMP_Throw ( "Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented ); - -} // SetGlobalOptions - - -// ------------------------------------------------------------------------------------------------- -// RegisterNamespace -// ----------------- - -/* class-static */ void -XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix ) -{ - if ( (*namespaceURI == 0) || (*prefix == 0) ) { - XMP_Throw ( "Empty namespace URI or prefix", kXMPErr_BadParam ); - } - - XMP_VarString nsURI ( namespaceURI ); - XMP_VarString prfix ( prefix ); - if ( prfix[prfix.size()-1] != ':' ) prfix += ':'; - VerifySimpleXMLName ( prefix, prefix+prfix.size()-1 ); // Exclude the colon. - - // Set the new namespace in both maps. - (*sNamespaceURIToPrefixMap)[nsURI] = prfix; - (*sNamespacePrefixToURIMap)[prfix] = nsURI; - -} // RegisterNamespace - - -// ------------------------------------------------------------------------------------------------- -// GetNamespacePrefix -// ------------------ - -/* class-static */ bool -XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI, - XMP_StringPtr * namespacePrefix, - XMP_StringLen * prefixSize ) -{ - bool found = false; - - XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper. - XMP_Assert ( (namespacePrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper. - - XMP_VarString nsURI ( namespaceURI ); - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI ); - - if ( uriPos != sNamespaceURIToPrefixMap->end() ) { - *namespacePrefix = uriPos->second.c_str(); - *prefixSize = uriPos->second.size(); - found = true; - } - - return found; - -} // GetNamespacePrefix - - -// ------------------------------------------------------------------------------------------------- -// GetNamespaceURI -// --------------- - -/* class-static */ bool -XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix, - XMP_StringPtr * namespaceURI, - XMP_StringLen * uriSize ) -{ - bool found = false; - - XMP_Assert ( *namespacePrefix != 0 ); // ! Enforced by wrapper. - XMP_Assert ( (namespacePrefix != 0) && (namespaceURI != 0) ); // ! Enforced by wrapper. - - XMP_VarString nsPrefix ( namespacePrefix ); - if ( nsPrefix[nsPrefix.size()-1] != ':' ) nsPrefix += ':'; - - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix ); - - if ( prefixPos != sNamespacePrefixToURIMap->end() ) { - *namespaceURI = prefixPos->second.c_str(); - *uriSize = prefixPos->second.size(); - found = true; - } - - return found; - -} // GetNamespaceURI - - -// ------------------------------------------------------------------------------------------------- -// DeleteNamespace -// --------------- - -// *** Don't allow standard namespaces to be deleted. -// *** We would be better off not having this. Instead, have local namespaces from parsing be -// *** restricted to the object that introduced them. - -/* class-static */ void -XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI ) -{ - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( namespaceURI ); - if ( uriPos == sNamespaceURIToPrefixMap->end() ) return; - - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( uriPos->second ); - if ( prefixPos == sNamespacePrefixToURIMap->end() ) return; - - sNamespaceURIToPrefixMap->erase ( uriPos ); - sNamespacePrefixToURIMap->erase ( prefixPos ); - -} // DeleteNamespace - - -// ------------------------------------------------------------------------------------------------- -// RegisterAlias -// ------------- -// -// Allow 3 kinds of alias: -// TopProp => TopProp -// TopProp => TopArray[1] -// TopProp => TopArray[@xml:lang='x-default'] -// -// A new alias can be made to something that is already aliased, as long as the net result is one of -// the legitimate forms. The new alias can already have aliases to it, also as long as result of -// adjusting all of the exiting aliases leaves them legal. -// -// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any -// ! conflicts will result in later references throwing bad XPath exceptions. - -/* class-static */ void -XMPMeta::RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm ) -{ - XMP_ExpandedXPath expAlias, expActual; - XMP_AliasMapPos mapPos; - XMP_ExpandedXPath * regActual = 0; - - XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper. - - // Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting - // the expanded XPath size remember that the schema URI is the first component. We don't have to - // compare the schema URIs though, the (unique) prefix is part of the top property name. - - ExpandXPath ( aliasNS, aliasProp, &expAlias ); - ExpandXPath ( actualNS, actualProp, &expActual ); - if ( (expAlias.size() != 2) || (expActual.size() != 2) ) { - XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath ); - } - - arrayForm = VerifySetOptions ( arrayForm, 0 ); - if ( arrayForm != 0 ) { - if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions ); - expActual[1].options |= arrayForm; // Set the array form for the top level step. - if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) { - expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) ); - } else { - expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) ); - } - } - - // See if there are any conflicts with existing aliases. A couple of the checks are easy. If the - // alias is already aliased it is only OK to reregister an identical alias. If the actual is - // already aliased to something else and the new chain is legal, just swap in the old base. - - mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step ); - if ( mapPos != sRegisteredAliasMap->end() ) { - - // This alias is already registered to something, make sure it is the same something. - - regActual = &mapPos->second; - if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) { - XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam ); - } - if ( expActual.size() != regActual->size() ) { - XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam ); - } - if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) { - XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam ); - } - if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) { - XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam ); - } - return; - - } - - mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step ); - if ( mapPos != sRegisteredAliasMap->end() ) { - - // The actual is already aliased to something else. - - regActual = &mapPos->second; - if ( expActual.size() == 2 ) { - expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base. - } else if ( regActual->size() != 2 ) { - XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope. - } else { - expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp : - expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name. - } - - } - - // Checking for existing aliases to this one is touchier. This involves updating the alias map, - // which must not be done unless all of the changes are legal. So we need 2 loops, one to verify - // that everything is OK, and one to make the changes. The bad case is: - // TopProp => TopArray[] => TopArray[] - // In the valid cases we back substitute the new base. - - for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { - regActual = &mapPos->second; - if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { - if ( (regActual->size() == 2) && (expAlias.size() == 2) ) { - XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); - } - } - } - - for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { - regActual = &mapPos->second; - if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { - - if ( regActual->size() == 1 ) { - *regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base. - } else { - (*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp : - (*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name. - } - - } - } - - // Finally, all is OK to register the new alias. - - (void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) ); - -} // RegisterAlias - - -// ------------------------------------------------------------------------------------------------- -// ResolveAlias -// ------------ - -/* class-static */ bool -XMPMeta::ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm ) -{ - XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper. - XMP_Assert ( (actualNS != 0) && (nsSize != 0) && (actualProp != 0) && (propSize != 0) && (arrayForm != 0) ); // Enforced by wrapper. - - // Expand the input path and look up the first component in the alias table. Return if not an alias. - - XMP_ExpandedXPath fullPath, minPath; - ExpandXPath ( aliasNS, aliasProp, &fullPath ); - XMP_Assert ( fullPath.size() >= 2 ); - - minPath.push_back ( fullPath[kSchemaStep] ); - minPath.push_back ( fullPath[kRootPropStep] ); - XMP_AliasMapPos mapPos = sRegisteredAliasMap->find ( minPath[kRootPropStep].step ); - if ( mapPos == sRegisteredAliasMap->end() ) return false; - - // Replace the alias portion of the full expanded path. Compose the output path string. - - const XMP_ExpandedXPath & actualPath = mapPos->second; - - fullPath[kSchemaStep] = actualPath[kSchemaStep]; - fullPath[kRootPropStep] = actualPath[kRootPropStep]; - if ( actualPath.size() > 2 ) { // This is an alias to an array item. - XMP_ExpandedXPathPos insertPos = fullPath.begin() + kAliasIndexStep; - fullPath.insert ( insertPos, actualPath[kAliasIndexStep] ); - } - - *sOutputNS = fullPath[kSchemaStep].step; - *actualNS = sOutputNS->c_str(); - *nsSize = sOutputNS->size(); - - ComposeXPath ( fullPath, sOutputStr ); - *actualProp = sOutputStr->c_str(); - *propSize = sOutputStr->size(); - - *arrayForm = actualPath[kRootPropStep].options & kXMP_PropArrayFormMask; - - #if XMP_DebugBuild // Test that the output string is valid and unchanged by round trip expand/compose. - XMP_ExpandedXPath rtPath; - ExpandXPath ( *actualNS, *actualProp, &rtPath ); - std::string rtString; - ComposeXPath ( rtPath, &rtString ); - XMP_Assert ( rtString == *sOutputStr ); - #endif - - return true; - -} // ResolveAlias - - -// ------------------------------------------------------------------------------------------------- -// DeleteAlias -// ----------- - -/* class-static */ void -XMPMeta::DeleteAlias ( XMP_StringPtr /*aliasNS*/, - XMP_StringPtr /*aliasProp*/ ) -{ - -// Todo: XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); / / Enforced by wrapper. - XMP_Throw ( "Unimplemented method XMPMeta::DeleteAlias", kXMPErr_Unimplemented ); // *** #error "write me" - -} // DeleteAlias - - -// ------------------------------------------------------------------------------------------------- -// RegisterStandardAliases -// ----------------------- - -/* class-static */ void -XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS ) -{ - XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - - const bool doAll = (*schemaNS == 0); - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_XMP ) ) { - // Aliases from XMP to DC. - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PDF ) ) { - // Aliases from PDF to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_Photoshop ) ) { - // Aliases from PHOTOSHOP to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_TIFF ) || XMP_LitMatch ( schemaNS, kXMP_NS_EXIF ) ) { - // Aliases from TIFF and EXIF to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PNG ) ) { // ! From Acrobat ImageCapture: - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText); - } - -} // RegisterStandardAliases - - -// ================================================================================================= -// Class Methods -// ============= -// -// -// ================================================================================================= - - -// ------------------------------------------------------------------------------------------------- -// DumpObject -// ---------- - -XMP_Status -XMPMeta::DumpObject ( XMP_TextOutputProc outProc, - void * refCon ) const -{ - XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; - - OutProcLiteral ( "Dumping XMPMeta object \"" ); - DumpClearString ( tree.name, outProc, refCon ); - OutProcNChars ( "\" ", 3 ); - status = DumpNodeOptions ( tree.options, outProc, refCon ); - if ( status != 0 ) goto EXIT; - #if 0 // *** XMP_DebugBuild - if ( (tree._namePtr != tree.name.c_str()) || - (tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( " ** bad debug string **" ); - #endif - OutProcNewline(); - - if ( ! tree.value.empty() ) { - OutProcLiteral ( "** bad root value ** \"" ); - DumpClearString ( tree.value, outProc, refCon ); - OutProcNChars ( "\"", 1 ); - OutProcNewline(); - } - - if ( ! tree.qualifiers.empty() ) { - OutProcLiteral ( "** bad root qualifiers **" ); - OutProcNewline(); - for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) { - status = DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon ); - } - } - - if ( ! tree.children.empty() ) { - - for ( size_t childNum = 0, childLim = tree.children.size(); childNum < childLim; ++childNum ) { - - const XMP_Node * currSchema = tree.children[childNum]; - - OutProcNewline(); - OutProcIndent ( 1 ); - DumpClearString ( currSchema->value, outProc, refCon ); - OutProcNChars ( " ", 2 ); - DumpClearString ( currSchema->name, outProc, refCon ); - OutProcNChars ( " ", 2 ); - status = DumpNodeOptions ( currSchema->options, outProc, refCon ); - if ( status != 0 ) goto EXIT; - #if 0 // *** XMP_DebugBuild - if ( (currSchema->_namePtr != currSchema->name.c_str()) || - (currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" ); - #endif - OutProcNewline(); - - if ( ! (currSchema->options & kXMP_SchemaNode) ) { - OutProcLiteral ( "** bad schema options **" ); - OutProcNewline(); - } - - if ( ! currSchema->qualifiers.empty() ) { - OutProcLiteral ( "** bad schema qualifiers **" ); - OutProcNewline(); - for ( size_t qualNum = 0, qualLim = currSchema->qualifiers.size(); qualNum < qualLim; ++qualNum ) { - DumpPropertyTree ( currSchema->qualifiers[qualNum], 3, 0, outProc, refCon ); - } - } - - for ( size_t childNum = 0, childLim = currSchema->children.size(); childNum < childLim; ++childNum ) { - DumpPropertyTree ( currSchema->children[childNum], 2, 0, outProc, refCon ); - } - - } - - } - -EXIT: - return status; - -} // DumpObject - - -// ------------------------------------------------------------------------------------------------- -// CountArrayItems -// --------------- - -XMP_Index -XMPMeta::CountArrayItems ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName ) const -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, arrayName, &expPath ); - - const XMP_Node * arrayNode = FindConstNode ( &tree, expPath ); - - if ( arrayNode == 0 ) return 0; - if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath ); - return arrayNode->children.size(); - -} // CountArrayItems - - -// ------------------------------------------------------------------------------------------------- -// GetObjectName -// ------------- - -void -XMPMeta::GetObjectName ( XMP_StringPtr * namePtr, - XMP_StringLen * nameLen ) const -{ - - *namePtr = tree.name.c_str(); - *nameLen = tree.name.size(); - -} // GetObjectName - - -// ------------------------------------------------------------------------------------------------- -// SetObjectName -// ------------- - -void -XMPMeta::SetObjectName ( XMP_StringPtr name ) -{ - VerifyUTF8 ( name ); // Throws if the string is not legit UTF-8. - tree.name = name; - -} // SetObjectName - - -// ------------------------------------------------------------------------------------------------- -// GetObjectOptions -// ---------------- - -XMP_OptionBits -XMPMeta::GetObjectOptions() const -{ - XMP_OptionBits options = 0; - - return options; - -} // GetObjectOptions - - -// ------------------------------------------------------------------------------------------------- -// SetObjectOptions -// ---------------- - -void -XMPMeta::SetObjectOptions ( XMP_OptionBits /*options*/ ) -{ - - XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented ); - -} // SetObjectOptions - - -// ------------------------------------------------------------------------------------------------- -// Sort -// ---- -// -// At the top level the namespaces are sorted by their prefixes. Within a namespace, the top level -// properties are sorted by name. Within a struct, the fields are sorted by their qualified name, -// i.e. their XML prefix:local form. Unordered arrays of simple items are sorted by value. Language -// Alternative arrays are sorted by the xml:lang qualifiers, with the "x-default" item placed first. - -void -XMPMeta::Sort() -{ - - if ( ! this->tree.qualifiers.empty() ) { - sort ( this->tree.qualifiers.begin(), this->tree.qualifiers.end(), CompareNodeNames ); - SortWithinOffspring ( this->tree.qualifiers ); - } - - if ( ! this->tree.children.empty() ) { - // The schema prefixes are the node's value, the name is the URI, so we sort schemas by value. - sort ( this->tree.children.begin(), this->tree.children.end(), CompareNodeValues ); - SortWithinOffspring ( this->tree.children ); - } - -} // Sort - - -// ------------------------------------------------------------------------------------------------- -// Erase -// ----- -// -// Clear everything except for clientRefs. - -void -XMPMeta::Erase() -{ - - this->prevTkVer = 0; - if ( this->xmlParser != 0 ) { - delete ( this->xmlParser ); - this->xmlParser = 0; - } - this->tree.ClearNode(); - -} // Erase - - -// ------------------------------------------------------------------------------------------------- -// Clone -// ----- - -void -XMPMeta::Clone ( XMPMeta * clone, XMP_OptionBits options ) const -{ - if ( clone == 0 ) XMP_Throw ( "Null clone pointer", kXMPErr_BadParam ); - if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions ); - XMP_Assert ( this->tree.parent == 0 ); - - clone->tree.ClearNode(); - - clone->tree.options = this->tree.options; - clone->tree.name = this->tree.name; - clone->tree.value = this->tree.value; - - #if 0 // *** XMP_DebugBuild - clone->tree._namePtr = clone->tree.name.c_str(); - clone->tree._valuePtr = clone->tree.value.c_str(); - #endif - - CloneOffspring ( &this->tree, &clone->tree ); - -} // Clone - -// ================================================================================================= diff --git a/xmpsdk/src/XMPMeta.hpp b/xmpsdk/src/XMPMeta.hpp deleted file mode 100644 index 68462dce64..0000000000 --- a/xmpsdk/src/XMPMeta.hpp +++ /dev/null @@ -1,418 +0,0 @@ -#ifndef __XMPMeta_hpp__ -#define __XMPMeta_hpp__ - -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" -#include "XMP_Const.h" -#include "XMPCore_Impl.hpp" -#include "XMLParserAdapter.hpp" - -// ------------------------------------------------------------------------------------------------- - -#ifndef DumpXMLParseTree - #define DumpXMLParseTree 0 -#endif - -extern XMP_VarString * xdefaultName; - -class XMPIterator; -class XMPUtils; - -// ------------------------------------------------------------------------------------------------- - -class XMPMeta { -public: - - static void - GetVersionInfo ( XMP_VersionInfo * info ); - - static bool - Initialize(); - static void - Terminate() RELEASE_NO_THROW; - - static void - Unlock ( XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - XMPMeta(); - - virtual ~XMPMeta() RELEASE_NO_THROW; - - // --------------------------------------------------------------------------------------------- - - static XMP_OptionBits - GetGlobalOptions(); - - static void - SetGlobalOptions ( XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - static XMP_Status - DumpNamespaces ( XMP_TextOutputProc outProc, - void * refCon ); - - static XMP_Status - DumpAliases ( XMP_TextOutputProc outProc, - void * refCon ); - - // --------------------------------------------------------------------------------------------- - - static void - RegisterNamespace ( XMP_StringPtr namespaceURI, - XMP_StringPtr prefix ); - - static bool - GetNamespacePrefix ( XMP_StringPtr namespaceURI, - XMP_StringPtr * namespacePrefix, - XMP_StringLen * prefixSize ); - - static bool - GetNamespaceURI ( XMP_StringPtr namespacePrefix, - XMP_StringPtr * namespaceURI, - XMP_StringLen * uriSize ); - - static void - DeleteNamespace ( XMP_StringPtr namespaceURI ); - - // --------------------------------------------------------------------------------------------- - - static void - RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm ); - - static bool - ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm ); - - static void - DeleteAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp ); - - static void - RegisterStandardAliases ( XMP_StringPtr schemaNS ); - - // --------------------------------------------------------------------------------------------- - - void - UnlockObject ( XMP_OptionBits options ) const; - - // --------------------------------------------------------------------------------------------- - - bool - GetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const; - - bool - GetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const; - - bool - GetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fieldValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const; - - bool - GetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - - void - SetProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr propValue, - XMP_OptionBits options ); - - void - SetArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr itemValue, - XMP_OptionBits options ); - - void - AppendArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits arrayOptions, - XMP_StringPtr itemValue, - XMP_OptionBits options ); - - void - SetStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_OptionBits options ); - - void - SetQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr qualValue, - XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - void - DeleteProperty ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ); - - void - DeleteArrayItem ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ); - - void - DeleteStructField ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ); - - void - DeleteQualifier ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ); - - // --------------------------------------------------------------------------------------------- - - bool - DoesPropertyExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName ) const; - - bool - DoesArrayItemExist ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex ) const; - - bool - DoesStructFieldExist ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName ) const; - - bool - DoesQualifierExist ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName ) const; - - // --------------------------------------------------------------------------------------------- - - bool - GetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr * actualLang, - XMP_StringLen * langSize, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, - XMP_OptionBits * options ) const; - - void - SetLocalizedText ( XMP_StringPtr schemaNS, - XMP_StringPtr altTextName, - XMP_StringPtr genericLang, - XMP_StringPtr specificLang, - XMP_StringPtr itemValue, - XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - bool - GetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool * propValue, - XMP_OptionBits * options ) const; - - bool - GetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 * propValue, - XMP_OptionBits * options ) const; - - bool - GetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 * propValue, - XMP_OptionBits * options ) const; - - bool - GetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double * propValue, - XMP_OptionBits * options ) const; - - bool - GetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_DateTime * propValue, - XMP_OptionBits * options ) const; - - // --------------------------------------------------------------------------------------------- - - void - SetProperty_Bool ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - bool propValue, - XMP_OptionBits options ); - - void - SetProperty_Int ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int32 propValue, - XMP_OptionBits options ); - - void - SetProperty_Int64 ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 propValue, - XMP_OptionBits options ); - - void - SetProperty_Float ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - double propValue, - XMP_OptionBits options ); - - void - SetProperty_Date ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - const XMP_DateTime & propValue, - XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - void - GetObjectName ( XMP_StringPtr * namePtr, - XMP_StringLen * nameLen ) const; - - void - SetObjectName ( XMP_StringPtr name ); - - XMP_OptionBits - GetObjectOptions() const; - - void - SetObjectOptions ( XMP_OptionBits options ); - - void - Sort(); - - void - Erase(); - - void - Clone ( XMPMeta * clone, XMP_OptionBits options ) const; - - XMP_Index - CountArrayItems ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName ) const; - - XMP_Status - DumpObject ( XMP_TextOutputProc outProc, - void * refCon ) const; - - // --------------------------------------------------------------------------------------------- - - void - ParseFromBuffer ( XMP_StringPtr buffer, - XMP_StringLen bufferSize, - XMP_OptionBits options ); - - void - SerializeToBuffer ( XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent, - XMP_Index baseIndent ) const; - - // ============================================================================================= - - // --------------------------------------------------------------------------------------------- - // - Everything is built out of standard nodes. Each node has a name, value, option flags, a - // vector of child nodes, and a vector of qualifier nodes. - // - // - The option flags are those passed to SetProperty and returned from GetProperty. They tell - // if the node is simple, a struct or an array; whether it has qualifiers, etc. - // - // - The name of the node is an XML qualified name, of the form "prefix:simple-name". Since we - // force all namespaces to be known and to have unique prefixes, this is semantically equivalent - // to using a URI and simple name pair. - // - // - Although the value part is only for leaf properties and the children part is only for - // structs and arrays, it is easier to simply have them in every node. This keeps things visible - // so that debugging is easier - // - // - The top level node children are the namespaces that contain properties, the next level are - // the top level properties, lower levels are the fields of structs or items of arrays. The name - // of the top level nodes is just the namespace prefix, with the colon terminator. The name of - // top level properties includes the namespace prefix. - // - // - Any property node, at any level, can have qualifiers. These are themselves general property - // nodes. And could in fact themselves have qualifiers! - - // ! Expose the implementation so that file static functions can see the data. - - XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0. - XMP_Int32 prevTkVer; // Previous toolkit version as MMmmuubbb (major, minor, micro, build). - XMP_Node tree; - - XMLParserAdapter * xmlParser; - - friend class XMPIterator; - friend class XMPUtils; - -private: - - // ! These are hidden on purpose: - XMPMeta ( const XMPMeta & /* original */ ) : clientRefs(0), prevTkVer(0), tree(XMP_Node(0,"",0)), xmlParser(0) - { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); }; - void operator= ( const XMPMeta & /* rhs */ ) - { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); }; - -}; // class XMPMeta - - -// ================================================================================================= - -#endif // __XMPMeta_hpp__ diff --git a/xmpsdk/src/XMPUtils-FileInfo.cpp b/xmpsdk/src/XMPUtils-FileInfo.cpp deleted file mode 100644 index f0f54ba327..0000000000 --- a/xmpsdk/src/XMPUtils-FileInfo.cpp +++ /dev/null @@ -1,1346 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPUtils.hpp" - -#include -#include -#include -#include -#include - -#include // For snprintf. - -#if XMP_WinBuild -#ifdef _MSC_VER - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) -#endif -#endif - -// ================================================================================================= -// Local Types and Constants -// ========================= - -typedef unsigned long UniCodePoint; - -enum UniCharKind { - UCK_normal, - UCK_space, - UCK_comma, - UCK_semicolon, - UCK_quote, - UCK_control -}; -typedef enum UniCharKind UniCharKind; - -#define UnsByte(c) ((unsigned char)(c)) -#define UCP(u) ((UniCodePoint)(u)) - // ! Needed on Windows (& PC Linux?) for inequalities with literals ito avoid sign extension. - -#ifndef TraceMultiFile - #define TraceMultiFile 0 -#endif - -// ================================================================================================= -// Static Variables -// ================ - -// ================================================================================================= -// Local Utilities -// =============== - -// ------------------------------------------------------------------------------------------------- -// ClassifyCharacter -// ----------------- - -static void -ClassifyCharacter ( XMP_StringPtr fullString, size_t offset, - UniCharKind * charKind, size_t * charSize, UniCodePoint * uniChar ) -{ - *charKind = UCK_normal; // Assume typical case. - - unsigned char currByte = UnsByte ( fullString[offset] ); - - if ( currByte < UnsByte(0x80) ) { - - // ---------------------------------------- - // We've got a single byte ASCII character. - - *charSize = 1; - *uniChar = currByte; - - if ( currByte > UnsByte(0x22) ) { - - if ( currByte == UnsByte(0x2C) ) { - *charKind = UCK_comma; - } else if ( currByte == UnsByte(0x3B) ) { - *charKind = UCK_semicolon; - } else if ( (currByte == UnsByte(0x5B)) || (currByte == UnsByte(0x5D)) ) { - *charKind = UCK_quote; // ! ASCII '[' and ']' are used as quotes in Chinese and Korean. - } - - } else { // currByte <= 0x22 - - if ( currByte == UnsByte(0x22) ) { - *charKind = UCK_quote; - } else if ( currByte == UnsByte(0x21) ) { - *charKind = UCK_normal; - } else if ( currByte == UnsByte(0x20) ) { - *charKind = UCK_space; - } else { - *charKind = UCK_control; - } - - } - - } else { // currByte >= 0x80 - - // --------------------------------------------------------------------------------------- - // We've got a multibyte Unicode character. The first byte has the number of bytes and the - // highest order bits. The other bytes each add 6 more bits. Compose the UTF-32 form so we - // can classify directly with the Unicode code points. Order the upperBits tests to be - // fastest for Japan, probably the most common non-ASCII usage. - - *charSize = 0; - *uniChar = currByte; - while ( (*uniChar & 0x80) != 0 ) { // Count the leading 1 bits in the byte. - ++(*charSize); - *uniChar = *uniChar << 1; - } - XMP_Assert ( (offset + *charSize) <= strlen(fullString) ); - - *uniChar = *uniChar & 0x7F; // Put the character bits in the bottom of uniChar. - *uniChar = *uniChar >> *charSize; - - for ( size_t i = (offset + 1); i < (offset + *charSize); ++i ) { - *uniChar = (*uniChar << 6) | (UnsByte(fullString[i]) & 0x3F); - } - - XMP_Uns32 upperBits = *uniChar >> 8; // First filter on just the high order 24 bits. - - if ( upperBits == 0xFF ) { // U+FFxx - - if ( *uniChar == UCP(0xFF0C) ) { - *charKind = UCK_comma; // U+FF0C, full width comma. - } else if ( *uniChar == UCP(0xFF1B) ) { - *charKind = UCK_semicolon; // U+FF1B, full width semicolon. - } else if ( *uniChar == UCP(0xFF64) ) { - *charKind = UCK_comma; // U+FF64, half width ideographic comma. - } - - } else if ( upperBits == 0xFE ) { // U+FE-- - - if ( *uniChar == UCP(0xFE50) ) { - *charKind = UCK_comma; // U+FE50, small comma. - } else if ( *uniChar == UCP(0xFE51) ) { - *charKind = UCK_comma; // U+FE51, small ideographic comma. - } else if ( *uniChar == UCP(0xFE54) ) { - *charKind = UCK_semicolon; // U+FE54, small semicolon. - } - - } else if ( upperBits == 0x30 ) { // U+30-- - - if ( *uniChar == UCP(0x3000) ) { - *charKind = UCK_space; // U+3000, ideographic space. - } else if ( *uniChar == UCP(0x3001) ) { - *charKind = UCK_comma; // U+3001, ideographic comma. - } else if ( (UCP(0x3008) <= *uniChar) && (*uniChar <= UCP(0x300F)) ) { - *charKind = UCK_quote; // U+3008..U+300F, various quotes. - } else if ( *uniChar == UCP(0x303F) ) { - *charKind = UCK_space; // U+303F, ideographic half fill space. - } else if ( (UCP(0x301D) <= *uniChar) && (*uniChar <= UCP(0x301F)) ) { - *charKind = UCK_quote; // U+301D..U+301F, double prime quotes. - } - - } else if ( upperBits == 0x20 ) { // U+20-- - - if ( (UCP(0x2000) <= *uniChar) && (*uniChar <= UCP(0x200B)) ) { - *charKind = UCK_space; // U+2000..U+200B, en quad through zero width space. - } else if ( *uniChar == UCP(0x2015) ) { - *charKind = UCK_quote; // U+2015, dash quote. - } else if ( (UCP(0x2018) <= *uniChar) && (*uniChar <= UCP(0x201F)) ) { - *charKind = UCK_quote; // U+2018..U+201F, various quotes. - } else if ( *uniChar == UCP(0x2028) ) { - *charKind = UCK_control; // U+2028, line separator. - } else if ( *uniChar == UCP(0x2029) ) { - *charKind = UCK_control; // U+2029, paragraph separator. - } else if ( (*uniChar == UCP(0x2039)) || (*uniChar == UCP(0x203A)) ) { - *charKind = UCK_quote; // U+2039 and U+203A, guillemet quotes. - } - - } else if ( upperBits == 0x06 ) { // U+06-- - - if ( *uniChar == UCP(0x060C) ) { - *charKind = UCK_comma; // U+060C, Arabic comma. - } else if ( *uniChar == UCP(0x061B) ) { - *charKind = UCK_semicolon; // U+061B, Arabic semicolon. - } - - } else if ( upperBits == 0x05 ) { // U+05-- - - if ( *uniChar == UCP(0x055D) ) { - *charKind = UCK_comma; // U+055D, Armenian comma. - } - - } else if ( upperBits == 0x03 ) { // U+03-- - - if ( *uniChar == UCP(0x037E) ) { - *charKind = UCK_semicolon; // U+037E, Greek "semicolon" (really a question mark). - } - - } else if ( upperBits == 0x00 ) { // U+00-- - - if ( (*uniChar == UCP(0x00AB)) || (*uniChar == UCP(0x00BB)) ) { - *charKind = UCK_quote; // U+00AB and U+00BB, guillemet quotes. - } - - } - - } - -} // ClassifyCharacter - - -// ------------------------------------------------------------------------------------------------- -// IsClosingingQuote -// ----------------- - -static inline bool -IsClosingingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote ) -{ - - if ( (uniChar == closeQuote) || - ( (openQuote == UCP(0x301D)) && ((uniChar == UCP(0x301E)) || (uniChar == UCP(0x301F))) ) ) { - return true; - } else { - return false; - } - -} // IsClosingingQuote - - -// ------------------------------------------------------------------------------------------------- -// IsSurroundingQuote -// ------------------ - -static inline bool -IsSurroundingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote ) -{ - - if ( (uniChar == openQuote) || IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) { - return true; - } else { - return false; - } - -} // IsSurroundingQuote - - -// ------------------------------------------------------------------------------------------------- -// GetClosingQuote -// --------------- - -static UniCodePoint -GetClosingQuote ( UniCodePoint openQuote ) -{ - UniCodePoint closeQuote; - - switch ( openQuote ) { - - case UCP(0x0022) : closeQuote = UCP(0x0022); // ! U+0022 is both opening and closing. - break; - case UCP(0x005B) : closeQuote = UCP(0x005D); - break; - case UCP(0x00AB) : closeQuote = UCP(0x00BB); // ! U+00AB and U+00BB are reversible. - break; - case UCP(0x00BB) : closeQuote = UCP(0x00AB); - break; - case UCP(0x2015) : closeQuote = UCP(0x2015); // ! U+2015 is both opening and closing. - break; - case UCP(0x2018) : closeQuote = UCP(0x2019); - break; - case UCP(0x201A) : closeQuote = UCP(0x201B); - break; - case UCP(0x201C) : closeQuote = UCP(0x201D); - break; - case UCP(0x201E) : closeQuote = UCP(0x201F); - break; - case UCP(0x2039) : closeQuote = UCP(0x203A); // ! U+2039 and U+203A are reversible. - break; - case UCP(0x203A) : closeQuote = UCP(0x2039); - break; - case UCP(0x3008) : closeQuote = UCP(0x3009); - break; - case UCP(0x300A) : closeQuote = UCP(0x300B); - break; - case UCP(0x300C) : closeQuote = UCP(0x300D); - break; - case UCP(0x300E) : closeQuote = UCP(0x300F); - break; - case UCP(0x301D) : closeQuote = UCP(0x301F); // ! U+301E also closes U+301D. - break; - default : closeQuote = 0; - break; - - } - - return closeQuote; - -} // GetClosingQuote - - -// ------------------------------------------------------------------------------------------------- -// CodePointToUTF8 -// --------------- - -static void -CodePointToUTF8 ( UniCodePoint uniChar, XMP_VarString & utf8Str ) -{ - size_t i, byteCount; - XMP_Uns8 buffer [8]; - UniCodePoint cpTemp; - - if ( uniChar <= 0x7F ) { - - i = 7; - byteCount = 1; - buffer[7] = char(uniChar); - - } else { - - // --------------------------------------------------------------------------------------- - // Copy the data bits from the low order end to the high order end, include the 0x80 mask. - - i = 8; - cpTemp = uniChar; - while ( cpTemp != 0 ) { - -- i; // Exit with i pointing to the last byte stored. - buffer[i] = UnsByte(0x80) | (UnsByte(cpTemp) & 0x3F); - cpTemp = cpTemp >> 6; - } - byteCount = 8 - i; // The total number of bytes needed. - XMP_Assert ( (2 <= byteCount) && (byteCount <= 6) ); - - // ------------------------------------------------------------------------------------- - // Make sure the high order byte can hold the byte count mask, compute and set the mask. - - size_t bitCount = 0; // The number of data bits in the first byte. - for ( cpTemp = (buffer[i] & UnsByte(0x3F)); cpTemp != 0; cpTemp = cpTemp >> 1 ) bitCount += 1; - if ( bitCount > (8 - (byteCount + 1)) ) byteCount += 1; - - i = 8 - byteCount; // First byte index and mask shift count. - XMP_Assert ( (0 <= i) && (i <= 6) ); - buffer[i] |= (UnsByte(0xFF) << i) & UnsByte(0xFF); // AUDIT: Safe, i is between 0 and 6. - - } - - utf8Str.assign ( (char*)(&buffer[i]), byteCount ); - -} // CodePointToUTF8 - - -// ------------------------------------------------------------------------------------------------- -// ApplyQuotes -// ----------- - -static void -ApplyQuotes ( XMP_VarString * item, UniCodePoint openQuote, UniCodePoint closeQuote, bool allowCommas ) -{ - bool prevSpace = false; - size_t charOffset, charLen; - UniCharKind charKind; - UniCodePoint uniChar; - - // ----------------------------------------------------------------------------------------- - // See if there are any separators in the value. Stop at the first occurrance. This is a bit - // tricky in order to make typical typing work conveniently. The purpose of applying quotes - // is to preserve the values when splitting them back apart. That is CatenateContainerItems - // and SeparateContainerItems must round trip properly. For the most part we only look for - // separators here. Internal quotes, as in -- Irving "Bud" Jones -- won't cause problems in - // the separation. An initial quote will though, it will make the value look quoted. - - charOffset = 0; - ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar ); - - if ( charKind != UCK_quote ) { - - for ( charOffset = 0; size_t(charOffset) < item->size(); charOffset += charLen ) { - - ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar ); - - if ( charKind == UCK_space ) { - if ( prevSpace ) break; // Multiple spaces are a separator. - prevSpace = true; - } else { - prevSpace = false; - if ( (charKind == UCK_semicolon) || (charKind == UCK_control) ) break; - if ( (charKind == UCK_comma) && (! allowCommas) ) break; - } - - } - - } - - if ( size_t(charOffset) < item->size() ) { - - // -------------------------------------------------------------------------------------- - // Create a quoted copy, doubling any internal quotes that match the outer ones. Internal - // quotes did not stop the "needs quoting" search, but they do need doubling. So we have - // to rescan the front of the string for quotes. Handle the special case of U+301D being - // closed by either U+301E or U+301F. - - XMP_VarString newItem; - size_t splitPoint; - - for ( splitPoint = 0; splitPoint <= charOffset; ++splitPoint ) { - ClassifyCharacter ( item->c_str(), splitPoint, &charKind, &charLen, &uniChar ); - if ( charKind == UCK_quote ) break; - } - - CodePointToUTF8 ( openQuote, newItem ); - newItem.append ( *item, 0, splitPoint ); // Copy the leading "normal" portion. - - for ( charOffset = splitPoint; size_t(charOffset) < item->size(); charOffset += charLen ) { - ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar ); - newItem.append ( *item, charOffset, charLen ); - if ( (charKind == UCK_quote) && IsSurroundingQuote ( uniChar, openQuote, closeQuote ) ) { - newItem.append ( *item, charOffset, charLen ); - } - } - - XMP_VarString closeStr; - CodePointToUTF8 ( closeQuote, closeStr ); - newItem.append ( closeStr ); - - *item = newItem; - - } - -} // ApplyQuotes - - -// ------------------------------------------------------------------------------------------------- -// IsInternalProperty -// ------------------ - -// *** Need static checks of the schema prefixes! - -#define IsExternalProperty(s,p) (! IsInternalProperty ( s, p )) - -static bool -IsInternalProperty ( const XMP_VarString & schema, const XMP_VarString & prop ) -{ - bool isInternal = false; - - if ( schema == kXMP_NS_DC ) { - - if ( (prop == "dc:format") || - (prop == "dc:language") ) { - isInternal = true; - } - - } else if ( schema == kXMP_NS_XMP ) { - - if ( (prop == "xmp:BaseURL") || - (prop == "xmp:CreatorTool") || - (prop == "xmp:Format") || - (prop == "xmp:Locale") || - (prop == "xmp:MetadataDate") || - (prop == "xmp:ModifyDate") ) { - isInternal = true; - } - - } else if ( schema == kXMP_NS_PDF ) { - - if ( (prop == "pdf:BaseURL") || - (prop == "pdf:Creator") || - (prop == "pdf:ModDate") || - (prop == "pdf:PDFVersion") || - (prop == "pdf:Producer") ) { - isInternal = true; - } - - } else if ( schema == kXMP_NS_TIFF ) { - - isInternal = true; // ! The TIFF properties are internal by default. - if ( (prop == "tiff:ImageDescription") || // ! ImageDescription, Artist, and Copyright are aliased. - (prop == "tiff:Artist") || - (prop == "tiff:Copyright") ) { - isInternal = false; - } - - } else if ( schema == kXMP_NS_EXIF ) { - - isInternal = true; // ! The EXIF properties are internal by default. - if ( prop == "exif:UserComment" ) isInternal = false; - - } else if ( schema == kXMP_NS_EXIF_Aux ) { - - isInternal = true; // ! The EXIF Aux properties are internal by default. - - } else if ( schema == kXMP_NS_Photoshop ) { - - if ( prop == "photoshop:ICCProfile" ) isInternal = true; - - } else if ( schema == kXMP_NS_CameraRaw ) { - - if ( (prop == "crs:Version") || - (prop == "crs:RawFileName") || - (prop == "crs:ToneCurveName") ) { - isInternal = true; - } - - } else if ( schema == kXMP_NS_AdobeStockPhoto ) { - - isInternal = true; // ! The bmsp schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_MM ) { - - isInternal = true; // ! The xmpMM schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_Text ) { - - isInternal = true; // ! The xmpT schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_PagedFile ) { - - isInternal = true; // ! The xmpTPg schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_Graphics ) { - - isInternal = true; // ! The xmpG schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_Image ) { - - isInternal = true; // ! The xmpGImg schema has only internal properties. - - } else if ( schema == kXMP_NS_XMP_Font ) { - - isInternal = true; // ! The stFNT schema has only internal properties. - - } - - return isInternal; - -} // IsInternalProperty - - -// ------------------------------------------------------------------------------------------------- -// RemoveSchemaChildren -// -------------------- - -static void -RemoveSchemaChildren ( XMP_NodePtrPos schemaPos, bool doAll ) -{ - XMP_Node * schemaNode = *schemaPos; - XMP_Assert ( XMP_NodeIsSchema ( schemaNode->options ) ); - - // ! Iterate backwards to reduce shuffling as children are erased and to simplify the logic for - // ! denoting the current child. (Erasing child n makes the old n+1 now be n.) - - size_t propCount = schemaNode->children.size(); - XMP_NodePtrPos beginPos = schemaNode->children.begin(); - - for ( size_t propNum = propCount-1, propLim = (size_t)(-1); propNum != propLim; --propNum ) { - XMP_NodePtrPos currProp = beginPos + propNum; - if ( doAll || IsExternalProperty ( schemaNode->name, (*currProp)->name ) ) { - delete *currProp; // ! Both delete the node and erase the pointer from the parent. - schemaNode->children.erase ( currProp ); - } - } - - if ( schemaNode->children.empty() ) { - XMP_Node * tree = schemaNode->parent; - tree->children.erase ( schemaPos ); - delete schemaNode; - } - -} // RemoveSchemaChildren - - -// ------------------------------------------------------------------------------------------------- -// ItemValuesMatch -// --------------- -// -// Does the value comparisons for array merging as part of XMPUtils::AppendProperties. - -static bool -ItemValuesMatch ( const XMP_Node * leftNode, const XMP_Node * rightNode ) -{ - const XMP_OptionBits leftForm = leftNode->options & kXMP_PropCompositeMask; - const XMP_OptionBits rightForm = leftNode->options & kXMP_PropCompositeMask; - - if ( leftForm != rightForm ) return false; - - if ( leftForm == 0 ) { - - // Simple nodes, check the values and xml:lang qualifiers. - - if ( leftNode->value != rightNode->value ) return false; - if ( (leftNode->options & kXMP_PropHasLang) != (rightNode->options & kXMP_PropHasLang) ) return false; - if ( leftNode->options & kXMP_PropHasLang ) { - if ( leftNode->qualifiers[0]->value != rightNode->qualifiers[0]->value ) return false; - } - - } else if ( leftForm == kXMP_PropValueIsStruct ) { - - // Struct nodes, see if all fields match, ignoring order. - - if ( leftNode->children.size() != rightNode->children.size() ) return false; - - for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) { - const XMP_Node * leftField = leftNode->children[leftNum]; - const XMP_Node * rightField = FindConstChild ( rightNode, leftField->name.c_str() ); - if ( (rightField == 0) || (! ItemValuesMatch ( leftField, rightField )) ) return false; - } - - } else { - - // Array nodes, see if the "leftNode" values are present in the "rightNode", ignoring order, duplicates, - // and extra values in the rightNode-> The rightNode is the destination for AppendProperties. - - XMP_Assert ( leftForm & kXMP_PropValueIsArray ); - - for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) { - - const XMP_Node * leftItem = leftNode->children[leftNum]; - - size_t rightNum, rightLim; - for ( rightNum = 0, rightLim = rightNode->children.size(); rightNum != rightLim; ++rightNum ) { - const XMP_Node * rightItem = rightNode->children[rightNum]; - if ( ItemValuesMatch ( leftItem, rightItem ) ) break; - } - if ( rightNum == rightLim ) return false; - - } - - } - - return true; // All of the checks passed. - -} // ItemValuesMatch - - -// ------------------------------------------------------------------------------------------------- -// AppendSubtree -// ------------- -// -// The main implementation of XMPUtils::AppendProperties. See the description in TXMPMeta.hpp. - -static void -AppendSubtree ( const XMP_Node * sourceNode, XMP_Node * destParent, const bool replaceOld, const bool deleteEmpty ) -{ - XMP_NodePtrPos destPos; - XMP_Node * destNode = FindChildNode ( destParent, sourceNode->name.c_str(), kXMP_ExistingOnly, &destPos ); - - bool valueIsEmpty = false; - if ( deleteEmpty ) { - if ( XMP_PropIsSimple ( sourceNode->options ) ) { - valueIsEmpty = sourceNode->value.empty(); - } else { - valueIsEmpty = sourceNode->children.empty(); - } - } - - if ( deleteEmpty & valueIsEmpty ) { - - if ( destNode != 0 ) { - delete ( destNode ); - destParent->children.erase ( destPos ); - } - - } else if ( destNode == 0 ) { - - // The one easy case, the destination does not exist. - CloneSubtree ( sourceNode, destParent ); - - } else if ( replaceOld ) { - - // The destination exists and should be replaced. - - destNode->value = sourceNode->value; // *** Should use SetNode. - destNode->options = sourceNode->options; - destNode->RemoveChildren(); - destNode->RemoveQualifiers(); - CloneOffspring ( sourceNode, destNode ); - - #if 0 // *** XMP_DebugBuild - destNode->_valuePtr = destNode->value.c_str(); - #endif - - } else { - - // The destination exists and is not totally replaced. Structs and arrays are merged. - - XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask; - XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask; - if ( sourceForm != destForm ) return; - - if ( sourceForm == kXMP_PropValueIsStruct ) { - - // To merge a struct process the fields recursively. E.g. add simple missing fields. The - // recursive call to AppendSubtree will handle deletion for fields with empty values. - - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - const XMP_Node * sourceField = sourceNode->children[sourceNum]; - AppendSubtree ( sourceField, destNode, replaceOld, deleteEmpty ); - if ( deleteEmpty && destNode->children.empty() ) { - delete ( destNode ); - destParent->children.erase ( destPos ); - } - } - - } else if ( sourceForm & kXMP_PropArrayIsAltText ) { - - // Merge AltText arrays by the xml:lang qualifiers. Make sure x-default is first. Make a - // special check for deletion of empty values. Meaningful in AltText arrays because the - // xml:lang qualifier provides unambiguous source/dest correspondence. - - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - - const XMP_Node * sourceItem = sourceNode->children[sourceNum]; - if ( sourceItem->qualifiers.empty() || (sourceItem->qualifiers[0]->name != "xml:lang") ) continue; - - XMP_Index destIndex = LookupLangItem ( destNode, sourceItem->qualifiers[0]->value ); - - if ( deleteEmpty && sourceItem->value.empty() ) { - - if ( destIndex != -1 ) { - delete ( destNode->children[destIndex] ); - destNode->children.erase ( destNode->children.begin() + destIndex ); - if ( destNode->children.empty() ) { - delete ( destNode ); - destParent->children.erase ( destPos ); - } - } - - } else { - - if ( destIndex != -1 ) continue; // Not replacing, keep the existing item. - - if ( (sourceItem->qualifiers[0]->value != "x-default") || destNode->children.empty() ) { - CloneSubtree ( sourceItem, destNode ); - } else { - XMP_Node * destItem = new XMP_Node ( destNode, sourceItem->name, sourceItem->value, sourceItem->options ); - CloneOffspring ( sourceItem, destItem ); - destNode->children.insert ( destNode->children.begin(), destItem ); - } - - } - - } - - } else if ( sourceForm & kXMP_PropValueIsArray ) { - - // Merge other arrays by item values. Don't worry about order or duplicates. Source - // items with empty values do not cause deletion, that conflicts horribly with merging. - - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - const XMP_Node * sourceItem = sourceNode->children[sourceNum]; - - size_t destNum, destLim; - for ( destNum = 0, destLim = destNode->children.size(); destNum != destLim; ++destNum ) { - const XMP_Node * destItem = destNode->children[destNum]; - if ( ItemValuesMatch ( sourceItem, destItem ) ) break; - } - if ( destNum == destLim ) CloneSubtree ( sourceItem, destNode ); - - } - - } - - } - -} // AppendSubtree - - -// ================================================================================================= -// Class Static Functions -// ====================== - -// ------------------------------------------------------------------------------------------------- -// CatenateArrayItems -// ------------------ - -/* class static */ void -XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen ) -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // ! Enforced by wrapper. - XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) && (catedLen != 0) ); // ! Enforced by wrapper. - - size_t strLen=0, strPos=0, charLen=0; - UniCharKind charKind; - UniCodePoint currUCP, openQuote, closeQuote; - - const bool allowCommas = ((options & kXMPUtil_AllowCommas) != 0); - - const XMP_Node * arrayNode = 0; // ! Move up to avoid gcc complaints. - XMP_OptionBits arrayForm = 0; - const XMP_Node * currItem = 0; - - // Make sure the separator is OK. It must be one semicolon surrounded by zero or more spaces. - // Any of the recognized semicolons or spaces are allowed. - - strPos = 0; - strLen = strlen ( separator ); - bool haveSemicolon = false; - - while ( strPos < strLen ) { - ClassifyCharacter ( separator, strPos, &charKind, &charLen, &currUCP ); - strPos += charLen; - if ( charKind == UCK_semicolon ) { - if ( haveSemicolon ) XMP_Throw ( "Separator can have only one semicolon", kXMPErr_BadParam ); - haveSemicolon = true; - } else if ( charKind != UCK_space ) { - XMP_Throw ( "Separator can have only spaces and one semicolon", kXMPErr_BadParam ); - } - }; - if ( ! haveSemicolon ) XMP_Throw ( "Separator must have one semicolon", kXMPErr_BadParam ); - - // Make sure the open and close quotes are a legitimate pair. - - strLen = strlen ( quotes ); - ClassifyCharacter ( quotes, 0, &charKind, &charLen, &openQuote ); - if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam ); - - if ( charLen == strLen ) { - closeQuote = openQuote; - } else { - strPos = charLen; - ClassifyCharacter ( quotes, strPos, &charKind, &charLen, &closeQuote ); - if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam ); - if ( (strPos + charLen) != strLen ) XMP_Throw ( "Quoting string too long", kXMPErr_BadParam ); - } - if ( closeQuote != GetClosingQuote ( openQuote ) ) XMP_Throw ( "Mismatched quote pair", kXMPErr_BadParam ); - - // Return an empty result if the array does not exist, hurl if it isn't the right form. - - sCatenatedItems->erase(); - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - - arrayNode = FindConstNode ( &xmpObj.tree, arrayPath ); - if ( arrayNode == 0 ) goto EXIT; // ! Need to set the output pointer and length. - - arrayForm = arrayNode->options & kXMP_PropCompositeMask; - if ( (! (arrayForm & kXMP_PropValueIsArray)) || (arrayForm & kXMP_PropArrayIsAlternate) ) { - XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadParam ); - } - if ( arrayNode->children.empty() ) goto EXIT; // ! Need to set the output pointer and length. - - // Build the result, quoting the array items, adding separators. Hurl if any item isn't simple. - // Start the result with the first value, then add the rest with a preceding separator. - - currItem = arrayNode->children[0]; - - if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam ); - *sCatenatedItems = currItem->value; - ApplyQuotes ( sCatenatedItems, openQuote, closeQuote, allowCommas ); - - for ( size_t itemNum = 1, itemLim = arrayNode->children.size(); itemNum != itemLim; ++itemNum ) { - const XMP_Node * currItem = arrayNode->children[itemNum]; - if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam ); - XMP_VarString tempStr ( currItem->value ); - ApplyQuotes ( &tempStr, openQuote, closeQuote, allowCommas ); - *sCatenatedItems += separator; - *sCatenatedItems += tempStr; - } - -EXIT: - *catedStr = sCatenatedItems->c_str(); - *catedLen = sCatenatedItems->size(); - -} // CatenateArrayItems - - -// ------------------------------------------------------------------------------------------------- -// SeparateArrayItems -// ------------------ - -/* class static */ void -XMPUtils::SeparateArrayItems ( XMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr ) -{ - XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (catedStr != 0) ); // ! Enforced by wrapper. - - XMP_VarString itemValue; - size_t itemStart, itemEnd; - size_t nextSize, charSize = 0; // Avoid VS uninit var warnings. - UniCharKind nextKind, charKind = UCK_normal; - UniCodePoint nextChar, uniChar = 0; - - // Extract "special" option bits, verify and normalize the others. - - bool preserveCommas = false; - if ( options & kXMPUtil_AllowCommas ) { - preserveCommas = true; - options ^= kXMPUtil_AllowCommas; - } - - options = VerifySetOptions ( options, 0 ); // Keep a zero value, has special meaning below. - if ( options & ~kXMP_PropArrayFormMask ) XMP_Throw ( "Options can only provide array form", kXMPErr_BadOptions ); - - // Find the array node, make sure it is OK. Move the current children aside, to be readded later if kept. - - XMP_ExpandedXPath arrayPath; - ExpandXPath ( schemaNS, arrayName, &arrayPath ); - XMP_Node * arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_ExistingOnly ); - - if ( arrayNode != 0 ) { - // The array exists, make sure the form is compatible. Zero arrayForm means take what exists. - XMP_OptionBits arrayForm = arrayNode->options & kXMP_PropArrayFormMask; - if ( (arrayForm == 0) || (arrayForm & kXMP_PropArrayIsAlternate) ) { - XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadXPath ); - } - if ( (options != 0) && (options != arrayForm) ) XMP_Throw ( "Mismatch of specified and existing array form", kXMPErr_BadXPath ); // *** Right error? - } else { - // The array does not exist, try to create it. - arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_CreateNodes, (options | kXMP_PropValueIsArray) ); - if ( arrayNode == 0 ) XMP_Throw ( "Failed to create named array", kXMPErr_BadXPath ); - } - - XMP_NodeOffspring oldChildren ( arrayNode->children ); - size_t oldChildCount = oldChildren.size(); - arrayNode->children.clear(); - - // Extract the item values one at a time, until the whole input string is done. Be very careful - // in the extraction about the string positions. They are essentially byte pointers, while the - // contents are UTF-8. Adding or subtracting 1 does not necessarily move 1 Unicode character! - - size_t endPos = strlen ( catedStr ); - - itemEnd = 0; - while ( itemEnd < endPos ) { - - // Skip any leading spaces and separation characters. Always skip commas here. They can be - // kept when within a value, but not when alone between values. - - for ( itemStart = itemEnd; itemStart < endPos; itemStart += charSize ) { - ClassifyCharacter ( catedStr, itemStart, &charKind, &charSize, &uniChar ); - if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) break; - } - if ( itemStart >= endPos ) break; - - if ( charKind != UCK_quote ) { - - // This is not a quoted value. Scan for the end, create an array item from the substring. - - for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) { - - ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar ); - - if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) continue; - if ( (charKind == UCK_comma) && preserveCommas ) continue; - if ( charKind != UCK_space ) break; - - if ( (itemEnd + charSize) >= endPos ) break; // Anything left? - ClassifyCharacter ( catedStr, (itemEnd+charSize), &nextKind, &nextSize, &nextChar ); - if ( (nextKind == UCK_normal) || (nextKind == UCK_quote) ) continue; - if ( (nextKind == UCK_comma) && preserveCommas ) continue; - break; // Have multiple spaces, or a space followed by a separator. - - } - - itemValue.assign ( catedStr, itemStart, (itemEnd - itemStart) ); - - } else { - - // Accumulate quoted values into a local string, undoubling internal quotes that - // match the surrounding quotes. Do not undouble "unmatching" quotes. - - UniCodePoint openQuote = uniChar; - UniCodePoint closeQuote = GetClosingQuote ( openQuote ); - - itemStart += charSize; // Skip the opening quote; - itemValue.erase(); - - for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) { - - ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar ); - - if ( (charKind != UCK_quote) || (! IsSurroundingQuote ( uniChar, openQuote, closeQuote)) ) { - - // This is not a matching quote, just append it to the item value. - itemValue.append ( catedStr, itemEnd, charSize ); - - } else { - - // This is a "matching" quote. Is it doubled, or the final closing quote? Tolerate - // various edge cases like undoubled opening (non-closing) quotes, or end of input. - - if ( (itemEnd + charSize) < endPos ) { - ClassifyCharacter ( catedStr, itemEnd+charSize, &nextKind, &nextSize, &nextChar ); - } else { - nextKind = UCK_semicolon; nextSize = 0; nextChar = 0x3B; - } - - if ( uniChar == nextChar ) { - // This is doubled, copy it and skip the double. - itemValue.append ( catedStr, itemEnd, charSize ); - itemEnd += nextSize; // Loop will add in charSize. - } else if ( ! IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) { - // This is an undoubled, non-closing quote, copy it. - itemValue.append ( catedStr, itemEnd, charSize ); - } else { - // This is an undoubled closing quote, skip it and exit the loop. - itemEnd += charSize; - break; - } - - } - - } // Loop to accumulate the quoted value. - - } - - // Add the separated item to the array. Keep a matching old value in case it had separators. - - size_t oldChild; - for ( oldChild = 0; oldChild < oldChildCount; ++oldChild ) { - if ( (oldChildren[oldChild] != 0) && (itemValue == oldChildren[oldChild]->value) ) break; - } - - XMP_Node * newItem = 0; - if ( oldChild == oldChildCount ) { - newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue.c_str(), 0 ); - } else { - newItem = oldChildren[oldChild]; - oldChildren[oldChild] = 0; // ! Don't match again, let duplicates be seen. - } - arrayNode->children.push_back ( newItem ); - - } // Loop through all of the returned items. - - // Delete any of the old children that were not kept. - for ( size_t i = 0; i < oldChildCount; ++i ) { - if ( oldChildren[i] != 0 ) delete oldChildren[i]; - } - -} // SeparateArrayItems - - -// ------------------------------------------------------------------------------------------------- -// RemoveProperties -// ---------------- - -/* class static */ void -XMPUtils::RemoveProperties ( XMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ) -{ - XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // ! Enforced by wrapper. - - const bool doAll = XMP_TestOption (options, kXMPUtil_DoAllProperties ); - const bool includeAliases = XMP_TestOption ( options, kXMPUtil_IncludeAliases ); - - if ( *propName != 0 ) { - - // Remove just the one indicated property. This might be an alias, the named schema might - // not actually exist. So don't lookup the schema node. - - if ( *schemaNS == 0 ) XMP_Throw ( "Property name requires schema namespace", kXMPErr_BadParam ); - - XMP_ExpandedXPath expPath; - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_NodePtrPos propPos; - XMP_Node * propNode = FindNode ( &(xmpObj->tree), expPath, kXMP_ExistingOnly, kXMP_NoOptions, &propPos ); - if ( propNode != 0 ) { - if ( doAll || IsExternalProperty ( expPath[kSchemaStep].step, expPath[kRootPropStep].step ) ) { - XMP_Node * parent = propNode->parent; // *** Should have XMP_Node::RemoveChild(pos). - delete propNode; // ! Both delete the node and erase the pointer from the parent. - parent->children.erase ( propPos ); - DeleteEmptySchema ( parent ); - } - } - - } else if ( *schemaNS != 0 ) { - - // Remove all properties from the named schema. Optionally include aliases, in which case - // there might not be an actual schema node. - - XMP_NodePtrPos schemaPos; - XMP_Node * schemaNode = FindSchemaNode ( &xmpObj->tree, schemaNS, kXMP_ExistingOnly, &schemaPos ); - if ( schemaNode != 0 ) RemoveSchemaChildren ( schemaPos, doAll ); - - if ( includeAliases ) { - - // We're removing the aliases also. Look them up by their namespace prefix. Yes, the - // alias map is sorted so we could process just that portion. But that takes more code - // and the extra speed isn't worth it. (Plus this way we avoid a dependence on the map - // implementation.) Lookup the XMP node from the alias, to make sure the actual exists. - - XMP_StringPtr nsPrefix; - XMP_StringLen nsLen; - (void) XMPMeta::GetNamespacePrefix ( schemaNS, &nsPrefix, &nsLen ); - - XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin(); - XMP_AliasMapPos endAlias = sRegisteredAliasMap->end(); - - for ( ; currAlias != endAlias; ++currAlias ) { - if ( strncmp ( currAlias->first.c_str(), nsPrefix, nsLen ) == 0 ) { - XMP_NodePtrPos actualPos; - XMP_Node * actualProp = FindNode ( &xmpObj->tree, currAlias->second, kXMP_ExistingOnly, kXMP_NoOptions, &actualPos ); - if ( actualProp != 0 ) { - XMP_Node * rootProp = actualProp; - while ( ! XMP_NodeIsSchema ( rootProp->parent->options ) ) rootProp = rootProp->parent; - if ( doAll || IsExternalProperty ( rootProp->parent->name, rootProp->name ) ) { - XMP_Node * parent = actualProp->parent; - delete actualProp; // ! Both delete the node and erase the pointer from the parent. - parent->children.erase ( actualPos ); - DeleteEmptySchema ( parent ); - } - } - } - } - - } - - } else { - - // Remove all appropriate properties from all schema. In this case we don't have to be - // concerned with aliases, they are handled implicitly from the actual properties. - - // ! Iterate backwards to reduce shuffling if schema are erased and to simplify the logic - // ! for denoting the current schema. (Erasing schema n makes the old n+1 now be n.) - - size_t schemaCount = xmpObj->tree.children.size(); - XMP_NodePtrPos beginPos = xmpObj->tree.children.begin(); - - for ( size_t schemaNum = schemaCount-1, schemaLim = (size_t)(-1); schemaNum != schemaLim; --schemaNum ) { - XMP_NodePtrPos currSchema = beginPos + schemaNum; - RemoveSchemaChildren ( currSchema, doAll ); - } - - } - -} // RemoveProperties - - -// ------------------------------------------------------------------------------------------------- -// AppendProperties -// ---------------- - -/* class static */ void -XMPUtils::AppendProperties ( const XMPMeta & source, - XMPMeta * dest, - XMP_OptionBits options ) -{ - XMP_Assert ( dest != 0 ); // ! Enforced by wrapper. - - const bool doAll = ((options & kXMPUtil_DoAllProperties) != 0); - const bool replaceOld = ((options & kXMPUtil_ReplaceOldValues) != 0); - const bool deleteEmpty = ((options & kXMPUtil_DeleteEmptyValues) != 0); - - for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) { - - const XMP_Node * sourceSchema = source.tree.children[schemaNum]; - - // Make sure we have a destination schema node. Remember if it is newly created. - - XMP_Node * destSchema = FindSchemaNode ( &dest->tree, sourceSchema->name.c_str(), kXMP_ExistingOnly ); - const bool newDestSchema = (destSchema == 0); - if ( newDestSchema ) { - destSchema = new XMP_Node ( &dest->tree, sourceSchema->name, sourceSchema->value, kXMP_SchemaNode ); - dest->tree.children.push_back ( destSchema ); - } - - // Process the source schema's children. Do this backwards in case deleteEmpty is set. - - for ( long propNum = ((long)sourceSchema->children.size() - 1); propNum >= 0; --propNum ) { - const XMP_Node * sourceProp = sourceSchema->children[propNum]; - if ( doAll || IsExternalProperty ( sourceSchema->name, sourceProp->name ) ) { - AppendSubtree ( sourceProp, destSchema, replaceOld, deleteEmpty ); -// *** RemoveMultiValueInfo ( dest, sourceSchema->name.c_str(), sourceProp->name.c_str() ); - } - } - - if ( destSchema->children.empty() ) { - if ( newDestSchema ) { - delete ( destSchema ); - dest->tree.children.pop_back(); - } else if ( deleteEmpty ) { - DeleteEmptySchema ( destSchema ); - } - } - - } - -} // AppendProperties - - -// ------------------------------------------------------------------------------------------------- -// DuplicateSubtree -// ---------------- - -/* class static */ void -XMPUtils::DuplicateSubtree ( const XMPMeta & source, - XMPMeta * dest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS, - XMP_StringPtr destRoot, - XMP_OptionBits options ) -{ - UNUSED(options); - - bool fullSourceTree = false; - bool fullDestTree = false; - - XMP_ExpandedXPath sourcePath, destPath; - - const XMP_Node * sourceNode = 0; - XMP_Node * destNode = 0; - - XMP_Assert ( (sourceNS != 0) && (*sourceNS != 0) ); - XMP_Assert ( (sourceRoot != 0) && (*sourceRoot != 0) ); - XMP_Assert ( (dest != 0) && (destNS != 0) && (destRoot != 0) ); - - if ( *destNS == 0 ) destNS = sourceNS; - if ( *destRoot == 0 ) destRoot = sourceRoot; - - if ( XMP_LitMatch ( sourceNS, "*" ) ) fullSourceTree = true; - if ( XMP_LitMatch ( destNS, "*" ) ) fullDestTree = true; - - if ( (&source == dest) && (fullSourceTree | fullDestTree) ) { - XMP_Throw ( "Can't duplicate tree onto itself", kXMPErr_BadParam ); - } - - if ( fullSourceTree & fullDestTree ) XMP_Throw ( "Use Clone for full tree to full tree", kXMPErr_BadParam ); - - if ( fullSourceTree ) { - - // The destination must be an existing empty struct, copy all of the source top level as fields. - - ExpandXPath ( destNS, destRoot, &destPath ); - destNode = FindNode ( &dest->tree, destPath, kXMP_ExistingOnly ); - - if ( (destNode == 0) || (! XMP_PropIsStruct ( destNode->options )) ) { - XMP_Throw ( "Destination must be an existing struct", kXMPErr_BadXPath ); - } - - if ( ! destNode->children.empty() ) { - if ( options & kXMP_DeleteExisting ) { - destNode->RemoveChildren(); - } else { - XMP_Throw ( "Destination must be an empty struct", kXMPErr_BadXPath ); - } - } - - for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { - - const XMP_Node * currSchema = source.tree.children[schemaNum]; - - for ( size_t propNum = 0, propLim = currSchema->children.size(); propNum < propLim; ++propNum ) { - sourceNode = currSchema->children[propNum]; - XMP_Node * copyNode = new XMP_Node ( destNode, sourceNode->name, sourceNode->value, sourceNode->options ); - destNode->children.push_back ( copyNode ); - CloneOffspring ( sourceNode, copyNode ); - } - - } - - } else if ( fullDestTree ) { - - // The source node must be an existing struct, copy all of the fields to the dest top level. - - XMP_ExpandedXPath sourcePath; - ExpandXPath ( sourceNS, sourceRoot, &sourcePath ); - sourceNode = FindConstNode ( &source.tree, sourcePath ); - - if ( (sourceNode == 0) || (! XMP_PropIsStruct ( sourceNode->options )) ) { - XMP_Throw ( "Source must be an existing struct", kXMPErr_BadXPath ); - } - - destNode = &dest->tree; - - if ( ! destNode->children.empty() ) { - if ( options & kXMP_DeleteExisting ) { - destNode->RemoveChildren(); - } else { - XMP_Throw ( "Destination tree must be empty", kXMPErr_BadXPath ); - } - } - - std::string nsPrefix; - XMP_StringPtr nsURI; - XMP_StringLen nsLen; - - for ( size_t fieldNum = 0, fieldLim = sourceNode->children.size(); fieldNum < fieldLim; ++fieldNum ) { - - const XMP_Node * currField = sourceNode->children[fieldNum]; - - size_t colonPos = currField->name.find ( ':' ); - nsPrefix.assign ( currField->name.c_str(), colonPos ); - bool nsOK = XMPMeta::GetNamespaceURI ( nsPrefix.c_str(), &nsURI, &nsLen ); - if ( ! nsOK ) XMP_Throw ( "Source field namespace is not global", kXMPErr_BadSchema ); - - XMP_Node * destSchema = FindSchemaNode ( &dest->tree, nsURI, kXMP_CreateNodes ); - if ( destSchema == 0 ) XMP_Throw ( "Failed to find destination schema", kXMPErr_BadSchema ); - - XMP_Node * copyNode = new XMP_Node ( destSchema, currField->name, currField->value, currField->options ); - destSchema->children.push_back ( copyNode ); - CloneOffspring ( currField, copyNode ); - - } - - } else { - - // Find the root nodes for the source and destination subtrees. - - ExpandXPath ( sourceNS, sourceRoot, &sourcePath ); - ExpandXPath ( destNS, destRoot, &destPath ); - - sourceNode = FindConstNode ( &source.tree, sourcePath ); - if ( sourceNode == 0 ) XMP_Throw ( "Can't find source subtree", kXMPErr_BadXPath ); - - destNode = FindNode ( &dest->tree, destPath, kXMP_ExistingOnly ); // Dest must not yet exist. - if ( destNode != 0 ) XMP_Throw ( "Destination subtree must not exist", kXMPErr_BadXPath ); - - destNode = FindNode ( &dest->tree, destPath, kXMP_CreateNodes ); // Now create the dest. - if ( destNode == 0 ) XMP_Throw ( "Can't create destination root node", kXMPErr_BadXPath ); - - // Make sure the destination is not within the source! The source can't be inside the destination - // because the source already existed and the destination was just created. - - if ( &source == dest ) { - for ( XMP_Node * testNode = destNode; testNode != 0; testNode = testNode->parent ) { - if ( testNode == sourceNode ) { - // *** delete the just-created dest root node - XMP_Throw ( "Destination subtree is within the source subtree", kXMPErr_BadXPath ); - } - } - } - - // *** Could use a CloneTree util here and maybe elsewhere. - - destNode->value = sourceNode->value; // *** Should use SetNode. - destNode->options = sourceNode->options; - CloneOffspring ( sourceNode, destNode ); - - } - -} // DuplicateSubtree - - -// ================================================================================================= diff --git a/xmpsdk/src/XMPUtils.cpp b/xmpsdk/src/XMPUtils.cpp deleted file mode 100644 index 89afd3d62d..0000000000 --- a/xmpsdk/src/XMPUtils.cpp +++ /dev/null @@ -1,2157 +0,0 @@ -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" - -#include "XMPUtils.hpp" - -#include "MD5.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include // For snprintf. - -#if XMP_WinBuild -#ifdef _MSC_VER - #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning) - #pragma warning ( disable : 4996 ) // '...' was declared deprecated -#endif -#endif - -// ================================================================================================= -// Local Types and Constants -// ========================= - -static const char * sBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -// ================================================================================================= -// Static Variables -// ================ - -XMP_VarString * sComposedPath = 0; // *** Only really need 1 string. Shrink periodically? -XMP_VarString * sConvertedValue = 0; -XMP_VarString * sBase64Str = 0; -XMP_VarString * sCatenatedItems = 0; -XMP_VarString * sStandardXMP = 0; -XMP_VarString * sExtendedXMP = 0; -XMP_VarString * sExtendedDigest = 0; - -// ================================================================================================= -// Local Utilities -// =============== - - -// ------------------------------------------------------------------------------------------------- -// ANSI Time Functions -// ------------------- -// -// A bit of hackery to use the best available time functions. Mac and UNIX have thread safe versions -// of gmtime and localtime. On Mac the CodeWarrior functions are buggy, use Apple's. - -#if XMP_UNIXBuild - - typedef time_t ansi_tt; - typedef struct tm ansi_tm; - - #define ansi_time time - #define ansi_mktime mktime - #define ansi_difftime difftime - - #define ansi_gmtime gmtime_r - #define ansi_localtime localtime_r - -#elif XMP_WinBuild - - // ! VS.Net 2003 (VC7) does not provide thread safe versions of gmtime and localtime. - // ! VS.Net 2005 (VC8) inverts the parameters for the safe versions of gmtime and localtime. - - typedef time_t ansi_tt; - typedef struct tm ansi_tm; - - #define ansi_time time - #define ansi_mktime mktime - #define ansi_difftime difftime - - #if defined(_MSC_VER) && (_MSC_VER >= 1400) - #define ansi_gmtime(tt,tm) gmtime_s ( tm, tt ) - #define ansi_localtime(tt,tm) localtime_s ( tm, tt ) - #else - static inline void ansi_gmtime ( const ansi_tt * ttTime, ansi_tm * tmTime ) - { - ansi_tm * tmx = gmtime ( ttTime ); // ! Hope that there is no race! - if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C gmtime function", kXMPErr_ExternalFailure ); - *tmTime = *tmx; - } - static inline void ansi_localtime ( const ansi_tt * ttTime, ansi_tm * tmTime ) - { - ansi_tm * tmx = localtime ( ttTime ); // ! Hope that there is no race! - if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C localtime function", kXMPErr_ExternalFailure ); - *tmTime = *tmx; - } - #endif - -#elif XMP_MacBuild - - #if ! __MWERKS__ - - typedef time_t ansi_tt; - typedef struct tm ansi_tm; - - #define ansi_time time - #define ansi_mktime mktime - #define ansi_difftime difftime - - #define ansi_gmtime gmtime_r - #define ansi_localtime localtime_r - - #else - - // ! The CW versions are buggy. Use Apple's code, time_t, and "struct tm". - - #include - - typedef _BSD_TIME_T_ ansi_tt; - - typedef struct apple_tm { - int tm_sec; /* seconds after the minute [0-60] */ - int tm_min; /* minutes after the hour [0-59] */ - int tm_hour; /* hours since midnight [0-23] */ - int tm_mday; /* day of the month [1-31] */ - int tm_mon; /* months since January [0-11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday [0-6] */ - int tm_yday; /* days since January 1 [0-365] */ - int tm_isdst; /* Daylight Savings Time flag */ - long tm_gmtoff; /* offset from CUT in seconds */ - char *tm_zone; /* timezone abbreviation */ - } ansi_tm; - - - typedef ansi_tt (* GetTimeProc) ( ansi_tt * ttTime ); - typedef ansi_tt (* MakeTimeProc) ( ansi_tm * tmTime ); - typedef double (* DiffTimeProc) ( ansi_tt t1, ansi_tt t0 ); - - typedef void (* ConvertTimeProc) ( const ansi_tt * ttTime, ansi_tm * tmTime ); - - static GetTimeProc ansi_time = 0; - static MakeTimeProc ansi_mktime = 0; - static DiffTimeProc ansi_difftime = 0; - - static ConvertTimeProc ansi_gmtime = 0; - static ConvertTimeProc ansi_localtime = 0; - - static void LookupTimeProcs() - { - _dyld_lookup_and_bind_with_hint ( "_time", "libSystem", (XMP_Uns32*)&ansi_time, 0 ); - _dyld_lookup_and_bind_with_hint ( "_mktime", "libSystem", (XMP_Uns32*)&ansi_mktime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_difftime", "libSystem", (XMP_Uns32*)&ansi_difftime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_gmtime_r", "libSystem", (XMP_Uns32*)&ansi_gmtime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_localtime_r", "libSystem", (XMP_Uns32*)&ansi_localtime, 0 ); - } - - #endif - -#endif - - -// ------------------------------------------------------------------------------------------------- -// IsLeapYear -// ---------- - -static bool -IsLeapYear ( long year ) -{ - // This code uses the Gregorian calendar algorithm: - // https://en.wikipedia.org/wiki/Leap_year#Algorithm - - if ( (year % 4) != 0 ) return false; // Not a multiple of 4. - if ( (year % 100) != 0 ) return true; // A multiple of 4 but not a multiple of 100. - if ( (year % 400) == 0 ) return true; // A multiple of 400. - - return false; // A multiple of 100 but not a multiple of 400. - -} // IsLeapYear - - -// ------------------------------------------------------------------------------------------------- -// DaysInMonth -// ----------- - -static int -DaysInMonth ( XMP_Int32 year, XMP_Int32 month ) -{ - - static short daysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec - - int days = daysInMonth [ month ]; - if ( (month == 2) && IsLeapYear ( year ) ) days += 1; - - return days; - -} // DaysInMonth - - -// ------------------------------------------------------------------------------------------------- -// AdjustTimeOverflow -// ------------------ - -static void -AdjustTimeOverflow ( XMP_DateTime * time ) -{ - enum { kBillion = 1000*1000*1000L }; - - // ---------------------------------------------------------------------------------------------- - // To be safe against pathalogical overflow we first adjust from month to second, then from - // nanosecond back up to month. This leaves each value closer to zero before propagating into it. - // For example if the hour and minute are both near max, adjusting minutes first can cause the - // hour to overflow. - - // ! Photoshop 8 creates "time only" values with zeros for year, month, and day. - - if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) { - - while ( time->month < 1 ) { - time->year -= 1; - time->month += 12; - } - - while ( time->month > 12 ) { - time->year += 1; - time->month -= 12; - } - - while ( time->day < 1 ) { - time->month -= 1; - if ( time->month < 1 ) { // ! Keep the months in range for indexing daysInMonth! - time->year -= 1; - time->month += 12; - } - time->day += DaysInMonth ( time->year, time->month ); // ! Decrement month before so index here is right! - } - - while ( time->day > DaysInMonth ( time->year, time->month ) ) { - time->day -= DaysInMonth ( time->year, time->month ); // ! Increment month after so index here is right! - time->month += 1; - if ( time->month > 12 ) { - time->year += 1; - time->month -= 12; - } - } - - } - - while ( time->hour < 0 ) { - time->day -= 1; - time->hour += 24; - } - - while ( time->hour >= 24 ) { - time->day += 1; - time->hour -= 24; - } - - while ( time->minute < 0 ) { - time->hour -= 1; - time->minute += 60; - } - - while ( time->minute >= 60 ) { - time->hour += 1; - time->minute -= 60; - } - - while ( time->second < 0 ) { - time->minute -= 1; - time->second += 60; - } - - while ( time->second >= 60 ) { - time->minute += 1; - time->second -= 60; - } - - while ( time->nanoSecond < 0 ) { - time->second -= 1; - time->nanoSecond += kBillion; - } - - while ( time->nanoSecond >= kBillion ) { - time->second += 1; - time->nanoSecond -= kBillion; - } - - while ( time->second < 0 ) { - time->minute -= 1; - time->second += 60; - } - - while ( time->second >= 60 ) { - time->minute += 1; - time->second -= 60; - } - - while ( time->minute < 0 ) { - time->hour -= 1; - time->minute += 60; - } - - while ( time->minute >= 60 ) { - time->hour += 1; - time->minute -= 60; - } - - while ( time->hour < 0 ) { - time->day -= 1; - time->hour += 24; - } - - while ( time->hour >= 24 ) { - time->day += 1; - time->hour -= 24; - } - - if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) { - - while ( time->month < 1 ) { // Make sure the months are OK first, for DaysInMonth. - time->year -= 1; - time->month += 12; - } - - while ( time->month > 12 ) { - time->year += 1; - time->month -= 12; - } - - while ( time->day < 1 ) { - time->month -= 1; - if ( time->month < 1 ) { - time->year -= 1; - time->month += 12; - } - time->day += DaysInMonth ( time->year, time->month ); - } - - while ( time->day > DaysInMonth ( time->year, time->month ) ) { - time->day -= DaysInMonth ( time->year, time->month ); - time->month += 1; - if ( time->month > 12 ) { - time->year += 1; - time->month -= 12; - } - } - - } - -} // AdjustTimeOverflow - - -// ------------------------------------------------------------------------------------------------- -// GatherInt -// --------- - -static XMP_Int32 -GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg ) -{ - size_t pos = *_pos; - XMP_Int32 value = 0; - - // Limits for overflow checking. Assuming that the maximum value of XMP_Int32 - // is 2147483647, then tens_upperbound == 214748364 and ones_upperbound == 7. - // Most of the time, we can just check that value < tens_upperbound to confirm - // that the calculation won't overflow, which makes the bounds checking more - // efficient for the common case. - const XMP_Int32 tens_upperbound = std::numeric_limits::max() / 10; - const XMP_Int32 ones_upperbound = std::numeric_limits::max() % 10; - - for ( char ch = strValue[pos]; ('0' <= ch) && (ch <= '9'); ++pos, ch = strValue[pos] ) { - const XMP_Int32 digit = ch - '0'; - if (value >= tens_upperbound) { - if (value > tens_upperbound || digit > ones_upperbound) { - XMP_Throw ( errMsg, kXMPErr_BadParam ); - } - } - value = (value * 10) + digit; - } - - if ( pos == *_pos ) XMP_Throw ( errMsg, kXMPErr_BadParam ); - *_pos = pos; - return value; - -} // GatherInt - - -// ------------------------------------------------------------------------------------------------- - -static void FormatFullDateTime ( XMP_DateTime & tempDate, char * buffer, size_t bufferLen ) -{ - - AdjustTimeOverflow ( &tempDate ); // Make sure all time parts are in range. - - if ( (tempDate.second == 0) && (tempDate.nanoSecond == 0) ) { - - // Output YYYY-MM-DDThh:mmTZD. - snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d", // AUDIT: Callers pass sizeof(buffer). - static_cast(tempDate.year), static_cast(tempDate.month), static_cast(tempDate.day), static_cast(tempDate.hour), static_cast(tempDate.minute) ); - - } else if ( tempDate.nanoSecond == 0 ) { - - // Output YYYY-MM-DDThh:mm:ssTZD. - snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d", // AUDIT: Callers pass sizeof(buffer). - static_cast(tempDate.year), static_cast(tempDate.month), static_cast(tempDate.day), - static_cast(tempDate.hour), static_cast(tempDate.minute), static_cast(tempDate.second) ); - - } else { - - // Output YYYY-MM-DDThh:mm:ss.sTZD. - snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d.%09d", // AUDIT: Callers pass sizeof(buffer). - static_cast(tempDate.year), static_cast(tempDate.month), static_cast(tempDate.day), - static_cast(tempDate.hour), static_cast(tempDate.minute), static_cast(tempDate.second), static_cast(tempDate.nanoSecond) ); - for ( size_t i = strlen(buffer)-1; buffer[i] == '0'; --i ) buffer[i] = 0; // Trim excess digits. - - } - -} // FormatFullDateTime - - -// ------------------------------------------------------------------------------------------------- -// DecodeBase64Char -// ---------------- - -// The decode mapping: -// -// encoded encoded raw -// char value value -// ------- ------- ----- -// A .. Z 0x41 .. 0x5A 0 .. 25 -// a .. z 0x61 .. 0x7A 26 .. 51 -// 0 .. 9 0x30 .. 0x39 52 .. 61 -// + 0x2B 62 -// / 0x2F 63 - -static unsigned char -DecodeBase64Char ( XMP_Uns8 ch ) -{ - - if ( ('A' <= ch) && (ch <= 'Z') ) { - ch = ch - 'A'; - } else if ( ('a' <= ch) && (ch <= 'z') ) { - ch = ch - 'a' + 26; - } else if ( ('0' <= ch) && (ch <= '9') ) { - ch = ch - '0' + 52; - } else if ( ch == '+' ) { - ch = 62; - } else if ( ch == '/' ) { - ch = 63; - } else if ( (ch == ' ') || (ch == kTab) || (ch == kLF) || (ch == kCR) ) { - ch = 0xFF; // Will be ignored by the caller. - } else { - XMP_Throw ( "Invalid base-64 encoded character", kXMPErr_BadParam ); - } - - return ch; - -} // DecodeBase64Char (); - - -// ------------------------------------------------------------------------------------------------- -// EstimateSizeForJPEG -// ------------------- -// -// Estimate the serialized size for the subtree of an XMP_Node. Support for PackageForJPEG. - -static size_t -EstimateSizeForJPEG ( const XMP_Node * xmpNode ) -{ - - size_t estSize = 0; - size_t nameSize = xmpNode->name.size(); - bool includeName = (! XMP_PropIsArray ( xmpNode->parent->options )); - - if ( XMP_PropIsSimple ( xmpNode->options ) ) { - - if ( includeName ) estSize += (nameSize + 3); // Assume attribute form. - estSize += xmpNode->value.size(); - - } else if ( XMP_PropIsArray ( xmpNode->options ) ) { - - // The form of the value portion is: ...... - if ( includeName ) estSize += (2*nameSize + 5); - size_t arraySize = xmpNode->children.size(); - estSize += 9 + 10; // The rdf:Xyz tags. - estSize += arraySize * (8 + 9); // The rdf:li tags. - for ( size_t i = 0; i < arraySize; ++i ) { - estSize += EstimateSizeForJPEG ( xmpNode->children[i] ); - } - - } else { - - // The form is: ...fields... - if ( includeName ) estSize += (2*nameSize + 5); - estSize += 25; // The rdf:parseType="Resource" attribute. - size_t fieldCount = xmpNode->children.size(); - for ( size_t i = 0; i < fieldCount; ++i ) { - estSize += EstimateSizeForJPEG ( xmpNode->children[i] ); - } - - } - - return estSize; - -} // EstimateSizeForJPEG - - -// ------------------------------------------------------------------------------------------------- -// MoveOneProperty -// --------------- - -static bool MoveOneProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, - XMP_StringPtr schemaURI, XMP_StringPtr propName ) -{ - - XMP_Node * propNode = 0; - XMP_NodePtrPos stdPropPos; - - XMP_Node * stdSchema = FindSchemaNode ( &stdXMP.tree, schemaURI, kXMP_ExistingOnly, 0 ); - if ( stdSchema != 0 ) { - propNode = FindChildNode ( stdSchema, propName, kXMP_ExistingOnly, &stdPropPos ); - } - if ( propNode == 0 ) return false; - - XMP_Node * extSchema = FindSchemaNode ( &extXMP->tree, schemaURI, kXMP_CreateNodes ); - - propNode->parent = extSchema; - - extSchema->options &= ~kXMP_NewImplicitNode; - extSchema->children.push_back ( propNode ); - - stdSchema->children.erase ( stdPropPos ); - DeleteEmptySchema ( stdSchema ); - - return true; - -} // MoveOneProperty - - -// ------------------------------------------------------------------------------------------------- -// CreateEstimatedSizeMap -// ---------------------- - -#ifndef Trace_PackageForJPEG - #define Trace_PackageForJPEG 0 -#endif - -typedef std::pair < XMP_VarString*, XMP_VarString* > StringPtrPair; -typedef std::multimap < size_t, StringPtrPair > PropSizeMap; - -static void CreateEstimatedSizeMap ( XMPMeta & stdXMP, PropSizeMap * propSizes ) -{ - #if Trace_PackageForJPEG - printf ( " Creating top level property map:\n" ); - #endif - - for ( size_t s = stdXMP.tree.children.size(); s > 0; --s ) { - - XMP_Node * stdSchema = stdXMP.tree.children[s-1]; - - for ( size_t p = stdSchema->children.size(); p > 0; --p ) { - - XMP_Node * stdProp = stdSchema->children[p-1]; - if ( (stdSchema->name == kXMP_NS_XMP_Note) && - (stdProp->name == "xmpNote:HasExtendedXMP") ) continue; // ! Don't move xmpNote:HasExtendedXMP. - - size_t propSize = EstimateSizeForJPEG ( stdProp ); - StringPtrPair namePair ( &stdSchema->name, &stdProp->name ); - PropSizeMap::value_type mapValue ( propSize, namePair ); - - (void) propSizes->insert ( propSizes->upper_bound ( propSize ), mapValue ); - #if Trace_PackageForJPEG - printf ( " %d bytes, %s in %s\n", propSize, stdProp->name.c_str(), stdSchema->name.c_str() ); - #endif - - } - - } - -} // CreateEstimatedSizeMap - - -// ------------------------------------------------------------------------------------------------- -// MoveLargestProperty -// ------------------- - -static size_t MoveLargestProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, PropSizeMap & propSizes ) -{ - XMP_Assert ( ! propSizes.empty() ); - - #if 0 - // *** Xcode 2.3 on Mac OS X 10.4.7 seems to have a bug where this does not pick the last - // *** item in the map. We'll just avoid it on all platforms until thoroughly tested. - PropSizeMap::iterator lastPos = propSizes.end(); - --lastPos; // Move to the actual last item. - #else - PropSizeMap::iterator lastPos = propSizes.begin(); - PropSizeMap::iterator nextPos = lastPos; - for ( ++nextPos; nextPos != propSizes.end(); ++nextPos ) lastPos = nextPos; - #endif - - size_t propSize = lastPos->first; - const char * schemaURI = lastPos->second.first->c_str(); - const char * propName = lastPos->second.second->c_str(); - - #if Trace_PackageForJPEG - printf ( " Move %s, %d bytes\n", propName, propSize ); - #endif - - bool moved = MoveOneProperty ( stdXMP, extXMP, schemaURI, propName ); - XMP_Assert ( moved ); - UNUSED(moved); - - propSizes.erase ( lastPos ); - return propSize; - -} // MoveLargestProperty - - -// ================================================================================================= -// Class Static Functions -// ====================== - - -// ------------------------------------------------------------------------------------------------- -// Initialize -// ---------- - -/* class static */ bool -XMPUtils::Initialize() -{ - sComposedPath = new XMP_VarString(); - sConvertedValue = new XMP_VarString(); - sBase64Str = new XMP_VarString(); - sCatenatedItems = new XMP_VarString(); - sStandardXMP = new XMP_VarString(); - sExtendedXMP = new XMP_VarString(); - sExtendedDigest = new XMP_VarString(); - - #if XMP_MacBuild && __MWERKS__ - LookupTimeProcs(); - #endif - - return true; - -} // Initialize - - -// ------------------------------------------------------------------------------------------------- -// Terminate -// --------- - -#define EliminateGlobal(g) delete ( g ); g = 0 - -/* class static */ void -XMPUtils::Terminate() RELEASE_NO_THROW -{ - EliminateGlobal ( sComposedPath ); - EliminateGlobal ( sConvertedValue ); - EliminateGlobal ( sBase64Str ); - EliminateGlobal ( sCatenatedItems ); - EliminateGlobal ( sStandardXMP ); - EliminateGlobal ( sExtendedXMP ); - EliminateGlobal ( sExtendedDigest ); - - return; - -} // Terminate - - -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ - -/* class static */ void -XMPUtils::Unlock ( XMP_OptionBits options ) -{ - UNUSED(options); - - XMPMeta::Unlock ( 0 ); - -} // Unlock - -// ------------------------------------------------------------------------------------------------- -// ComposeArrayItemPath -// -------------------- -// -// Return "arrayName[index]". - -/* class static */ void -XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) -{ - XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - XMP_Assert ( *arrayName != 0 ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. - ExpandXPath ( schemaNS, arrayName, &expPath ); - - if ( (itemIndex < 0) && (itemIndex != kXMP_ArrayLastItem) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadParam ); - - XMP_StringLen reserveLen = strlen(arrayName) + 2 + 32; // Room plus padding. - - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - sComposedPath->append ( reserveLen, ' ' ); - - if ( itemIndex != kXMP_ArrayLastItem ) { - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast(sComposedPath->c_str()), sComposedPath->size(), "%s[%d]", arrayName, static_cast(itemIndex) ); - } else { - *sComposedPath = arrayName; - *sComposedPath += "[last()] "; - (*sComposedPath)[sComposedPath->size()-1] = 0; // ! Final null is for the strlen at exit. - } - - *fullPath = sComposedPath->c_str(); - *pathSize = strlen ( *fullPath ); // ! Don't use sComposedPath->size()! - - XMP_Enforce ( *pathSize < sComposedPath->size() ); // Rather late, but complain about buffer overflow. - -} // ComposeArrayItemPath - - -// ------------------------------------------------------------------------------------------------- -// ComposeStructFieldPath -// ---------------------- -// -// Return "structName/ns:fieldName". - -/* class static */ void -XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) -{ - XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) ); // Enforced by wrapper. - XMP_Assert ( (*structName != 0) && (*fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. - ExpandXPath ( schemaNS, structName, &expPath ); - - XMP_ExpandedXPath fieldPath; - ExpandXPath ( fieldNS, fieldName, &fieldPath ); - if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath ); - - XMP_StringLen reserveLen = strlen(structName) + fieldPath[kRootPropStep].step.size() + 1; - - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = structName; - *sComposedPath += '/'; - *sComposedPath += fieldPath[kRootPropStep].step; - - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); - -} // ComposeStructFieldPath - - -// ------------------------------------------------------------------------------------------------- -// ComposeQualifierPath -// -------------------- -// -// Return "propName/?ns:qualName". - -/* class static */ void -XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) -{ - XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper. - XMP_Assert ( (*propName != 0) && (*qualName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. - ExpandXPath ( schemaNS, propName, &expPath ); - - XMP_ExpandedXPath qualPath; - ExpandXPath ( qualNS, qualName, &qualPath ); - if ( qualPath.size() != 2 ) XMP_Throw ( "The qualifier name must be simple", kXMPErr_BadXPath ); - - XMP_StringLen reserveLen = strlen(propName) + qualPath[kRootPropStep].step.size() + 2; - - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = propName; - *sComposedPath += "/?"; - *sComposedPath += qualPath[kRootPropStep].step; - - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); - -} // ComposeQualifierPath - - -// ------------------------------------------------------------------------------------------------- -// ComposeLangSelector -// ------------------- -// -// Return "arrayName[?xml:lang="lang"]". - -// *** #error "handle quotes in the lang - or verify format" - -/* class static */ void -XMPUtils::ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr _langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) -{ - XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - XMP_Assert ( (*arrayName != 0) && (*_langName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. - ExpandXPath ( schemaNS, arrayName, &expPath ); - - XMP_VarString langName ( _langName ); - NormalizeLangValue ( &langName ); - - XMP_StringLen reserveLen = strlen(arrayName) + langName.size() + 14; - - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = arrayName; - *sComposedPath += "[?xml:lang=\""; - *sComposedPath += langName; - *sComposedPath += "\"]"; - - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); - -} // ComposeLangSelector - - -// ------------------------------------------------------------------------------------------------- -// ComposeFieldSelector -// -------------------- -// -// Return "arrayName[ns:fieldName="fieldValue"]". - -// *** #error "handle quotes in the value" - -/* class static */ void -XMPUtils::ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) -{ - XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) && (fieldValue != 0) ); // Enforced by wrapper. - XMP_Assert ( (*arrayName != 0) && (*fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. - - XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. - ExpandXPath ( schemaNS, arrayName, &expPath ); - - XMP_ExpandedXPath fieldPath; - ExpandXPath ( fieldNS, fieldName, &fieldPath ); - if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath ); - - XMP_StringLen reserveLen = strlen(arrayName) + fieldPath[kRootPropStep].step.size() + strlen(fieldValue) + 5; - - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = arrayName; - *sComposedPath += '['; - *sComposedPath += fieldPath[kRootPropStep].step; - *sComposedPath += "=\""; - *sComposedPath += fieldValue; - *sComposedPath += "\"]"; - - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); - -} // ComposeFieldSelector - - -// ------------------------------------------------------------------------------------------------- -// ConvertFromBool -// --------------- - -/* class static */ void -XMPUtils::ConvertFromBool ( bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) -{ - XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. - - if ( binValue ) { - *strValue = kXMP_TrueStr; - *strSize = strlen ( kXMP_TrueStr ); - } else { - *strValue = kXMP_FalseStr; - *strSize = strlen ( kXMP_FalseStr ); - } - -} // ConvertFromBool - - -// ------------------------------------------------------------------------------------------------- -// ConvertFromInt -// -------------- - -/* class static */ void -XMPUtils::ConvertFromInt ( XMP_Int32 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) -{ - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. - - if ( *format == 0 ) format = "%d"; - - sConvertedValue->erase(); - sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 100, ' ' ); - - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); - - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. - -} // ConvertFromInt - - -// ------------------------------------------------------------------------------------------------- -// ConvertFromInt64 -// ---------------- - -/* class static */ void -XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) -{ - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. - - if ( *format == 0 ) format = "%lld"; - - sConvertedValue->erase(); - sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 100, ' ' ); - - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); - - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. - -} // ConvertFromInt64 - - -// ------------------------------------------------------------------------------------------------- -// ConvertFromFloat -// ---------------- - -/* class static */ void -XMPUtils::ConvertFromFloat ( double binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) -{ - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. - - if ( *format == 0 ) format = "%f"; - - sConvertedValue->erase(); - sConvertedValue->reserve ( 1000 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 1000, ' ' ); - - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); - - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. - -} // ConvertFromFloat - - -// ------------------------------------------------------------------------------------------------- -// ConvertFromDate -// --------------- -// -// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: -// YYYY -// YYYY-MM -// YYYY-MM-DD -// YYYY-MM-DDThh:mmTZD -// YYYY-MM-DDThh:mm:ssTZD -// YYYY-MM-DDThh:mm:ss.sTZD -// -// YYYY = four-digit year -// MM = two-digit month (01=January, etc.) -// DD = two-digit day of month (01 through 31) -// hh = two digits of hour (00 through 23) -// mm = two digits of minute (00 through 59) -// ss = two digits of second (00 through 59) -// s = one or more digits representing a decimal fraction of a second -// TZD = time zone designator (Z or +hh:mm or -hh:mm) -// -// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow -// any year, even negative ones. The year is formatted as "%.4d". - -// *** Need to check backward compatibility for partial forms! - -/* class static */ void -XMPUtils::ConvertFromDate ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) -{ - XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. - - bool addTimeZone = false; - char buffer [100]; // Plenty long enough. - - // Pick the format, use snprintf to format into a local buffer, assign to static output string. - // Don't use AdjustTimeOverflow at the start, that will wipe out zero month or day values. - - // ! Photoshop 8 creates "time only" values with zeros for year, month, and day. - - XMP_DateTime tempDate = binValue; - - // Temporary fix for bug 1269463, silently fix out of range month or day. - - bool haveDay = (tempDate.day != 0); - bool haveTime = ( (tempDate.hour != 0) || (tempDate.minute != 0) || - (tempDate.second != 0) || (tempDate.nanoSecond != 0) || - (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ); - - if ( tempDate.month == 0 ) { - if ( haveDay || haveTime ) tempDate.month = 1; - } else { - if ( tempDate.month < 1 ) tempDate.month = 1; - if ( tempDate.month > 12 ) tempDate.month = 12; - } - - if ( tempDate.day == 0 ) { - if ( haveTime ) tempDate.day = 1; - } else { - if ( tempDate.day < 1 ) tempDate.day = 1; - if ( tempDate.day > 31 ) tempDate.day = 31; - } - - // Now carry on with the original logic. - - if ( tempDate.month == 0 ) { - - // Output YYYY if all else is zero, otherwise output a full string for the quasi-bogus - // "time only" values from Photoshop CS. - if ( (tempDate.day == 0) && (tempDate.hour == 0) && (tempDate.minute == 0) && - (tempDate.second == 0) && (tempDate.nanoSecond == 0) && - (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) { - snprintf ( buffer, sizeof(buffer), "%.4d", static_cast(tempDate.year) ); // AUDIT: Using sizeof for snprintf length is safe. - } else if ( (tempDate.year == 0) && (tempDate.day == 0) ) { - FormatFullDateTime ( tempDate, buffer, sizeof(buffer) ); - addTimeZone = true; - } else { - XMP_Throw ( "Invalid partial date", kXMPErr_BadParam); - } - - } else if ( tempDate.day == 0 ) { - - // Output YYYY-MM. - if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); - if ( (tempDate.hour != 0) || (tempDate.minute != 0) || - (tempDate.second != 0) || (tempDate.nanoSecond != 0) || - (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ) { - XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam); - } - snprintf ( buffer, sizeof(buffer), "%.4d-%02d", static_cast(tempDate.year), static_cast(tempDate.month) ); // AUDIT: Using sizeof for snprintf length is safe. - - } else if ( (tempDate.hour == 0) && (tempDate.minute == 0) && - (tempDate.second == 0) && (tempDate.nanoSecond == 0) && - (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) { - - // Output YYYY-MM-DD. - if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); - if ( (tempDate.day < 1) || (tempDate.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam); - snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", static_cast(tempDate.year), static_cast(tempDate.month), static_cast(tempDate.day) ); // AUDIT: Using sizeof for snprintf length is safe. - - } else { - - FormatFullDateTime ( tempDate, buffer, sizeof(buffer) ); - addTimeZone = true; - - } - - sConvertedValue->assign ( buffer ); - - if ( addTimeZone ) { - - if ( (tempDate.tzHour < 0) || (tempDate.tzHour > 23) || - (tempDate.tzMinute < 0 ) || (tempDate.tzMinute > 59) || - (tempDate.tzSign < -1) || (tempDate.tzSign > +1) || - ((tempDate.tzSign != 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0)) || - ((tempDate.tzSign == 0) && ((tempDate.tzHour != 0) || (tempDate.tzMinute != 0))) ) { - XMP_Throw ( "Invalid time zone values", kXMPErr_BadParam ); - } - - if ( tempDate.tzSign == 0 ) { - *sConvertedValue += 'Z'; - } else { - snprintf ( buffer, sizeof(buffer), "+%02d:%02d", static_cast(tempDate.tzHour), static_cast(tempDate.tzMinute) ); // AUDIT: Using sizeof for snprintf length is safe. - if ( tempDate.tzSign < 0 ) buffer[0] = '-'; - *sConvertedValue += buffer; - } - - } - - *strValue = sConvertedValue->c_str(); - *strSize = sConvertedValue->size(); - -} // ConvertFromDate - - -// ------------------------------------------------------------------------------------------------- -// ConvertToBool -// ------------- -// -// Formally the string value should be "True" or "False", but we should be more flexible here. Map -// the string to lower case. Allow any of "true", "false", "t", "f", "1", or "0". - -/* class static */ bool -XMPUtils::ConvertToBool ( XMP_StringPtr strValue ) -{ - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue ); - - bool result = false; - XMP_VarString strObj ( strValue ); - - for ( XMP_VarStringPos ch = strObj.begin(); ch != strObj.end(); ++ch ) { - if ( ('A' <= *ch) && (*ch <= 'Z') ) *ch += 0x20; - } - - if ( (strObj == "true") || (strObj == "t") || (strObj == "1") ) { - result = true; - } else if ( (strObj == "false") || (strObj == "f") || (strObj == "0") ) { - result = false; - } else { - XMP_Throw ( "Invalid Boolean string", kXMPErr_BadParam ); - } - - return result; - -} // ConvertToBool - - -// ------------------------------------------------------------------------------------------------- -// ConvertToInt -// ------------ - -/* class static */ XMP_Int32 -XMPUtils::ConvertToInt ( XMP_StringPtr strValue ) -{ - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue ); - - int count; - char nextCh; - XMP_Int32 result; - - if ( ! XMP_LitNMatch ( strValue, "0x", 2 ) ) { - count = sscanf ( strValue, "%d%c", (int*)&result, &nextCh ); - } else { - count = sscanf ( strValue, "%x%c", (unsigned int*)&result, &nextCh ); - } - - if ( count != 1 ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam ); - - return result; - -} // ConvertToInt - - -// ------------------------------------------------------------------------------------------------- -// ConvertToInt64 -// -------------- - -/* class static */ XMP_Int64 -XMPUtils::ConvertToInt64 ( XMP_StringPtr strValue ) -{ -#if defined(__MINGW32__)// || defined(__MINGW64__) - return ConvertToInt(strValue); -#else - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue ); - - int count; - char nextCh; - XMP_Int64 result; - - if ( ! XMP_LitNMatch ( strValue, "0x", 2 ) ) { - count = sscanf ( strValue, "%lld%c", &result, &nextCh ); - } else { - count = sscanf ( strValue, "%llx%c", &result, &nextCh ); - } - - if ( count != 1 ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam ); - - return result; -#endif -} // ConvertToInt64 - - -// ------------------------------------------------------------------------------------------------- -// ConvertToFloat -// -------------- - -/* class static */ double -XMPUtils::ConvertToFloat ( XMP_StringPtr strValue ) -{ - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue ); - - XMP_VarString oldLocale; // Try to make sure number conversion uses '.' as the decimal point. - XMP_StringPtr oldLocalePtr = setlocale ( LC_ALL, 0 ); - if ( oldLocalePtr != 0 ) { - oldLocale.assign ( oldLocalePtr ); - setlocale ( LC_ALL, "C" ); - } - - errno = 0; - char * numEnd; - double result = strtod ( strValue, &numEnd ); - - if ( oldLocalePtr != 0 ) setlocale ( LC_ALL, oldLocalePtr ); // ! Reset locale before possible throw! - if ( (errno != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid float string", kXMPErr_BadParam ); - - return result; - -} // ConvertToFloat - - -// ------------------------------------------------------------------------------------------------- -// ConvertToDate -// ------------- -// -// Parse a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: -// YYYY -// YYYY-MM -// YYYY-MM-DD -// YYYY-MM-DDThh:mmTZD -// YYYY-MM-DDThh:mm:ssTZD -// YYYY-MM-DDThh:mm:ss.sTZD -// -// YYYY = four-digit year -// MM = two-digit month (01=January, etc.) -// DD = two-digit day of month (01 through 31) -// hh = two digits of hour (00 through 23) -// mm = two digits of minute (00 through 59) -// ss = two digits of second (00 through 59) -// s = one or more digits representing a decimal fraction of a second -// TZD = time zone designator (Z or +hh:mm or -hh:mm) -// -// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow -// any year, even negative ones. The year is formatted as "%.4d". - -// ! Tolerate missing TZD, assume the time is in local time -// ! Tolerate missing date portion, in case someone foolishly writes a time-only value that way. - -// *** Put the ISO format comments in the header documentation. - -/* class static */ void -XMPUtils::ConvertToDate ( XMP_StringPtr strValue, - XMP_DateTime * binValue ) -{ - if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue); - - size_t pos = 0; - XMP_Int32 temp; - - XMP_Assert ( sizeof(*binValue) == sizeof(XMP_DateTime) ); - (void) memset ( binValue, 0, sizeof(*binValue) ); // AUDIT: Safe, using sizeof destination. - - bool timeOnly = ( (strValue[0] == 'T') || - ((strlen(strValue) >= 2) && (strValue[1] == ':')) || - ((strlen(strValue) >= 3) && (strValue[2] == ':')) ); - - if ( ! timeOnly ) { - - if ( strValue[0] == '-' ) pos = 1; - - temp = GatherInt ( strValue, &pos, "Invalid year in date string" ); // Extract the year. - if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after year", kXMPErr_BadParam ); - if ( strValue[0] == '-' ) temp = -temp; - binValue->year = temp; - if ( strValue[pos] == 0 ) return; - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid month in date string" ); // Extract the month. - if ( (temp < 1) || (temp > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam ); - if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after month", kXMPErr_BadParam ); - binValue->month = temp; - if ( strValue[pos] == 0 ) return; - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid day in date string" ); // Extract the day. - if ( (temp < 1) || (temp > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam ); - if ( (strValue[pos] != 0) && (strValue[pos] != 'T') ) XMP_Throw ( "Invalid date string, after day", kXMPErr_BadParam ); - binValue->day = temp; - if ( strValue[pos] == 0 ) return; - - // Allow year, month, and day to all be zero; implies the date portion is missing. - if ( (binValue->year != 0) || (binValue->month != 0) || (binValue->day != 0) ) { - // Temporary fix for bug 1269463, silently fix out of range month or day. - // if ( (binValue->month < 1) || (binValue->month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam ); - // if ( (binValue->day < 1) || (binValue->day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam ); - if ( binValue->month < 1 ) binValue->month = 1; - if ( binValue->month > 12 ) binValue->month = 12; - if ( binValue->day < 1 ) binValue->day = 1; - if ( binValue->day > 31 ) binValue->day = 31; - } - - } - - if ( strValue[pos] == 'T' ) { - ++pos; - } else if ( ! timeOnly ) { - XMP_Throw ( "Invalid date string, missing 'T' after date", kXMPErr_BadParam ); - } - - temp = GatherInt ( strValue, &pos, "Invalid hour in date string" ); // Extract the hour. - if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after hour", kXMPErr_BadParam ); - if ( temp < 0 || temp > 23 ) temp = 23; // *** 1269463: XMP_Throw ( "Hour is out of range", kXMPErr_BadParam ); - binValue->hour = temp; - // Don't check for done, we have to work up to the time zone. - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid minute in date string" ); // And the minute. - if ( (strValue[pos] != ':') && (strValue[pos] != 'Z') && - (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) XMP_Throw ( "Invalid date string, after minute", kXMPErr_BadParam ); - if ( temp < 0 || temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Minute is out of range", kXMPErr_BadParam ); - binValue->minute = temp; - // Don't check for done, we have to work up to the time zone. - - if ( strValue[pos] == ':' ) { - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid whole seconds in date string" ); // Extract the whole seconds. - if ( (strValue[pos] != '.') && (strValue[pos] != 'Z') && - (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) { - XMP_Throw ( "Invalid date string, after whole seconds", kXMPErr_BadParam ); - } - if ( temp < 0 || temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Whole second is out of range", kXMPErr_BadParam ); - binValue->second = temp; - // Don't check for done, we have to work up to the time zone. - - if ( strValue[pos] == '.' ) { - - ++pos; - size_t digits = pos; // Will be the number of digits later. - - temp = GatherInt ( strValue, &pos, "Invalid fractional seconds in date string" ); // Extract the fractional seconds. - if ( (strValue[pos] != 'Z') && (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) { - XMP_Throw ( "Invalid date string, after fractional second", kXMPErr_BadParam ); - } - - digits = pos - digits; - for ( ; digits > 9; --digits ) temp = temp / 10; - for ( ; digits < 9; ++digits ) temp = temp * 10; - - if ( temp < 0 || temp >= 1000*1000*1000 ) XMP_Throw ( "Fractional second is out of range", kXMPErr_BadParam ); - binValue->nanoSecond = temp; - // Don't check for done, we have to work up to the time zone. - - } - - } - - if ( strValue[pos] == 'Z' ) { - - ++pos; - - } else if ( strValue[pos] != 0 ) { - - if ( strValue[pos] == '+' ) { - binValue->tzSign = kXMP_TimeEastOfUTC; - } else if ( strValue[pos] == '-' ) { - binValue->tzSign = kXMP_TimeWestOfUTC; - } else { - XMP_Throw ( "Time zone must begin with 'Z', '+', or '-'", kXMPErr_BadParam ); - } - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid time zone hour in date string" ); // Extract the time zone hour. - if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after time zone hour", kXMPErr_BadParam ); - if ( temp < 0 || temp > 23 ) XMP_Throw ( "Time zone hour is out of range", kXMPErr_BadParam ); - binValue->tzHour = temp; - - ++pos; - temp = GatherInt ( strValue, &pos, "Invalid time zone minute in date string" ); // Extract the time zone minute. - if ( temp < 0 || temp > 59 ) XMP_Throw ( "Time zone minute is out of range", kXMPErr_BadParam ); - binValue->tzMinute = temp; - - } else { - - XMPUtils::SetTimeZone( binValue ); - - } - - if ( strValue[pos] != 0 ) XMP_Throw ( "Invalid date string, extra chars at end", kXMPErr_BadParam ); - -} // ConvertToDate - - -// ------------------------------------------------------------------------------------------------- -// EncodeToBase64 -// -------------- -// -// Encode a string of raw data bytes in base 64 according to RFC 2045. For the encoding definition -// see section 6.8 in . Although it isn't needed for RDF, we -// do insert a linefeed character as a newline for every 76 characters of encoded output. - -/* class static */ void -XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen ) -{ - if ( (rawStr == 0) && (rawLen != 0) ) XMP_Throw ( "Null raw data buffer", kXMPErr_BadParam ); - if ( rawLen == 0 ) { - *encodedStr = 0; - *encodedLen = 0; - return; - } - - char encChunk[4]; - - unsigned long in, out; - unsigned char c1, c2, c3; - unsigned long merge; - - const size_t outputSize = (rawLen / 3) * 4; // Approximate, might be small. - - sBase64Str->erase(); - sBase64Str->reserve ( outputSize ); - - // ---------------------------------------------------------------------------------------- - // Each 6 bits of input produces 8 bits of output, so 3 input bytes become 4 output bytes. - // Process the whole chunks of 3 bytes first, then deal with any remainder. Be careful with - // the loop comparison, size-2 could be negative! - - for ( in = 0, out = 0; (in+2) < rawLen; in += 3, out += 4 ) { - - c1 = rawStr[in]; - c2 = rawStr[in+1]; - c3 = rawStr[in+2]; - - merge = (c1 << 16) + (c2 << 8) + c3; - - encChunk[0] = sBase64Chars [ merge >> 18 ]; - encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ]; - encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ]; - encChunk[3] = sBase64Chars [ merge & 0x3F ]; - - if ( out >= 76 ) { - sBase64Str->append ( 1, kLF ); - out = 0; - } - sBase64Str->append ( encChunk, 4 ); - - } - - // ------------------------------------------------------------------------------------------ - // The output must always be a multiple of 4 bytes. If there is a 1 or 2 byte input remainder - // we need to create another chunk. Zero pad with bits to a 6 bit multiple, then add one or - // two '=' characters to pad out to 4 bytes. - - switch ( rawLen - in ) { - - case 0: // Done, no remainder. - break; - - case 1: // One input byte remains. - - c1 = rawStr[in]; - merge = c1 << 16; - - encChunk[0] = sBase64Chars [ merge >> 18 ]; - encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ]; - encChunk[2] = encChunk[3] = '='; - - if ( out >= 76 ) sBase64Str->append ( 1, kLF ); - sBase64Str->append ( encChunk, 4 ); - break; - - case 2: // Two input bytes remain. - - c1 = rawStr[in]; - c2 = rawStr[in+1]; - merge = (c1 << 16) + (c2 << 8); - - encChunk[0] = sBase64Chars [ merge >> 18 ]; - encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ]; - encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ]; - encChunk[3] = '='; - - if ( out >= 76 ) sBase64Str->append ( 1, kLF ); - sBase64Str->append ( encChunk, 4 ); - break; - - } - - // ------------------------- - // Assign the output values. - - *encodedStr = sBase64Str->c_str(); - *encodedLen = sBase64Str->size(); - -} // EncodeToBase64 - - -// ------------------------------------------------------------------------------------------------- -// DecodeFromBase64 -// ---------------- -// -// Decode a string of raw data bytes from base 64 according to RFC 2045. For the encoding definition -// see section 6.8 in . RFC 2045 talks about ignoring all "bad" -// input but warning about non-whitespace. For XMP use we ignore space, tab, LF, and CR. Any other -// bad input is rejected. - -/* class static */ void -XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen ) -{ - if ( (encodedStr == 0) && (encodedLen != 0) ) XMP_Throw ( "Null encoded data buffer", kXMPErr_BadParam ); - if ( encodedLen == 0 ) { - *rawStr = 0; - *rawLen = 0; - return; - } - - unsigned char ch, rawChunk[3]; - unsigned long inStr, inChunk, inLimit, merge, padding; - - XMP_StringLen outputSize = (encodedLen / 4) * 3; // Only a close approximation. - - sBase64Str->erase(); - sBase64Str->reserve ( outputSize ); - - - // ---------------------------------------------------------------------------------------- - // Each 8 bits of input produces 6 bits of output, so 4 input bytes become 3 output bytes. - // Process all but the last 4 data bytes first, then deal with the final chunk. Whitespace - // in the input must be ignored. The first loop finds where the last 4 data bytes start and - // counts the number of padding equal signs. - - padding = 0; - for ( inStr = 0, inLimit = encodedLen; (inStr < 4) && (inLimit > 0); ) { - inLimit -= 1; // ! Don't do in the loop control, the decr/test order is wrong. - ch = encodedStr[inLimit]; - if ( ch == '=' ) { - padding += 1; // The equal sign padding is a data byte. - } else if ( DecodeBase64Char(ch) == 0xFF ) { - continue; // Ignore whitespace, don't increment inStr. - } else { - inStr += 1; - } - } - - // ! Be careful to count whitespace that is immediately before the final data. Otherwise - // ! middle portion will absorb the final data and mess up the final chunk processing. - - while ( (inLimit > 0) && (DecodeBase64Char(encodedStr[inLimit-1]) == 0xFF) ) --inLimit; - - if ( inStr == 0 ) return; // Nothing but whitespace. - if ( padding > 2 ) XMP_Throw ( "Invalid encoded string", kXMPErr_BadParam ); - - // ------------------------------------------------------------------------------------------- - // Now process all but the last chunk. The limit ensures that we have at least 4 data bytes - // left when entering the output loop, so the inner loop will succeed without overrunning the - // end of the data. At the end of the outer loop we might be past inLimit though. - - inStr = 0; - while ( inStr < inLimit ) { - - merge = 0; - for ( inChunk = 0; inChunk < 4; ++inStr ) { // ! Yes, increment inStr on each pass. - ch = DecodeBase64Char ( encodedStr [inStr] ); - if ( ch == 0xFF ) continue; // Ignore whitespace. - merge = (merge << 6) + ch; - inChunk += 1; - } - - rawChunk[0] = (unsigned char) (merge >> 16); - rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF); - rawChunk[2] = (unsigned char) (merge & 0xFF); - - sBase64Str->append ( (char*)rawChunk, 3 ); - - } - - // ------------------------------------------------------------------------------------------- - // Process the final, possibly partial, chunk of data. The input is always a multiple 4 bytes, - // but the raw data can be any length. The number of padding '=' characters determines if the - // final chunk has 1, 2, or 3 raw data bytes. - - XMP_Assert ( inStr < encodedLen ); - - merge = 0; - for ( inChunk = 0; inChunk < 4-padding; ++inStr ) { // ! Yes, increment inStr on each pass. - ch = DecodeBase64Char ( encodedStr[inStr] ); - if ( ch == 0xFF ) continue; // Ignore whitespace. - merge = (merge << 6) + ch; - inChunk += 1; - } - - if ( padding == 2 ) { - - rawChunk[0] = (unsigned char) (merge >> 4); - sBase64Str->append ( (char*)rawChunk, 1 ); - - } else if ( padding == 1 ) { - - rawChunk[0] = (unsigned char) (merge >> 10); - rawChunk[1] = (unsigned char) ((merge >> 2) & 0xFF); - sBase64Str->append ( (char*)rawChunk, 2 ); - - } else { - - rawChunk[0] = (unsigned char) (merge >> 16); - rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF); - rawChunk[2] = (unsigned char) (merge & 0xFF); - sBase64Str->append ( (char*)rawChunk, 3 ); - - } - - // ------------------------- - // Assign the output values. - - *rawStr = sBase64Str->c_str(); - *rawLen = sBase64Str->size(); - -} // DecodeFromBase64 - - -// ------------------------------------------------------------------------------------------------- -// PackageForJPEG -// -------------- - -/* class static */ void -XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen ) -{ - enum { kStdXMPLimit = 65000 }; - static const char * kPacketTrailer = ""; - static size_t kTrailerLen = strlen ( kPacketTrailer ); - - XMP_StringPtr tempStr; - XMP_StringLen tempLen; - - XMPMeta stdXMP, extXMP; - - sStandardXMP->clear(); // Clear the static strings that get returned to the client. - sExtendedXMP->clear(); - sExtendedDigest->clear(); - - XMP_OptionBits keepItSmall = kXMP_UseCompactFormat | kXMP_OmitAllFormatting; - - // Try to serialize everything. Note that we're making internal calls to SerializeToBuffer, so - // we'll be getting back the pointer and length for its internal string. - - origXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - #if Trace_PackageForJPEG - printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempLen ); - #endif - - if ( tempLen > kStdXMPLimit ) { - - // Couldn't fit everything, make a copy of the input XMP and make sure there is no xmp:Thumbnails property. - - stdXMP.tree.options = origXMP.tree.options; - stdXMP.tree.name = origXMP.tree.name; - stdXMP.tree.value = origXMP.tree.value; - CloneOffspring ( &origXMP.tree, &stdXMP.tree ); - - if ( stdXMP.DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) { - stdXMP.DeleteProperty ( kXMP_NS_XMP, "Thumbnails" ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - #if Trace_PackageForJPEG - printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempLen ); - #endif - } - - } - - if ( tempLen > kStdXMPLimit ) { - - // Still doesn't fit, move all of the Camera Raw namespace. Add a dummy value for xmpNote:HasExtendedXMP. - - stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", "123456789-123456789-123456789-12", 0 ); - - XMP_NodePtrPos crSchemaPos; - XMP_Node * crSchema = FindSchemaNode ( &stdXMP.tree, kXMP_NS_CameraRaw, kXMP_ExistingOnly, &crSchemaPos ); - - if ( crSchema != 0 ) { - crSchema->parent = &extXMP.tree; - extXMP.tree.children.push_back ( crSchema ); - stdXMP.tree.children.erase ( crSchemaPos ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - #if Trace_PackageForJPEG - printf ( " Move Camera Raw schema, %d bytes left\n", tempLen ); - #endif - } - - } - - if ( tempLen > kStdXMPLimit ) { - - // Still doesn't fit, move photoshop:History. - - bool moved = MoveOneProperty ( stdXMP, &extXMP, kXMP_NS_Photoshop, "photoshop:History" ); - - if ( moved ) { - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - #if Trace_PackageForJPEG - printf ( " Move photoshop:History, %d bytes left\n", tempLen ); - #endif - } - - } - - if ( tempLen > kStdXMPLimit ) { - - // Still doesn't fit, move top level properties in order of estimated size. This is done by - // creating a multi-map that maps the serialized size to the string pair for the schema URI - // and top level property name. Since maps are inherently ordered, a reverse iteration of - // the map can be done to move the largest things first. We use a double loop to keep going - // until the serialization actually fits, in case the estimates are off. - - PropSizeMap propSizes; - CreateEstimatedSizeMap ( stdXMP, &propSizes ); - - #if Trace_PackageForJPEG - if ( ! propSizes.empty() ) { - printf ( " Top level property map, smallest to largest:\n" ); - PropSizeMap::iterator mapPos = propSizes.begin(); - PropSizeMap::iterator mapEnd = propSizes.end(); - for ( ; mapPos != mapEnd; ++mapPos ) { - size_t propSize = mapPos->first; - const char * schemaName = mapPos->second.first->c_str(); - const char * propName = mapPos->second.second->c_str(); - printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName ); - } - } - #endif - - #if 0 // Trace_PackageForJPEG *** Xcode 2.3 on 10.4.7 has bugs in backwards iteration - if ( ! propSizes.empty() ) { - printf ( " Top level property map, largest to smallest:\n" ); - PropSizeMap::iterator mapPos = propSizes.end(); - PropSizeMap::iterator mapBegin = propSizes.begin(); - for ( --mapPos; true; --mapPos ) { - size_t propSize = mapPos->first; - const char * schemaName = mapPos->second.first->c_str(); - const char * propName = mapPos->second.second->c_str(); - printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName ); - if ( mapPos == mapBegin ) break; - } - } - #endif - - // Outer loop to make sure enough is actually moved. - - while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) { - - // Inner loop, move what seems to be enough according to the estimates. - - while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) { - - size_t propSize = MoveLargestProperty ( stdXMP, &extXMP, propSizes ); - XMP_Assert ( propSize > 0 ); - - if ( propSize > tempLen ) propSize = tempLen; // ! Don't go negative. - tempLen -= propSize; - - } - - // Reserialize the remaining standard XMP. - - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - - } - - } - - if ( tempLen > kStdXMPLimit ) { - // Still doesn't fit, throw an exception and let the client decide what to do. - // ! This should never happen with the policy of moving any and all top level properties. - XMP_Throw ( "Can't reduce XMP enough for JPEG file", kXMPErr_TooLargeForJPEG ); - } - - // Set the static output strings. - - if ( extXMP.tree.children.empty() ) { - - // Just have the standard XMP. - sStandardXMP->assign ( tempStr, tempLen ); - - } else { - - // Have extended XMP. Serialize it, compute the digest, reset xmpNote:HasExtendedXMP, and - // reserialize the standard XMP. - - extXMP.SerializeToBuffer ( &tempStr, &tempLen, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 ); - sExtendedXMP->assign ( tempStr, tempLen ); - - MD5_CTX context; - XMP_Uns8 digest [16]; - MD5Init ( &context ); - MD5Update ( &context, (XMP_Uns8*)tempStr, tempLen ); - MD5Final ( digest, &context ); - - sExtendedDigest->reserve ( 32 ); - for ( size_t i = 0; i < 16; ++i ) { - XMP_Uns8 byte = digest[i]; - sExtendedDigest->push_back ( kHexDigits [ byte>>4 ] ); - sExtendedDigest->push_back ( kHexDigits [ byte&0xF ] ); - } - - stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", sExtendedDigest->c_str(), 0 ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - sStandardXMP->assign ( tempStr, tempLen ); - - } - - // Adjust the standard XMP padding to be up to 2KB. - - XMP_Assert ( (sStandardXMP->size() > kTrailerLen) && (sStandardXMP->size() <= kStdXMPLimit) ); - const char * packetEnd = 0; - packetEnd = sStandardXMP->c_str() + sStandardXMP->size() - kTrailerLen; - XMP_Assert ( XMP_LitMatch ( packetEnd, kPacketTrailer ) ); - UNUSED(packetEnd); - - size_t extraPadding = kStdXMPLimit - sStandardXMP->size(); // ! Do this before erasing the trailer. - if ( extraPadding > 2047 ) extraPadding = 2047; - sStandardXMP->erase ( sStandardXMP->size() - kTrailerLen ); - sStandardXMP->append ( extraPadding, ' ' ); - sStandardXMP->append ( kPacketTrailer ); - - // Assign the output pointer and sizes. - - *stdStr = sStandardXMP->c_str(); - *stdLen = sStandardXMP->size(); - *extStr = sExtendedXMP->c_str(); - *extLen = sExtendedXMP->size(); - *digestStr = sExtendedDigest->c_str(); - *digestLen = sExtendedDigest->size(); - -} // PackageForJPEG - - -// ------------------------------------------------------------------------------------------------- -// MergeFromJPEG -// ------------- -// -// Copy all of the top level properties from extendedXMP to fullXMP, replacing any duplicates. -// Delete the xmpNote:HasExtendedXMP property from fullXMP. - -/* class static */ void -XMPUtils::MergeFromJPEG ( XMPMeta * fullXMP, - const XMPMeta & extendedXMP ) -{ - - XMPUtils::AppendProperties ( extendedXMP, fullXMP, kXMPUtil_DoAllProperties ); - fullXMP->DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" ); - -} // MergeFromJPEG - - -// ------------------------------------------------------------------------------------------------- -// CurrentDateTime -// --------------- - -/* class static */ void -XMPUtils::CurrentDateTime ( XMP_DateTime * xmpTime ) -{ - XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper. - - ansi_tt binTime = ansi_time(0); - if ( binTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure ); - ansi_tm currTime; - ansi_localtime ( &binTime, &currTime ); - - xmpTime->year = currTime.tm_year + 1900; - xmpTime->month = currTime.tm_mon + 1; - xmpTime->day = currTime.tm_mday; - xmpTime->hour = currTime.tm_hour; - xmpTime->minute = currTime.tm_min; - xmpTime->second = currTime.tm_sec; - - xmpTime->nanoSecond = 0; - xmpTime->tzSign = 0; - xmpTime->tzHour = 0; - xmpTime->tzMinute = 0; - - XMPUtils::SetTimeZone ( xmpTime ); - -} // CurrentDateTime - - -// ------------------------------------------------------------------------------------------------- -// SetTimeZone -// ----------- -// -// Sets just the time zone part of the time. Useful for determining the local time zone or for -// converting a "zone-less" time to a proper local time. The ANSI C time functions are smart enough -// to do all the right stuff, as long as we call them properly! - -/* class static */ void -XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime ) -{ - XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper. - - if ( (xmpTime->tzSign != 0) || (xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0) ) { - XMP_Throw ( "SetTimeZone can only be used on \"zoneless\" times", kXMPErr_BadParam ); - } - - // Create ansi_tt form of the input time. Need the ansi_tm form to make the ansi_tt form. - - ansi_tt ttTime; - ansi_tm tmLocal, tmUTC; - - if ( (xmpTime->year == 0) && (xmpTime->month == 0) && (xmpTime->day == 0) ) { - ansi_tt now = ansi_time(0); - if ( now == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure ); - ansi_localtime ( &now, &tmLocal ); - } else { - if (xmpTime->year < std::numeric_limits::min() + 1900) { - XMP_Throw ( "Invalid year", kXMPErr_BadParam); - } else if (xmpTime->year > std::numeric_limits::max()) { - XMP_Throw ( "Invalid year", kXMPErr_BadParam); - } else { - tmLocal.tm_year = xmpTime->year - 1900; - } - tmLocal.tm_mon = xmpTime->month - 1; - tmLocal.tm_mday = xmpTime->day; - } - - tmLocal.tm_hour = xmpTime->hour; - tmLocal.tm_min = xmpTime->minute; - tmLocal.tm_sec = xmpTime->second; - tmLocal.tm_isdst = -1; // Don't know if daylight time is in effect. - - ttTime = ansi_mktime ( &tmLocal ); - if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure ); - - // Convert back to a localized ansi_tm time and get the corresponding UTC ansi_tm time. - - ansi_localtime ( &ttTime, &tmLocal ); - ansi_gmtime ( &ttTime, &tmUTC ); - - // Get the offset direction and amount. - - ansi_tm tmx = tmLocal; // ! Note that mktime updates the ansi_tm parameter, messing up difftime! - ansi_tm tmy = tmUTC; - tmx.tm_isdst = tmy.tm_isdst = 0; - ansi_tt ttx = ansi_mktime ( &tmx ); - ansi_tt tty = ansi_mktime ( &tmy ); - double diffSecs; - - if ( (ttx != -1) && (tty != -1) ) { - diffSecs = ansi_difftime ( ttx, tty ); - } else { - #if XMP_MacBuild - // Looks like Apple's mktime is buggy - see W1140533. But the offset is visible. - diffSecs = tmLocal.tm_gmtoff; - #else - // Win and UNIX don't have a visible offset. Make sure we know about the failure, - // then try using the current date/time as a close fallback. - ttTime = ansi_time(0); - if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure ); - ansi_localtime ( &ttTime, &tmx ); - ansi_gmtime ( &ttTime, &tmy ); - tmx.tm_isdst = tmy.tm_isdst = 0; - ttx = ansi_mktime ( &tmx ); - tty = ansi_mktime ( &tmy ); - if ( (ttx == -1) || (tty == -1) ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure ); - diffSecs = ansi_difftime ( ttx, tty ); - #endif - } - - if ( diffSecs > 0.0 ) { - xmpTime->tzSign = kXMP_TimeEastOfUTC; - } else if ( diffSecs == 0.0 ) { - xmpTime->tzSign = kXMP_TimeIsUTC; - } else { - xmpTime->tzSign = kXMP_TimeWestOfUTC; - diffSecs = -diffSecs; - } - xmpTime->tzHour = XMP_Int32 ( diffSecs / 3600.0 ); - xmpTime->tzMinute = XMP_Int32 ( (diffSecs / 60.0) - (xmpTime->tzHour * 60.0) ); - - // *** Save the tm_isdst flag in a qualifier? - - XMP_Assert ( (0 <= xmpTime->tzHour) && (xmpTime->tzHour <= 23) ); - XMP_Assert ( (0 <= xmpTime->tzMinute) && (xmpTime->tzMinute <= 59) ); - XMP_Assert ( (-1 <= xmpTime->tzSign) && (xmpTime->tzSign <= +1) ); - XMP_Assert ( (xmpTime->tzSign == 0) ? ((xmpTime->tzHour == 0) && (xmpTime->tzMinute == 0)) : - ((xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0)) ); - -} // SetTimeZone - - -// ------------------------------------------------------------------------------------------------- -// ConvertToUTCTime -// ---------------- - -/* class static */ void -XMPUtils::ConvertToUTCTime ( XMP_DateTime * time ) -{ - XMP_Assert ( time != 0 ); // ! Enforced by wrapper. - - XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) ); - XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) ); - XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) ); - XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) : - ((time->tzHour != 0) || (time->tzMinute != 0)) ); - - if ( time->tzSign == kXMP_TimeEastOfUTC ) { - // We are before (east of) GMT, subtract the offset from the time. - time->hour -= time->tzHour; - time->minute -= time->tzMinute; - } else if ( time->tzSign == kXMP_TimeWestOfUTC ) { - // We are behind (west of) GMT, add the offset to the time. - time->hour += time->tzHour; - time->minute += time->tzMinute; - } - - AdjustTimeOverflow ( time ); - time->tzSign = time->tzHour = time->tzMinute = 0; - -} // ConvertToUTCTime - - -// ------------------------------------------------------------------------------------------------- -// ConvertToLocalTime -// ------------------ - -/* class static */ void -XMPUtils::ConvertToLocalTime ( XMP_DateTime * time ) -{ - XMP_Assert ( time != 0 ); // ! Enforced by wrapper. - - XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) ); - XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) ); - XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) ); - XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) : - ((time->tzHour != 0) || (time->tzMinute != 0)) ); - - ConvertToUTCTime ( time ); // The existing time zone might not be the local one. - SetTimeZone ( time ); // Fill in the local timezone offset, then adjust the time. - - if ( time->tzSign > 0 ) { - // We are before (east of) GMT, add the offset to the time. - time->hour += time->tzHour; - time->minute += time->tzMinute; - } else if ( time->tzSign < 0 ) { - // We are behind (west of) GMT, subtract the offset from the time. - time->hour -= time->tzHour; - time->minute -= time->tzMinute; - } - - AdjustTimeOverflow ( time ); - -} // ConvertToLocalTime - - -// ------------------------------------------------------------------------------------------------- -// CompareDateTime -// --------------- - -/* class static */ int -XMPUtils::CompareDateTime ( const XMP_DateTime & _in_left, - const XMP_DateTime & _in_right ) -{ - int result; - - XMP_DateTime left = _in_left; - XMP_DateTime right = _in_right; - - ConvertToUTCTime ( &left ); - ConvertToUTCTime ( &right ); - - // *** We could use memcmp if the XMP_DateTime stuct has no holes. - - if ( left.year < right.year ) { - result = -1; - } else if ( left.year > right.year ) { - result = +1; - } else if ( left.month < right.month ) { - result = -1; - } else if ( left.month > right.month ) { - result = +1; - } else if ( left.day < right.day ) { - result = -1; - } else if ( left.day > right.day ) { - result = +1; - } else if ( left.hour < right.hour ) { - result = -1; - } else if ( left.hour > right.hour ) { - result = +1; - } else if ( left.minute < right.minute ) { - result = -1; - } else if ( left.minute > right.minute ) { - result = +1; - } else if ( left.second < right.second ) { - result = -1; - } else if ( left.second > right.second ) { - result = +1; - } else if ( left.nanoSecond < right.nanoSecond ) { - result = -1; - } else if ( left.nanoSecond > right.nanoSecond ) { - result = +1; - } else { - result = 0; - } - - return result; - -} // CompareDateTime - -// ================================================================================================= diff --git a/xmpsdk/src/XMPUtils.hpp b/xmpsdk/src/XMPUtils.hpp deleted file mode 100644 index e1c7e78d01..0000000000 --- a/xmpsdk/src/XMPUtils.hpp +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef __XMPUtils_hpp__ -#define __XMPUtils_hpp__ - -// ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= - -#include "XMP_Environment.h" -#include "XMP_Const.h" - -#include "XMPMeta.hpp" -#include "XMPCore_Impl.hpp" -#include "client-glue/WXMPUtils.hpp" - -// ------------------------------------------------------------------------------------------------- - -extern XMP_VarString * sComposedPath; // *** Only really need 1 string. Shrink periodically? -extern XMP_VarString * sConvertedValue; -extern XMP_VarString * sBase64Str; -extern XMP_VarString * sCatenatedItems; -extern XMP_VarString * sStandardXMP; -extern XMP_VarString * sExtendedXMP; -extern XMP_VarString * sExtendedDigest; - -// ------------------------------------------------------------------------------------------------- - -class XMPUtils { -public: - - static bool - Initialize(); // ! For internal use only! - - static void - Terminate() RELEASE_NO_THROW; // ! For internal use only! - - static void - Unlock ( XMP_OptionBits options ); - - // --------------------------------------------------------------------------------------------- - - static void - ComposeArrayItemPath ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); - - static void - ComposeStructFieldPath ( XMP_StringPtr schemaNS, - XMP_StringPtr structName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); - - static void - ComposeQualifierPath ( XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_StringPtr qualNS, - XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); - - static void - ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); - - static void - ComposeFieldSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr fieldNS, - XMP_StringPtr fieldName, - XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); - - // --------------------------------------------------------------------------------------------- - - static void - ConvertFromBool ( bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); - - static void - ConvertFromInt ( XMP_Int32 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); - - static void - ConvertFromInt64 ( XMP_Int64 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); - - static void - ConvertFromFloat ( double binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); - - static void - ConvertFromDate ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); - - // --------------------------------------------------------------------------------------------- - - static bool - ConvertToBool ( XMP_StringPtr strValue ); - - static XMP_Int32 - ConvertToInt ( XMP_StringPtr strValue ); - - static XMP_Int64 - ConvertToInt64 ( XMP_StringPtr strValue ); - - static double - ConvertToFloat ( XMP_StringPtr strValue ); - - static void - ConvertToDate ( XMP_StringPtr strValue, - XMP_DateTime * binValue ); - - // --------------------------------------------------------------------------------------------- - - static void - CurrentDateTime ( XMP_DateTime * time ); - - static void - SetTimeZone ( XMP_DateTime * time ); - - static void - ConvertToUTCTime ( XMP_DateTime * time ); - - static void - ConvertToLocalTime ( XMP_DateTime * time ); - - static int - CompareDateTime ( const XMP_DateTime & left, - const XMP_DateTime & right ); - // --------------------------------------------------------------------------------------------- - - static void - EncodeToBase64 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen ); - - static void - DecodeFromBase64 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen ); - - // --------------------------------------------------------------------------------------------- - - static void - PackageForJPEG ( const XMPMeta & xmpObj, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen ); - - static void - MergeFromJPEG ( XMPMeta * fullXMP, - const XMPMeta & extendedXMP ); - - // --------------------------------------------------------------------------------------------- - - static void - CatenateArrayItems ( const XMPMeta & xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen ); - - static void - SeparateArrayItems ( XMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_OptionBits options, - XMP_StringPtr catedStr ); - - static void - RemoveProperties ( XMPMeta * xmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_OptionBits options ); - - static void - AppendProperties ( const XMPMeta & source, - XMPMeta * dest, - XMP_OptionBits options ); - - static void - DuplicateSubtree ( const XMPMeta & source, - XMPMeta * dest, - XMP_StringPtr sourceNS, - XMP_StringPtr sourceRoot, - XMP_StringPtr destNS, - XMP_StringPtr destRoot, - XMP_OptionBits options ); - -}; // XMPUtils - -// ================================================================================================= - -#endif // __XMPUtils_hpp__ diff --git a/xmpsdk/src/XMP_BuildInfo.h b/xmpsdk/src/XMP_BuildInfo.h deleted file mode 100644 index 2b387c86fa..0000000000 --- a/xmpsdk/src/XMP_BuildInfo.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __XMP_BuildInfo_h__ -#define __XMP_BuildInfo_h__ 1 - -/* --------------------------------------------------------------------------------------------- */ -/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */ -/* --------------------------------------------------------------------------------------------- */ - -/* -// ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated -// All Rights Reserved. -// -// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms -// of the Adobe license agreement accompanying it. -// ================================================================================================= -*/ - -#define kXMP_Copyright Copyright (c) 2002-2008, Adobe Systems Incorporated -#define kXMP_CopyrightStr "Copyright (c) 2002-2008, Adobe Systems Incorporated" -#define kXMP_AdobeIPStr "" - -#endif /* __XMP_BuildInfo_h__ */ From 5aa17e3598c3acd02779edaa5b4e89d92434bc60 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Wed, 10 Jul 2024 12:20:41 +0400 Subject: [PATCH 03/20] adds a hacky workaround to work with MD5 implementation from XMP-Toolkit-sdk --- src/convert.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/convert.cpp b/src/convert.cpp index 0cd22f4f64..147ac88106 100644 --- a/src/convert.cpp +++ b/src/convert.cpp @@ -1257,7 +1257,7 @@ std::string Converter::computeExifDigest(bool tiff) { continue; DataBuf data(pos->size()); pos->copy(data.data(), littleEndian /* FIXME ? */); - MD5Update(&context, data.c_data(), static_cast(data.size())); + MD5Update(&context, const_cast(data.c_data()), static_cast(data.size())); } } MD5Final(digest, &context); From d9afb41f5dab63b314adb777b486fa283fed46a3 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Wed, 10 Jul 2024 13:14:31 +0400 Subject: [PATCH 04/20] adds submodules cloning for github actions --- .github/workflows/codeql-analysis.yml | 2 ++ .../workflows/nightly_Linux_distributions.yml | 2 ++ .github/workflows/on_PR_linux_fuzz.yml | 2 ++ .github/workflows/on_PR_linux_matrix.yml | 5 +++++ .../workflows/on_PR_linux_special_builds.yml | 10 +++++++++ .../workflows/on_PR_linux_staticAnalysis.yml | 2 ++ .github/workflows/on_PR_mac_matrix.yml | 2 ++ .../workflows/on_PR_mac_special_builds.yml | 2 ++ .github/workflows/on_PR_meson.yaml | 22 +++++++++++++++++++ .github/workflows/on_PR_windows_matrix.yml | 8 +++++++ .github/workflows/on_push_BasicWinLinMac.yml | 6 +++++ .../workflows/on_push_ExtraJobsForMain.yml | 2 ++ .github/workflows/on_push_clang_format.yml | 2 ++ .github/workflows/release.yml | 6 +++++ 14 files changed, 73 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3ea542e53c..8449891cbb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,6 +39,8 @@ jobs: uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/nightly_Linux_distributions.yml b/.github/workflows/nightly_Linux_distributions.yml index ec6b1026fc..764d6c3e76 100644 --- a/.github/workflows/nightly_Linux_distributions.yml +++ b/.github/workflows/nightly_Linux_distributions.yml @@ -36,6 +36,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: ./ci/install_dependencies.sh - name: Build and install diff --git a/.github/workflows/on_PR_linux_fuzz.yml b/.github/workflows/on_PR_linux_fuzz.yml index b6117d00ab..643ad0b9f7 100644 --- a/.github/workflows/on_PR_linux_fuzz.yml +++ b/.github/workflows/on_PR_linux_fuzz.yml @@ -28,6 +28,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | sudo ./ci/install_dependencies.sh diff --git a/.github/workflows/on_PR_linux_matrix.yml b/.github/workflows/on_PR_linux_matrix.yml index 74ab374a00..797f767ab7 100644 --- a/.github/workflows/on_PR_linux_matrix.yml +++ b/.github/workflows/on_PR_linux_matrix.yml @@ -24,6 +24,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -76,6 +78,9 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + shell: bash + run: git submodule update --init --depth=1 - uses: jirutka/setup-alpine@v1 with: arch: ${{matrix.arch}} diff --git a/.github/workflows/on_PR_linux_special_builds.yml b/.github/workflows/on_PR_linux_special_builds.yml index 006e5a7fea..a83c55b753 100644 --- a/.github/workflows/on_PR_linux_special_builds.yml +++ b/.github/workflows/on_PR_linux_special_builds.yml @@ -21,6 +21,8 @@ jobs: fetch-depth: 2 persist-credentials: false # Trying to deal with warning: -> Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0 + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -68,6 +70,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -106,6 +110,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -142,6 +148,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -166,6 +174,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_PR_linux_staticAnalysis.yml b/.github/workflows/on_PR_linux_staticAnalysis.yml index 0648b3ecbe..91b200b223 100644 --- a/.github/workflows/on_PR_linux_staticAnalysis.yml +++ b/.github/workflows/on_PR_linux_staticAnalysis.yml @@ -21,6 +21,8 @@ jobs: fetch-depth: 2 persist-credentials: false # Trying to deal with warning: -> Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0 + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_PR_mac_matrix.yml b/.github/workflows/on_PR_mac_matrix.yml index 5bb466a52e..4789352154 100644 --- a/.github/workflows/on_PR_mac_matrix.yml +++ b/.github/workflows/on_PR_mac_matrix.yml @@ -24,6 +24,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_PR_mac_special_builds.yml b/.github/workflows/on_PR_mac_special_builds.yml index 38b187c798..5c159a2292 100644 --- a/.github/workflows/on_PR_mac_special_builds.yml +++ b/.github/workflows/on_PR_mac_special_builds.yml @@ -19,6 +19,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_PR_meson.yaml b/.github/workflows/on_PR_meson.yaml index b59a06c657..9910fe88fe 100644 --- a/.github/workflows/on_PR_meson.yaml +++ b/.github/workflows/on_PR_meson.yaml @@ -18,6 +18,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - uses: egor-tensin/setup-gcc@v2 with: version: ${{matrix.cxx}} @@ -41,6 +43,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - uses: egor-tensin/setup-clang@v2 with: version: ${{matrix.cxx}} @@ -76,6 +80,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install packages run: | @@ -106,6 +112,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install packages run: | @@ -140,6 +148,9 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + shell: bash + run: git submodule update --init --depth=1 - uses: msys2/setup-msys2@v2 with: @@ -169,6 +180,9 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + shell: bash + run: git submodule update --init --depth=1 - uses: msys2/setup-msys2@v2 with: msystem: 'MSYS' @@ -193,6 +207,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install packages run: | @@ -210,6 +226,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - uses: vmactions/freebsd-vm@v1 with: prepare: | @@ -224,6 +242,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - uses: vmactions/omnios-vm@v1 with: prepare: | @@ -238,6 +258,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install packages run: | sudo apt install -y meson diff --git a/.github/workflows/on_PR_windows_matrix.yml b/.github/workflows/on_PR_windows_matrix.yml index 18c833df42..66489297d6 100644 --- a/.github/workflows/on_PR_windows_matrix.yml +++ b/.github/workflows/on_PR_windows_matrix.yml @@ -32,6 +32,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Set up Visual Studio shell uses: ilammy/msvc-dev-cmd@v1 @@ -99,6 +101,9 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + shell: bash + run: git submodule update --init --depth=1 - name: Set up MSYS2 uses: msys2/setup-msys2@v2 @@ -157,6 +162,9 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + shell: bash + run: git submodule update --init --depth=1 - name: Set up Cygwin uses: cygwin/cygwin-install-action@v6 diff --git a/.github/workflows/on_push_BasicWinLinMac.yml b/.github/workflows/on_push_BasicWinLinMac.yml index 211093d848..e4a28a7189 100644 --- a/.github/workflows/on_push_BasicWinLinMac.yml +++ b/.github/workflows/on_push_BasicWinLinMac.yml @@ -23,6 +23,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Set up Visual Studio shell uses: ilammy/msvc-dev-cmd@v1 @@ -61,6 +63,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -97,6 +101,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_push_ExtraJobsForMain.yml b/.github/workflows/on_push_ExtraJobsForMain.yml index 5e4f95eac7..4bec6d7b78 100644 --- a/.github/workflows/on_push_ExtraJobsForMain.yml +++ b/.github/workflows/on_push_ExtraJobsForMain.yml @@ -23,6 +23,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | diff --git a/.github/workflows/on_push_clang_format.yml b/.github/workflows/on_push_clang_format.yml index 9826571d18..0d0035dcc3 100644 --- a/.github/workflows/on_push_clang_format.yml +++ b/.github/workflows/on_push_clang_format.yml @@ -10,6 +10,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - uses: DoozyX/clang-format-lint-action@v0.20 with: source: '.' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3708d662c3..83f4de1487 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,6 +25,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -77,6 +79,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Install dependencies run: | @@ -122,6 +126,8 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + - name: Checkout submodules + run: git submodule update --init --depth=1 - name: Set up Visual Studio shell uses: ilammy/msvc-dev-cmd@v1 From 567ffc43015bb7c24a9f8efc55a8a3fa76c121a7 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 11 Jul 2024 19:33:42 +0400 Subject: [PATCH 05/20] fixes xmp encoding of multiple items with same lang for langAlt type properties --- src/xmp.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/xmp.cpp b/src/xmp.cpp index b923016759..51cdd965f1 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -851,13 +851,32 @@ int XmpParser::encode(std::string& xmpPacket, const XmpData& xmpData, uint16_t f if (!la) throw Error(ErrorCode::kerEncodeLangAltPropertyFailed, xmp.key()); - int idx = 1; for (const auto& [lang, specs] : la->value_) { if (!specs.empty()) { // remove lang specs with no value printNode(ns, xmp.tagName(), specs, 0); - meta.AppendArrayItem(ns.c_str(), xmp.tagName().c_str(), kXMP_PropArrayIsAlternate, specs.c_str()); - const std::string item = xmp.tagName() + "[" + toString(idx++) + "]"; - meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", lang.c_str()); + + // Check if there is already an item in the array with the given lang + std::size_t item_cnt = meta.CountArrayItems(ns.c_str(), xmp.tagName().c_str()); + std::size_t existing_item_idx = 0; // 0 means not found (XMP arrays are 1-indexed) + for (std::size_t i = 1; i <= item_cnt; ++i) { + std::string qualifier_value; + const std::string item = xmp.tagName() + "[" + toString(i) + "]"; + + if (meta.GetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", &qualifier_value, nullptr) && + qualifier_value == lang) { + existing_item_idx = i; + break; + } + } + + if (existing_item_idx) { + meta.SetArrayItem(ns.c_str(), xmp.tagName().c_str(), existing_item_idx, specs.c_str()); + } else { + meta.AppendArrayItem(ns.c_str(), xmp.tagName().c_str(), kXMP_PropArrayIsAlternate, specs.c_str()); + auto index = meta.CountArrayItems(ns.c_str(), xmp.tagName().c_str()); + const std::string item = xmp.tagName() + "[" + toString(index) + "]"; + meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", lang.c_str()); + } } } continue; From 8881da41e9f9c43dd6e4b1381218bcbc24bfde96 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 17:06:56 +0400 Subject: [PATCH 06/20] update meson build for XMP-Toolkit-SDK submodule Update xmpsdk/meson.build to use the new submodule source paths, add required platform-specific compile definitions (UNIX_ENV, MAC_ENV, WIN_ENV, BanAllEntityUsage, EXV_ADOBE_XMPSDK), and propagate xmp_args to the library build in src/meson.build. --- src/meson.build | 5 +- xmpsdk/meson.build | 137 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/meson.build b/src/meson.build index 6cfc2d7a5c..84463690a1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -88,12 +88,11 @@ exiv2int_dep = declare_dependency( exiv2 = library( 'exiv2', base_lib, - xmp_lib, - cpp_args: cargs, + cpp_args: [cargs, xmp_public_args], version: meson.project_version(), soversion: sover, gnu_symbol_visibility: 'hidden', - dependencies: [exiv2int_dep, brotli_dep, curl_dep, expat_dep, iconv_dep, net_dep], + dependencies: [exiv2int_dep, xmp_dep, brotli_dep, curl_dep, expat_dep, iconv_dep, net_dep], install: true, ) diff --git a/xmpsdk/meson.build b/xmpsdk/meson.build index e164bb8907..2424720ccf 100644 --- a/xmpsdk/meson.build +++ b/xmpsdk/meson.build @@ -1,24 +1,123 @@ if not expat_dep.found() - xmp_lib = files() + xmp_dep = disabler() + xmp_public_args = [] subdir_done() endif -libinc = [libinc, include_directories('include')] -xmp_lib = files( - 'src/ExpatAdapter.cpp', - 'src/MD5.cpp', - 'src/ParseRDF.cpp', - 'src/UnicodeConversions.cpp', - 'src/WXMPIterator.cpp', - 'src/WXMPMeta.cpp', - 'src/WXMPUtils.cpp', - 'src/XML_Node.cpp', - 'src/XMPCore_Impl.cpp', - 'src/XMPIterator.cpp', - 'src/XMPMeta-GetSet.cpp', - 'src/XMPMeta-Parse.cpp', - 'src/XMPMeta-Serialize.cpp', - 'src/XMPMeta.cpp', - 'src/XMPUtils-FileInfo.cpp', - 'src/XMPUtils.cpp', +sdk = 'XMP-Toolkit-SDK' + +# The SDK includes expat as "third-party/expat/lib/expat.h". +# A wrapper header at xmpsdk/third-party/expat/lib/expat.h redirects +# this to the system expat via #include_next. +# Note: sdk / 'source' is intentionally NOT on the include path. +# SDK files use "source/..." relative includes (resolved via the SDK root), +# and adding source/ directly causes a case-insensitive collision on Windows +# (Cygwin/MSYS2) between SDK's Endian.h and system . +xmp_inc = include_directories( + '.', + sdk / 'public/include', + sdk, + sdk / 'third-party/zuid', + sdk / 'third-party/zuid/interfaces', +) + +xmp_sources = files( + # XMPCore sources + sdk / 'XMPCore/source/ExpatAdapter.cpp', + sdk / 'XMPCore/source/ParseRDF.cpp', + sdk / 'XMPCore/source/WXMPMeta.cpp', + sdk / 'XMPCore/source/WXMPUtils.cpp', + sdk / 'XMPCore/source/WXMPIterator.cpp', + sdk / 'XMPCore/source/XMPCore_Impl.cpp', + sdk / 'XMPCore/source/XMPIterator.cpp', + sdk / 'XMPCore/source/XMPMeta.cpp', + sdk / 'XMPCore/source/XMPMeta-GetSet.cpp', + sdk / 'XMPCore/source/XMPMeta-Parse.cpp', + sdk / 'XMPCore/source/XMPMeta-Serialize.cpp', + sdk / 'XMPCore/source/XMPUtils.cpp', + sdk / 'XMPCore/source/XMPUtils-FileInfo.cpp', + # Shared sources + sdk / 'source/IOUtils.cpp', + sdk / 'source/PerfUtils.cpp', + sdk / 'source/SafeStringAPIs.cpp', + sdk / 'source/UnicodeConversions.cpp', + sdk / 'source/XIO.cpp', + sdk / 'source/XML_Node.cpp', + sdk / 'source/XMPFiles_IO.cpp', + sdk / 'source/XMP_LibUtils.cpp', + sdk / 'source/XMP_ProgressTracker.cpp', + # MD5 + sdk / 'third-party/zuid/interfaces/MD5.cpp', +) + +# Public args propagate to consumers (exiv2lib) via xmp_dep. +# Private args apply only to XMP SDK compilation. +xmp_public_args = ['-DBanAllEntityUsage=1', '-DEXV_ADOBE_XMPSDK=2016'] +xmp_private_args = [] + +if host_machine.system() == 'windows' + xmp_sources += files(sdk / 'source/Host_IO-Win.cpp') + xmp_public_args += '-DWIN_ENV' + # UNICODE/_UNICODE: The XMP SDK uses wide-char Windows APIs internally + # (e.g. FindFirstFileW, WIN32_FIND_DATAW in Host_IO-Win.cpp) but also + # calls generic macros like FindNextFile() that resolve to the A (ANSI) + # or W (wide) variant based on the UNICODE define. Without these defines, + # FindNextFile resolves to FindNextFileA, causing a type mismatch with + # the WIN32_FIND_DATAW struct the SDK code passes to it. + # These are PRIVATE because UNICODE affects Windows API macros globally + # and would break exiv2 code (e.g. gai_strerror → gai_strerrorW). + xmp_private_args += ['-DXML_STATIC', '-DUNICODE', '-D_UNICODE', '-DWIN32', + '-D_CRT_SECURE_NO_WARNINGS', '-D_SCL_SECURE_NO_WARNINGS'] + if cpp.get_id() not in ['msvc', 'clang-cl'] + # Non-MSVC compilers (MinGW-GCC, MSYS2-Clang) on Windows lack MSVC's + # header which defines SAL annotations used by the XMP SDK's + # SafeStringAPIs.h. Force-include our compatibility shim that defines + # them as empty. clang-cl uses the MSVC toolchain and has . + # See sal_compat.h for details. + xmp_private_args += ['-include', meson.current_source_dir() / 'sal_compat.h'] + # https://stackoverflow.com/questions/18551409/localtime-r-support-on-mingw + xmp_private_args += '-D_POSIX_THREAD_SAFE_FUNCTIONS' + endif +elif host_machine.system() == 'darwin' + xmp_sources += files(sdk / 'source/Host_IO-POSIX.cpp') + xmp_public_args += '-DMAC_ENV' +else + xmp_sources += files(sdk / 'source/Host_IO-POSIX.cpp') + xmp_public_args += '-DUNIX_ENV' + # The SDK's EndianUtils.hpp only auto-detects endianness for GCC on + # x86/x86_64/SPARC under UNIX_ENV. For other architectures (ARM, WASM, + # etc.) or non-GCC compilers, define it explicitly using meson's host info. + if host_machine.endian() == 'big' + xmp_private_args += '-DkBigEndianHost=1' + else + xmp_private_args += '-DkBigEndianHost=0' + endif +endif + +# Third-party SDK: suppress warnings and errors from third-party code. +# - warning_level=0: avoid project-level -Wall/-Wextra/-Wpedantic +# - cpp_std=c++20: the SDK uses bitwise ops between different unnamed enum +# types (e.g. kXMP_PropValueIsStruct | kRDF_HasValueElem in ParseRDF.cpp). +# In C++20 this is deprecated (a warning), but in C++26 (c++latest) it is +# ill-formed (a hard error that -Wno flags cannot suppress). Capping at +# C++20 keeps it as a suppressible warning. Future SDK versions will likely +# fix this; revisit the cap when updating the submodule. +# - Wno-deprecated-enum-enum-conversion: suppresses the C++20 deprecation +# warning for the enum-enum bitwise ops (defense-in-depth for -Werror) +xmp_warn_args = [] +if cpp.has_argument('-Wno-deprecated-enum-enum-conversion') + xmp_warn_args += '-Wno-deprecated-enum-enum-conversion' +endif + +xmp_static = static_library('exiv2-xmp', xmp_sources, + cpp_args: [xmp_public_args, xmp_private_args, xmp_warn_args], + include_directories: xmp_inc, + dependencies: expat_dep, + override_options: ['warning_level=0', 'cpp_std=c++20'], +) + +xmp_dep = declare_dependency( + compile_args: xmp_public_args, + include_directories: xmp_inc, + link_with: xmp_static, ) From 157c1ea69dfa31eb6a73f71b4f0d9e2b8677bf40 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 17:07:16 +0400 Subject: [PATCH 07/20] disable DeleteNamespace call unsupported by XMP-Toolkit-SDK SXMPMeta::DeleteNamespace has never been implemented in the upstream XMP-Toolkit-SDK (throws kXMPErr_Unimplemented). The old in-source copy had a custom implementation that was added by the exiv2 project. Log a warning when a namespace re-registration with a different prefix is attempted. --- src/xmp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xmp.cpp b/src/xmp.cpp index 51cdd965f1..a6e6069c69 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -549,9 +549,12 @@ void XmpParser::registerNsImpl(const std::string& ns, const std::string& prefix) // Already registered correctly, skip overhead return; } + // DeleteNamespace is not implemented in XMP-Toolkit-SDK, so we cannot + // re-register a namespace URI with a different prefix. + EXV_WARNING << "Cannot re-register namespace " << ns << " with prefix " << prefix + << " (already registered with prefix " << existingPrefix << ").\n"; } - SXMPMeta::DeleteNamespace(ns.c_str()); #ifdef EXV_ADOBE_XMPSDK SXMPMeta::RegisterNamespace(ns.c_str(), prefix.c_str(), nullptr); #else From ffe346d304c19f27518af77d5d14f8de26f2941a Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 19:14:55 +0400 Subject: [PATCH 08/20] work around NormalizeLangArray overwriting lang-specific values XMP-Toolkit-SDK's NormalizeLangArray (called during serialization) overwrites the second item's value with x-default's when a LangAlt array has exactly 2 items. The old in-source SDK had this behavior disabled since 2007 (commented out by Andreas Huggel as unexpected --- src/xmp.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/xmp.cpp b/src/xmp.cpp index a6e6069c69..d73a0f2a42 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -882,6 +882,33 @@ int XmpParser::encode(std::string& xmpPacket, const XmpData& xmpData, uint16_t f } } } + + // XMP-Toolkit-SDK's NormalizeLangArray (called during serialization) overwrites + // the second item's value with x-default's when there are exactly 2 items. + // To preserve language-specific values, update x-default to match the sole + // language entry so the normalization becomes a no-op. + auto item_cnt = meta.CountArrayItems(ns.c_str(), xmp.tagName().c_str()); + if (item_cnt == 2) { + std::size_t xd_idx = 0; + std::size_t lang_idx = 0; + for (std::size_t i = 1; i <= 2; ++i) { + std::string qualifier_value; + const std::string item = xmp.tagName() + "[" + toString(i) + "]"; + if (meta.GetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", &qualifier_value, nullptr)) { + if (qualifier_value == "x-default") + xd_idx = i; + else + lang_idx = i; + } + } + if (xd_idx && lang_idx) { + std::string lang_value; + meta.GetArrayItem(ns.c_str(), xmp.tagName().c_str(), static_cast(lang_idx), &lang_value, + nullptr); + meta.SetArrayItem(ns.c_str(), xmp.tagName().c_str(), static_cast(xd_idx), lang_value.c_str()); + } + } + continue; } From 26eb19fbf4365cc99c794e60ebf1b166e105bb6a Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 19:32:34 +0400 Subject: [PATCH 09/20] update StaffPhotographer reference for date-only timezone handling The new XMP-Toolkit-SDK correctly skips timezone conversion for date-only values (no time component). The old SDK unconditionally applied the local timezone offset, making the test result depend on the machine's timezone (e.g. 08:00:00 on UTC+8). --- .../data/test_reference_files/StaffPhotographer-Example.xmp.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/test_reference_files/StaffPhotographer-Example.xmp.out b/test/data/test_reference_files/StaffPhotographer-Example.xmp.out index f50b2c8833..62c7e22b16 100644 --- a/test/data/test_reference_files/StaffPhotographer-Example.xmp.out +++ b/test/data/test_reference_files/StaffPhotographer-Example.xmp.out @@ -11,7 +11,7 @@ Exif.Image.Copyright Ascii 42 ©2003 Big Newspaper Exif.Photo.ColorSpace Short 1 1 sRGB Exif.Photo.PixelXDimension Long 1 432 432 Exif.Photo.PixelYDimension Long 1 293 293 -Exif.Photo.DateTimeOriginal Ascii 20 2003:04:03 08:00:00 2003:04:03 08:00:00 +Exif.Photo.DateTimeOriginal Ascii 20 2003:04:03 00:00:00 2003:04:03 00:00:00 Exif.Photo.DateTimeDigitized Ascii 20 2005:03:13 16:01:44 2005:03:13 16:01:44 Iptc.Application2.ObjectName String 8 01661gdx 01661gdx Iptc.Envelope.CharacterSet String 3 %G %G From 73d20321fa404922f62b5dd0a8c841cf660a2250 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:09:32 +0400 Subject: [PATCH 10/20] detect XMP toolkit version at test runtime via $xmp_toolkit_version Instead of hardcoding "XMP Core 4.4.0-Exiv2" in test expectations (which breaks on every SDK upgrade), detect the version dynamically by writing minimal XMP to a temp file and extracting the x:xmptk attribute. The version is exposed as $xmp_toolkit_version for use in test string templates via the existing CaseMeta variable expansion. --- tests/system_tests.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/system_tests.py b/tests/system_tests.py index a37044021d..7bfa18ade3 100644 --- a/tests/system_tests.py +++ b/tests/system_tests.py @@ -167,6 +167,35 @@ def configure_suite(config_file): ) _config_variables[key] = abs_path + # Detect the XMP toolkit version string by writing minimal XMP and + # extracting the x:xmptk attribute. This avoids hardcoding the version + # in test expectations, which would break on SDK upgrades. + import re, tempfile + exiv2_path = _config_variables.get('exiv2', '') + # shutil.which handles Windows .exe extension resolution (the config + # path omits the extension, so os.path.isfile would fail on Windows). + if exiv2_path and shutil.which(exiv2_path): + data_path = _config_variables.get('data_path', '') + empty_jpg = os.path.join(data_path, 'exiv2-empty.jpg') + if os.path.isfile(empty_jpg): + fd, tmp_path = tempfile.mkstemp(suffix='.jpg') + os.close(fd) + shutil.copy2(empty_jpg, tmp_path) + try: + subprocess.run( + [exiv2_path, '-M', 'set Xmp.dc.title test', tmp_path], + capture_output=True, timeout=10 + ) + result = subprocess.run( + [exiv2_path, '-pX', tmp_path], + capture_output=True, timeout=10 + ) + match = re.search(r'x:xmptk="([^"]+)"', result.stdout.decode('utf-8', errors='replace')) + if match: + _config_variables['xmp_toolkit_version'] = match.group(1) + finally: + os.unlink(tmp_path) + for key in _config_variables: if key in globals(): raise ValueError("Variable name {!s} already used.") From 32e2912ffaecaddf3b2d87eab8966ca6ccf3d790 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:10:30 +0400 Subject: [PATCH 11/20] update tests to use $xmp_toolkit_version instead of hardcoded version Replace all hardcoded "XMP Core 4.4.0-Exiv2" strings with the $xmp_toolkit_version variable detected at runtime (see previous commit). Affects 11 test cases across 6 files: - test_pr1475_HEIC (1 test): x:xmptk in XMP packet output - test_pr1475_HIF (2 tests): same - test_pr_2000 (4 text tests): same - test_issue_1112: XMP sidecar output - test_issue_1229: XMP sidecar output (refactored local variable to class attribute so CaseMeta expansion can reach it) - test_issue_799: XMP packet output For test_pr_2000.TestVerboseExtractRawMetadataToStdout (binary test): instead of comparing against a static reference file that embeds the version string, generate the reference at test time by extracting to a temp file, then verify that stdout extraction produces identical bytes. This makes the test fully version-independent. --- tests/bugfixes/github/test_pr1475_HEIC.py | 2 +- tests/bugfixes/github/test_pr1475_HIF.py | 4 +-- tests/bugfixes/github/test_pr_2000.py | 34 +++++++++++++++++++---- tests/bugfixes/redmine/test_issue_1112.py | 4 +-- tests/bugfixes/redmine/test_issue_1229.py | 14 +++++----- tests/bugfixes/redmine/test_issue_799.py | 4 +-- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/tests/bugfixes/github/test_pr1475_HEIC.py b/tests/bugfixes/github/test_pr1475_HEIC.py index 8df929da77..a010d7aaff 100644 --- a/tests/bugfixes/github/test_pr1475_HEIC.py +++ b/tests/bugfixes/github/test_pr1475_HEIC.py @@ -434,7 +434,7 @@ class pr_1475_Stonehenge_heic(metaclass=system_tests.CaseMeta): Exiv2::BmffImage::boxHandler: mdat 532->1 """, """ - + 147464 """, """ - + 1252197 """, """ - + - + - + - + - + @@ -163,6 +165,11 @@ class TestVerboseExtractRawMetadataToStdout(metaclass=CaseMeta): """ Regression test for 'verbose extracting raw metadata to stdout' bug described in: https://github.com/Exiv2/exiv2/issues/1934 + + Instead of comparing against a static reference file (which would break + on XMP-Toolkit-SDK upgrades due to the version string in the XMP packet), + we extract to a temp file first and verify that stdout extraction produces + identical bytes. """ url = "https://github.com/Exiv2/exiv2/issues/1934" @@ -170,10 +177,25 @@ class TestVerboseExtractRawMetadataToStdout(metaclass=CaseMeta): encodings = [bytes] def setUp(self): - self.stdout = [bytes(open(self.expand_variables("$filename_ref"), "rb").read())] + import shutil, subprocess, tempfile + src = self.expand_variables("$filename") + exiv2 = self.expand_variables("$exiv2") + fd, self._tmp_jpg = tempfile.mkstemp(suffix='.jpg') + os.close(fd) + shutil.copy2(src, self._tmp_jpg) + subprocess.run( + [exiv2, '--verbose', '--extract', 'XXeix', self._tmp_jpg], + capture_output=True, timeout=30 + ) + exv_path = self._tmp_jpg.replace('.jpg', '.exv') + self.stdout = [bytes(open(exv_path, "rb").read())] + os.unlink(exv_path) + + def tearDown(self): + if hasattr(self, '_tmp_jpg') and os.path.exists(self._tmp_jpg): + os.unlink(self._tmp_jpg) filename = path("$data_path/issue_1934_poc4.jpg") - filename_ref = path("$data_path/issue_1934_poc4_ref.exv") commands = ["$exiv2 --verbose --extract XXeix- $filename"] diff --git a/tests/bugfixes/redmine/test_issue_1112.py b/tests/bugfixes/redmine/test_issue_1112.py index f7adb69d99..0a6c0e567a 100644 --- a/tests/bugfixes/redmine/test_issue_1112.py +++ b/tests/bugfixes/redmine/test_issue_1112.py @@ -15,7 +15,7 @@ class CheckXmpTimeZoneInformation(metaclass=system_tests.CaseMeta): retval = [0] xmp_packet = """ - + - + expected_xmp = """ + """ - self.assertMultiLineEqual(expected, content) + def post_tests_hook(self): + with open(self.filename_xmp, "r", encoding='utf-8') as xmp: + content = xmp.read(-1) + + self.assertMultiLineEqual(self.expand_variables(self.expected_xmp), content) diff --git a/tests/bugfixes/redmine/test_issue_799.py b/tests/bugfixes/redmine/test_issue_799.py index e156e8907b..6ed2d828a8 100644 --- a/tests/bugfixes/redmine/test_issue_799.py +++ b/tests/bugfixes/redmine/test_issue_799.py @@ -24,10 +24,10 @@ class WrongXmpTypeForNestedXmpKeys(metaclass=CaseMeta): def post_tests_hook(self): with open(self.xmpfile, "r", encoding='utf-8') as xmp_file: - self.assertMultiLineEqual(self.xmp_packet, xmp_file.read(-1)) + self.assertMultiLineEqual(self.expand_variables(self.xmp_packet), xmp_file.read(-1)) xmp_packet = """ - + Date: Thu, 12 Feb 2026 20:11:24 +0400 Subject: [PATCH 12/20] update tests for XMP property alias changes in new SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XMP-Toolkit-SDK 6.0.0 resolves property aliases differently than the old in-source 4.4.0 build: tiff:Artist → dc:creator (was kept as separate property) tiff:Copyright → dc:rights (was kept as separate property) tiff:ImageDescription → dc:description (was kept as separate property) tiff:Software → xmp:CreatorTool (new alias direction) exif:DateTimeDigitized → xmp:CreateDate (no longer emitted separately) When the canonical form (dc:*, xmp:*) is already present in the file, the aliased tiff:/exif: form is no longer duplicated in the output. The underlying metadata is unchanged — only the property key shown by "exiv2 -px" / "exiv2 -Pkycvt" differs. Bugfix tests updated: - test_issue_540: removed 4 tiff alias properties, added CreatorTool - test_issue_937: removed Xmp.exif.DateTimeDigitized from -g Date output Regression reference files regenerated (same root cause): - ReaganLargePng.png.out, ReaganSmallPng.png.out (DateTimeDigitized) - exiv2-bug1225.exv.out (DateTimeDigitized + Artist/CreateDate) - exiv2-bug540.jpg.out (Artist/Copyright/ImageDescription/Software) - exiv2-bug884c.jpg.out (DateTimeDigitized) - exiv2-bug937.jpg.out (DateTimeDigitized) - issue_ghsa_5p8g_9xf3_gfrr_poc.{exv,webp}.out (Software→CreatorTool) --- .../ReaganLargePng.png.out | 2 -- .../ReaganSmallPng.png.out | 1 - .../exiv2-bug1225.exv.out | 3 +-- .../test_reference_files/exiv2-bug540.jpg.out | 5 +---- .../exiv2-bug884c.jpg.out | 1 - .../test_reference_files/exiv2-bug937.jpg.out | Bin 26399 -> 26278 bytes .../issue_ghsa_5p8g_9xf3_gfrr_poc.exv.out | 2 +- .../issue_ghsa_5p8g_9xf3_gfrr_poc.webp.out | 2 +- tests/bugfixes/redmine/test_issue_540.py | 5 +---- tests/bugfixes/redmine/test_issue_937.py | 3 +-- 10 files changed, 6 insertions(+), 18 deletions(-) diff --git a/test/data/test_reference_files/ReaganLargePng.png.out b/test/data/test_reference_files/ReaganLargePng.png.out index 24bbe2e8d6..577fea570a 100644 --- a/test/data/test_reference_files/ReaganLargePng.png.out +++ b/test/data/test_reference_files/ReaganLargePng.png.out @@ -111,7 +111,6 @@ Xmp.exif.ColorSpace XmpText 1 1 sRGB Xmp.exif.CompressedBitsPerPixel XmpText 3 4/1 4/1 Xmp.exif.Contrast XmpText 1 0 Normal Xmp.exif.CustomRendered XmpText 1 0 Normal process -Xmp.exif.DateTimeDigitized XmpText 25 2004-06-21T23:37:53+01:00 2004-06-21T23:37:53+01:00 Xmp.exif.DateTimeOriginal XmpText 25 2004-06-21T23:37:53+01:00 2004-06-21T23:37:53+01:00 Xmp.exif.DigitalZoomRatio XmpText 3 1/1 1/1 Xmp.exif.ExifVersion XmpText 4 0220 2.20 @@ -161,7 +160,6 @@ Xmp.photoshop.Source XmpText 24 Navy Visual News Ser Xmp.photoshop.Urgency XmpText 1 5 5 Xmp.photoshop.SupplementalCategories XmpBag 1 703-614-9154, navyvisualnews@navy.mil, UNCLASSFIED 703-614-9154, navyvisualnews@navy.mil, UNCLASSFIED Xmp.tiff.Compression XmpText 1 1 1 -Xmp.tiff.DateTime XmpText 19 2016:09:13 12:23:27 2016:09:13 12:23:27 Xmp.tiff.ImageLength XmpText 3 130 130 Xmp.tiff.ImageWidth XmpText 3 200 200 Xmp.tiff.Make XmpText 17 NIKON CORPORATION NIKON CORPORATION diff --git a/test/data/test_reference_files/ReaganSmallPng.png.out b/test/data/test_reference_files/ReaganSmallPng.png.out index aa8acb707e..e5c84cc208 100644 --- a/test/data/test_reference_files/ReaganSmallPng.png.out +++ b/test/data/test_reference_files/ReaganSmallPng.png.out @@ -107,7 +107,6 @@ Xmp.exif.ColorSpace XmpText 1 1 sRGB Xmp.exif.CompressedBitsPerPixel XmpText 3 4/1 4/1 Xmp.exif.Contrast XmpText 1 0 Normal Xmp.exif.CustomRendered XmpText 1 0 Normal process -Xmp.exif.DateTimeDigitized XmpText 25 2004-06-21T23:37:53+01:00 2004-06-21T23:37:53+01:00 Xmp.exif.DateTimeOriginal XmpText 25 2004-06-21T23:37:53+01:00 2004-06-21T23:37:53+01:00 Xmp.exif.DigitalZoomRatio XmpText 3 1/1 1/1 Xmp.exif.ExifVersion XmpText 4 0220 2.20 diff --git a/test/data/test_reference_files/exiv2-bug1225.exv.out b/test/data/test_reference_files/exiv2-bug1225.exv.out index 656fe4fc37..4ae512c111 100644 --- a/test/data/test_reference_files/exiv2-bug1225.exv.out +++ b/test/data/test_reference_files/exiv2-bug1225.exv.out @@ -162,7 +162,6 @@ Xmp.iptc.Location XmpText 11 Snowy Flats Snowy F Xmp.iptc.CreatorContactInfo XmpText 13 type="Struct" type="Struct" Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiEmailWork XmpText 27 mark.jekabsons@yahoo.com.au mark.jekabsons@yahoo.com.au Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiTelWork XmpText 12 +61401922543 +61401922543 -Xmp.exif.DateTimeDigitized XmpText 25 2016-03-17T16:37:48+11:00 2016-03-17T16:37:48+11:00 Xmp.exif.DateTimeOriginal XmpText 25 2016-03-17T16:37:48+11:00 2016-03-17T16:37:48+11:00 Xmp.exif.GPSAltitude XmpText 6 1601/1 1601/1 Xmp.exif.GPSAltitudeRef XmpText 1 0 Above sea level @@ -176,10 +175,10 @@ Xmp.exif.GPSVersionID XmpText 7 2.2.0.0 2.2.0.0 Xmp.photoshop.City XmpText 21 Namadgi National Park Namadgi National Park Xmp.photoshop.Country XmpText 9 Australia Australia Xmp.photoshop.State XmpText 28 Australian Capital Territory Australian Capital Territory -Xmp.tiff.Artist XmpText 14 Mark Jekabsons Mark Jekabsons Xmp.xmp.BaseURL XmpText 40 https://www.flickr.com/photos/jekabsons/ https://www.flickr.com/photos/jekabsons/ Xmp.xmp.ModifyDate XmpText 25 2016-03-17T16:37:48+11:00 2016-03-17T16:37:48+11:00 Xmp.xmp.CreatorTool XmpText 37 Microsoft Photo Gallery 16.4.3528.331 Microsoft Photo Gallery 16.4.3528.331 +Xmp.xmp.CreateDate XmpText 25 2016-03-17T16:37:48+11:00 2016-03-17T16:37:48+11:00 Xmp.prefix0.PipelineVersion XmpText 5 01.00 01.00 Xmp.prefix0.CameraModelID XmpText 0 Xmp.prefix0.StreamType XmpText 1 3 3 diff --git a/test/data/test_reference_files/exiv2-bug540.jpg.out b/test/data/test_reference_files/exiv2-bug540.jpg.out index c50d11ae84..28a60af60a 100644 --- a/test/data/test_reference_files/exiv2-bug540.jpg.out +++ b/test/data/test_reference_files/exiv2-bug540.jpg.out @@ -42,23 +42,20 @@ Xmp.photoshop.Headline XmpText 14 Communications Comm Xmp.photoshop.State XmpText 1 Xmp.photoshop.SupplementalCategories XmpBag 1 Communications Communications Xmp.photoshop.Urgency XmpText 1 5 5 -Xmp.tiff.Artist XmpText 11 Ian Britton Ian Britton Xmp.tiff.BitsPerSample XmpSeq 1 8 8 Xmp.tiff.Compression XmpText 1 6 6 -Xmp.tiff.Copyright LangAlt 1 lang="x-default" ian Britton - FreeFoto.com lang="x-default" ian Britton - FreeFoto.com -Xmp.tiff.ImageDescription LangAlt 1 lang="x-default" Communications lang="x-default" Communications Xmp.tiff.ImageLength XmpText 3 400 400 Xmp.tiff.ImageWidth XmpText 3 600 600 Xmp.tiff.Make XmpText 8 FUJIFILM FUJIFILM Xmp.tiff.Model XmpText 12 FinePixS1Pro FinePixS1Pro Xmp.tiff.Orientation XmpText 1 1 top, left Xmp.tiff.ResolutionUnit XmpText 1 2 inch -Xmp.tiff.Software XmpText 19 Adobe Photoshop 7.0 Adobe Photoshop 7.0 Xmp.tiff.XResolution XmpText 5 300/1 300 Xmp.tiff.YCbCrPositioning XmpText 1 2 Co-sited Xmp.tiff.YResolution XmpText 5 300/1 300 Xmp.xmp.CreateDate XmpText 20 2002-07-13T15:58:28Z 2002-07-13T15:58:28Z Xmp.xmp.ModifyDate XmpText 20 2002-07-19T13:28:10Z 2002-07-19T13:28:10Z +Xmp.xmp.CreatorTool XmpText 19 Adobe Photoshop 7.0 Adobe Photoshop 7.0 Xmp.xmpBJ.JobRef XmpText 10 type="Bag" type="Bag" Xmp.xmpBJ.JobRef[1] XmpText 13 type="Struct" type="Struct" Xmp.xmpBJ.JobRef[1]/stJob:name XmpText 12 Photographer Photographer diff --git a/test/data/test_reference_files/exiv2-bug884c.jpg.out b/test/data/test_reference_files/exiv2-bug884c.jpg.out index ce57b8604d..b92d902dd1 100644 --- a/test/data/test_reference_files/exiv2-bug884c.jpg.out +++ b/test/data/test_reference_files/exiv2-bug884c.jpg.out @@ -109,7 +109,6 @@ Exif.Photo.SubjectDistanceRange Short 1 2 Close view Xmp.exif.PixelXDimension XmpText 3 240 240 Xmp.exif.PixelYDimension XmpText 3 160 160 Xmp.exif.DateTimeOriginal XmpText 20 2013-01-30T19:30:52Z 2013:01:30 19:30:52 -Xmp.exif.DateTimeDigitized XmpText 20 2013-01-30T19:30:52Z 2013-01-30T19:30:52Z Xmp.tiff.ImageWidth XmpText 1 1 1 Xmp.tiff.ImageHeight XmpText 3 160 160 Xmp.xmp.CreateDate XmpText 20 2013-01-30T19:30:52Z 2013-01-30T19:30:52Z diff --git a/test/data/test_reference_files/exiv2-bug937.jpg.out b/test/data/test_reference_files/exiv2-bug937.jpg.out index fb48a85eb6b01186d488fe734c0f2db7fb396669..8df201f983436086ac9e17db3591d497387fbbbe 100644 GIT binary patch delta 14 WcmbP#j&a#p#tjR3HcRocMgagZ5CwSv delta 87 zcmZ2>mT~?$#tjR3CM&W?O}@a#>tJN5pkQQRV4-VZtZQfzVrXb(Y-nX-p=V$T6f(Cm NFd!hkxt~Wo3IP9E6+i$0 diff --git a/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.exv.out b/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.exv.out index 13c534d879..d6b4ee8fc7 100644 --- a/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.exv.out +++ b/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.exv.out @@ -166,10 +166,10 @@ Xmp.tiff.YResolution XmpText 5 300/1 300 Xmp.tiff.ResolutionUnit XmpText 1 2 inch Xmp.tiff.Make XmpText 17 NIKON CORPORATION NIKON CORPORATION Xmp.tiff.Model XmpText 11 NIKON D5300 NIKON D5300 -Xmp.tiff.Software XmpText 10 GIMP 2.9.5 GIMP 2.9.5 Xmp.tiff.BitsPerSample XmpSeq 1 8 8 8 8 8 8 Xmp.xmp.ModifyDate XmpText 19 2016-08-13T10:54:16 2016-08-13T10:54:16 Xmp.xmp.CreateDate XmpText 22 2015-07-16T15:38:54.00 2015-07-16T15:38:54.00 +Xmp.xmp.CreatorTool XmpText 10 GIMP 2.9.5 GIMP 2.9.5 Xmp.exif.ExifVersion XmpText 4 0230 2.30 Xmp.exif.FlashpixVersion XmpText 4 0100 1.00 Xmp.exif.ColorSpace XmpText 1 1 sRGB diff --git a/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.webp.out b/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.webp.out index 13c534d879..d6b4ee8fc7 100644 --- a/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.webp.out +++ b/test/data/test_reference_files/issue_ghsa_5p8g_9xf3_gfrr_poc.webp.out @@ -166,10 +166,10 @@ Xmp.tiff.YResolution XmpText 5 300/1 300 Xmp.tiff.ResolutionUnit XmpText 1 2 inch Xmp.tiff.Make XmpText 17 NIKON CORPORATION NIKON CORPORATION Xmp.tiff.Model XmpText 11 NIKON D5300 NIKON D5300 -Xmp.tiff.Software XmpText 10 GIMP 2.9.5 GIMP 2.9.5 Xmp.tiff.BitsPerSample XmpSeq 1 8 8 8 8 8 8 Xmp.xmp.ModifyDate XmpText 19 2016-08-13T10:54:16 2016-08-13T10:54:16 Xmp.xmp.CreateDate XmpText 22 2015-07-16T15:38:54.00 2015-07-16T15:38:54.00 +Xmp.xmp.CreatorTool XmpText 10 GIMP 2.9.5 GIMP 2.9.5 Xmp.exif.ExifVersion XmpText 4 0230 2.30 Xmp.exif.FlashpixVersion XmpText 4 0100 1.00 Xmp.exif.ColorSpace XmpText 1 1 sRGB diff --git a/tests/bugfixes/redmine/test_issue_540.py b/tests/bugfixes/redmine/test_issue_540.py index 77be3319f6..78ed93b7cd 100644 --- a/tests/bugfixes/redmine/test_issue_540.py +++ b/tests/bugfixes/redmine/test_issue_540.py @@ -53,23 +53,20 @@ class PrettyPrintXmp(metaclass=system_tests.CaseMeta): Xmp.photoshop.State XmpText 1 Xmp.photoshop.SupplementalCategories XmpBag 1 Communications Xmp.photoshop.Urgency XmpText 1 5 -Xmp.tiff.Artist XmpText 11 Ian Britton Xmp.tiff.BitsPerSample XmpSeq 1 8 Xmp.tiff.Compression XmpText 1 6 -Xmp.tiff.Copyright LangAlt 1 lang="x-default" ian Britton - FreeFoto.com -Xmp.tiff.ImageDescription LangAlt 1 lang="x-default" Communications Xmp.tiff.ImageLength XmpText 3 400 Xmp.tiff.ImageWidth XmpText 3 600 Xmp.tiff.Make XmpText 8 FUJIFILM Xmp.tiff.Model XmpText 12 FinePixS1Pro Xmp.tiff.Orientation XmpText 1 top, left Xmp.tiff.ResolutionUnit XmpText 1 inch -Xmp.tiff.Software XmpText 19 Adobe Photoshop 7.0 Xmp.tiff.XResolution XmpText 5 300 Xmp.tiff.YCbCrPositioning XmpText 1 Co-sited Xmp.tiff.YResolution XmpText 5 300 Xmp.xmp.CreateDate XmpText 20 2002-07-13T15:58:28Z Xmp.xmp.ModifyDate XmpText 20 2002-07-19T13:28:10Z +Xmp.xmp.CreatorTool XmpText 19 Adobe Photoshop 7.0 Xmp.xmpBJ.JobRef XmpText 10 type="Bag" Xmp.xmpBJ.JobRef[1] XmpText 13 type="Struct" Xmp.xmpBJ.JobRef[1]/stJob:name XmpText 12 Photographer diff --git a/tests/bugfixes/redmine/test_issue_937.py b/tests/bugfixes/redmine/test_issue_937.py index 27779b2fe1..1a681cefaf 100644 --- a/tests/bugfixes/redmine/test_issue_937.py +++ b/tests/bugfixes/redmine/test_issue_937.py @@ -190,8 +190,7 @@ class DarwinCoreXmpMetadataPrint(metaclass=CaseMeta): Xmp.dwc.MeasurementOrFact/dwc:measurementMethod XmpText 20 barometric altimeter Xmp.dwc.MeasurementOrFact/dwc:measurementRemarks XmpText 19 tip of tail missing """, - """Xmp.exif.DateTimeDigitized Date and Time Digitized XmpText 29 2008-03-14T11:31:48.098-07:00 -Xmp.exif.DateTimeOriginal Date and Time Original XmpText 25 2008-03-14T13:59:26-06:00 + """Xmp.exif.DateTimeOriginal Date and Time Original XmpText 25 2008-03-14T13:59:26-06:00 Xmp.photoshop.DateCreated Date Created XmpText 29 2008-03-14T13:59:26.054-06:00 Xmp.xmp.MetadataDate Metadata Date XmpText 29 2013-02-07T21:56:33.820-06:00 Xmp.xmp.CreateDate Create Date XmpText 24 2008-03-14T20:59:26.535Z From 43b1e2894ce0d8961d7d81f17a67a66491209097 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:12:08 +0400 Subject: [PATCH 13/20] update AVIF tests for IPTC namespace prefix change in new SDK XMP-Toolkit-SDK 6.0.0 registers the IPTC Extensions namespace (http://iptc.org/std/Iptc4xmpExt/2008-02-29/) with prefix "Iptc4xmpExt" instead of "iptcExt" used by the old in-source build. This only affects the XML prefix in serialized XMP packets (the -pX output). The exiv2 internal property names (Xmp.iptcExt.*) shown by -pa are unchanged since those come from exiv2's own namespace registry. Also switches x:xmptk to $xmp_toolkit_version (same as previous commit). --- tests/bugfixes/github/test_pr1475_AVIF.py | 44 +++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/bugfixes/github/test_pr1475_AVIF.py b/tests/bugfixes/github/test_pr1475_AVIF.py index 624e6add95..bcd73acdc2 100644 --- a/tests/bugfixes/github/test_pr1475_AVIF.py +++ b/tests/bugfixes/github/test_pr1475_AVIF.py @@ -148,10 +148,10 @@ class pr_1475_exif_xmp_avif(metaclass=system_tests.CaseMeta): Exiv2::BmffImage::boxHandler: mdat 411->10452 """, """ - + - + - - + + - - + + - - + + - + 9404 """, """ - + - + - - + + - - + + - - + + - + Date: Thu, 12 Feb 2026 20:12:55 +0400 Subject: [PATCH 14/20] update namespace re-registration test for new SDK behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XMP-Toolkit-SDK 6.0.0 does not support SXMPMeta::DeleteNamespace, so re-registering a prefix with a different URI cannot reuse the original prefix. Instead, the SDK assigns a new prefix (e.g. "imageapp_1_"). Old behavior (SDK 4.4.0, DeleteNamespace worked): 1. reg imageapp=orig/ → prefix "imageapp" maps to orig/ 2. reg imageapp=dest/ → deletes orig/, re-registers as dest/ 3. serialize → still wrote orig/ (property bound to orig/) 4. reload → reversed dest/→orig/ in internal registry New behavior (SDK 6.0.0, DeleteNamespace unimplemented): 1. reg imageapp=orig/ → prefix "imageapp" maps to orig/ 2. reg imageapp=dest/ → SDK assigns "imageapp_1_" for dest/ 3. serialize → writes imageapp_1_=dest/ 4. reload → no conflict (fresh process), no warning Changes: - xmp_packets[1]: xmlns:imageapp_1_="dest/" (was imageapp="orig/") - stderr[3]: empty (was "Updating namespace URI" warning) - Also switches x:xmptk to $xmp_toolkit_version --- tests/bugfixes/redmine/test_issue_751.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/bugfixes/redmine/test_issue_751.py b/tests/bugfixes/redmine/test_issue_751.py index d5f17b3e86..0a0f20a541 100644 --- a/tests/bugfixes/redmine/test_issue_751.py +++ b/tests/bugfixes/redmine/test_issue_751.py @@ -25,12 +25,12 @@ def read_xmpfile(): return xmp.read(-1) if i in (2,4): - self.assertMultiLineEqual(self.xmp_packets[i//2 - 1], read_xmpfile()) + self.assertMultiLineEqual(self.expand_variables(self.xmp_packets[i//2 - 1]), read_xmpfile()) xmp_packets = [ """ - + """, """ - + + xmlns:imageapp_1_="dest/" + imageapp_1_:uuid="abcd"/> """ @@ -66,7 +66,6 @@ def read_xmpfile(): "", """Warning: Updating namespace URI for imageapp from orig/ to dest/ """, - """Warning: Updating namespace URI for imageapp from dest/ to orig/ -""", + "", ] retval = [0] * 4 From fc800776b01664c57fbd71d8f512854bb6b05aad Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:14:03 +0400 Subject: [PATCH 15/20] update tests for changed XMP parsing strictness in new SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XMP-Toolkit-SDK 6.0.0 handles edge-case XMP differently: Stricter — issue_1901 poc4.xmp: The file has malformed namespace URIs (xmlns:x=" "). The old SDK was lenient enough to parse them; the new SDK rejects the XMP entirely, so exiv2 now reports "No Exif data found" (exit 253) instead of silently succeeding (exit 0). Stricter — issue_94_poc3.pgf: Fuzz-PoC with garbled XMP. Old SDK produced 9 lines of mangled Xmp.rdf.* properties; new SDK rejects the malformed RDF and produces only the 2 non-XMP Exif lines. Arguably more correct. More lenient — ReaganLargeJpg.jpg: Old SDK threw error 203 "Duplicate property or field node" and produced no XMP output (62 lines total). New SDK parses the duplicate properties successfully, exposing 72 additional XMP properties (134 lines total). --- .../ReaganLargeJpg.jpg.out | 76 ++++++++++++++++++- .../issue_94_poc3.pgf.out | 7 -- tests/bugfixes/github/test_issue_1901.py | 5 +- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/test/data/test_reference_files/ReaganLargeJpg.jpg.out b/test/data/test_reference_files/ReaganLargeJpg.jpg.out index 793ea63172..1b699328b2 100644 --- a/test/data/test_reference_files/ReaganLargeJpg.jpg.out +++ b/test/data/test_reference_files/ReaganLargeJpg.jpg.out @@ -1,5 +1,3 @@ -Error: XMP Toolkit error 203: Duplicate property or field node -Warning: Failed to decode XMP metadata. Exif.Image.ImageDescription Ascii 403 040621-N-6536T-062 USS Ronald Reagan (CVN 76), June 21, 2004 - USS Ronald Reagan (CVN 76) sails through the Straits of Magellan on its way to the Pacific Ocean. The Navyís newest aircraft carrier is underway circumnavigating South America in transit to its new homeport of San Diego. U.S. Navy photo by Photographerís Mate 3rd Class (AW) Elizabeth Thompson. (RELEASE) 040621-N-6536T-062 @@ -59,3 +57,77 @@ Exif.Thumbnail.YResolution Rational 1 72/1 72 Exif.Thumbnail.ResolutionUnit Short 1 2 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 1352 1352 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 2713 2713 +Xmp.xmp.ModifyDate XmpText 20 2016-03-23T13:26:36Z 2016-03-23T13:26:36Z +Xmp.xmp.CreateDate XmpText 20 2016-03-23T13:26:36Z 2016-03-23T13:26:36Z +Xmp.xmp.MetadataDate XmpText 20 2016-03-23T13:26:36Z 2016-03-23T13:26:36Z +Xmp.xmp.CreatorTool XmpText 38 Adobe Photoshop Elements 6.0 Macintosh Adobe Photoshop Elements 6.0 Macintosh +Xmp.photoshop.ColorMode XmpText 1 3 3 +Xmp.photoshop.ICCProfile XmpText 17 sRGB IEC61966-2.1 sRGB IEC61966-2.1 +Xmp.photoshop.History XmpText 0 +Xmp.photoshop.Instructions XmpText 49 Credit as U.S. Navy photo by Elizabeth Thompson. Credit as U.S. Navy photo by Elizabeth Thompson. +Xmp.photoshop.CaptionWriter XmpText 9 Dir. NVNS Dir. NVNS +Xmp.photoshop.Urgency XmpText 1 5 5 +Xmp.photoshop.City XmpText 19 Straits of Magellan Straits of Magellan +Xmp.photoshop.Category XmpText 1 N N +Xmp.photoshop.Country XmpText 13 South America South America +Xmp.photoshop.Credit XmpText 8 U.S Navy U.S Navy +Xmp.photoshop.AuthorsPosition XmpText 21 U.S Navy Photographer U.S Navy Photographer +Xmp.photoshop.DateCreated XmpText 10 2004-06-21 2004-06-21 +Xmp.photoshop.Source XmpText 24 Navy Visual News Service Navy Visual News Service +Xmp.photoshop.SupplementalCategories XmpText 12 703-614-9154 703-614-9154 +Xmp.xmpMM.InstanceID XmpText 37 uuid:D7CBDC1D8DF2E511BA6BFBE914561F6D uuid:D7CBDC1D8DF2E511BA6BFBE914561F6D +Xmp.xmpMM.DocumentID XmpText 37 uuid:D6CBDC1D8DF2E511BA6BFBE914561F6D uuid:D6CBDC1D8DF2E511BA6BFBE914561F6D +Xmp.xmpMM.DerivedFrom XmpText 13 type="Struct" type="Struct" +Xmp.dc.format XmpText 10 image/jpeg image/jpeg +Xmp.dc.description LangAlt 1 lang="x-default" x-default lang="x-default" x-default +Xmp.dc.title LangAlt 1 lang="x-default" x-default lang="x-default" x-default +Xmp.dc.creator XmpSeq 1 Photographerís Mate 3rd Class (A Photographerís Mate 3rd Class (A +Xmp.dc.subject XmpBag 10 ronald reagan, reagan, cvn 76, cvn-76, straights magellan, magellan, carrier, nimitz-class, ship, underway ronald reagan, reagan, cvn 76, cvn-76, straights magellan, magellan, carrier, nimitz-class, ship, underway +Xmp.tiff.ImageWidth XmpText 3 200 200 +Xmp.tiff.ImageLength XmpText 3 130 130 +Xmp.tiff.Compression XmpText 1 1 1 +Xmp.tiff.PhotometricInterpretation XmpText 1 2 2 +Xmp.tiff.Orientation XmpText 1 1 top, left +Xmp.tiff.SamplesPerPixel XmpText 1 4 4 +Xmp.tiff.PlanarConfiguration XmpText 1 1 1 +Xmp.tiff.XResolution XmpText 13 3000000/10000 300 +Xmp.tiff.YResolution XmpText 13 3000000/10000 300 +Xmp.tiff.ResolutionUnit XmpText 1 2 inch +Xmp.tiff.Make XmpText 17 NIKON CORPORATION NIKON CORPORATION +Xmp.tiff.Model XmpText 9 NIKON D1X NIKON D1X +Xmp.tiff.NativeDigest XmpText 134 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;2C2119D37A161F76DA14FA023F3064DD 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;2C2119D37A161F76DA14FA023F3064DD +Xmp.tiff.BitsPerSample XmpSeq 4 8, 8, 8, 8 8, 8, 8, 8 +Xmp.exif.ExifVersion XmpText 4 0220 2.20 +Xmp.exif.FlashpixVersion XmpText 4 0100 1.00 +Xmp.exif.ColorSpace XmpText 1 1 sRGB +Xmp.exif.CompressedBitsPerPixel XmpText 3 4/1 4/1 +Xmp.exif.PixelXDimension XmpText 3 200 200 +Xmp.exif.PixelYDimension XmpText 3 130 130 +Xmp.exif.DateTimeOriginal XmpText 25 2004-06-21T23:37:53+01:00 2004-06-21T23:37:53+01:00 +Xmp.exif.ExposureTime XmpText 5 1/125 1/125 +Xmp.exif.FNumber XmpText 3 5/1 F5 +Xmp.exif.ExposureProgram XmpText 1 1 Manual +Xmp.exif.ExposureBiasValue XmpText 3 1/3 +1/3 EV +Xmp.exif.MaxApertureValue XmpText 3 3/1 3/1 +Xmp.exif.MeteringMode XmpText 1 2 Center weighted average +Xmp.exif.LightSource XmpText 2 10 Cloudy weather +Xmp.exif.FocalLength XmpText 4 42/1 42.0 mm +Xmp.exif.SensingMethod XmpText 1 2 One-chip color area +Xmp.exif.FileSource XmpText 1 3 Digital still camera +Xmp.exif.SceneType XmpText 1 1 Directly photographed +Xmp.exif.CustomRendered XmpText 1 0 Normal process +Xmp.exif.ExposureMode XmpText 1 1 Manual +Xmp.exif.WhiteBalance XmpText 1 1 Manual +Xmp.exif.DigitalZoomRatio XmpText 3 1/1 1/1 +Xmp.exif.FocalLengthIn35mmFilm XmpText 2 63 63 +Xmp.exif.SceneCaptureType XmpText 1 0 Standard +Xmp.exif.GainControl XmpText 1 0 None +Xmp.exif.Contrast XmpText 1 0 Normal +Xmp.exif.Saturation XmpText 1 0 Normal +Xmp.exif.Sharpness XmpText 1 0 Normal +Xmp.exif.SubjectDistanceRange XmpText 1 0 Unknown +Xmp.exif.ImageUniqueID XmpText 32 127c1377b054a3f65bf2754ebb24e7f2 127c1377b054a3f65bf2754ebb24e7f2 +Xmp.exif.GPSVersionID XmpText 7 2.2.0.0 2.2.0.0 +Xmp.exif.NativeDigest XmpText 414 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;1AE366A6D482AC48AF09C3363A3B2183 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;1AE366A6D482AC48AF09C3363A3B2183 +Xmp.exif.ComponentsConfiguration XmpSeq 4 1, 2, 3, 0 YCbCr +Xmp.exif.Flash XmpText 13 type="Struct" type="Struct" diff --git a/test/data/test_reference_files/issue_94_poc3.pgf.out b/test/data/test_reference_files/issue_94_poc3.pgf.out index 5858d51873..383749b291 100644 --- a/test/data/test_reference_files/issue_94_poc3.pgf.out +++ b/test/data/test_reference_files/issue_94_poc3.pgf.out @@ -1,8 +1 @@ Warning: Removing 54 characters from the beginning of the XMP packet -Xmp.rdf.a0000 XmpText 0 -Xmp.tiff.S0000000 XmpText 36 000000000000000000000000000000000000 000000000000000000000000000000000000 -Xmp.tiff.I000000000 XmpText 3 000 000 -Xmp.tiff.I0000000000 XmpText 3 000 000 -Xmp.xap.C0000000000 XmpText 36 000000000000000000000000000000000000 000000000000000000000000000000000000 -Xmp.tiff.P00000000000000 XmpText 3 000 000 -Xmp.tiff.P0000000000000n XmpText 3 000 000 diff --git a/tests/bugfixes/github/test_issue_1901.py b/tests/bugfixes/github/test_issue_1901.py index 12076e8861..b69a006bcc 100644 --- a/tests/bugfixes/github/test_issue_1901.py +++ b/tests/bugfixes/github/test_issue_1901.py @@ -28,8 +28,9 @@ class XMPUtilsSetTimeZoneIntegerOverflow(metaclass=CaseMeta): """, """$filename3: No Exif data found in the file """, - "", + """$filename4: No Exif data found in the file +""", ] - retval = [253, 253, 253, 0] + retval = [253, 253, 253, 253] compare_stdout = check_no_ASAN_UBSAN_errors From 2f270fd5daa916699dff78d0463a661146459aa7 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:57:14 +0400 Subject: [PATCH 16/20] handle LangAlt encoding for aliased XMP properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XMP-Toolkit-SDK registers standard aliases like tiff:ImageDescription → dc:description[?xml:lang="x-default"] that resolve to a specific array item rather than the array itself. When XmpParser::encode() tried to call CountArrayItems or AppendArrayItem on such aliases, the SDK's internal path resolution found a simple value node (the x-default item) instead of an array node, causing "XMP Toolkit error 102: The named property is not an array" and crashing programs like xmpsample. Fix by detecting this situation with a try-catch around CountArrayItems. When the alias-to-array-item case is detected, fall back to SetProperty which correctly handles alias resolution for the x-default value. Other language variants are not representable through a single-value alias and belong on the canonical property (e.g. dc:description). --- src/xmp.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/xmp.cpp b/src/xmp.cpp index d73a0f2a42..d51442d4a3 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -854,6 +854,36 @@ int XmpParser::encode(std::string& xmpPacket, const XmpData& xmpData, uint16_t f if (!la) throw Error(ErrorCode::kerEncodeLangAltPropertyFailed, xmp.key()); + // XMP-Toolkit-SDK registers standard aliases (e.g. tiff:ImageDescription → + // dc:description[?xml:lang="x-default"]) that resolve to a specific array item + // rather than the array itself. Array operations like CountArrayItems and + // AppendArrayItem fail on such aliases because the SDK finds a simple value node + // instead of an array node. Detect this situation and fall back to SetProperty, + // which correctly handles alias resolution for the x-default value. + bool isArrayItemAlias = false; + try { + meta.CountArrayItems(ns.c_str(), xmp.tagName().c_str()); + } catch (const XMP_Error& e) { + if (e.GetID() == kXMPErr_BadXPath) + isArrayItemAlias = true; + else + throw; + } + + if (isArrayItemAlias) { + // Set only the x-default value through the alias (the SDK resolves it to + // the correct array item). Other language variants are not representable + // through a single-value alias; they belong on the canonical property. + auto it = la->value_.find("x-default"); + if (it == la->value_.end()) + it = la->value_.begin(); + if (it != la->value_.end() && !it->second.empty()) { + printNode(ns, xmp.tagName(), it->second, 0); + meta.SetProperty(ns.c_str(), xmp.tagName().c_str(), it->second.c_str()); + } + continue; + } + for (const auto& [lang, specs] : la->value_) { if (!specs.empty()) { // remove lang specs with no value printNode(ns, xmp.tagName(), specs, 0); From 7bc2efd8be1afa8a0db6fa957e2b9c50e96ecb78 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:57:33 +0400 Subject: [PATCH 17/20] =?UTF-8?q?update=20conversions=20test=20for=20tiff:?= =?UTF-8?q?Software=20=E2=86=92=20xmp:CreatorTool=20alias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new XMP-Toolkit-SDK resolves tiff:Software as an alias for xmp:CreatorTool. When Exif.Image.Software is converted to XMP, it now appears as Xmp.xmp.CreatorTool instead of Xmp.tiff.Software. The reverse conversion (XMP → Exif) no longer produces Exif.Image.Software because CreatorTool is not mapped back to the tiff namespace. Affects testcases 10 and 11 in the conversions bash test. --- test/data/test_reference_files/conversions.out | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/data/test_reference_files/conversions.out b/test/data/test_reference_files/conversions.out index f623318f43..851a6cf010 100644 --- a/test/data/test_reference_files/conversions.out +++ b/test/data/test_reference_files/conversions.out @@ -80,15 +80,13 @@ Iptc.Application2.Keywords String 11 Rock'n'roll Testcase 10 =========== Exif.Image.Software Ascii 6 Exiv2 -Xmp.tiff.Software XmpText 5 Exiv2 -Exif.Image.Software Ascii 6 Exiv2 +Xmp.xmp.CreatorTool XmpText 5 Exiv2 File 1/1: q.xmp q.xmp: No IPTC data found in the file Testcase 11 =========== -Xmp.tiff.Software XmpText 5 Exiv2 -Exif.Image.Software Ascii 6 Exiv2 +Xmp.xmp.CreatorTool XmpText 5 Exiv2 File 1/1: r.jpg r.jpg: No IPTC data found in the file From 41bd25007a7d29bce870a412fb38c4bcc6a39979 Mon Sep 17 00:00:00 2001 From: Sergey Hovakimyan Date: Thu, 12 Feb 2026 20:57:47 +0400 Subject: [PATCH 18/20] update stdin and webp tests for shorter XMP toolkit version string The XMP toolkit version string changed from "XMP Core 4.4.0-Exiv2" (20 chars) to "XMP Core 6.0.0" (14 chars), making every serialized XMP packet 6 bytes smaller. This shifts JPEG APP1 segment sizes and offsets in the stdin test, and RIFF container / XMP chunk sizes in the webp test. No semantic change to the metadata content. --- test/data/issue_1998.xmp | 2 +- test/data/test_reference_files/stdin-test.out | 90 +++++++++---------- test/data/test_reference_files/webp-test.out | 36 ++++---- 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/test/data/issue_1998.xmp b/test/data/issue_1998.xmp index c1b84fa44d..3492be7c51 100644 --- a/test/data/issue_1998.xmp +++ b/test/data/issue_1998.xmp @@ -1,5 +1,5 @@ - + ..?.Nw..iN......xE....z..[..} | 0x054b9d1e - 52121 | IDAT | 7066 | ...q.B...2*@..#....T....h..v.. | 0x327f1e3e - 59199 | IEND | 0 | | 0xae426082 + 11812 | iTXt | 7057 | XML:com.adobe.xmp.......?.Nw..iN......xE....z..[..} | 0x054b9d1e + 52061 | IDAT | 7066 | ...q.B...2*@..#....T....h..v.. | 0x327f1e3e + 59139 | IEND | 0 | | 0xae426082 STRUCTURE OF WEBP FILE: exiv2-bug1199.webp Chunk | Length | Offset | Payload - RIFF | 190110 | 0 | WEBP + RIFF | 190104 | 0 | WEBP VP8X | 10 | 12 | ,........ ICCP | 3144 | 30 | ...HLino....mntrRGB XYZ ........ VP8 | 172008 | 3182 | .G...*.. .>1..B.!..o.. ......].. EXIF | 12040 | 175198 | II*........................... . - XMP | 2864 | 187246 | 1..B.!..o.. ......].. EXIF | 12040 | 172046 | II*........................... . - XMP | 2864 | 184094 | 1..B.!..o.. ......].. - XMP | 2864 | 172614 | 1..B.!..o.. ......].. - XMP | 2864 | 172046 | 1..B.!..o.. ......].. EXIF | 12040 | 175198 | II*........................... . - XMP | 2864 | 187246 | 1..B.!..o.. ......].. EXIF | 12040 | 172614 | II*........................... . - XMP | 2864 | 184662 | 1..B.!..o.. ......].. EXIF | 12040 | 172614 | II*........................... . - XMP | 4661 | 184662 | 1..B.!..o.. ......].. EXIF | 12040 | 172614 | II*........................... . - XMP | 3407 | 184662 | 1..B.!..o.. ......].. EXIF | 12040 | 172614 | II*........................... . - XMP | 1679484 | 184662 | 1..B.!..o.. ......].. EXIF | 12198 | 172614 | II*............................. - XMP | 2864 | 184820 | Date: Thu, 12 Feb 2026 20:58:17 +0400 Subject: [PATCH 19/20] update xmpparser test for new SDK version, prefixes, and alias handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three types of changes in the xmpparser bash test reference: 1. Version string: "XMP Core 4.4.0-Exiv2" → "XMP Core 6.0.0" in all serialized XMP packets (4 occurrences). 2. Namespace prefix modernization: the new SDK re-serializes the BlueSquare.xmp file using modern prefixes (xap → xmp, xapMM → xmpMM, xapRights → xmpRights), which changes the diff output between the original and round-tripped file. 3. xmpsample alias resolution: tiff:ImageDescription is now resolved through its alias to dc:description[?xml:lang="x-default"]. The tiff:ImageDescription property no longer appears as a separate element in the serialized XMP, and dc:description's x-default value reflects the alias write. --- .../test_reference_files/xmpparser-test.out | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/test/data/test_reference_files/xmpparser-test.out b/test/data/test_reference_files/xmpparser-test.out index 983f13ab26..85598898e5 100644 --- a/test/data/test_reference_files/xmpparser-test.out +++ b/test/data/test_reference_files/xmpparser-test.out @@ -31,7 +31,7 @@ Xmp.exif.NativeDigest XmpText 414 36864,40960,40961,37 2c2 < --- -> +> 35d34 < Blue Square Test File - .jpg 36a36 @@ -144,13 +144,56 @@ Xmp.wine.Recommend XmpText 5 False 2c2 < --- -> +> 4c4 < xapMM:InstanceID="uuid:0f410644-9396-11d9-bb8e-a67e6693b6e9" +9,2c9,2 +< xmlns:xap="http://ns.adobe.com/xap/1.0/" +< xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/" +--- +> xmlns:xmp="http://ns.adobe.com/xap/1.0/" +> xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" +12c12 +< xmlns:xapRights="http://ns.adobe.com/xap/1.0/rights/" +--- +> xmlns:xmpRights="http://ns.adobe.com/xap/1.0/rights/" +42,7c42,8 +< xap:CreateDate="2005-03-13T02:01:44-06:00" +< xap:ModifyDate="2005-03-13T02:01:44-06:00" +< xap:MetadataDate="2007-01-08T13:25:45+01:00" +< xap:CreatorTool="Adobe Photoshop CS Windows" +< xapMM:DocumentID="adobe:docid:photoshop:0f410643-9396-11d9-bb8e-a67e6693b6e9" +< xapRights:WebStatement="http://www.bignewspaper.com/" +< xapRights:Marked="True" +--- +> xmp:CreateDate="2005-03-13T02:01:44-06:00" +> xmp:ModifyDate="2005-03-13T02:01:44-06:00" +> xmp:MetadataDate="2007-01-08T13:25:45+01:00" +> xmp:CreatorTool="Adobe Photoshop CS Windows" +> xmpMM:DocumentID="adobe:docid:photoshop:0f410643-9396-11d9-bb8e-a67e6693b6e9" +> xmpMM:InstanceID="uuid:0f410644-9396-11d9-bb8e-a67e6693b6e9" +> xmpRights:WebStatement="http://www.bignewspaper.com/" +> xmpRights:Marked="True" +78c79 +< +--- +> +85,2c86,2 +< +< +--- +> +> +90c91 +< +--- +> 160,191c161 < < @@ -258,7 +301,7 @@ Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field2 XmpText 12 < --- > -> +> > > xmlns:ns1="ns:test1/" @@ -353,12 +396,11 @@ Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity XmpText 12 Kuala Lumpur Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCtry XmpText 8 Malaysia Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork XmpText 20 http://www.exiv2.org - + - Hello, World + TIFF image description Hallo, Welt @@ -410,12 +452,6 @@ Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork XmpText 20 http://www.exi - - - TIFF image description - TIFF Bildbeschreibung - - Date: Fri, 13 Feb 2026 13:00:21 +0400 Subject: [PATCH 20/20] add submodule check for XMP-Toolkit-SDK at configure time Fresh clones without --recurse-submodules would fail with cryptic source-file-not-found errors. Add an explicit check for the SDK's presence in both CMake and Meson, with a clear error message telling the user to run git submodule update --init --recursive. --- xmpsdk/CMakeLists.txt | 6 ++++++ xmpsdk/meson.build | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/xmpsdk/CMakeLists.txt b/xmpsdk/CMakeLists.txt index 299e9deddf..8e99b1e188 100644 --- a/xmpsdk/CMakeLists.txt +++ b/xmpsdk/CMakeLists.txt @@ -1,3 +1,9 @@ +if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/XMP-Toolkit-SDK/public/include/XMP_Const.h") + message(FATAL_ERROR + "XMP-Toolkit-SDK submodule not found. Please run:\n" + " git submodule update --init --recursive") +endif() + add_library( exiv2-xmp OBJECT XMP-Toolkit-SDK/public/include/XMP_Const.h diff --git a/xmpsdk/meson.build b/xmpsdk/meson.build index 2424720ccf..0d099fb8d5 100644 --- a/xmpsdk/meson.build +++ b/xmpsdk/meson.build @@ -6,6 +6,12 @@ endif sdk = 'XMP-Toolkit-SDK' +fs = import('fs') +if not fs.is_file(sdk / 'public' / 'include' / 'XMP_Const.h') + error('XMP-Toolkit-SDK submodule not found. Please run:\n' + + ' git submodule update --init --recursive') +endif + # The SDK includes expat as "third-party/expat/lib/expat.h". # A wrapper header at xmpsdk/third-party/expat/lib/expat.h redirects # this to the system expat via #include_next.