summaryrefslogtreecommitdiff
path: root/XMPFiles
diff options
context:
space:
mode:
authorHubert Figuière <hub@figuiere.net>2016-12-07 00:25:52 -0500
committerHubert Figuière <hub@figuiere.net>2016-12-07 00:29:32 -0500
commit1696cff2133f0eab1fea45c164cb771a6e5e4526 (patch)
treed526dab08731fd8f6a4978b67df6e788979b567c /XMPFiles
parent93571bfffb172a92f602de38a615902c52da111a (diff)
parent6071af09b5e263b63e57b28ab8a78484bc65e3fe (diff)
Merge branch 'adobe-sdk' into integration
Merge Adobe SDK CC 2016.07
Diffstat (limited to 'XMPFiles')
-rw-r--r--XMPFiles/build/CMakeLists.txt3
-rw-r--r--XMPFiles/build/CMakeListsCommon.txt100
-rw-r--r--XMPFiles/resource/ios/expat_config.h107
-rw-r--r--XMPFiles/resource/linux/expat_config.h120
-rw-r--r--XMPFiles/resource/mac/expat_config.h107
-rw-r--r--XMPFiles/resource/win/expat_config.h99
-rw-r--r--XMPFiles/source/FileHandlers/GIF_Handler.cpp395
-rw-r--r--XMPFiles/source/FileHandlers/GIF_Handler.hpp50
-rw-r--r--XMPFiles/source/FileHandlers/JPEG_Handler.cpp7
-rw-r--r--XMPFiles/source/FileHandlers/MP3_Handler.cpp16
-rw-r--r--XMPFiles/source/FileHandlers/MP3_Handler.hpp5
-rw-r--r--XMPFiles/source/FileHandlers/MPEG4_Handler.cpp29
-rw-r--r--XMPFiles/source/FileHandlers/P2_Handler.cpp80
-rw-r--r--XMPFiles/source/FileHandlers/P2_Handler.hpp1
-rw-r--r--XMPFiles/source/FileHandlers/PSD_Handler.cpp3
-rw-r--r--XMPFiles/source/FileHandlers/PostScript_Handler.cpp6
-rw-r--r--XMPFiles/source/FileHandlers/RIFF_Handler.cpp3
-rw-r--r--XMPFiles/source/FileHandlers/RIFF_Handler.hpp3
-rw-r--r--XMPFiles/source/FileHandlers/SVG_Handler.cpp689
-rw-r--r--XMPFiles/source/FileHandlers/SVG_Handler.hpp76
-rw-r--r--XMPFiles/source/FileHandlers/TIFF_Handler.cpp3
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp8
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMFAM_Handler.cpp677
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp71
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMSAM_Handler.cpp429
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp58
-rw-r--r--XMPFiles/source/FileHandlers/XDCAM_Handler.cpp1013
-rw-r--r--XMPFiles/source/FileHandlers/XDCAM_Handler.hpp60
-rw-r--r--XMPFiles/source/FormatSupport/ID3_Support.cpp64
-rw-r--r--XMPFiles/source/FormatSupport/ID3_Support.hpp2
-rw-r--r--XMPFiles/source/FormatSupport/IPTC_Support.cpp56
-rw-r--r--XMPFiles/source/FormatSupport/IPTC_Support.hpp2
-rw-r--r--XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp40
-rw-r--r--XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp16
-rw-r--r--XMPFiles/source/FormatSupport/MOOV_Support.cpp39
-rw-r--r--XMPFiles/source/FormatSupport/MOOV_Support.hpp31
-rw-r--r--XMPFiles/source/FormatSupport/RIFF.cpp27
-rw-r--r--XMPFiles/source/FormatSupport/RIFF.hpp1
-rw-r--r--XMPFiles/source/FormatSupport/RIFF_Support.cpp356
-rw-r--r--XMPFiles/source/FormatSupport/ReconcileIPTC.cpp28
-rw-r--r--XMPFiles/source/FormatSupport/ReconcileTIFF.cpp16
-rw-r--r--XMPFiles/source/FormatSupport/SVG_Adapter.cpp464
-rw-r--r--XMPFiles/source/FormatSupport/SVG_Adapter.hpp79
-rw-r--r--XMPFiles/source/FormatSupport/TIFF_FileWriter.cpp21
-rw-r--r--XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp51
-rw-r--r--XMPFiles/source/FormatSupport/TIFF_Support.hpp19
-rw-r--r--XMPFiles/source/FormatSupport/TimeConversionUtils.hpp5
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/CartMetadata.h8
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp6
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp69
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp189
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h35
-rw-r--r--XMPFiles/source/FormatSupport/XMPScanner.cpp12
-rw-r--r--XMPFiles/source/HandlerRegistry.cpp12
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IMetadata.h2
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IReconcile.h1
-rw-r--r--XMPFiles/source/NativeMetadataSupport/ValueObject.h12
-rw-r--r--XMPFiles/source/PluginHandler/FileHandlerInstance.cpp131
-rw-r--r--XMPFiles/source/PluginHandler/FileHandlerInstance.h2
-rw-r--r--XMPFiles/source/PluginHandler/HostAPIImpl.cpp477
-rw-r--r--XMPFiles/source/PluginHandler/ModuleUtils.h1
-rw-r--r--XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp24
-rw-r--r--XMPFiles/source/PluginHandler/PluginManager.cpp7
-rw-r--r--XMPFiles/source/PluginHandler/PluginManager.h31
-rw-r--r--XMPFiles/source/WXMPFiles.cpp3
-rw-r--r--XMPFiles/source/XMPFiles.cpp197
-rw-r--r--XMPFiles/source/XMPFiles.hpp19
-rw-r--r--XMPFiles/source/XMPFiles_Impl.cpp7
-rw-r--r--XMPFiles/source/XMPFiles_Impl.hpp20
69 files changed, 5299 insertions, 1501 deletions
diff --git a/XMPFiles/build/CMakeLists.txt b/XMPFiles/build/CMakeLists.txt
index 76bdae0..2bd632d 100644
--- a/XMPFiles/build/CMakeLists.txt
+++ b/XMPFiles/build/CMakeLists.txt
@@ -9,7 +9,7 @@
# ==============================================================================
# define minimum cmake version
-cmake_minimum_required(VERSION 2.8.6)
+cmake_minimum_required(VERSION 3.5.2)
# Enable folder grouping of projects in IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -41,6 +41,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/${XMP_THIS_PROJECT_RELATIVEPATH}/build/XMP_C
set(TP_ZUID_PATH "${XMPROOT_DIR}/third-party/zuid/interfaces")
+set(TP_EXPAT_PATH "${PROJECT_ROOT}/../../third-party/expat/lib/")
set(LIB_ADOBEXMP XMPCore)
# ==============================================================================
diff --git a/XMPFiles/build/CMakeListsCommon.txt b/XMPFiles/build/CMakeListsCommon.txt
index 2f116d0..234d0d0 100644
--- a/XMPFiles/build/CMakeListsCommon.txt
+++ b/XMPFiles/build/CMakeListsCommon.txt
@@ -22,7 +22,6 @@ source_group("Header Files\\Internal Headers\\Common Code" FILES ${INTERNAL_HEAD
file (GLOB INTERNAL_HEADER_FILEHANDLERS ${SOURCE_ROOT}/FileHandlers/*.hpp)
list (REMOVE_ITEM INTERNAL_HEADER_FILEHANDLERS
${SOURCE_ROOT}/FileHandlers/AIFF_Handler.hpp
- ${SOURCE_ROOT}/FileHandlers/GIF_Handler.hpp
)
source_group("Header Files\\Internal Headers\\File Handlers" FILES ${INTERNAL_HEADER_FILEHANDLERS})
@@ -36,9 +35,7 @@ file (GLOB INTERNAL_HEADER_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/
source_group("Header Files\\Internal Headers\\Format Support\\WAVE" FILES ${INTERNAL_HEADER_FORMATSUPPORT_WAVE})
file (GLOB INTERNAL_HEADER_FORMATSUPPORT ${SOURCE_ROOT}/FormatSupport/*.hpp)
-list (REMOVE_ITEM INTERNAL_HEADER_FORMATSUPPORT
- ${SOURCE_ROOT}/FormatSupport/GIF_Support.hpp
- )
+
list (REMOVE_ITEM INTERNAL_HEADER_FORMATSUPPORT
# ${SOURCE_ROOT}/source/MD5.cpp
${XMPROOT_DIR}/source/UnicodeConversions.cpp
@@ -74,6 +71,14 @@ list (REMOVE_ITEM HEADERFILES_THIRDPARTY_ZLIB
)
source_group("Header Files\\ThirdParty\\zlib" FILES ${HEADERFILES_THIRDPARTY_ZLIB})
+list (APPEND FILES_THIRDPARTY_EXPAT
+ ${TP_EXPAT_PATH}/xmlparse.c
+ ${TP_EXPAT_PATH}/xmlrole.c
+ ${TP_EXPAT_PATH}/xmltok.c
+ )
+list (APPEND FILES_THIRDPARTY_EXPAT ${RESOURCE_ROOT}/../../XMPCore/resource/${XMP_PLATFORM_SHORT}/expat_config.h)
+source_group("Source Files\\ThirdParty\\expat" FILES ${FILES_THIRDPARTY_EXPAT})
+
list (APPEND HEADERFILES
${XMPROOT_DIR}/source/Host_IO.hpp
${XMPROOT_DIR}/source/XIO.hpp
@@ -120,9 +125,7 @@ file (GLOB SOURCEFILES_FILEHANDLERS ${SOURCE_ROOT}/FileHandlers/*.cpp)
list (APPEND SOURCEFILES_FILEHANDLERS
${SOURCE_ROOT}/FileHandlers/AIFF_Handler.hpp
)
-list (REMOVE_ITEM SOURCEFILES_FILEHANDLERS
- ${SOURCE_ROOT}/FileHandlers/GIF_Handler.cpp
- )
+
source_group("Source Files\\File Handlers" FILES ${SOURCEFILES_FILEHANDLERS})
file (GLOB SOURCEFILES_FORMATSUPPORT_AIFF ${SOURCE_ROOT}/FormatSupport/AIFF/*.cpp)
@@ -135,9 +138,7 @@ file (GLOB SOURCEFILES_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/*.cp
source_group("Source Files\\Format Support\\WAVE" FILES ${SOURCEFILES_FORMATSUPPORT_WAVE})
file (GLOB SOURCEFILES_FORMATSUPPORT ${SOURCE_ROOT}/FormatSupport/*.cpp)
-list (REMOVE_ITEM SOURCEFILES_FORMATSUPPORT
- ${SOURCE_ROOT}/FormatSupport/GIF_Support.cpp
- )
+
source_group("Source Files\\Format Support" FILES ${SOURCEFILES_FORMATSUPPORT})
if (NOT APPLE_IOS)
@@ -160,6 +161,13 @@ if (NOT APPLE_IOS)
source_group("Source Files\\PluginHandler" FILES ${SOURCEFILES_PLUGINHANDLER})
endif()
+#Core & Common public source files
+file (GLOB PUBLIC_XMPCOMMON_CLIENTGLUE_FILES ${XMPROOT_DIR}/public/include/XMPCommon/source/*.*)
+source_group("Source Files\\Public\\XMPCommon" FILES ${PUBLIC_XMPCOMMON_CLIENTGLUE_FILES})
+
+file (GLOB PUBLIC_XMPCORE_CLIENTGLUE_FILES ${XMPROOT_DIR}/public/include/XMPCore/source/*.*)
+source_group("Source Files\\Public\\XMPCore" FILES ${PUBLIC_XMPCORE_CLIENTGLUE_FILES})
+
list (APPEND HEADERFILES_THIRDPARTY_ZLIB
${XMPROOT_DIR}/third-party/zlib/adler32.c
${XMPROOT_DIR}/third-party/zlib/compress.c
@@ -197,13 +205,17 @@ list(APPEND SOURCE_FILES
${SOURCEFILES_FORMATSUPPORT_WAVE}
${SOURCEFILES_FORMATSUPPORT}
${SOURCEFILES_PLUGINHANDLER}
+ ${PUBLIC_XMPCOMMON_CLIENTGLUE_FILES}
+ ${PUBLIC_XMPCORE_CLIENTGLUE_FILES}
${HEADERFILES_THIRDPARTY_ZLIB}
+ ${FILES_THIRDPARTY_EXPAT}
)
# include directories
include_directories(${XMPROOT_DIR})
include_directories(${XMPROOT_DIR}/public/include)
-include_directories(${XMPROOT_DIR}/third-party/expat/zlib)
+include_directories(${TP_EXPAT_PATH})
+include_directories(${XMPROOT_DIR}/third-party/expat/public/lib)
include_directories(${XMPROOT_DIR}/XMPFilesPlugins/api/source)
include_directories(${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT})
@@ -214,25 +226,47 @@ link_directories(${OUTPUT_DIR})
# Define what to do, lib, exe, etc
if (UNIX AND APPLE AND NOT ${XMP_BUILD_STATIC})
# preprocess Info.plist
- add_custom_target(${TARGET_NAME}InfoPlist
- COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
- COMMAND if [ $(CONFIGURATION) != Debug ]; then
- ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.plist
- -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
- -DPRODUCT_NAME=${TARGET_NAME} -DMAC_ENV=1 -DNDEBUG=1
- -include ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}PList.h
- -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
- \; else
- ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.plist
- -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
- -DPRODUCT_NAME=${TARGET_NAME} -DMAC_ENV=1 -DDEBUG=1
- -include ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}PList.h
- -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
- \; fi
- COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
- COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
- COMMENT "Preprocessing Info-plist"
- )
+ if(NOT APPLE_IOS)
+ add_custom_target(${TARGET_NAME}InfoPlist
+ COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+ COMMAND if [ $(CONFIGURATION) != Debug ]; then
+ ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.plist
+ -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ -DPRODUCT_NAME=${TARGET_NAME} -DMAC_ENV=1 -DNDEBUG=1
+ -include ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}PList.h
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
+ \; else
+ ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.plist
+ -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ -DPRODUCT_NAME=${TARGET_NAME} -DMAC_ENV=1 -DDEBUG=1
+ -include ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}PList.h
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
+ \; fi
+ COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
+ COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
+ COMMENT "Preprocessing Info-plist"
+ )
+ else()
+ add_custom_target(${TARGET_NAME}InfoPlist
+ COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+ COMMAND if [ $(CONFIGURATION) != Debug ]; then
+ ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/ios/${TARGET_NAME}.plist
+ -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ -DPRODUCT_NAME=${TARGET_NAME} -DIOS_ENV=1 -DNDEBUG=1
+ -include ${RESOURCE_ROOT}/ios/${TARGET_NAME}PList.h
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
+ \; else
+ ${GCCTOOL} -E -P -x c ${RESOURCE_ROOT}/ios/${TARGET_NAME}.plist
+ -F${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ -DPRODUCT_NAME=${TARGET_NAME} -DIOS_ENV=1 -DDEBUG=1
+ -include ${RESOURCE_ROOT}/ios/${TARGET_NAME}PList.h
+ -o ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist
+ \; fi
+ COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
+ COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../CMakeFiles/${TARGET_NAME}.dir/Info.plist
+ COMMENT "Preprocessing Info-plist"
+ )
+ endif()
set(DEPENDENCY_LIST "ALL:${TARGET_NAME}InfoPlist" "DLL:XMPCore")
else ()
set(DEPENDENCY_LIST "DLL:XMPCore")
@@ -258,13 +292,17 @@ else(WIN32)
endif()
endif()
-set(FRAMEWORK_LIST "Mac:CoreFoundation" "Mac:CoreServices" "Mac:${LIB_ADOBEXMP}" "Mac:${XMP_PLATFORM_LINK}")
+set(FRAMEWORK_LIST "ALL:CoreFoundation" "Mac:CoreServices" "ALL:${LIB_ADOBEXMP}" "ALL:${XMP_PLATFORM_LINK}")
AddMacFramework(${TARGET_NAME} FRAMEWORK_LIST)
if(UNIX)
if (NOT APPLE)
SetPlatformLinkFlags(${TARGET_NAME} "-Xlinker --version-script -Xlinker \"${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.exp\"" "")
else()
+ if(APPLE_IOS AND NOT XMP_BUILD_STATIC)
+ set_target_properties(${TARGET_NAME} PROPERTIES XCODE_ATTRIBUTE_DYLIB_INSTALL_NAME_BASE "@rpath")
+ set_target_properties(${TARGET_NAME} PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.adobe.Adobe${TARGET_NAME}")
+ endif()
set_target_properties(${TARGET_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH ON INSTALL_NAME_DIR "@executable_path/../Frameworks")
SetPlatformLinkFlags(${TARGET_NAME} "-exported_symbols_list \"${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.exp\"" "${XMPFILES_LIB}")
endif()
diff --git a/XMPFiles/resource/ios/expat_config.h b/XMPFiles/resource/ios/expat_config.h
new file mode 100644
index 0000000..a21de6e
--- /dev/null
+++ b/XMPFiles/resource/ios/expat_config.h
@@ -0,0 +1,107 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Xcode builds on PowerPC and x86 */
+
+#if __BIG_ENDIAN__
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 4321
+
+ /* whether byteorder is bigendian */
+ #define WORDS_BIGENDIAN 1
+
+#else
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 1234
+
+ /* whether byteorder is bigendian */
+ /* #define WORDS_BIGENDIAN 1 */
+
+#endif
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/XMPFiles/resource/linux/expat_config.h b/XMPFiles/resource/linux/expat_config.h
new file mode 100644
index 0000000..7d147e7
--- /dev/null
+++ b/XMPFiles/resource/linux/expat_config.h
@@ -0,0 +1,120 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for generic UNIX builds **** */
+
+#ifdef WORDS_BIGENDIAN
+ #error "WORDS_BIGENDIAN must be initially undefined"
+#endif
+
+#if TargetOS == i80386linux
+ /* #undef WORDS_BIGENDIAN */
+ #define HAVE_MMAP 1
+ #define HAVE_STDINT_H 1
+ /* #undef const */
+#elif TargetOS == sparcsolaris
+ #define WORDS_BIGENDIAN 1
+ #define HAVE_MMAP 1
+ /* #undef HAVE_STDINT_H */
+ /* #undef const */
+#elif TargetOS == rs60000aix
+ #define WORDS_BIGENDIAN 1
+ /* #undef HAVE_MMAP */
+ /* #undef HAVE_STDINT_H */
+ /* #undef const */
+#elif TargetOS == hppahpux
+ #define WORDS_BIGENDIAN 1
+ /* #undef HAVE_MMAP */
+ /* #undef HAVE_STDINT_H */
+ #define const
+#elif TargetOS == ia64hpux
+ #define WORDS_BIGENDIAN 1
+ /* #undef HAVE_MMAP */
+ /* #undef HAVE_STDINT_H */
+ #define const
+#else
+ #error "Unknown target OS"
+#endif
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#if WORDS_BIGENDIAN
+ #define BYTEORDER 4321
+#else
+ #define BYTEORDER 1234
+#endif
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/XMPFiles/resource/mac/expat_config.h b/XMPFiles/resource/mac/expat_config.h
new file mode 100644
index 0000000..a21de6e
--- /dev/null
+++ b/XMPFiles/resource/mac/expat_config.h
@@ -0,0 +1,107 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Xcode builds on PowerPC and x86 */
+
+#if __BIG_ENDIAN__
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 4321
+
+ /* whether byteorder is bigendian */
+ #define WORDS_BIGENDIAN 1
+
+#else
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 1234
+
+ /* whether byteorder is bigendian */
+ /* #define WORDS_BIGENDIAN 1 */
+
+#endif
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/XMPFiles/resource/win/expat_config.h b/XMPFiles/resource/win/expat_config.h
new file mode 100644
index 0000000..e6d2f63
--- /dev/null
+++ b/XMPFiles/resource/win/expat_config.h
@@ -0,0 +1,99 @@
+#if WIN_ENV
+ #pragma warning ( disable : 4244 ) // possible loss of data (temporary for 64 bit builds)
+#endif
+
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Windows builds */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 1234
+
+/* Define to 1 if you have the `bcopy' function. */
+/* #define HAVE_BCOPY 1 */
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #define HAVE_DLFCN_H 1 */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+/* #define HAVE_FCNTL_H 1 */
+
+/* Define to 1 if you have the `getpagesize' function. */
+/* #define HAVE_GETPAGESIZE 1 */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #define HAVE_INTTYPES_H 1 */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+/* #define HAVE_MMAP 1 */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #define HAVE_STDINT_H 1 */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #define HAVE_STRINGS_H 1 */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+/* #define HAVE_SYS_STAT_H 1 */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+/* #define HAVE_SYS_TYPES_H 1 */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #define HAVE_UNISTD_H 1 */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* whether byteorder is bigendian */
+/* #define WORDS_BIGENDIAN 1 */
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/XMPFiles/source/FileHandlers/GIF_Handler.cpp b/XMPFiles/source/FileHandlers/GIF_Handler.cpp
index 39090ea..ded9954 100644
--- a/XMPFiles/source/FileHandlers/GIF_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/GIF_Handler.cpp
@@ -1,20 +1,23 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 Adobe Systems Incorporated
+// Copyright 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.
+//
+// This file includes implementation of GIF file metadata, according to GIF89a Specification.
+// https://www.w3.org/Graphics/GIF/spec-gif89a.txt
+// The Graphics Interchange Format(c) is the Copyright property of CompuServe Incorporated.
+// GIF(sm) is a Service Mark property of CompuServe Incorporated.
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
//
-// Derived from PNG_Handler.cpp by Ian Jacobi
// =================================================================================================
-#include "GIF_Handler.hpp"
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "XMPFiles/source/FileHandlers/GIF_Handler.hpp"
#include "source/XIO.hpp"
-#include "XMPFiles/source/FormatSupport/GIF_Support.hpp"
-
-using namespace std;
// =================================================================================================
/// \file GIF_Handler.hpp
@@ -34,24 +37,32 @@ XMPFileHandler * GIF_MetaHandlerCTor ( XMPFiles * parent )
} // GIF_MetaHandlerCTor
+#define GIF_89_Header_LEN 6
+#define GIF_89_Header_DATA "\x47\x49\x46\x38\x39\x61" // must be GIF89a, nothing else as XMP is supported only in 89a version
+
+#define APP_ID_LEN 11
+#define XMP_APP_ID_DATA "\x58\x4D\x50\x20\x44\x61\x74\x61\x58\x4D\x50"
+
+#define MAGIC_TRAILER_LEN 258
+
// =================================================================================================
// GIF_CheckFormat
// ===============
bool GIF_CheckFormat ( XMP_FileFormat format,
XMP_StringPtr filePath,
- XMP_IO* fileRef,
+ XMP_IO* fileRef,
XMPFiles * parent )
{
IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent);
XMP_Assert ( format == kXMP_GIFFile );
- IOBuffer ioBuf;
+ if ( fileRef->Length() < GIF_89_Header_LEN ) return false;
+ XMP_Uns8 buffer[ GIF_89_Header_LEN ];
fileRef->Rewind();
- if ( ! CheckFileSpace ( fileRef, &ioBuf, GIF_SIGNATURE_LEN ) ) return false; // We need at least 3, so the buffer is not filled.
-
- if ( ! CheckBytes ( ioBuf.ptr, GIF_SIGNATURE_DATA, GIF_SIGNATURE_LEN ) ) return false;
+ fileRef->Read( buffer, GIF_89_Header_LEN );
+ if ( !CheckBytes( buffer, GIF_89_Header_DATA, GIF_89_Header_LEN ) ) return false;
return true;
@@ -61,12 +72,12 @@ bool GIF_CheckFormat ( XMP_FileFormat format,
// GIF_MetaHandler::GIF_MetaHandler
// ==================================
-GIF_MetaHandler::GIF_MetaHandler ( XMPFiles * _parent )
+GIF_MetaHandler::GIF_MetaHandler( XMPFiles * _parent ) : XMPPacketOffset( 0 ), XMPPacketLength( 0 ), trailerOffset( 0 )
{
this->parent = _parent;
this->handlerFlags = kGIF_HandlerFlags;
// It MUST be UTF-8.
- this->stdCharForm = kXMP_Char8Bit;
+ this->stdCharForm = kXMP_Char8Bit;
}
@@ -84,52 +95,31 @@ GIF_MetaHandler::~GIF_MetaHandler()
void GIF_MetaHandler::CacheFileData()
{
-
this->containsXMP = false;
- XMP_IO* fileRef ( this->parent->ioRef );
- if ( fileRef == 0) return;
-
- // We try to navigate through the blocks to find the XMP block.
- GIF_Support::BlockState blockState;
- long numBlocks = GIF_Support::OpenGIF ( fileRef, blockState );
- if ( numBlocks == 0 ) return;
+ XMP_IO * fileRef = this->parent->ioRef;
- if (blockState.xmpLen != 0)
+ // Try to navigate through the blocks to find the XMP block.
+ if ( this->ParseGIFBlocks( fileRef ) )
{
- // XMP present
+ // XMP packet present
+ this->xmpPacket.assign( XMPPacketLength, ' ' );
- this->xmpPacket.reserve(blockState.xmpLen);
- this->xmpPacket.assign(blockState.xmpLen, ' ');
+ // 13 bytes for the block size and 2 bytes for Extension ID and Label
+ this->SeekFile( fileRef, XMPPacketOffset, kXMP_SeekFromStart );
+ fileRef->ReadAll( ( void* )this->xmpPacket.data(), XMPPacketLength );
- if (GIF_Support::ReadBuffer ( fileRef, blockState.xmpPos, blockState.xmpLen, const_cast<char *>(this->xmpPacket.data()) ))
- {
- this->packetInfo.offset = blockState.xmpPos;
- this->packetInfo.length = blockState.xmpLen;
- this->containsXMP = true;
- }
- }
- else
- {
- // no XMP
+ this->packetInfo.offset = XMPPacketOffset;
+ this->packetInfo.length = XMPPacketLength;
+ this->containsXMP = true;
}
+ // else no XMP
} // GIF_MetaHandler::CacheFileData
// =================================================================================================
-// GIF_MetaHandler::ProcessTNail
-// ==============================
-
-void GIF_MetaHandler::ProcessTNail()
-{
-
- XMP_Throw ( "GIF_MetaHandler::ProcessTNail isn't implemented yet", kXMPErr_Unimplemented );
-
-} // GIF_MetaHandler::ProcessTNail
-
-// =================================================================================================
// GIF_MetaHandler::ProcessXMP
-// ============================
+// ===========================
//
// Process the raw XMP and legacy metadata that was previously cached.
@@ -140,10 +130,10 @@ void GIF_MetaHandler::ProcessXMP()
// Process the XMP packet.
if ( ! this->xmpPacket.empty() ) {
-
+
XMP_Assert ( this->containsXMP );
XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = this->xmpPacket.size();
+ XMP_StringLen packetLen = (XMP_StringLen) this->xmpPacket.size();
this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
@@ -154,111 +144,280 @@ void GIF_MetaHandler::ProcessXMP()
} // GIF_MetaHandler::ProcessXMP
// =================================================================================================
-// GIF_MetaHandler::UpdateFile
-// ============================
+// GIF_MetaHandler::ParseGIFBlocks
+// ===========================
-void GIF_MetaHandler::UpdateFile ( bool doSafeUpdate )
+bool GIF_MetaHandler::ParseGIFBlocks( XMP_IO* fileRef )
{
- bool updated = false;
-
- if ( ! this->needsUpdate ) return;
- if ( doSafeUpdate ) XMP_Throw ( "GIF_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
-
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = xmpPacket.size();
- if ( packetLen == 0 ) return;
+ fileRef->Rewind();
- XMP_IO* fileRef(this->parent->ioRef);
- if ( fileRef == 0 ) return;
+ // Checking for GIF header
+ XMP_Uns8 buffer[ GIF_89_Header_LEN ];
- GIF_Support::BlockState blockState;
- long numBlocks = GIF_Support::OpenGIF ( fileRef, blockState );
- if ( numBlocks == 0 ) return;
+ fileRef->Read( buffer, GIF_89_Header_LEN );
+ XMP_Enforce( memcmp( buffer, GIF_89_Header_DATA, GIF_89_Header_LEN ) == 0 );
- // write/update block(s)
- if (blockState.xmpLen == 0)
+ bool IsXMPExists = false;
+ bool IsTrailerExists = false;
+
+ ReadLogicalScreenDesc( fileRef );
+
+ // Parsing rest of the blocks
+ while ( fileRef->Offset() != fileRef->Length() )
{
- // no current chunk -> inject
- updated = SafeWriteFile();
+ XMP_Uns8 blockType;
+
+ // Read the block type byte
+ fileRef->Read( &blockType, 1 );
+
+ if ( blockType == kXMP_block_ImageDesc )
+ {
+
+ // ImageDesc is a special case, So read data just like its structure.
+ long tableSize = 0;
+ XMP_Uns8 fields;
+ // Reading Dimesnions of image as
+ // 2 bytes = Image Left Position
+ // + 2 bytes = Image Right Position
+ // + 2 bytes = Image Width
+ // + 2 bytes = Image Height
+ // = 8 bytes
+ this->SeekFile( fileRef, 8, kXMP_SeekFromCurrent );
+
+ // Reading one byte for Packed Fields
+ fileRef->Read( &fields, 1 );
+
+ // Getting Local Table Size and skipping table size
+ if ( fields & 0x80 )
+ {
+ tableSize = ( 1 << ( ( fields & 0x07 ) + 1 ) ) * 3;
+ this->SeekFile( fileRef, tableSize, kXMP_SeekFromCurrent );
+ }
+
+ // 1 byte LZW Minimum code size
+ this->SeekFile( fileRef, 1, kXMP_SeekFromCurrent );
+
+ XMP_Uns8 subBlockSize;
+ // 1 byte compressed sub-block size
+ fileRef->Read( &subBlockSize, 1 );
+
+ while ( subBlockSize != 0x00 )
+ {
+ // Skipping compressed data sub-block
+ this->SeekFile( fileRef, subBlockSize, kXMP_SeekFromCurrent );
+
+ // 1 byte compressed sub-block size
+ fileRef->Read( &subBlockSize, 1 );
+ }
+
+ }
+ else if ( blockType == kXMP_block_Extension )
+ {
+ XMP_Uns8 extensionLbl;
+ XMP_Uns32 blockSize = 0;
+ XMP_Uns64 blockOffset = fileRef->Offset();
+
+ // Extension Label
+ fileRef->Read( &extensionLbl, 1 );
+
+ // Block or Sub-Block size
+ fileRef->Read( &blockSize, 1 );
+
+ // Checking for Application Extension label and blockSize
+ if ( extensionLbl == 0xFF && blockSize == APP_ID_LEN )
+ {
+ XMP_Uns8 idData[ APP_ID_LEN ];
+ fileRef->Read( idData, APP_ID_LEN, true );
+
+ // Checking For XMP ID
+ if ( memcmp( idData, XMP_APP_ID_DATA, APP_ID_LEN ) == 0 )
+ {
+ XMPPacketOffset = fileRef->Offset();
+ IsXMPExists = true;
+ }
+
+ // Parsing sub-blocks
+ XMP_Uns8 subBlockSize;
+ fileRef->Read( &subBlockSize, 1 );
+ while ( subBlockSize != 0x00 )
+ {
+ this->SeekFile( fileRef, subBlockSize, kXMP_SeekFromCurrent );
+ fileRef->Read( &subBlockSize, 1 );
+ }
+ if ( IsXMPExists )
+ XMPPacketLength = static_cast< XMP_Uns32 >( fileRef->Offset() - XMPPacketOffset - MAGIC_TRAILER_LEN );
+ }
+ else
+ {
+ // Extension block other than Application Extension
+ while ( blockSize != 0x00 )
+ {
+ // Seeking block size or sub-block size
+ this->SeekFile( fileRef, blockSize, kXMP_SeekFromCurrent );
+
+ // Block Size
+ fileRef->Read( &blockSize, 1 );
+ }
+ }
+ }
+ else if ( blockType == kXMP_block_Trailer )
+ {
+ // 1 byte is subtracted for block type
+ trailerOffset = fileRef->Offset() - 1;
+ IsTrailerExists = true;
+ break;
+ }
+ else
+ XMP_Throw( "Invaild GIF Block", kXMPErr_BadBlockFormat );
}
- else if (blockState.xmpLen >= packetLen )
+
+ if ( !IsTrailerExists )
+ XMP_Throw( "No trailer exists for GIF file", kXMPErr_BadFileFormat );
+
+ return IsXMPExists;
+
+} // GIF_MetaHandler::ParseGIFBlocks
+
+// =================================================================================================
+// GIF_MetaHandler::ReadLogicalScreenDesc
+// ===========================
+
+void GIF_MetaHandler::ReadLogicalScreenDesc( XMP_IO* fileRef )
+{
+ XMP_Uns8 fields;
+
+ // 2 bytes for Screen Width
+ // + 2 bytes for Screen Height
+ // = 4 Bytes
+ this->SeekFile( fileRef, 4, kXMP_SeekFromCurrent );
+
+ // 1 byte for Packed Fields
+ fileRef->Read( &fields, 1 );
+
+ // 1 byte for Background Color Index
+ // + 1 byte for Pixel Aspect Ratio
+ // = 2 bytes
+ this->SeekFile( fileRef, 2, kXMP_SeekFromCurrent );
+
+ // Look for Global Color Table if exists
+ if ( fields & 0x80 )
+ {
+ long tableSize = ( 1 << ( ( fields & 0x07 ) + 1 ) ) * 3;
+ this->SeekFile( fileRef, tableSize, kXMP_SeekFromCurrent );
+ }
+
+} // GIF_MetaHandler::ReadLogicalScreenDesc
+
+// =================================================================================================
+// GIF_MetaHandler::SeekFile
+// ===========================
+
+void GIF_MetaHandler::SeekFile( XMP_IO * fileRef, XMP_Int64 offset, SeekMode mode )
+{
+ if ( offset > fileRef->Length() || ( mode == kXMP_SeekFromCurrent && fileRef->Offset() + offset > fileRef->Length() ) )
{
- // current chunk size is sufficient -> write and update CRC (in place update)
- updated = GIF_Support::WriteBuffer(fileRef, blockState.xmpPos, packetLen, packetStr );
- // GIF doesn't have a CRC like PNG.
+ XMP_Throw( "Out of range seek operation", kXMPErr_InternalFailure );
}
- else if (blockState.xmpLen < packetLen)
+ else
+ fileRef->Seek( offset, mode );
+
+} // GIF_MetaHandler::SeekFile
+
+// =================================================================================================
+// GIF_MetaHandler::UpdateFile
+// ===========================
+
+void GIF_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ XMP_Assert( !doSafeUpdate ); // This should only be called for "unsafe" updates.
+
+ if ( ! this->needsUpdate ) return;
+
+ XMP_IO * fileRef = this->parent->ioRef;
+
+ XMP_StringPtr packetStr = xmpPacket.c_str();
+ XMP_StringLen newPacketLength = (XMP_StringLen)xmpPacket.size();
+
+ if ( newPacketLength == XMPPacketLength )
{
- // XMP is too large for current chunk -> expand
- updated = SafeWriteFile();
+ this->SeekFile( fileRef, this->packetInfo.offset, kXMP_SeekFromStart );
+ fileRef->Write( this->xmpPacket.c_str(), newPacketLength );
}
+ else
+ {
+ XMP_IO* tempFile = fileRef->DeriveTemp();
+ if ( tempFile == 0 ) XMP_Throw( "Failure creating GIF temp file", kXMPErr_InternalFailure );
- if ( ! updated )return; // If there's an error writing the chunk, bail.
+ this->WriteTempFile( tempFile );
+ fileRef->AbsorbTemp();
+ }
this->needsUpdate = false;
} // GIF_MetaHandler::UpdateFile
// =================================================================================================
-// GIF_MetaHandler::WriteFile
-// ===========================
+// GIF_MetaHandler::WriteTempFile
+// ==============================
void GIF_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
{
- XMP_IO* originalRef = this->parent->ioRef;
+ XMP_Assert( this->needsUpdate );
- GIF_Support::BlockState blockState;
- long numBlocks = GIF_Support::OpenGIF ( originalRef, blockState );
- if ( numBlocks == 0 ) return;
+ XMP_IO* originalRef = this->parent->ioRef;
+ originalRef->Rewind();
- tempRef->Truncate( 0 );
- // LFA_Write(destRef, GIF_SIGNATURE_DATA, GIF_SIGNATURE_LEN);
+ tempRef->Truncate ( 0 );
+
+ if ( XMPPacketOffset != 0 )
+ {
+ // Copying blocks before XMP Application Block
+ XIO::Copy( originalRef, tempRef, XMPPacketOffset );
- GIF_Support::BlockIterator curPos = blockState.blocks.begin();
- GIF_Support::BlockIterator endPos = blockState.blocks.end();
+ // Writing XMP Packet
+ tempRef->Write( this->xmpPacket.c_str(), (XMP_Uns32)this->xmpPacket.size() );
- long blockCount;
+ // Copying Rest of the file
+ originalRef->Seek( XMPPacketLength, kXMP_SeekFromCurrent );
+ XIO::Copy( originalRef, tempRef, originalRef->Length() - originalRef->Offset() );
- for (blockCount = 0; (curPos != endPos); ++curPos, ++blockCount)
+ }
+ else
{
- GIF_Support::BlockData block = *curPos;
+ if ( trailerOffset == 0 )
+ XMP_Throw( "Not able to write XMP packet in GIF file", kXMPErr_BadFileFormat );
- // discard existing XMP block
- if (block.xmp)
- continue;
+ // Copying blocks before XMP Application Block
+ XIO::Copy( originalRef, tempRef, trailerOffset );
- // copy any other block
- GIF_Support::CopyBlock(originalRef, tempRef, block);
+ // Writing Extension Introducer
+ XIO::WriteUns8( tempRef, kXMP_block_Extension );
- // place XMP block immediately before trailer
- if (blockCount == numBlocks - 2)
- {
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = xmpPacket.size();
+ // Writing Application Extension label
+ XIO::WriteUns8( tempRef, 0xFF );
- GIF_Support::WriteXMPBlock(tempRef, packetLen, packetStr );
- }
- }
+ // Writing Application Extension label
+ XIO::WriteUns8( tempRef, APP_ID_LEN );
-} // GIF_MetaHandler::WriteFile
+ // Writing Application Extension label
+ tempRef->Write( XMP_APP_ID_DATA, APP_ID_LEN );
-// =================================================================================================
-// GIF_MetaHandler::SafeWriteFile
-// ===========================
+ // Writing XMP Packet
+ tempRef->Write( this->xmpPacket.c_str(), (XMP_Uns32)this->xmpPacket.size() );
-bool GIF_MetaHandler::SafeWriteFile ()
-{
- bool ret = false;
+ // Writing Magic trailer
+ XMP_Uns8 magicByte = 0x01;
+ tempRef->Write( &magicByte, 1 );
+ for ( magicByte = 0xFF; magicByte != 0x00; --magicByte )
+ tempRef->Write( &magicByte, 1 );
+ tempRef->Write( &magicByte, 1 );
+ tempRef->Write( &magicByte, 1 );
- XMP_IO* originalFile = this->parent->ioRef;
- XMP_IO* tempFile = originalFile->DeriveTemp();
- if ( tempFile == 0 )
- XMP_Throw ( "Failure creating GIF temp file", kXMPErr_InternalFailure );
+ // Copying Rest of the file
+ XIO::Copy( originalRef, tempRef, originalRef->Length() - originalRef->Offset() );
- this->WriteTempFile( tempFile );
- originalFile->AbsorbTemp();
+ }
- return true;
-} // GIF_MetaHandler::SafeWriteFile
+} // GIF_MetaHandler::WriteTempFile
// =================================================================================================
diff --git a/XMPFiles/source/FileHandlers/GIF_Handler.hpp b/XMPFiles/source/FileHandlers/GIF_Handler.hpp
index 40f7046..10ef3f9 100644
--- a/XMPFiles/source/FileHandlers/GIF_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/GIF_Handler.hpp
@@ -3,24 +3,27 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 Adobe Systems Incorporated
+// Copyright 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.
+//
+// This file includes implementation of GIF file metadata, according to GIF89a Specification.
+// https://www.w3.org/Graphics/GIF/spec-gif89a.txt
+// The Graphics Interchange Format(c) is the Copyright property of CompuServe Incorporated.
+// GIF(sm) is a Service Mark property of CompuServe Incorporated.
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
//
-// Derived from PNG_Handler.hpp by Ian Jacobi
+//Derived from PNG_Handler.hpp by Ian Jacobi
// =================================================================================================
-#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
#include "public/include/XMP_Const.h"
#include "public/include/XMP_IO.hpp"
#include "XMPFiles/source/XMPFiles_Impl.hpp"
-#include "source/XMPFiles_IO.hpp"
-
-#include "XMPFiles/source/FormatSupport/GIF_Support.hpp"
// =================================================================================================
/// \file GIF_Handler.hpp
@@ -35,14 +38,14 @@
extern XMPFileHandler* GIF_MetaHandlerCTor ( XMPFiles* parent );
extern bool GIF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- XMP_IO* fileRef,
+ XMP_StringPtr filePath,
+ XMP_IO* fileRef,
XMPFiles* parent );
-static const XMP_OptionBits kGIF_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
+static const XMP_OptionBits kGIF_HandlerFlags = ( kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
kXMPFiles_ReturnsRawPacket |
kXMPFiles_NeedsReadOnlyPacket
);
@@ -52,17 +55,34 @@ class GIF_MetaHandler : public XMPFileHandler
public:
void CacheFileData();
- void ProcessTNail();
void ProcessXMP();
-
+
void UpdateFile ( bool doSafeUpdate );
- void WriteTempFile ( XMP_IO* tempRef );
+ void WriteTempFile ( XMP_IO* tempRef );
bool SafeWriteFile ();
GIF_MetaHandler ( XMPFiles* parent );
virtual ~GIF_MetaHandler();
+private:
+
+ enum GIFBlockType
+ {
+ kXMP_block_ImageDesc = 0x2C,
+ kXMP_block_Extension = 0x21,
+ kXMP_block_Trailer = 0x3B,
+ kXMP_block_Header = 0x47
+ };
+
+ XMP_Uns64 XMPPacketOffset;
+ XMP_Uns32 XMPPacketLength;
+ XMP_Uns64 trailerOffset;
+
+ bool ParseGIFBlocks( XMP_IO * fileRef );
+ void ReadLogicalScreenDesc( XMP_IO* fileRef );
+ void SeekFile( XMP_IO * fileRef, XMP_Int64 offset, SeekMode mode );
+
}; // GIF_MetaHandler
// =================================================================================================
diff --git a/XMPFiles/source/FileHandlers/JPEG_Handler.cpp b/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
index bdc5505..a37f78e 100644
--- a/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
@@ -24,6 +24,8 @@
#include "third-party/zuid/interfaces/MD5.h"
+#include <algorithm>
+
using namespace std;
// =================================================================================================
@@ -651,8 +653,7 @@ void JPEG_MetaHandler::ProcessXMP()
// Process the legacy metadata.
if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if (iptcInfo.dataLen) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
this->containsXMP = true; // Assume we had something for the XMP.
@@ -961,7 +962,7 @@ void JPEG_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
}
if ( copySegment && (signatureLen == kExtXMPSignatureLength) &&
- CheckBytes ( &buffer[0], kExtXMPSignatureString, kExtXMPPrefixLength ) ) {
+ CheckBytes ( &buffer[0], kExtXMPSignatureString, kExtXMPSignatureLength ) ) {
copySegment = false;
}
diff --git a/XMPFiles/source/FileHandlers/MP3_Handler.cpp b/XMPFiles/source/FileHandlers/MP3_Handler.cpp
index 55211c9..9295a2e 100644
--- a/XMPFiles/source/FileHandlers/MP3_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/MP3_Handler.cpp
@@ -14,11 +14,14 @@
#include "XMPFiles/source/XMPFiles_Impl.hpp"
#include "XMPFiles/source/FormatSupport/Reconcile_Impl.hpp"
+#include "source/UnicodeConversions.hpp"
#include "source/XMPFiles_IO.hpp"
#include "source/XIO.hpp"
#include "XMPFiles/source/FileHandlers/MP3_Handler.hpp"
+#include <sstream>
+
// =================================================================================================
/// \file MP3_Handler.cpp
/// \brief MP3 handler class.
@@ -204,7 +207,10 @@ void MP3_MetaHandler::CacheFileData()
// read frames
XMP_Uns32 xmpID = XMP_V23_ID;
- if ( this->majorVersion == 2 ) xmpID = XMP_V22_ID;
+ if ( this->majorVersion == 2 )
+ {
+ xmpID = XMP_V22_ID;
+ }
while ( file->Offset() < this->oldTagSize ) {
@@ -442,10 +448,9 @@ void MP3_MetaHandler::ProcessXMP()
if ( xmpObj.GetProperty_Date ( kXMP_NS_XMP, "CreateDate", &oldDateTime, 0 ) )
{
- haveNewDateTime = haveNewDateTime &&
- ( (newDateTime.year != oldDateTime.year) ||
- ( (newDateTime.month != 0 ) && ( (newDateTime.day != oldDateTime.day) || (newDateTime.month != oldDateTime.month) ) ) ||
- ( newDateTime.hasTime && ( (newDateTime.hour != oldDateTime.hour) || (newDateTime.minute != oldDateTime.minute) ) ) );
+ haveNewDateTime = haveNewDateTime && ( (newDateTime.year != oldDateTime.year) || ( (newDateTime.month != 0 )
+ && ( (newDateTime.day != oldDateTime.day) || (newDateTime.month != oldDateTime.month) ) )
+ || ( newDateTime.hasTime && ( (newDateTime.hour != oldDateTime.hour) || (newDateTime.minute != oldDateTime.minute) ) ) );
}
// NOTE: no further validation nessesary the function "SetProperty_Date" will care about validating date and time
// any exception will be caught and block import
@@ -727,3 +732,4 @@ void MP3_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
IgnoreParam(tempRef);
XMP_Throw ( "MP3_MetaHandler::WriteTempFile: Not supported", kXMPErr_Unimplemented );
} // MP3_MetaHandler::WriteTempFile
+
diff --git a/XMPFiles/source/FileHandlers/MP3_Handler.hpp b/XMPFiles/source/FileHandlers/MP3_Handler.hpp
index 05345c6..6916f2e 100644
--- a/XMPFiles/source/FileHandlers/MP3_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/MP3_Handler.hpp
@@ -23,14 +23,12 @@ extern bool MP3_CheckFormat ( XMP_FileFormat format,
XMP_StringPtr filePath,
XMP_IO* fileRef,
XMPFiles * parent );
-
static const XMP_OptionBits kMP3_HandlerFlags = (kXMPFiles_CanInjectXMP |
kXMPFiles_CanExpand |
kXMPFiles_PrefersInPlace |
kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket|
+ kXMPFiles_ReturnsRawPacket |
kXMPFiles_CanReconcile);
-
class MP3_MetaHandler : public XMPFileHandler
{
public:
@@ -43,7 +41,6 @@ public:
void WriteTempFile ( XMP_IO* tempRef );
void ProcessXMP();
-
private:
////////////////////////////////////////////////////////////////////////////////////
// instance vars
diff --git a/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp b/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
index 905f19f..ee25d7a 100644
--- a/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
@@ -179,8 +179,8 @@ static inline bool IsXMPUUID ( XMP_IO * fileRef,XMP_Uns64 contentSize, bool unmo
//
// An MPEG-4 or modern QuickTime file is an instance of an ISO Base Media file, ISO 14496-12 and -14.
// A classic QuickTime file has the same physical box structure, but somewhat different box types.
-// The ISO files must begin with an 'ftyp' box containing 'mp41', 'mp42', 'f4v ', or 'qt ' in the
-// compatible brands.
+// The ISO files must begin with an 'ftyp' box containing 'mp41', 'mp42', 'f4v ', 'qt ', 'isom','3gp4',
+// '3g2a','3g2b' or '3g2c' in the compatible brands.
//
// The general box structure is:
//
@@ -259,8 +259,11 @@ bool MPEG4_CheckFormat ( XMP_FileFormat format,
parent->format = kXMP_MOVFile;
parent->tempUI32 = MOOV_Manager::kFileIsModernQT;
return true;
- } else if ( (brand == ISOMedia::k_mp41) || (brand == ISOMedia::k_mp42) ||
- (brand == ISOMedia::k_f4v) || ( brand == ISOMedia::k_avc1 ) ) {
+ }
+ else if ( ( brand == ISOMedia::k_mp41 ) || ( brand == ISOMedia::k_mp42 ) ||
+ ( brand == ISOMedia::k_f4v ) || ( brand == ISOMedia::k_avc1 ) || ( brand == ISOMedia::k_isom ) ||
+ ( brand == ISOMedia::k_3gp4 ) || ( brand == ISOMedia::k_3g2a ) || ( brand == ISOMedia::k_3g2b ) ||
+ ( brand == ISOMedia::k_3g2c ) ) {
haveCompatibleBrand = true; // Need to keep looking in case 'qt ' follows.
}
@@ -1774,7 +1777,7 @@ static void AttemptFileRepair ( XMP_IO* qtFile, XMP_Int64 fileSpace, QTErrorMode
}
AtomInfo info;
- XMP_Int64 headerSize;
+ XMP_Int64 headerSize(0);
// Process the top level atoms until an error is found.
@@ -2062,7 +2065,7 @@ void MPEG4_MetaHandler::CacheFileData()
bool xmpOnly = XMP_OptionIsSet ( openFlags, kXMPFiles_OpenOnlyXMP );
bool haveISOFile = (this->fileMode == MOOV_Manager::kFileIsNormalISO);
- bool uuidFound = (! haveISOFile); // Ignore the XMP 'uuid' box for QuickTime files.
+ bool xmpUuidFound = (! haveISOFile); // Ignore the XMP 'uuid' box for QuickTime files.
bool moovIgnored = (xmpOnly & haveISOFile); // Ignore the 'moov' box for XMP-only ISO files.
bool moovFound = moovIgnored;
@@ -2089,24 +2092,24 @@ void MPEG4_MetaHandler::CacheFileData()
this->moovBoxPos = boxPos;
this->moovBoxSize = (XMP_Uns32)fullMoovSize;
moovFound = true;
- if ( uuidFound ) break; // Exit the loop when both are found.
+ if ( xmpUuidFound ) break; // Exit the loop when both are found.
- } else if ( (! uuidFound) && (currBox.boxType == ISOMedia::k_uuid) && IsXMPUUID(fileRef,currBox.contentSize) ) {
+ } else if ( (! xmpUuidFound) && (currBox.boxType == ISOMedia::k_uuid) && ( memcmp( currBox.idUUID, ISOMedia::k_xmpUUID, 16 ) == 0 ) ) {
XMP_Uns64 fullUuidSize = currBox.headerSize + currBox.contentSize;
if ( fullUuidSize > moovBoxSizeLimit ) { // From here on we know 32-bit offsets are safe.
XMP_Throw ( "Oversize XMP 'uuid' box", kXMPErr_EnforceFailure );
}
- this->packetInfo.offset = boxPos + currBox.headerSize + 16; // The 16 is for the UUID.
- this->packetInfo.length = (XMP_Int32) (currBox.contentSize - 16);
+ this->packetInfo.offset = boxPos + currBox.headerSize ;
+ this->packetInfo.length = (XMP_Int32) (currBox.contentSize);
this->xmpPacket.assign ( this->packetInfo.length, ' ' );
fileRef->ReadAll ( (void*)this->xmpPacket.data(), this->packetInfo.length );
this->xmpBoxPos = boxPos;
this->xmpBoxSize = (XMP_Uns32)fullUuidSize;
- uuidFound = true;
+ xmpUuidFound = true;
if ( moovFound ) break; // Exit the loop when both are found.
}
@@ -2679,7 +2682,7 @@ void MPEG4_MetaHandler::OptimizeFileLayout()
needsOptimization = mdatFound;
if ( xmpFound ) break; // Don't need to look further.
- } else if ( currBox.boxType == ISOMedia::k_uuid && IsXMPUUID(originalFile,currBox.contentSize) ) {
+ } else if ( currBox.boxType == ISOMedia::k_uuid && ( memcmp( currBox.idUUID, ISOMedia::k_xmpUUID, 16 ) == 0 ) ) {
xmpFound = true;
xmpIndex = boxCount-1; // Need later for optimization.
@@ -3009,7 +3012,7 @@ void MPEG4_MetaHandler::UpdateFile ( bool doSafeUpdate )
// The uuid form of XMP has the 16-byte UUID in front of the XMP packet. Form the complete
// box (including size/type header) for UpdateTopLevelBox.
RawDataBlock uuidBox;
- XMP_Uns32 uuidSize = 4+4 + 16 + (XMP_Uns32)this->xmpPacket.size();
+ XMP_Uns32 uuidSize = 4 + 4 + 16 + (XMP_Uns32)this->xmpPacket.size();
uuidBox.assign ( uuidSize, 0 );
PutUns32BE ( uuidSize, &uuidBox[0] );
PutUns32BE ( ISOMedia::k_uuid, &uuidBox[4] );
diff --git a/XMPFiles/source/FileHandlers/P2_Handler.cpp b/XMPFiles/source/FileHandlers/P2_Handler.cpp
index d99235d..1b7ad09 100644
--- a/XMPFiles/source/FileHandlers/P2_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/P2_Handler.cpp
@@ -718,6 +718,7 @@ void P2_MetaHandler::SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoCont
} else if ( p2FrameRate == "50p" ) {
dmTimeFormat = "50Timecode";
+ this->AdjustTimeCode( p2StartTimecode, false );
} else if ( ( p2FrameRate == "59.94p" ) && ( p2DropFrameFlag != 0 ) ) {
@@ -726,6 +727,7 @@ void P2_MetaHandler::SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoCont
} else if ( XMP_LitMatch ( p2DropFrameFlag, "false" ) ) {
dmTimeFormat = "5994NonDropTimecode";
}
+ this->AdjustTimeCode( p2StartTimecode, false );
} else if ( (p2FrameRate == "59.94i") || (p2FrameRate == "29.97p") ) {
@@ -767,6 +769,56 @@ void P2_MetaHandler::SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoCont
} // P2_MetaHandler::SetStartTimecodeFromLegacyXML
+// =================================================================================================
+// P2_MetaHandler::AdjustTimeCode
+// ===========================================
+
+void P2_MetaHandler::AdjustTimeCode( std::string & p2Timecode, const XMP_Bool & isXMPtoXMLConversion )
+{
+ /*
+ XMP is storing frame number for 50P and 59.94P as [0-49] and [0-59] respectively,
+ but NRT XML can store frame number for these format as [0-29].
+ So, XMP need to adjust values for these cases.
+ */
+ try
+ {
+ XMP_Int64 strLength = p2Timecode.length();
+ XMP_Int64 index = strLength - 1;
+ for (; index > 0; --index)
+ if (p2Timecode.at(index) == ':')
+ break;
+ std::string FFValue;
+ if ( index == strLength - 2 ) // HH:MM:SS:F
+ FFValue = p2Timecode.substr(index + 1, 1);
+ else if ( index == strLength - 3 )
+ FFValue = p2Timecode.substr(index + 1, 2); // HH:MM:SS:FF
+ else
+ throw; // Invalid format
+ stringstream timeCodeStream (FFValue);
+ XMP_Uns32 frameNumber;
+ timeCodeStream >> frameNumber;
+ if (isXMPtoXMLConversion) // Conversion from XMP to XML so doing half the value
+ {
+ frameNumber /= 2;
+ XMP_Assert(frameNumber >= 0 && frameNumber < 30);
+ }
+ else // Conversion from XML to XMP so doubling the value
+ {
+ XMP_Assert(frameNumber >= 0 && frameNumber < 30);
+ frameNumber *= 2;
+ }
+ timeCodeStream.clear();
+ timeCodeStream << p2Timecode.substr(0, index + 1);
+ if (frameNumber < 10)
+ timeCodeStream << '0';
+ timeCodeStream << frameNumber;
+ p2Timecode = timeCodeStream.str();
+ }
+ catch (...)
+ {
+ XMP_Throw("P2 Invalid Timecode.", kXMPErr_InternalFailure);
+ }
+} // P2_MetaHandler::AdjustTimeCode
// =================================================================================================
// P2_MetaHandler::SetGPSPropertyFromLegacyXML
@@ -1235,7 +1287,35 @@ void P2_MetaHandler::UpdateFile ( bool doSafeUpdate )
updateLegacyXML = true;
}
}
+ }
+ // Half the startTimeCode frame number value in XML if require so
+ std::string xmpStartTimeCode;
+ bool isTimecodeExists = this->xmpObj.GetStructField(kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", &xmpStartTimeCode, 0);
+ if (isTimecodeExists)
+ {
+ std::string frameFormat;
+ this->xmpObj.GetStructField(kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", &frameFormat, 0);
+ if (frameFormat == "50Timecode" || frameFormat == "5994DropTimecode" || frameFormat == "5994NonDropTimecode")
+ {
+ p2Clip = this->p2ClipManager.GetManagedClip();
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
+ XML_NodePtr legacyVideoContext = p2Clip->GetEssenceListNode();
+ if (legacyVideoContext != 0)
+ {
+ legacyVideoContext = legacyVideoContext->GetNamedElement(p2NS, "Video");
+ XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement(p2NS, "StartTimecode");
+ if ((legacyProp != 0) && legacyProp->IsLeafContentNode())
+ {
+ AdjustTimeCode( xmpStartTimeCode, true );
+ if (xmpStartTimeCode != legacyProp->GetLeafContentValue())
+ {
+ legacyProp->SetLeafContentValue(xmpStartTimeCode.c_str());
+ updateLegacyXML = true;
+ }
+ }
+ }
+ }
}
std::string newDigest;
diff --git a/XMPFiles/source/FileHandlers/P2_Handler.hpp b/XMPFiles/source/FileHandlers/P2_Handler.hpp
index 5e492ee..8ef6da3 100644
--- a/XMPFiles/source/FileHandlers/P2_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/P2_Handler.hpp
@@ -99,6 +99,7 @@ private:
void SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoContext, bool digestFound );
void SetGPSPropertyFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound, XMP_StringPtr propName, XMP_StringPtr legacyPropName );
void SetAltitudeFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound );
+ void AdjustTimeCode( std::string & p2Timecode, const XMP_Bool & isXMPtoXMLConversion );
XML_Node * ForceChildElement ( XML_Node * parent, XMP_StringPtr localName, XMP_Int32 indent, XMP_Bool insertAtFront );
diff --git a/XMPFiles/source/FileHandlers/PSD_Handler.cpp b/XMPFiles/source/FileHandlers/PSD_Handler.cpp
index e5847e9..312e855 100644
--- a/XMPFiles/source/FileHandlers/PSD_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/PSD_Handler.cpp
@@ -250,8 +250,7 @@ void PSD_MetaHandler::ProcessXMP()
// Process the legacy metadata.
if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if (iptcInfo.dataLen) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
this->containsXMP = true; // Assume we now have something in the XMP.
diff --git a/XMPFiles/source/FileHandlers/PostScript_Handler.cpp b/XMPFiles/source/FileHandlers/PostScript_Handler.cpp
index d21ab8d..4467794 100644
--- a/XMPFiles/source/FileHandlers/PostScript_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/PostScript_Handler.cpp
@@ -885,7 +885,11 @@ void PostScript_MetaHandler::ParsePSFile()
if (CheckBytes ( ioBuf.ptr, Uns8Ptr("iler"), 4 ))
{
ioBuf.ptr+=4;
- while(!IsNewline(*ioBuf.ptr)) ++ioBuf.ptr;
+ while ( !IsNewline( *ioBuf.ptr ) )
+ {
+ if ( !CheckFileSpace( fileRef, &ioBuf, 1 ) ) return;
+ ++ioBuf.ptr;
+ }
setTokenInfo(kPS_Trailer,begStartpos,ioBuf.filePos+ioBuf.ptr-ioBuf.data-begStartpos);
}
}
diff --git a/XMPFiles/source/FileHandlers/RIFF_Handler.cpp b/XMPFiles/source/FileHandlers/RIFF_Handler.cpp
index 7d6fdb3..5884390 100644
--- a/XMPFiles/source/FileHandlers/RIFF_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/RIFF_Handler.cpp
@@ -71,10 +71,11 @@ RIFF_MetaHandler::RIFF_MetaHandler ( XMPFiles * _parent )
this->oldFileSize = this->newFileSize = this->trailingGarbageSize = 0;
this->level = 0;
- this->listInfoChunk = this->listTdatChunk = 0;
+ this->listInfoChunk = this->listTdatChunk = this->listHdlrChunk = 0;
this->dispChunk = this->bextChunk = this->cr8rChunk = this->prmlChunk = 0;
this->xmpChunk = 0;
this->lastChunk = 0;
+ this->iditChunk = 0;
this->hasListInfoINAM = false;
}
diff --git a/XMPFiles/source/FileHandlers/RIFF_Handler.hpp b/XMPFiles/source/FileHandlers/RIFF_Handler.hpp
index d8c83a2..bfa7b2a 100644
--- a/XMPFiles/source/FileHandlers/RIFF_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/RIFF_Handler.hpp
@@ -57,11 +57,12 @@ public:
// state variables, needed during parsing
XMP_Uns8 level;
- RIFF::ContainerChunk *listInfoChunk, *listTdatChunk;
+ RIFF::ContainerChunk *listInfoChunk, *listTdatChunk,*listHdlrChunk;
RIFF::ValueChunk* dispChunk;
RIFF::ValueChunk* bextChunk;
RIFF::ValueChunk* cr8rChunk;
RIFF::ValueChunk* prmlChunk;
+ RIFF::ValueChunk* iditChunk;
RIFF::XMPChunk* xmpChunk;
RIFF::ContainerChunk* lastChunk;
bool hasListInfoINAM; // needs to be known for the special 3-way merge around dc:title
diff --git a/XMPFiles/source/FileHandlers/SVG_Handler.cpp b/XMPFiles/source/FileHandlers/SVG_Handler.cpp
new file mode 100644
index 0000000..93ef108
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/SVG_Handler.cpp
@@ -0,0 +1,689 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+//
+// This file includes implementation of SVG metadata, according to Scalable Vector Graphics (SVG) 1.1 Specification.
+// "https://www.w3.org/TR/2003/REC-SVG11-20030114/"
+// Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology,
+// Institut National de Recherche en Informatique et en Automatique, Keio University).
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
+//
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include "source/XMPFiles_IO.hpp"
+#include "source/XIO.hpp"
+
+#include "XMPFiles/source/FileHandlers/SVG_Handler.hpp"
+
+using namespace std;
+
+/*
+ Currently supporting only UTF-8 encoded SVG
+*/
+
+// =================================================================================================
+// SVG_CheckFormat
+// ===============
+
+bool SVG_CheckFormat( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ XMP_IO * fileRef,
+ XMPFiles * parent )
+{
+ // 8K buffer is provided just to handle maximum SVG files
+ // We can't check for SVG element in whole file which could take a lot of time for valid XML files
+ IgnoreParam( filePath ); IgnoreParam( parent );
+
+ XMP_Assert( format == kXMP_SVGFile );
+
+ fileRef->Rewind();
+
+ XMP_Uns8 buffer[ 1024 ];
+
+ // Reading 4 bytes for BOM
+ XMP_Uns32 bytesRead = fileRef->Read( buffer, 4 );
+ if ( bytesRead != 4 )
+ return false;
+
+ // Checking for UTF-16 BOM and UTF-32 BOM
+ if ( ( buffer[ 0 ] == 0xFF && buffer[ 1 ] == 0xFE ) || ( buffer[ 0 ] == 0xFE && buffer[ 1 ] == 0xFF ) || ( buffer[ 0 ] == buffer[ 1 ] == 0x00 && buffer[ 2 ] == 0xFE && buffer[ 3 ] == 0xFF ) )
+ {
+ return false;
+ }
+
+ // Initially we are intersted only in "svg" element.
+ SVG_Adapter * svgChecker = new SVG_Adapter();
+ if ( svgChecker == 0 )
+ return false;
+
+ bool isSVG = false;
+
+ fileRef->Rewind();
+ for ( XMP_Uns8 index = 0; index < 8; ++index )
+ {
+ XMP_Int32 ioCount = fileRef->Read( buffer, sizeof( buffer ) );
+ if ( ioCount == 0 ) break;
+
+ // Checking for well formed XML
+ if ( !svgChecker->ParseBufferNoThrow( buffer, ioCount, false /* not the end */ ) )
+ break;
+
+ if ( svgChecker->tree.GetNamedElement( "http://www.w3.org/2000/svg", "svg" ) )
+ {
+ isSVG = true;
+ break;
+ }
+ }
+
+ if ( svgChecker )
+ delete ( svgChecker );
+
+ return isSVG;
+
+} // SVG_CheckFormat
+
+// =================================================================================================
+// SVG_MetaHandlerCTor
+// ===================
+
+XMPFileHandler * SVG_MetaHandlerCTor( XMPFiles * parent )
+{
+ return new SVG_MetaHandler( parent );
+
+} // SVG_MetaHandlerCTor
+
+// =================================================================================================
+// SVG_MetaHandler::SVG_MetaHandler
+// ================================
+
+SVG_MetaHandler::SVG_MetaHandler( XMPFiles * _parent ) : svgNode( 0 ), svgAdapter( 0 ), isTitleUpdateReq( false ), isDescUpdateReq( false )
+{
+ this->parent = _parent;
+ this->handlerFlags = kSVG_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+}
+
+// =================================================================================================
+// SVG_MetaHandler::~SVG_MetaHandler
+// =================================
+
+SVG_MetaHandler::~SVG_MetaHandler()
+{
+
+ if ( this->svgAdapter != 0 )
+ {
+ delete ( this->svgAdapter );
+ this->svgAdapter = 0;
+ }
+}
+
+// =================================================================================================
+// SVG_MetaHandler::GetSerializeOptions
+// ===================================
+//
+// Override default implementation to ensure Canonical packet.
+
+XMP_OptionBits SVG_MetaHandler::GetSerializeOptions()
+{
+
+ return ( kXMP_UseCanonicalFormat );
+
+} // SVG_MetaHandler::GetSerializeOptions
+
+// =================================================================================================
+// SVG_MetaHandler::CacheFileData
+// ==============================
+
+void SVG_MetaHandler::CacheFileData()
+{
+ XMP_Assert( !this->containsXMP );
+
+ XMP_IO * fileRef = this->parent->ioRef;
+
+ XMP_Uns8 marker[ 4 ];
+ fileRef->Rewind();
+ fileRef->Read( marker, 4 );
+
+ // Checking for UTF-16 BOM and UTF-32 BOM
+ if ( ( marker[ 0 ] == 0xFF && marker[ 1 ] == 0xFE ) || ( marker[ 0 ] == 0xFE && marker[ 1 ] == 0xFF ) || ( marker[ 0 ] == marker[ 1 ] == 0x00 && marker[ 2 ] == 0xFE && marker[ 3 ] == 0xFF ) )
+ {
+ XMP_Error error( kXMPErr_BadXML, "Invalid SVG file" );
+ this->NotifyClient( &this->parent->errorCallback, kXMPErrSev_OperationFatal, error );
+ }
+
+ // Creating a new SVG Parser
+ svgAdapter = new SVG_Adapter();
+ if ( svgAdapter == 0 )
+ XMP_Throw( "SVG_MetaHandler: Can't create SVG adapter", kXMPErr_NoMemory );
+ svgAdapter->SetErrorCallback( &this->parent->errorCallback );
+
+ // Registering all the required tags to SVG Parser
+ svgAdapter->RegisterPI( "xpacket" );
+ svgAdapter->RegisterElement( "metadata", "svg" );
+ svgAdapter->RegisterElement( "xmpmeta", "metadata" );
+ svgAdapter->RegisterElement( "RDF", "metadata" );
+ svgAdapter->RegisterElement( "title", "svg" );
+ svgAdapter->RegisterElement( "desc", "svg" );
+
+ // Parsing the whole buffer
+ fileRef->Rewind();
+ XMP_Uns8 buffer[ 64 * 1024 ];
+ while ( true ) {
+ XMP_Int32 ioCount = fileRef->Read( buffer, sizeof( buffer ) );
+ if ( ioCount == 0 || !svgAdapter->IsParsingRequire() ) break;
+ svgAdapter->ParseBuffer( buffer, ioCount, false /* not the end */ );
+ }
+ svgAdapter->ParseBuffer( 0, 0, true ); // End the parse.
+
+ XML_Node & xmlTree = this->svgAdapter->tree;
+ XML_NodePtr rootElem = 0;
+
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i )
+ {
+ if ( xmlTree.content[ i ]->kind == kElemNode ) {
+ rootElem = xmlTree.content[ i ];
+ }
+ }
+ if ( rootElem == 0 )
+ XMP_Throw( "Not a valid SVG File", kXMPErr_BadFileFormat );
+
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( ! XMP_LitMatch( rootLocalName, "svg" ) )
+ XMP_Throw( "Not able to parse such SVG File", kXMPErr_BadFileFormat );
+
+ // Making SVG node as Root Node
+ svgNode = rootElem;
+
+ bool FoundPI = false;
+ bool FoundWrapper = false;
+ XML_NodePtr metadataNode = svgNode->GetNamedElement( rootElem->ns.c_str(), "metadata" );
+
+ // We are intersted only in the Metadata tag of outer SVG element
+ // XMP should be present only in metadata Node of SVG
+ if ( metadataNode != NULL )
+ {
+ XMP_Int64 packetLength = -1;
+ XMP_Int64 packetOffset = -1;
+ XMP_Int64 PIOffset = svgAdapter->GetPIOffset( "xpacket", 1 );
+ OffsetStruct wrapperOffset = svgAdapter->GetElementOffsets( "xmpmeta" );
+ OffsetStruct rdfOffset = svgAdapter->GetElementOffsets( "RDF" );
+
+ // Checking XMP PI's position
+ if ( PIOffset != -1 )
+ {
+ if ( wrapperOffset.startOffset != -1 && wrapperOffset.startOffset < PIOffset )
+ packetOffset = wrapperOffset.startOffset;
+ else
+ {
+ XMP_Int64 trailerOffset = svgAdapter->GetPIOffset( "xpacket", 2 );
+ XML_NodePtr trailerNode = metadataNode->GetNamedElement( "", "xpacket", 1 );
+ if ( trailerOffset != -1 || trailerNode != 0 )
+ {
+ packetLength = 2; // "<?" = 2
+ packetLength += trailerNode->name.length(); // Node's name
+ packetLength += 1; // Empty Space after Node's name
+ packetLength += trailerNode->value.length(); // Value
+ packetLength += 2; // "?>" = 2
+ packetLength += ( trailerOffset - PIOffset );
+ packetOffset = PIOffset;
+ }
+ }
+ }
+ else if ( wrapperOffset.startOffset != -1 ) // XMP Wrapper is present without PI
+ {
+ XML_NodePtr wrapperNode = metadataNode->GetNamedElement( "adobe:ns:meta/", "xmpmeta" );
+ if ( wrapperNode != 0 )
+ {
+ std::string trailerWrapper = "</x:xmpmeta>";
+ packetLength = trailerWrapper.length();
+ packetLength += ( wrapperOffset.endOffset - wrapperOffset.startOffset );
+ packetOffset = wrapperOffset.startOffset;
+ }
+ }
+ else // RDF packet is present without PI and wrapper
+ {
+ XML_NodePtr rdfNode = metadataNode->GetNamedElement( "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF" );
+ if ( rdfNode != 0 )
+ {
+ std::string rdfTrailer = "</rdf:RDF>";
+ packetLength = rdfTrailer.length();
+ packetLength += ( rdfOffset.endOffset - rdfOffset.startOffset );
+ packetOffset = rdfOffset.startOffset;
+ }
+ }
+
+ // Fill the necesarry information and packet with XMP data
+ if ( packetOffset != -1 )
+ {
+ this->packetInfo.offset = packetOffset;
+ this->packetInfo.length = ( XMP_Int32 ) packetLength;
+ this->xmpPacket.assign( this->packetInfo.length, ' ' );
+ fileRef->Seek( packetOffset, kXMP_SeekFromStart );
+ fileRef->ReadAll( ( void* )this->xmpPacket.data(), this->packetInfo.length );
+ FillPacketInfo( this->xmpPacket, &this->packetInfo );
+ this->containsXMP = true;
+ return;
+ }
+ }
+ this->containsXMP = false;
+
+} // SVG_MetaHandler::CacheFileData
+
+// =================================================================================================
+// SVG_MetaHandler::ProcessXMP
+// ==============================
+
+void SVG_MetaHandler::ProcessXMP()
+{
+ //
+ // Here we are intersted in Only 2 childs, title and desc
+ //
+ this->processedXMP = true; // Make sure we only come through here once.
+
+ if ( svgNode == NULL )
+ return;
+
+ if ( !this->xmpPacket.empty() ) {
+ XMP_Assert( this->containsXMP );
+ this->xmpObj.ParseFromBuffer( this->xmpPacket.c_str(), ( XMP_StringLen )this->xmpPacket.size() );
+ }
+
+ // Description
+ XML_NodePtr descNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "desc" );
+ if ( descNode != 0 && descNode->content.size() == 1 && descNode->content[0]->kind == kCDataNode )
+ {
+ this->xmpObj.SetLocalizedText( kXMP_NS_DC, "description", "", "x-default", descNode->content[0]->value, kXMP_DeleteExisting );
+ this->containsXMP = true;
+ }
+
+ // Title
+ XML_NodePtr titleNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "title" );
+ if ( titleNode != 0 && titleNode->content.size() == 1 && titleNode->content[ 0 ]->kind == kCDataNode )
+ {
+ this->xmpObj.SetLocalizedText( kXMP_NS_DC, "title", "", "x-default", titleNode->content[0]->value, kXMP_DeleteExisting );
+ this->containsXMP = true;
+ }
+
+} // SVG_MetaHandler::ProcessXMP
+
+// =================================================================================================
+// SVG_MetaHandler::ProcessTitle
+// ===========================
+// It is handling the updation and deletion case
+void SVG_MetaHandler::ProcessTitle( XMP_IO* sourceRef, XMP_IO * destRef, const std::string &value, XMP_Int64 &currentOffset, const OffsetStruct & titleOffset )
+{
+ if ( value.empty() )
+ {
+ XIO::Copy( sourceRef, destRef, titleOffset.startOffset - currentOffset );
+ sourceRef->Seek( titleOffset.nextOffset, kXMP_SeekFromStart );
+ currentOffset = titleOffset.nextOffset;
+ }
+ else
+ {
+ std::string titleElement = "<title>";
+ XIO::Copy( sourceRef, destRef, titleOffset.startOffset - currentOffset + titleElement.length() );
+ destRef->Write( value.c_str(), static_cast< int >( value.length() ) );
+ sourceRef->Seek( titleOffset.endOffset, kXMP_SeekFromStart );
+ currentOffset = titleOffset.endOffset;
+ }
+} // SVG_MetaHandler::ProcessTitle
+
+// =================================================================================================
+// SVG_MetaHandler::ProcessDescription
+// ===========================
+// It is handling the updation and deletion case
+void SVG_MetaHandler::ProcessDescription( XMP_IO* sourceRef, XMP_IO * destRef, const std::string &value, XMP_Int64 &currentOffset, const OffsetStruct & descOffset )
+{
+ if ( value.empty() )
+ {
+ XIO::Copy( sourceRef, destRef, descOffset.startOffset - currentOffset );
+ sourceRef->Seek( descOffset.nextOffset, kXMP_SeekFromStart );
+ currentOffset = descOffset.nextOffset;
+ }
+ else
+ {
+ std::string descElement = "<desc>";
+ XIO::Copy( sourceRef, destRef, descOffset.startOffset - currentOffset + descElement.length() );
+ destRef->Write( value.c_str(), static_cast< int >( value.length() ) );
+ sourceRef->Seek( descOffset.endOffset, kXMP_SeekFromStart );
+ currentOffset = descOffset.endOffset;
+ }
+
+} // SVG_MetaHandler::ProcessDescription
+
+// =================================================================================================
+// SVG_MetaHandler::InsertNewTitle
+// ===========================
+// It is handling the insertion case
+void SVG_MetaHandler::InsertNewTitle( XMP_IO * destRef, const std::string &value )
+{
+ std::string titleElement = "<title>";
+ destRef->Write( titleElement.c_str(), static_cast< int >( titleElement.length() ) );
+ destRef->Write( value.c_str(), static_cast< int >( value.length() ) );
+ titleElement = "</title>\n";
+ destRef->Write( titleElement.c_str(), static_cast< int >( titleElement.length() ) );
+
+} // SVG_MetaHandler::InsertNewTitle
+
+// =================================================================================================
+// SVG_MetaHandler::InsertNewDescription
+// ===========================
+// It is handling the insertion case
+void SVG_MetaHandler::InsertNewDescription( XMP_IO * destRef, const std::string &value )
+{
+ std::string descElement = "<desc>";
+ destRef->Write( descElement.c_str(), static_cast< int >( descElement.length() ) );
+ destRef->Write( value.c_str(), static_cast< int >( value.length() ) );
+ descElement = "</desc>\n";
+ destRef->Write( descElement.c_str(), static_cast< int >( descElement.length() ) );
+
+} // SVG_MetaHandler::InsertNewDescription
+
+// =================================================================================================
+// SVG_MetaHandler::InsertNewMetadata
+// ===========================
+// It is handling the insertion case
+void SVG_MetaHandler::InsertNewMetadata( XMP_IO * destRef, const std::string &value )
+{
+
+ std::string metadataElement = "<metadata>";
+ destRef->Write( metadataElement.c_str(), static_cast< int >( metadataElement.length() ) );
+ destRef->Write( value.c_str(), static_cast< int >( value.length() ) );
+ metadataElement = "</metadata>\n";
+ destRef->Write( metadataElement.c_str(), static_cast< int >( metadataElement.length() ) );
+
+} // SVG_MetaHandler::InsertNewMetadata
+
+// =================================================================================================
+// SVG_MetaHandler::UpdateFile
+// ===========================
+
+void SVG_MetaHandler::UpdateFile( bool doSafeUpdate )
+{
+ XMP_Assert( !doSafeUpdate ); // This should only be called for "unsafe" updates.
+
+ XMP_IO* sourceRef = this->parent->ioRef;
+
+ if ( sourceRef == NULL || svgNode == NULL )
+ return;
+
+ // Checking whether Title updation requires or not
+ std::string title;
+ XML_NodePtr titleNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "title" );
+ (void) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "title", "", "x-default", 0, &title, 0 );
+ if ( ( titleNode == NULL ) == ( title.empty() ) )
+ {
+ if ( titleNode != NULL && titleNode->content.size() == 1 && titleNode->content[ 0 ]->kind == kCDataNode && !XMP_LitMatch( titleNode->content[ 0 ]->value.c_str(), title.c_str() ) )
+ isTitleUpdateReq = true;
+ }
+ else
+ isTitleUpdateReq = true;
+
+ // Checking whether Description updation requires or not
+ std::string description;
+ XML_NodePtr descNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "desc" );
+ ( void ) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "description", "", "x-default", 0, &description, 0 );
+ if ( ( descNode == NULL ) == ( description.empty() ) )
+ {
+ if ( descNode != NULL && descNode->content.size() == 1 && descNode->content[ 0 ]->kind == kCDataNode && !XMP_LitMatch( descNode->content[ 0 ]->value.c_str(), description.c_str() ) )
+ isDescUpdateReq = true;
+ }
+ else
+ isDescUpdateReq = true;
+
+ // If any updation is required then don't do inplace replace
+ bool isUpdateRequire = isTitleUpdateReq | isDescUpdateReq | (this->packetInfo.offset == kXMPFiles_UnknownOffset);
+
+ // Inplace Updation of XMP
+ if ( !isUpdateRequire && this->xmpPacket.size() == this->packetInfo.length )
+ {
+ sourceRef->Seek( this->packetInfo.offset, kXMP_SeekFromStart );
+ sourceRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.size() ) );
+ }
+ else
+ {
+ // Inplace is not possibe, So perform full updation
+ try
+ {
+ XMP_IO* tempRef = sourceRef->DeriveTemp();
+ this->WriteTempFile( tempRef );
+ }
+ catch ( ... )
+ {
+ sourceRef->DeleteTemp();
+ throw;
+ }
+
+ sourceRef->AbsorbTemp();
+ }
+
+ this->needsUpdate = false;
+
+} // SVG_MetaHandler::UpdateFile
+
+// =================================================================================================
+// SVG_MetaHandler::WriteTempFile
+// ==============================
+//
+void SVG_MetaHandler::WriteTempFile( XMP_IO* tempRef )
+{
+ XMP_Assert( this->needsUpdate );
+
+ XMP_IO* sourceRef = this->parent->ioRef;
+ if ( sourceRef == NULL || svgNode == NULL )
+ return;
+
+ tempRef->Rewind();
+ sourceRef->Rewind();
+
+ XMP_Int64 currentOffset = svgAdapter->firstSVGElementOffset;
+ XIO::Copy( sourceRef, tempRef, currentOffset );
+
+ OffsetStruct titleOffset = svgAdapter->GetElementOffsets( "title" );
+ OffsetStruct descOffset = svgAdapter->GetElementOffsets( "desc" );
+ OffsetStruct metadataOffset = svgAdapter->GetElementOffsets( "metadata" );
+
+ std::string title;
+ std::string description;
+
+ XML_NodePtr titleNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "title" );
+ ( void ) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "title", "", "x-default", 0, &title, 0 );
+
+ XML_NodePtr descNode = svgNode->GetNamedElement( svgNode->ns.c_str(), "desc" );
+ ( void ) this->xmpObj.GetLocalizedText( kXMP_NS_DC, "description", "", "x-default", 0, &description, 0 );
+
+ // Need to cover the case of both workflows
+ // This would have been called after inplace is not possible
+ // This would have called for safe update
+ if ( !isTitleUpdateReq )
+ {
+ if ( ( titleNode == NULL ) == ( title.empty() ) )
+ {
+ if ( titleNode != NULL && titleNode->content.size() == 1 && titleNode->content[ 0 ]->kind == kCDataNode && !XMP_LitMatch( titleNode->content[ 0 ]->value.c_str(), title.c_str() ) )
+ isTitleUpdateReq = true;
+ }
+ else
+ isTitleUpdateReq = true;
+ }
+ if ( !isDescUpdateReq )
+ {
+ if ( ( descNode == NULL ) == ( description.empty() ) )
+ {
+ if ( descNode != NULL && descNode->content.size() == 1 && descNode->content[ 0 ]->kind == kCDataNode && !XMP_LitMatch( descNode->content[ 0 ]->value.c_str(), description.c_str() ) )
+ isDescUpdateReq = true;
+ }
+ else
+ isDescUpdateReq = true;
+ }
+
+ // Initial Insertion/Updation
+
+ // Insert/Update Title if requires
+ // Don't insert/update it if Metadata or desc child comes before title child
+ bool isTitleWritten = !isTitleUpdateReq;
+ if ( isTitleUpdateReq )
+ {
+ // Insertion Case
+ if ( titleNode == NULL )
+ {
+ InsertNewTitle( tempRef, title );
+ isTitleWritten = true;
+ }
+ else if ( ( descOffset.startOffset == -1 || titleOffset.startOffset < descOffset.startOffset ) // Updation/Deletion Case
+ && ( metadataOffset.startOffset == -1 || titleOffset.startOffset < metadataOffset.startOffset ) )
+ {
+ ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
+ isTitleWritten = true;
+ }
+ }
+
+ // Insert/Update Description if requires
+ // Don't insert/update it if Metadata child comes before desc child
+ bool isDescWritten = !isDescUpdateReq;
+ if ( isDescUpdateReq )
+ {
+ if ( descNode == NULL )
+ {
+ if ( titleOffset.nextOffset != -1 )
+ {
+ XIO::Copy( sourceRef, tempRef, titleOffset.nextOffset - currentOffset );
+ currentOffset = titleOffset.nextOffset;
+ }
+ InsertNewDescription( tempRef, description );
+ isDescWritten = true;
+ }
+ else if ( metadataOffset.startOffset == -1 || descOffset.startOffset < metadataOffset.startOffset )
+ {
+ ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
+ isDescWritten = true;
+ }
+ }
+
+ // Insert/Update Metadata if requires
+ // Don't insert/update it if case is DTM
+ bool isMetadataWritten = false;
+ if ( metadataOffset.startOffset == -1 )
+ {
+ if ( descOffset.nextOffset != -1 )
+ {
+ XIO::Copy( sourceRef, tempRef, descOffset.nextOffset - currentOffset );
+ currentOffset = descOffset.nextOffset;
+ }
+ else if ( titleOffset.nextOffset != -1 )
+ {
+ XIO::Copy( sourceRef, tempRef, titleOffset.nextOffset - currentOffset );
+ currentOffset = titleOffset.nextOffset;
+ }
+ InsertNewMetadata( tempRef, this->xmpPacket );
+ isMetadataWritten = true;
+ }
+ else if ( !( !isTitleWritten && isDescWritten && titleOffset.startOffset < metadataOffset.startOffset ) ) // Not DTM
+ {
+ // No XMP packet was present in the file
+ if ( this->packetInfo.offset == kXMPFiles_UnknownOffset )
+ {
+ std::string metadataElement = "<metadata>";
+ XIO::Copy( sourceRef, tempRef, metadataOffset.startOffset - currentOffset + metadataElement.length() );
+ currentOffset = sourceRef->Offset();
+ tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
+ }
+ else // Replace XMP Packet
+ {
+ XIO::Copy( sourceRef, tempRef, this->packetInfo.offset - currentOffset );
+ tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
+ sourceRef->Seek( this->packetInfo.offset + this->packetInfo.length, kXMP_SeekFromStart );
+ currentOffset = sourceRef->Offset();
+ }
+ isMetadataWritten = true;
+ }
+
+ // If simple cases was followed then copy rest file
+ if ( isTitleWritten && isDescWritten && isMetadataWritten )
+ {
+ XIO::Copy( sourceRef, tempRef, ( sourceRef->Length() - currentOffset ) );
+ return;
+ }
+
+ // If the case is not Simple (TDM) then perform these operations
+ if ( isDescWritten ) // TDM, DTM, DMT
+ {
+ if ( !isTitleWritten ) // DTM, DMT
+ {
+ if ( titleOffset.startOffset < metadataOffset.startOffset ) // DTM
+ {
+ ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
+ isTitleWritten = true;
+
+ if ( this->packetInfo.offset == kXMPFiles_UnknownOffset )
+ {
+ std::string metadataElement = "<metadata>";
+ XIO::Copy( sourceRef, tempRef, metadataOffset.startOffset - currentOffset + metadataElement.length() );
+ currentOffset = sourceRef->Offset();
+ tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
+ }
+ else
+ {
+ XIO::Copy( sourceRef, tempRef, this->packetInfo.offset - currentOffset );
+ tempRef->Write( this->xmpPacket.c_str(), static_cast< int >( this->xmpPacket.length() ) );
+ sourceRef->Seek( this->packetInfo.offset + this->packetInfo.length, kXMP_SeekFromStart );
+ currentOffset = sourceRef->Offset();
+ }
+ isMetadataWritten = true;
+
+ }
+ else // DMT
+ {
+ ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
+ isTitleWritten = true;
+ }
+ }
+ // Else
+ // Would have already covered this case: TDM
+
+ }
+ else // TMD, MDT, MTD
+ {
+ if ( isTitleWritten ) // TMD
+ {
+ ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
+ isDescWritten = true;
+ }
+ else // MDT or MTD
+ {
+ if ( titleOffset.startOffset < descOffset.startOffset ) // MTD
+ {
+ ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
+ isTitleWritten = true;
+
+ ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
+ isDescWritten = true;
+ }
+ else // MDT
+ {
+ ProcessDescription( sourceRef, tempRef, description, currentOffset, descOffset );
+ isDescWritten = true;
+
+ ProcessTitle( sourceRef, tempRef, title, currentOffset, titleOffset );
+ isTitleWritten = true;
+ }
+ }
+ }
+
+ // Finally Everything would have been written
+ XMP_Enforce( isTitleWritten && isDescWritten && isMetadataWritten );
+ XIO::Copy( sourceRef, tempRef, ( sourceRef->Length() - currentOffset ) );
+ this->needsUpdate = false;
+
+} // SVG_MetaHandler::WriteTempFile
diff --git a/XMPFiles/source/FileHandlers/SVG_Handler.hpp b/XMPFiles/source/FileHandlers/SVG_Handler.hpp
new file mode 100644
index 0000000..4790a98
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/SVG_Handler.hpp
@@ -0,0 +1,76 @@
+#ifndef __SVG_Handler_hpp__
+#define __SVG_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+//
+// This file includes implementation of SVG metadata, according to Scalable Vector Graphics (SVG) 1.1 Specification.
+// "https://www.w3.org/TR/2003/REC-SVG11-20030114/"
+// Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology,
+// Institut National de Recherche en Informatique et en Automatique, Keio University).
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
+//
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include "XMPFiles/source/FormatSupport/SVG_Adapter.hpp"
+
+extern XMPFileHandler* SVG_MetaHandlerCTor( XMPFiles* parent );
+
+extern bool SVG_CheckFormat( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ XMP_IO * fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kSVG_HandlerFlags = ( kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_AllowsSafeUpdate );
+
+class SVG_MetaHandler : public XMPFileHandler {
+
+public:
+
+ void CacheFileData();
+ void ProcessXMP();
+
+ void UpdateFile( bool doSafeUpdate );
+ void WriteTempFile( XMP_IO* tempRef );
+
+ XMP_OptionBits GetSerializeOptions();
+
+ SVG_MetaHandler( XMPFiles* parent );
+ virtual ~SVG_MetaHandler();
+
+private:
+
+ SVG_MetaHandler() {};
+ SVG_Adapter * svgAdapter;
+ XML_NodePtr svgNode;
+ bool isTitleUpdateReq;
+ bool isDescUpdateReq;
+
+ void ProcessTitle( XMP_IO* sourceRef, XMP_IO * destRef, const std::string &value, XMP_Int64 &currentOffset, const OffsetStruct & titleOffset );
+ void ProcessDescription( XMP_IO* sourceRef, XMP_IO * destRef, const std::string &value, XMP_Int64 &currentOffset, const OffsetStruct & descOffset );
+ void InsertNewTitle( XMP_IO * destRef, const std::string &value );
+ void InsertNewDescription( XMP_IO * destRef, const std::string &value );
+ void InsertNewMetadata( XMP_IO * destRef, const std::string &value );
+
+}; // SVG_MetaHandler
+
+// =================================================================================================
+
+#endif /* __SVG_Handler_hpp__ */
diff --git a/XMPFiles/source/FileHandlers/TIFF_Handler.cpp b/XMPFiles/source/FileHandlers/TIFF_Handler.cpp
index a09b879..66075bd 100644
--- a/XMPFiles/source/FileHandlers/TIFF_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/TIFF_Handler.cpp
@@ -272,8 +272,7 @@ void TIFF_MetaHandler::ProcessXMP()
// Process the legacy metadata.
if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if (iptcInfo.dataLen) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
ImportPhotoData ( tiff, iptc, psir, iptcDigestState, &this->xmpObj, options );
this->containsXMP = true; // Assume we now have something in the XMP.
diff --git a/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
index 826cc0b..74c7c00 100644
--- a/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
@@ -624,12 +624,18 @@ void XDCAMEX_MetaHandler::GetTakeDuration ( const std::string & takeURI, std::st
std::string takeDir ( takeURI );
takeDir.erase ( 0, 1 ); // Change the leading "//" to "/", then all '/' to kDirChar.
+#if XMP_MacBuild
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
if ( kDirChar != '/' ) {
for ( size_t i = 0, limit = takeDir.size(); i < limit; ++i ) {
if ( takeDir[i] == '/' ) takeDir[i] = kDirChar;
}
}
-
+#if XMP_MacBuild
+#pragma clang diagnostic pop
+#endif
std::string takePath ( this->rootPath );
takePath += kDirChar;
takePath += "BPAV";
diff --git a/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.cpp
new file mode 100644
index 0000000..ded65c4
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.cpp
@@ -0,0 +1,677 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+// =================================================================================================
+//
+// This handler will handle FAM/FTP variant of XDCAM.
+// More information could be found in XDCAM_Handler.cpp
+//
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include "source/XMPFiles_IO.hpp"
+#include "source/XIO.hpp"
+#include "source/IOUtils.hpp"
+
+#include "XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp"
+#include "XMPFiles/source/FormatSupport/XDCAM_Support.hpp"
+#include "XMPFiles/source/FormatSupport/PackageFormat_Support.hpp"
+
+bool XDCAMFAM_CheckFormat ( XMP_FileFormat format,
+ const std::string & rootPath,
+ const std::string & groupName,
+ const std::string & parentName,
+ const std::string & leafName,
+ XMPFiles * parent )
+{
+ /* isXDStyle = true Means SxS Memory or XDStyle
+ , = false Means Professional Disk */
+ bool isXDStyle = false;
+ if ( (format != kXMP_XDCAM_FAMFile) && (format != kXMP_UnknownFile) ) return false;
+ if ( groupName.empty() != parentName.empty() ) return false;
+
+ if ( groupName.empty() && ( Host_IO::GetChildMode ( rootPath.c_str(), "PROAV" ) == Host_IO::kFMode_IsFolder ) ) return false;
+
+ std::string tempPath = rootPath;
+
+ if ( !parentName.empty() )
+ {
+ // Real Absolute Path exists
+ if ( ! ( parentName == "CLIP" || parentName == "SUB" || parentName == "LOCAL" ) )
+ return false;
+ tempPath += kDirChar + groupName;
+ }
+
+ // Some basic Checks
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCMETA.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode( tempPath.c_str(), "MEDIAPRO.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( ( Host_IO::GetChildMode( tempPath.c_str(), "Take" ) == Host_IO::kFMode_IsFolder ) || ( Host_IO::GetChildMode( tempPath.c_str(), "Local" ) == Host_IO::kFMode_IsFolder ) )
+ isXDStyle = true;
+
+ // XDStyle can't have INDEX.XML
+ if ( isXDStyle && ( Host_IO::GetChildMode( tempPath.c_str(), "INDEX.XML" ) == Host_IO::kFMode_IsFile ) )
+ return false;
+ // XDStyle can't have ALIAS.XML
+ if( isXDStyle && ( Host_IO::GetChildMode( tempPath.c_str(), "ALIAS.XML" ) == Host_IO::kFMode_IsFile ) )
+ return false;
+ // Non-XDStyle can't have CUEUP.XML file
+ if( ( !isXDStyle ) && ( Host_IO::GetChildMode( tempPath.c_str(), "CUEUP.XML" ) == Host_IO::kFMode_IsFile ) )
+ return false;
+
+ // We will get metadata from NRT file inside Clip folder only
+ tempPath += kDirChar;
+ tempPath += "Clip";
+ tempPath += kDirChar;
+
+ std::string clipName = leafName;
+ size_t length = clipName.length();
+
+ // Proxy file support
+ if ( ( parentName == "SUB" ) )
+ {
+ if( clipName.at( length - 3 ) != 'S' || ( ! IsDigit( clipName.at( length - 2 ) ) ) || ( ! IsDigit( clipName.at( length - 1 ) ) ) )
+ return false;
+ clipName.erase( clipName.begin() + length - 3, clipName.end() );
+ }
+
+ tempPath += clipName;
+
+ // .MXF file Existence with case sensitive is the new check inserted
+ std::string mxfPath = tempPath + ".MXF";
+ if ( Host_IO::GetFileMode ( mxfPath.c_str() ) != Host_IO::kFMode_IsFile )
+ {
+ mxfPath = tempPath + ".mxf";
+ if ( Host_IO::GetFileMode ( mxfPath.c_str() ) != Host_IO::kFMode_IsFile )
+ return false;
+ }
+
+ tempPath += "M01.XML";
+ if ( Host_IO::GetFileMode ( tempPath.c_str() ) != Host_IO::kFMode_IsFile )
+ return false;
+ return true;
+
+} // XDCAMFAM_CheckFormat
+
+XMPFileHandler * XDCAMFAM_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new XDCAMFAM_MetaHandler ( parent );
+
+} // XDCAM_MetaHandlerCTor
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::XDCAMFAM_MetaHandler
+// ====================================
+XDCAMFAM_MetaHandler::XDCAMFAM_MetaHandler ( XMPFiles * _parent ) : XDCAM_MetaHandler(_parent), isXDStyle( false )
+{
+ this->handlerFlags = kXDCAMFAM_HandlerFlags;
+ // Setting the various path variables
+ this->SetPathVariables ( this->parent->GetFilePath() );
+} // XDCAMFAM_MetaHandler::XDCAMFAM_MetaHandler
+
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::SetPathVariables
+// ====================================
+void XDCAMFAM_MetaHandler::SetPathVariables ( const std::string & clientPath )
+{
+ // No need to check for existing or non existing as would have been done at check file format if ForceGivenHandler flag is not provided
+ std::string tempPath = clientPath;
+ std::string parentName, GroupName;
+ std::string ignored;
+
+ XIO::SplitLeafName ( &tempPath, &this->clipName );
+
+ this->rootPath = tempPath;
+
+ if ( ! Host_IO::Exists( clientPath.c_str() ) )
+ {
+ // Logical Path exists
+ // No need to extract extension as clipname is given without extension
+ if ( ( Host_IO::GetChildMode( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile ) )
+ this->isXDStyle = true;
+ tempPath += kDirChar;
+ tempPath += "Clip";
+ XMP_Assert( Host_IO::GetFileMode( tempPath.c_str() ) == Host_IO::kFMode_IsFolder );
+ }
+ else
+ {
+ // Real Absolute Path exists
+ XIO::SplitFileExtension ( &this->clipName, &ignored );
+ XIO::SplitLeafName ( &tempPath, &parentName );
+ if ( ( Host_IO::GetChildMode( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile ) )
+ this->isXDStyle = true;
+ this->rootPath = tempPath;
+
+ size_t length = this->clipName.length();
+
+ // Proxy file support
+ if ( parentName == "Sub" )
+ {
+ XMP_Assert( IsDigit( clipName.at( length - 2 ) ) && IsDigit( clipName.at( length - 1 ) ) );
+ XMP_Assert( this->clipName.at( length - 3 ) == 'S' );
+ this->clipName.erase( this->clipName.begin() + length - 3, clipName.end() );
+ tempPath += kDirChar ;
+ tempPath += "Clip";
+ }
+ else
+ tempPath += kDirChar + parentName;
+ }
+
+ // Checks for Clip folder in XDCAM
+ XMP_Assert ( Host_IO::GetChildMode ( rootPath.c_str(), "Clip" ) == Host_IO::kFMode_IsFolder );
+
+ tempPath += kDirChar;
+ tempPath += this->clipName;
+ std::string mxfPath;
+
+ // Case sensitive Extension support to check for clipname.MXF or clipname.mxf as already cover in Checkformat
+ if ( !( MakeClipFilePath( &mxfPath, ".MXF", true ) || MakeClipFilePath( &mxfPath, ".mxf", true ) ) )
+ {
+ XMP_Error error( kXMPErr_FilePathNotAFile, "Clip MXF file must be exist" );
+ NotifyClient( &this->parent->errorCallback, kXMPErrSev_FileFatal, error );
+ }
+
+ // NRT file Check as already cover in checkformat
+ if ( ! MakeClipFilePath ( &this->mNRTFilePath, "M01.XML", true ) )
+ {
+ XMP_Error error( kXMPErr_FilePathNotAFile, "Clip NRT XML file must be exist" );
+ NotifyClient( &this->parent->errorCallback, kXMPErrSev_FileFatal, error );
+ }
+
+ // Setting correct sidecar path
+ if ( this->isXDStyle || (Host_IO::GetChildMode ( rootPath.c_str(), "UserData" ) == Host_IO::kFMode_IsFolder ) )
+ {
+ if ( ! ( MakeClipFilePath( &this->sidecarPath, ".xmp", true ) || MakeClipFilePath( &this->sidecarPath, ".XMP", true ) ) )
+ this->sidecarPath = mxfPath + ".xmp";
+ }
+ else
+ {
+ if ( ! ( MakeClipFilePath( &this->sidecarPath, "M01.XMP", true ) || MakeClipFilePath( &this->sidecarPath, "M01.xmp", true ) ) )
+ this->sidecarPath = tempPath + "M01.XMP";
+ }
+
+} // XDCAMFAM_MetaHandler::SetPathVariables
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::FillAssociatedResources
+// ====================================
+void XDCAMFAM_MetaHandler::FillAssociatedResources( std::vector<std::string> * resourceList )
+{
+ //Add RootPath
+ std::string filePath = rootPath + kDirChar;
+ PackageFormat_Support::AddResourceIfExists( resourceList, filePath );
+
+ // Get the files present directly inside root folder.
+ filePath = rootPath + kDirChar + "ALIAS.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ // INDEX.XML doesn't exist for XDStyle
+ if( ! this->isXDStyle )
+ {
+ filePath = rootPath + kDirChar + "INDEX.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ }
+
+ filePath = rootPath + kDirChar + "DISCMETA.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ filePath = rootPath + kDirChar + "MEDIAPRO.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ filePath = rootPath + kDirChar + "MEDIAPRO.BUP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ // CUEUP.XML don't exist for Professional Disk XDCAM
+ if( this->isXDStyle )
+ {
+ filePath = rootPath + kDirChar + "CUEUP.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ filePath = rootPath + kDirChar + "CUEUP.BUP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ }
+
+ // Add the UserData folder
+ filePath = rootPath + kDirChar + "UserData" + kDirChar;
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+
+ // Get the files present inside clip folder.
+ XMP_VarString clipPath = rootPath + kDirChar + "Clip" + kDirChar ;
+ size_t oldCount = resourceList->size();
+
+ XMP_VarString regExp;
+ XMP_StringVector regExpVec;
+
+ regExp = "^" + clipName + ".MXF$";
+ regExpVec.push_back ( regExp );
+ regExp = "^" + clipName + "M\\d\\d.XML$";
+ regExpVec.push_back ( regExp );
+ if ( this->isXDStyle )
+ {
+ regExp = "^" + clipName + "R\\d\\d.BIM$";
+ regExpVec.push_back ( regExp );
+ }
+ else
+ {
+ regExp = "^" + clipName + "M\\d\\d.KLV$";
+ regExpVec.push_back ( regExp );
+ }
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
+ PackageFormat_Support::AddResourceIfExists( resourceList, this->sidecarPath);
+ if ( resourceList->size() <= oldCount )
+ {
+ PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
+ }
+
+ //Get the files Under Sub folder
+ clipPath = rootPath + kDirChar + "Sub" + kDirChar ;
+ regExpVec.clear();
+ regExp = "^" + clipName + "S\\d\\d.MXF$";
+ regExpVec.push_back ( regExp );
+ oldCount = resourceList->size();
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
+ // Add Sub folder if no file inside this, was added.
+ if ( resourceList->size() <= oldCount )
+ {
+ PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
+ }
+
+ // Get the files Under Local folder if it is XDStyle
+ if ( isXDStyle )
+ {
+ clipPath = rootPath + kDirChar + "Local" + kDirChar ;
+ regExpVec.clear();
+ // ClipInfo file
+ regExp = "^" + clipName + "C\\d\\d.SMI$";
+ regExpVec.push_back ( regExp );
+ // Picture pointer file
+ regExp = "^" + clipName + "I\\d\\d.PPN$";
+ regExpVec.push_back ( regExp );
+ oldCount = resourceList->size();
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
+ // Add Local folder if no file inside this, was added.
+ if ( resourceList->size() <= oldCount )
+ {
+ PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
+ }
+ }
+
+ // Add the Edit lists associated to this clip
+ XMP_StringVector editInfoList;
+ bool atLeastOneFileAdded = false;
+ clipPath = rootPath + kDirChar + "Edit" + kDirChar ;
+ if ( GetInfoFiles ( editInfoList , clipPath ) )
+ {
+ size_t noOfEditInfoFiles = editInfoList.size() ;
+ for( size_t count = 0; count < noOfEditInfoFiles; count++ )
+ {
+ atLeastOneFileAdded = PackageFormat_Support::AddResourceIfExists(resourceList, editInfoList[count]) ? true : atLeastOneFileAdded;
+
+ XMP_VarString editNRTFile = editInfoList[count] ;
+ size_t filenamelen = editNRTFile.length() ;
+ if ( editNRTFile[ filenamelen - 7 ] == 'E'
+ && IsDigit( editNRTFile[ filenamelen - 6 ] )
+ && IsDigit( editNRTFile[ filenamelen - 5 ] ) )
+ {
+ editNRTFile.erase( editNRTFile.begin() + filenamelen - 7, editNRTFile.end() ) ;
+ }
+ else
+ {
+ editNRTFile.erase( editNRTFile.begin() + filenamelen - 4, editNRTFile.end() ) ;
+ }
+
+ XMP_VarString fileName;
+ size_t pos = editNRTFile.find_last_of ( kDirChar );
+ fileName = editNRTFile.substr ( pos + 1 );
+ XMP_VarString regExp = "^" + fileName + "M\\d\\d.XML$";
+ oldCount = resourceList->size();
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExp, false, true, true );
+ atLeastOneFileAdded = resourceList->size() > oldCount;
+
+ }
+ }
+ // Add Edit folder if no file inside this, was added.
+ if ( !atLeastOneFileAdded )
+ {
+ PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
+ }
+
+ atLeastOneFileAdded = false;
+
+ // Add the Takes associated to this clip,
+ // Take folder exists only for XDStyle
+ if( this->isXDStyle )
+ {
+ XMP_StringVector takeList;
+ clipPath = rootPath + kDirChar + "Take" + kDirChar ;
+ if( GetInfoFiles ( takeList , clipPath ) )
+ {
+ size_t noOfTakes = takeList.size() ;
+ for( size_t count = 0; count < noOfTakes; count++ )
+ {
+ atLeastOneFileAdded = PackageFormat_Support::AddResourceIfExists(resourceList, takeList[count]) ? true : atLeastOneFileAdded;
+ XMP_VarString takeNRTFile = takeList[count] ;
+ size_t filenamelen = takeList[count].length() ;
+ if ( takeNRTFile[ filenamelen - 7 ] == 'U'
+ && IsDigit( takeNRTFile[ filenamelen - 6 ] )
+ && IsDigit( takeNRTFile[ filenamelen - 5 ] ) )
+ {
+ takeNRTFile.erase( takeNRTFile.begin() + filenamelen - 7, takeNRTFile.end() ) ;
+ }
+ else
+ {
+ takeNRTFile.erase( takeNRTFile.begin() + filenamelen - 4, takeNRTFile.end() ) ;
+ }
+
+ XMP_VarString fileName;
+ size_t pos = takeNRTFile.find_last_of ( kDirChar );
+ fileName = takeNRTFile.substr ( pos + 1 );
+ XMP_VarString regExp = "^" + fileName + "M\\d\\d.XML$";
+ oldCount = resourceList->size();
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExp, false, true, true );
+ atLeastOneFileAdded = resourceList->size() > oldCount;
+ }
+ }
+ // Add Take folder if no file inside this, was added.
+ if(!atLeastOneFileAdded)
+ {
+ filePath = rootPath + kDirChar + "Take" + kDirChar;
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ }
+ }
+
+ // Add the Planning Metadata Files associated to this clip
+ // Planning Metadata exist for both SxS and Professional Disk
+ XMP_StringVector planList;
+ clipPath = rootPath + kDirChar + "General" + kDirChar + "Sony" + kDirChar+ "Planning" + kDirChar;
+ if( GetPlanningFiles ( planList , clipPath ) )
+ {
+ size_t noOfPlans = planList.size() ;
+ for( size_t count = 0; count < noOfPlans; count++ )
+ {
+ resourceList->push_back( planList[count] );
+ }
+ }
+} // XDCAMFAM_MetaHandler::FillAssociatedResources
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::MakeClipFilePath
+// ====================================
+bool XDCAMFAM_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ )
+{
+
+ *path = this->rootPath;
+ *path += kDirChar;
+
+ *path += "Clip"; // ! Yes, mixed case.
+
+ *path += kDirChar;
+ *path += this->clipName;
+ *path += suffix;
+
+ if ( ! checkFile ) return true;
+ return Host_IO::Exists ( path->c_str() );
+
+} // XDCAMFAM_MetaHandler::MakeClipFilePath
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::MakeLocalFilePath
+// ====================================
+bool XDCAMFAM_MetaHandler::MakeLocalFilePath ( std::string * path, XMP_Uns8 fileType, bool checkFile /* = false */ )
+{
+
+ *path = this->rootPath;
+ *path += kDirChar;
+
+ *path += "Local"; // ! Yes, mixed case.
+
+ *path += kDirChar;
+ *path += this->clipName;
+
+ if( fileType == k_LocalPPNFile )
+ *path += "I01.PPN";
+ else if ( fileType == k_LocalClipInfoFile )
+ *path += "S01.SMI";
+ else
+ return false;
+
+ if ( ! checkFile ) return true;
+ return Host_IO::Exists ( path->c_str() );
+
+} // XDCAMFAM_MetaHandler::MakeLocalFilePath
+
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::GetMediaProMetadata
+// ====================================
+bool XDCAMFAM_MetaHandler::GetMediaProMetadata ( SXMPMeta * xmpObjPtr,
+ const std::string& clipUMID,
+ bool digestFound )
+{
+ // Build a directory string to the MEDIAPRO file.
+ std::string mediaproPath;
+ MakeMediaproPath ( &mediaproPath );
+ return XDCAM_Support::GetMediaProLegacyMetadata ( xmpObjPtr, clipUMID, mediaproPath, digestFound );
+} // XDCAMFAM_MetaHandler::GetMediaProMetadata
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::GetPlanningFiles
+// ====================================
+bool XDCAMFAM_MetaHandler::GetPlanningFiles ( std::vector<std::string> &planInfoList, std::string pathToFolder)
+{
+ std::string clipUmid;
+ bool found = false;
+
+ if( GetClipUmid ( clipUmid ) )
+ {
+ if ( Host_IO::Exists( pathToFolder.c_str() ) &&
+ Host_IO::GetFileMode( pathToFolder.c_str() ) == Host_IO::kFMode_IsFolder
+ )
+ {
+ Host_IO::AutoFolder planFolder;
+ std::string listChild;
+
+ planFolder.folder = Host_IO::OpenFolder ( pathToFolder.c_str() );
+ while ( Host_IO::GetNextChild ( planFolder.folder, &listChild ) ) {
+ size_t filenamelen = listChild.size();
+ std::string listFilePath = pathToFolder + listChild ;
+ if ( ! ( filenamelen > 4 &&
+ ( listChild.compare ( filenamelen - 4, 4 , ".XML" ) == 0
+ ||
+ listChild.compare ( filenamelen - 4, 4 , ".xml" ) == 0
+ )
+ &&
+ Host_IO::GetFileMode( listFilePath.c_str() ) == Host_IO::kFMode_IsFile
+ ) ) continue;
+ if( IsClipsPlanning ( clipUmid , listFilePath.c_str() ) )
+ {
+ found = true ;
+ planInfoList.push_back( listFilePath );
+ }
+ }
+ }
+ }
+ return found;
+} // XDCAMFAM_MetaHandler::GetPlanningFiles
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::IsClipsPlanning
+// ====================================
+bool XDCAMFAM_MetaHandler::IsClipsPlanning ( std::string clipUmid , XMP_StringPtr planPath )
+{
+ ExpatAdapter* planniingExpat = 0 ;
+ XMP_StringPtr nameSpace = 0 ;
+ try {
+ readXMLFile( planPath, planniingExpat );
+ if ( planniingExpat != 0 )
+ {
+ XML_Node & xmlTree = planniingExpat->tree;
+ XML_NodePtr rootElem = 0;
+
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ rootElem = xmlTree.content[i];
+ }
+ }
+ if ( rootElem != 0 )
+ {
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( XMP_LitMatch ( rootLocalName, "PlanningMetadata" ) )
+ {
+ nameSpace = rootElem->ns.c_str() ;
+ size_t noOfMaterialGroups = rootElem->CountNamedElements ( nameSpace, "MaterialGroup" ) ;
+ while( noOfMaterialGroups-- )
+ {
+ XML_NodePtr mgNode = rootElem->GetNamedElement( nameSpace, "MaterialGroup" );
+ size_t noOfMaterialElements = mgNode->CountNamedElements ( nameSpace, "Material" ) ;
+ while( noOfMaterialElements-- )
+ {
+ XML_NodePtr materialNode = mgNode->GetNamedElement( nameSpace, "Material" );
+ XMP_StringPtr materialType = materialNode->GetAttrValue ( "type" );
+ if ( materialType && XMP_LitMatch( materialType , "clip" ) )
+ {
+ XMP_StringPtr umidValue = materialNode->GetAttrValue ( "umidRef" );
+ if ( umidValue != 0 && XMP_LitMatch( umidValue , clipUmid.c_str() ) )
+ {
+ delete ( planniingExpat ) ;
+ return true;
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ } catch ( ... ) {
+ }
+ delete ( planniingExpat ) ;
+ return false;
+} // XDCAMFAM_MetaHandler::IsClipsPlanning
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::GetInfoFiles
+// ====================================
+bool XDCAMFAM_MetaHandler::GetInfoFiles ( std::vector<std::string> &infoList, std::string pathToFolder)
+{
+ std::string clipUmid;
+ bool found = false;
+
+ if( GetClipUmid ( clipUmid ) )
+ {
+ if ( Host_IO::Exists( pathToFolder.c_str() ) &&
+ Host_IO::GetFileMode( pathToFolder.c_str() ) == Host_IO::kFMode_IsFolder
+ )
+ {
+ Host_IO::AutoFolder infoFolder;
+ std::string listChild;
+
+ infoFolder.folder = Host_IO::OpenFolder ( pathToFolder.c_str() );
+ while ( Host_IO::GetNextChild ( infoFolder.folder, &listChild ) ) {
+ size_t filenamelen = listChild.size();
+ std::string listFilePath = pathToFolder + listChild ;
+ if ( ! ( filenamelen > 7 &&
+ listChild.compare ( filenamelen - 4, 4 , ".SMI" ) == 0 &&
+ Host_IO::GetFileMode( listFilePath.c_str() ) == Host_IO::kFMode_IsFile
+ ) ) continue;
+ if( RefersClipUmid ( clipUmid , listFilePath.c_str() ) )
+ {
+ found = true ;
+ infoList.push_back( listFilePath );
+ }
+ }
+ }
+ }
+ return found;
+} // XDCAMFAM_MetaHandler::GetInfoFiles
+
+// =================================================================================================
+// XDCAMFAM_MetaHandler::GetClipUmid
+// ==============================
+bool XDCAMFAM_MetaHandler::GetClipUmid ( std::string &clipUmid )
+{
+ std::string clipInfoPath;
+ ExpatAdapter* clipInfoExpat = 0 ;
+ bool umidFound = false;
+ XMP_StringPtr nameSpace = 0;
+ try {
+ if ( this->MakeLocalFilePath ( &clipInfoPath, k_LocalClipInfoFile, true ) )
+ {
+ readXMLFile( clipInfoPath.c_str(), clipInfoExpat );
+ if ( clipInfoExpat != 0 )
+ {
+ XML_Node & xmlTree = clipInfoExpat->tree;
+ XML_NodePtr rootElem = 0;
+
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ rootElem = xmlTree.content[i];
+ }
+ }
+ if ( rootElem != 0 )
+ {
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( XMP_LitMatch ( rootLocalName, "smil" ) )
+ {
+ XMP_StringPtr umidValue = rootElem->GetAttrValue ( "umid" );
+ if ( umidValue != 0 ) {
+ clipUmid = umidValue;
+ umidFound = true;
+ }
+ }
+ }
+ }
+ }
+ if( ! umidFound )
+ { //try to get the umid from the NRT metadata
+ delete ( clipInfoExpat ) ; clipInfoExpat = 0;
+ this->MakeClipFilePath ( &clipInfoPath, "M01.XML" ) ;
+ readXMLFile( clipInfoPath.c_str(), clipInfoExpat ) ;
+ if ( clipInfoExpat != 0 )
+ {
+ XML_Node & xmlTree = clipInfoExpat->tree;
+ XML_NodePtr rootElem = 0;
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ rootElem = xmlTree.content[i];
+ }
+ }
+ if ( rootElem != 0 )
+ {
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( XMP_LitMatch ( rootLocalName, "NonRealTimeMeta" ) )
+ {
+ nameSpace = rootElem->ns.c_str() ;
+ XML_NodePtr targetProp = rootElem->GetNamedElement ( nameSpace, "TargetMaterial" );
+ if ( (targetProp != 0) && targetProp->IsEmptyLeafNode() ) {
+ XMP_StringPtr umidValue = targetProp->GetAttrValue ( "umidRef" );
+ if ( umidValue != 0 ) {
+ clipUmid = umidValue;
+ umidFound = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch ( ... ) {
+ }
+ delete ( clipInfoExpat ) ;
+ return umidFound;
+} // XDCAMFAM_MetaHandler::GetClipUmid
+
+// =================================================================================================
diff --git a/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp b/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp
new file mode 100644
index 0000000..b53e55b
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp
@@ -0,0 +1,71 @@
+#ifndef __XDCAMFAM_Handler_hpp__
+#define __XDCAMFAM_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "public/include/XMP_Environment.h" // ! This must be the first include.
+#include "XMPFiles/source/FileHandlers/XDCAM_Handler.hpp"
+
+
+extern XMPFileHandler * XDCAMFAM_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool XDCAMFAM_CheckFormat ( XMP_FileFormat format,
+ const std::string & rootPath,
+ const std::string & gpName,
+ const std::string & parentName,
+ const std::string & leafName,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kXDCAMFAM_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_HandlerOwnsFile |
+ kXMPFiles_AllowsSafeUpdate |
+ kXMPFiles_FolderBasedFormat);
+
+
+class XDCAMFAM_MetaHandler : public XDCAM_MetaHandler
+{
+
+public:
+
+ void FillAssociatedResources ( std::vector<std::string> * resourceList );
+ XDCAMFAM_MetaHandler ( XMPFiles * _parent );
+ virtual ~XDCAMFAM_MetaHandler() { };
+
+private:
+
+ bool isXDStyle;
+
+ bool MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false );
+ void SetPathVariables ( const std::string & clientPath );
+ bool GetMediaProMetadata ( SXMPMeta * xmpObjPtr, const std::string& clipUMID, bool digestFound );
+ bool GetInfoFiles ( std::vector<std::string> &infoList, std::string pathToFolder) ;
+ bool GetPlanningFiles ( std::vector<std::string> &planInfoList, std::string pathToFolder) ;
+ bool IsClipsPlanning ( std::string clipUmid , XMP_StringPtr planPath ) ;
+ bool GetClipUmid ( std::string &clipUmid );
+ bool MakeLocalFilePath ( std::string * path, XMP_Uns8 fileType, bool checkFile = false );
+
+ XDCAMFAM_MetaHandler() : XDCAM_MetaHandler() {}; // Hidden on purpose.
+
+ enum
+ {
+ k_LocalPPNFile,
+ k_LocalClipInfoFile
+ };
+
+}; // XDCAMFAM_MetaHandler
+
+// =================================================================================================
+#endif /* __XDCAMFAM_Handler_hpp__ */
diff --git a/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.cpp
new file mode 100644
index 0000000..f0303df
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.cpp
@@ -0,0 +1,429 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include "source/XMPFiles_IO.hpp"
+#include "source/XIO.hpp"
+#include "source/IOUtils.hpp"
+
+#include "XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp"
+#include "XMPFiles/source/FormatSupport/XDCAM_Support.hpp"
+#include "XMPFiles/source/FormatSupport/PackageFormat_Support.hpp"
+
+bool XDCAMSAM_CheckFormat ( XMP_FileFormat format,
+ const std::string & rootPath,
+ const std::string & groupName,
+ const std::string & parentName,
+ const std::string & leafName,
+ XMPFiles * parent )
+{
+ // We only support file in CLPR folder not in other folders
+
+ if ( ( format != kXMP_XDCAM_SAMFile ) && ( format != kXMP_UnknownFile ) ) return false;
+
+ // parentName or groupName empty means Logical path exists
+ if ( groupName.empty() != parentName.empty() ) return false;
+
+ std::string tempPath = rootPath;
+ std::string clipName = leafName;
+
+ if ( groupName.empty() )
+ {
+ // Logical clip exists
+ tempPath += kDirChar;
+ tempPath += "PROAV";
+
+ // Simple checks to ensure presence or absence of Management files or CLPR folder
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCMETA.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCINFO.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "CLPR" ) != Host_IO::kFMode_IsFolder ) return false;
+ if ( Host_IO::GetChildMode( tempPath.c_str(), "MEDIAPRO.XML" ) == Host_IO::kFMode_IsFile ) return false;
+ tempPath += kDirChar;
+ tempPath += "CLPR";
+ tempPath += kDirChar + leafName;
+ }
+ else if ( groupName == "CLPR" )
+ {
+ // XMP provides support only to files inside CLPR
+ // Simple checks to ensure presence or absence of Management files
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCMETA.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCINFO.XML" ) != Host_IO::kFMode_IsFile ) return false;
+ if ( ( Host_IO::GetChildMode( tempPath.c_str(), "MEDIAPRO.XML" ) == Host_IO::kFMode_IsFile ) ) return false;
+
+ tempPath += kDirChar + groupName;
+ tempPath += kDirChar + parentName;
+ size_t length = clipName.length();
+ const char fileType = clipName.at ( length - 3 );
+ if ( IsDigit( clipName.at( length - 1 ) ) && IsDigit( clipName.at( length - 2 ) ) )
+ {
+ // Last 3rd characater shows what is the file type
+ switch ( fileType )
+ {
+ case 'A' : // Audio
+ case 'C' : // ClipInfo
+ case 'I' : // Picture pointer
+ case 'M' : // NRT
+ case 'R' : // Real Time
+ case 'S' : // Sub (Proxy)
+ case 'V' : // Video
+ break;
+ default: // Unknown
+ return false;
+ }
+ clipName.erase ( clipName.begin() + length - 3, clipName.end() );
+ }
+ }
+ else
+ return false;
+ tempPath += kDirChar + clipName;
+ tempPath += "M01.XML";
+
+ // Checking for NRT file
+ if ( Host_IO::GetFileMode ( tempPath.c_str() ) != Host_IO::kFMode_IsFile )
+ return false;
+
+ return true;
+
+} // XDCAMSAM_CheckFormat
+
+XMPFileHandler * XDCAMSAM_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new XDCAMSAM_MetaHandler ( parent );
+} // XDCAMSAM_MetaHandlerCTor
+
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::XDCAMSAM_MetaHandler
+// ====================================
+XDCAMSAM_MetaHandler::XDCAMSAM_MetaHandler ( XMPFiles * _parent ) : XDCAM_MetaHandler(_parent)
+{
+ this->handlerFlags = kXDCAMSAM_HandlerFlags;
+ // Setting the various path variables
+ this->SetPathVariables ( this->parent->GetFilePath() );
+
+} // XDCAMSAM_MetaHandler::XDCAMSAM_MetaHandler
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::SetPathVariables
+// ====================================
+void XDCAMSAM_MetaHandler::SetPathVariables ( const std::string & clientPath )
+{
+ // No need to check for existing or non existing as would have been done at check file format if ForceGivenHandler flag is not provided
+ std::string tempPath = clientPath;
+ std::string parentName, groupName;
+ std::string ignored;
+
+ std::string leafName;
+ XIO::SplitLeafName ( &tempPath, &leafName );
+
+ if ( ! Host_IO::Exists( clientPath.c_str() ) )
+ {
+ // logical path exists
+ // No need to extract extension as clipname is given without extension
+ this->rootPath = tempPath;
+ tempPath += kDirChar;
+ tempPath += "PROAV";
+
+ XMP_Assert ( Host_IO::GetChildMode( tempPath.c_str(), "MEDIAPRO.XML" ) != Host_IO::kFMode_IsFile );
+
+ tempPath += kDirChar;
+ tempPath += "CLPR";
+ tempPath += kDirChar + leafName;
+ }
+ else
+ {
+ // Real Absolute Path exists
+ XIO::SplitFileExtension ( &leafName, &ignored );
+
+ XIO::SplitLeafName ( &tempPath, &parentName );
+ XIO::SplitLeafName ( &tempPath, &groupName );
+
+ std::string proav;
+ XIO::SplitLeafName ( &tempPath, &proav );
+ XMP_Assert ( proav == "PROAV" );
+
+ this->rootPath = tempPath;
+
+
+ XMP_Assert ( groupName == "CLPR" );
+
+ // Real Path may be ..PROAV//CLPR//clipName//clipname.MXF
+ // So XMP check for ..PROAV//CLPR//clipName//clipNameM01.xml
+ // XNP sidecar file will be ..PROAV//CLPR//clipName//clipNameM01.XMP
+ size_t length = leafName.length();
+
+ XMP_Assert ( IsDigit( leafName.at( length - 2 ) ) && IsDigit( leafName.at( length - 1 ) ) );
+ // Last 3rd character of file will inform us about its type
+ const char fileType = leafName.at( length - 3 );
+
+ // A = Audio, C = ClipInfo, I = Picture Pointer, M = Non-Realtime, R = Realtime, S = Sub (Proxy), V = Video
+ XMP_Assert ( fileType == 'A' || fileType == 'C' || fileType == 'I' || fileType == 'M' || fileType == 'R' || fileType == 'S' || fileType == 'V' );
+
+ leafName.erase ( leafName.begin() + length - 3, leafName.end() );
+
+ tempPath += kDirChar + proav;
+ tempPath += kDirChar + groupName;
+ tempPath += kDirChar + parentName;
+ }
+
+ this->clipName = leafName;
+
+
+ tempPath += kDirChar;
+ tempPath += leafName;
+
+ // NRT file Check as already cover in checkformat
+ if ( ! MakeClipFilePath( &this->mNRTFilePath, "M01.XML", true ) )
+ {
+ XMP_Error error( kXMPErr_FilePathNotAFile, "Clip NRT XML file must be exist" );
+ NotifyClient( &this->parent->errorCallback, kXMPErrSev_FileFatal, error );
+ }
+
+ // Setting correct sidecar path covering both .XMP and .xmp
+ if ( ! ( MakeClipFilePath( &this->sidecarPath, "M01.XMP", true ) || MakeClipFilePath( &this->sidecarPath, "M01.xmp", true ) ) )
+ this->sidecarPath = tempPath + "M01.XMP";
+
+} // XDCAMSAM_MetaHandler::SetPathVariables
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::FillAssociatedResources
+// ====================================
+void XDCAMSAM_MetaHandler::FillAssociatedResources( std::vector<std::string> * resourceList )
+{
+
+ std::string proavPath = rootPath + kDirChar + "PROAV" + kDirChar;
+ std::string filePath;
+
+ //Add RootPath
+ filePath = rootPath + kDirChar;
+ PackageFormat_Support::AddResourceIfExists( resourceList, filePath );
+
+ // Get the files present directly inside PROAV folder.
+ filePath = proavPath + "INDEX.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ filePath = proavPath + "INDEX.BUP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ filePath = proavPath + "DISCINFO.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+ filePath = proavPath + "DISCINFO.BUP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ filePath = proavPath + "DISCMETA.XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
+
+ // Covering files in clipname folder in CLPR folder
+ XMP_VarString clipPath = proavPath + "CLPR" + kDirChar + clipName + kDirChar;
+ XMP_VarString regExp;
+ XMP_StringVector regExpVec;
+
+ // ClipInfo file
+ regExp = "^" + clipName + "C\\d\\d.SMI$";
+ regExpVec.push_back ( regExp );
+ // Non-Real time metadata file
+ regExp = "^" + clipName + "M\\d\\d.XML$";
+ regExpVec.push_back ( regExp );
+ // Video file
+ regExp = "^" + clipName + "V\\d\\d.MXF$";
+ regExpVec.push_back ( regExp );
+ // Audio File
+ regExp = "^" + clipName + "A\\d\\d.MXF$";
+ regExpVec.push_back ( regExp );
+ // Real time metadata file
+ regExp = "^" + clipName + "R\\d\\d.BIM$";
+ regExpVec.push_back ( regExp );
+ // Picture pointer file
+ regExp = "^" + clipName + "I\\d\\d.PPN$";
+ regExpVec.push_back ( regExp );
+ // Sub(Proxy) files
+ regExp = "^" + clipName + "S\\d\\d.MXF$";
+ regExpVec.push_back ( regExp );
+ IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
+
+ // Adding sidecar file if exixts
+ PackageFormat_Support::AddResourceIfExists(resourceList, this->sidecarPath);
+
+ // Add the Edit lists that refer this clip
+ std::vector<std::string> editInfoList;
+ if( GetEditInfoFiles ( editInfoList ) )
+ {
+ size_t noOfEditInfoFiles = editInfoList.size() ;
+ for( size_t count = 0; count < noOfEditInfoFiles; count++ )
+ {
+ PackageFormat_Support::AddResourceIfExists(resourceList, editInfoList[count]);
+ std::string editNRTFile = editInfoList[count].c_str() ;
+ size_t filenamelen = editInfoList[count].length() ;
+ editNRTFile[ filenamelen - 7 ] = 'M';
+ editNRTFile[ filenamelen - 3 ] = 'X';
+ editNRTFile[ filenamelen - 2 ] = 'M';
+ editNRTFile[ filenamelen - 1 ] = 'L';
+ PackageFormat_Support::AddResourceIfExists(resourceList, editNRTFile );
+ }
+ }
+} // XDCAMSAM_MetaHandler::FillAssociatedResources
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::MakeClipFilePath
+// ====================================
+bool XDCAMSAM_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ )
+{
+ *path = this->rootPath;
+ *path += kDirChar;
+ *path += "PROAV";
+ *path += kDirChar;
+
+ *path += "CLPR"; // ! Yes, mixed case.
+
+ *path += kDirChar;
+ *path += this->clipName;
+ *path += kDirChar;
+ *path += this->clipName;
+ *path += suffix;
+
+ if ( ! checkFile ) return true;
+ return Host_IO::Exists ( path->c_str() );
+
+} // XDCAMSAM_MetaHandler::MakeClipFilePath
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::GetEditInfoFiles
+// ====================================
+bool XDCAMSAM_MetaHandler::GetEditInfoFiles ( std::vector<std::string> &editInfoList )
+{
+ std::string clipUmid;
+ bool found = false;
+
+ if( GetClipUmid ( clipUmid ) )
+ {
+ std::string editFolderPath = this->rootPath + kDirChar + "PROAV" + kDirChar + "EDTR" + kDirChar ;
+ if ( Host_IO::Exists( editFolderPath.c_str() ) &&
+ Host_IO::GetFileMode( editFolderPath.c_str() ) == Host_IO::kFMode_IsFolder
+ )
+ {
+ Host_IO::AutoFolder edtrFolder, editFolder;
+ std::string edtrChildName, edlistChild;
+
+ edtrFolder.folder = Host_IO::OpenFolder ( editFolderPath.c_str() );
+ while ( Host_IO::GetNextChild ( edtrFolder.folder, &edtrChildName ) ) {
+ size_t childLen = edtrChildName.size();
+ std::string editListFolderPath = editFolderPath + edtrChildName + kDirChar ;
+ if ( ! ( childLen == 5 &&
+ edtrChildName[0] == 'E' &&
+ IsDigit( edtrChildName[1] ) &&
+ IsDigit( edtrChildName[2] ) &&
+ IsDigit( edtrChildName[3] ) &&
+ IsDigit( edtrChildName[4] ) &&
+ Host_IO::GetFileMode( editListFolderPath.c_str() ) == Host_IO::kFMode_IsFolder
+ ) ) continue;
+
+ editFolder.folder = Host_IO::OpenFolder ( editListFolderPath.c_str() );
+ while ( Host_IO::GetNextChild ( editFolder.folder, &edlistChild ) ) {
+ size_t filenamelen = edlistChild.size();
+ std::string editListFilePath = editListFolderPath + edlistChild ;
+ if ( ! ( filenamelen == 12 &&
+ edlistChild.compare ( filenamelen - 4, 4 , ".SMI" ) == 0 &&
+ edlistChild.compare ( 0, edtrChildName.size(), edtrChildName ) == 0 &&
+ Host_IO::GetFileMode( editListFilePath.c_str() ) == Host_IO::kFMode_IsFile
+ ) ) continue;
+ if( RefersClipUmid ( clipUmid , editListFilePath.c_str() ) )
+ {
+ found = true ;
+ editInfoList.push_back( editListFilePath );
+ }
+ }
+ }
+ }
+ }
+ return found;
+} // XDCAMSAM_MetaHandler::GetEditInfoFiles
+
+// =================================================================================================
+// XDCAMSAM_MetaHandler::GetClipUmid
+// ==============================
+bool XDCAMSAM_MetaHandler::GetClipUmid ( std::string &clipUmid )
+{
+ std::string clipInfoPath;
+ ExpatAdapter* clipInfoExpat = 0 ;
+ bool umidFound = false;
+ XMP_StringPtr nameSpace = 0;
+ try {
+ this->MakeClipFilePath ( &clipInfoPath, "C01.SMI" ) ;
+ readXMLFile( clipInfoPath.c_str(), clipInfoExpat );
+ if ( clipInfoExpat != 0 )
+ {
+ XML_Node & xmlTree = clipInfoExpat->tree;
+ XML_NodePtr rootElem = 0;
+
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ rootElem = xmlTree.content[i];
+ }
+ }
+ if ( rootElem != 0 )
+ {
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( XMP_LitMatch ( rootLocalName, "smil" ) )
+ {
+ XMP_StringPtr umidValue = rootElem->GetAttrValue ( "umid" );
+ if ( umidValue != 0 ) {
+ clipUmid = umidValue;
+ umidFound = true;
+ }
+ }
+ }
+ }
+ if( ! umidFound )
+ { //try to get the umid from the NRT metadata
+ delete ( clipInfoExpat ) ; clipInfoExpat = 0;
+ this->MakeClipFilePath ( &clipInfoPath, "M01.XML" ) ;
+ readXMLFile( clipInfoPath.c_str(), clipInfoExpat ) ;
+ if ( clipInfoExpat != 0 )
+ {
+ XML_Node & xmlTree = clipInfoExpat->tree;
+ XML_NodePtr rootElem = 0;
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ rootElem = xmlTree.content[i];
+ }
+ }
+ if ( rootElem != 0 )
+ {
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+
+ if ( XMP_LitMatch ( rootLocalName, "NonRealTimeMeta" ) )
+ {
+ nameSpace = rootElem->ns.c_str() ;
+ XML_NodePtr targetProp = rootElem->GetNamedElement ( nameSpace, "TargetMaterial" );
+ if ( (targetProp != 0) && targetProp->IsEmptyLeafNode() ) {
+ XMP_StringPtr umidValue = targetProp->GetAttrValue ( "umidRef" );
+ if ( umidValue != 0 ) {
+ clipUmid = umidValue;
+ umidFound = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch ( ... ) {
+ }
+ delete ( clipInfoExpat ) ;
+ return umidFound;
+} // XDCAMSAM_MetaHandler::GetClipUmid
+
+// =================================================================================================
+
diff --git a/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp b/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp
new file mode 100644
index 0000000..b68334b
--- /dev/null
+++ b/XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp
@@ -0,0 +1,58 @@
+#ifndef __XDCAMSAM_Handler_hpp__
+#define __XDCAMSAM_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "public/include/XMP_Environment.h" // ! This must be the first include.
+#include "XMPFiles/source/FileHandlers/XDCAM_Handler.hpp"
+
+
+extern XMPFileHandler * XDCAMSAM_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool XDCAMSAM_CheckFormat ( XMP_FileFormat format,
+ const std::string & rootPath,
+ const std::string & groupName,
+ const std::string & parentName,
+ const std::string & leafName,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kXDCAMSAM_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_HandlerOwnsFile |
+ kXMPFiles_AllowsSafeUpdate |
+ kXMPFiles_FolderBasedFormat);
+
+class XDCAMSAM_MetaHandler : public XDCAM_MetaHandler
+{
+
+public:
+
+ void FillAssociatedResources ( std::vector<std::string> * resourceList );
+ XDCAMSAM_MetaHandler ( XMPFiles * _parent );
+ virtual ~XDCAMSAM_MetaHandler() { };
+
+private:
+
+ bool MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false );
+ void SetPathVariables ( const std::string & clientPath );
+ bool GetEditInfoFiles ( std::vector<std::string> &editInfoList );
+ bool GetClipUmid ( std::string &clipUmid );
+
+ XDCAMSAM_MetaHandler() : XDCAM_MetaHandler() {}; // Hidden on purpose.
+
+}; // XDCAMSAM_MetaHandler
+
+// =================================================================================================
+#endif /* __XDCAMSAM_Handler_hpp__ */
diff --git a/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
index 2a05be9..397b049 100644
--- a/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
@@ -194,358 +194,15 @@ using namespace std;
// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
// ! file exists for a full file path.
-bool XDCAM_CheckFormat ( XMP_FileFormat format,
- const std::string & _rootPath,
- const std::string & _gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent )
-{
- std::string rootPath = _rootPath; // ! Need tweaking in the existing file cases (FAM and SAM).
- std::string gpName = _gpName;
-
- bool isFAM = false;
-
- std::string tempPath, childName;
-
- std::string clipName = leafName;
-
- // Do some basic checks on the root path and component names. Decide if this is FAM or SAM.
-
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- if ( gpName.empty() ) {
-
- // This is the logical clip path case. Just look for PROAV to see if this is FAM or SAM.
- if ( Host_IO::GetChildMode ( rootPath.c_str(), "PROAV" ) != Host_IO::kFMode_IsFolder ) isFAM = true;
-
- } else {
-
- // This is the existing file case. See if this is FAM or SAM, tweak the clip name as needed.
-
- if ( (parentName == "CLIP") || (parentName == "EDIT") || (parentName == "SUB") ) {
- // ! The standard says Clip/Edit/Sub, but the caller has already shifted to upper case.
- isFAM = true;
- } else if ( (gpName != "CLPR") && (gpName != "EDTR") ) {
- return false;
- }
-
- if ( isFAM ) {
-
- // Put the proper root path together. Clean up the clip name if needed.
-
- if ( ! rootPath.empty() ) rootPath += kDirChar;
- rootPath += gpName;
- gpName.erase();
-
- // XMPilot has no ALIAS.XML, but does have a UserData folder, don't change the first
- // letter of the clip name for XMPilot.
- if ( (Host_IO::GetChildMode ( rootPath.c_str(), "ALIAS.XML" ) != Host_IO::kFMode_IsFile) &&
- (Host_IO::GetChildMode ( rootPath.c_str(), "UserData" ) != Host_IO::kFMode_IsFolder) ) {
- clipName[0] = 'C'; // ! See notes above about pending bug.
- }
-
- if ( clipName.size() > 3 ) {
- size_t clipMid = clipName.size() - 3;
- char c1 = clipName[clipMid];
- char c2 = clipName[clipMid+1];
- char c3 = clipName[clipMid+2];
- if ( ('A' <= c1) && (c1 <= 'Z') &&
- ('0' <= c2) && (c2 <= '9') && ('0' <= c3) && (c3 <= '9') ) {
- clipName.erase ( clipMid );
- }
- }
-
- } else {
-
- // Fix the clip name. Check for and strip the "PROAV" suffix on the root path.
-
- clipName = parentName; // ! We have a folder with the (almost) exact clip name.
- clipName[0] = 'C';
-
- std::string proav;
- XIO::SplitLeafName ( &rootPath, &proav );
- MakeUpperCase ( &proav );
- if ( (rootPath.empty()) || (proav != "PROAV") ) return false;
-
- }
-
- }
-
- // Make sure the general XDCAM package structure is legit. Set tempPath as a bogus path of the
- // form <root>/<FAM-or-SAM>/<clip>, e.g. ".../MyMovie/FAM/C0001". This is passed the handler via
- // the tempPtr hackery.
-
- if ( isFAM ) {
-
- if ( (format != kXMP_XDCAM_FAMFile) && (format != kXMP_UnknownFile) ) return false;
-
- tempPath = rootPath;
-
- // XMPilot does not have INDEX.XML but does have UserData.
- if ( (Host_IO::GetChildMode ( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile) &&
- !((Host_IO::GetChildMode ( rootPath.c_str(), "UserData" ) == Host_IO::kFMode_IsFolder)
- // Changes introduced by Sony for XDCAM Memory SxS format in the FAM file structure are
- // 1) There is no INDEX.XML in the root directory for XDCAM Memory SxS.
- // 2) There is a new Take folder(similar to XDCAMEX) in the root directory.
- || (Host_IO::GetChildMode ( tempPath.c_str(), "Take" ) == Host_IO::kFMode_IsFolder))) return false;
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCMETA.XML" ) != Host_IO::kFMode_IsFile ) return false;
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "MEDIAPRO.XML" ) != Host_IO::kFMode_IsFile ) return false;
-
- tempPath += kDirChar;
- tempPath += "Clip"; // ! Yes, mixed case.
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += "M01.XML";
- if ( Host_IO::GetFileMode ( tempPath.c_str() ) != Host_IO::kFMode_IsFile ) return false;
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "FAM";
- tempPath += kDirChar;
- tempPath += clipName;
-
- } else {
-
- if ( (format != kXMP_XDCAM_SAMFile) && (format != kXMP_UnknownFile) ) return false;
-
- // We already know about the PROAV folder, just check below it.
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "PROAV";
-
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile ) return false;
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCMETA.XML" ) != Host_IO::kFMode_IsFile ) return false;
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "DISCINFO.XML" ) != Host_IO::kFMode_IsFile ) return false;
- if ( Host_IO::GetChildMode ( tempPath.c_str(), "CLPR" ) != Host_IO::kFMode_IsFolder ) return false;
-
- tempPath += kDirChar;
- tempPath += "CLPR";
- tempPath += kDirChar;
- tempPath += clipName;
- if ( Host_IO::GetFileMode ( tempPath.c_str() ) != Host_IO::kFMode_IsFolder ) return false;
-
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += "M01.XML";
- if ( Host_IO::GetFileMode ( tempPath.c_str() ) != Host_IO::kFMode_IsFile ) return false;
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "SAM";
- tempPath += kDirChar;
- tempPath += clipName;
-
- }
-
- // Save the pseudo-path for the handler object. A bit of a hack, but the only way to get info
- // from here to there.
-
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for XDCAM clip info", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen ); // AUDIT: Safe, allocated above.
-
- return true;
-
-} // XDCAM_CheckFormat
-
-// =================================================================================================
-
-static void* CreatePseudoClipPath ( const std::string & clientPath ) {
-
- // Used to create the clip pseudo path when the CheckFormat function is skipped.
-
- std::string pseudoPath = clientPath;
- std::string clipName;
- bool isSAM;
-
- size_t pathLen;
- void* tempPtr = 0;
-
- if ( ! Host_IO::Exists ( pseudoPath.c_str() ) ) {
-
- // This is the logical clip path case. Look for PROAV to see if this is FAM or SAM.
-
- XIO::SplitLeafName ( &pseudoPath, &clipName ); // Extract the logical clip name, no extension.
- isSAM = ( Host_IO::GetChildMode ( pseudoPath.c_str(), "PROAV" ) == Host_IO::kFMode_IsFolder );
-
- } else {
-
- // The client passed a physical path. We have separate cases for FAM and SAM. If the last
- // folder, the parent of the file, is Clip, Edit, or Sub (ignoring case) then this is FAM
- // and things are a bit messy. For SAM, the parent folder is the almost clip name.
-
- std::string parentName, ignored;
-
- XIO::SplitLeafName ( &pseudoPath, &clipName ); // Extract the logical clip name.
- XIO::SplitFileExtension ( &clipName, &ignored );
-
- XIO::SplitLeafName ( &pseudoPath, &parentName );
- MakeUpperCase ( &parentName );
- isSAM = ( (parentName != "CLIP") && (parentName != "EDIT") && (parentName != "SUB") );
-
- if ( isSAM ) {
-
- // SAM is easy, the parent name is almost the clip name, the first letter gets coerced
- // to 'C'. There are 2 other folders to remove from the path.
-
- clipName = parentName;
- clipName[0] = 'C';
- XIO::SplitLeafName ( &pseudoPath, &ignored ); // Remove the 2 intermediate folder levels.
- XIO::SplitLeafName ( &pseudoPath, &ignored );
-
- } else {
-
- // FAM is a bit messy, study the comments and code of XDCAM_CheckFormat for details.
-
- if ( Host_IO::GetChildMode ( pseudoPath.c_str(), "ALIAS.XML" ) != Host_IO::kFMode_IsFile ) {
- clipName[0] = 'C'; // ! See notes in XDCAM_CheckFormat about pending bug.
- }
-
- if ( clipName.size() > 3 ) {
- size_t clipMid = clipName.size() - 3;
- char c1 = clipName[clipMid];
- char c2 = clipName[clipMid+1];
- char c3 = clipName[clipMid+2];
- if ( ('A' <= c1) && (c1 <= 'Z') &&
- ('0' <= c2) && (c2 <= '9') && ('0' <= c3) && (c3 <= '9') ) {
- clipName.erase ( clipMid );
- }
- }
-
- }
-
- }
-
- pseudoPath += kDirChar;
- if ( isSAM ) {
- pseudoPath += "SAM";
- } else {
- pseudoPath += "FAM";
- }
- pseudoPath += kDirChar;
- pseudoPath += clipName;
-
- pathLen = pseudoPath.size() + 1; // Include a terminating nul.
- tempPtr = malloc ( pathLen );
- if ( tempPtr == 0 ) XMP_Throw ( "No memory for XDCAM clip info", kXMPErr_NoMemory );
- memcpy ( tempPtr, pseudoPath.c_str(), pathLen );
-
- return tempPtr;
-
-} // CreatePseudoClipPath
-
-// =================================================================================================
-// XDCAM_MetaHandlerCTor
-// =====================
-
-XMPFileHandler * XDCAM_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new XDCAM_MetaHandler ( parent );
-
-} // XDCAM_MetaHandlerCTor
-
-
-// =================================================================================================
-// XDCAM_MetaHandler::SetSidecarPath
-// ====================================
-void XDCAM_MetaHandler::SetSidecarPath()
-{
- // Here, we set the appropriate sidecar name for this format.
- // If, the format if XMPilot (no INDEX.XML but UserData folder present) or
- // SxS (no INDEX.XML but Take folder present) then sidecar name will be
- // old name used by MXFHandler i.e, {clipName}.MXF.xmp or {clipname}.mxf.xmp
- // For all other cases, new side car name i.e, {clipname}M01.XMP will be used.
-
- try
- {
- if(this->isFAM && Host_IO::GetChildMode ( this->rootPath.c_str(), "INDEX.XML" ) != Host_IO::kFMode_IsFile &&
- (Host_IO::GetChildMode ( rootPath.c_str(), "UserData" ) == Host_IO::kFMode_IsFolder
- || Host_IO::GetChildMode ( this->rootPath.c_str(), "Take" ) == Host_IO::kFMode_IsFolder) )
- {
- // this is either XMPilot or SxS format.
- XMP_VarString mxfFilePath;
- if(MakeClipFilePath ( &mxfFilePath , ".MXF", true ) || MakeClipFilePath ( &mxfFilePath , ".mxf", true ) )
- {
- Host_IO::FileRef hostRef = Host_IO::Open ( mxfFilePath.c_str(), Host_IO::openReadOnly );
- if ( hostRef != Host_IO::noFileRef )
- {
-
- XMPFiles_IO mxfFile ( hostRef, mxfFilePath.c_str() , Host_IO::openReadOnly );
-
- if ( Host_IO::Length(hostRef) >= 16 )
- {
- XMP_Uns8 buffer[16];
- Host_IO::Seek(hostRef, 0, kXMP_SeekFromStart);
- XMP_Uns32 readBytes = Host_IO::Read(hostRef, buffer, 16 );
-
- if ( ( readBytes == 16 ) &&
- ( GetUns32BE(&buffer[0]) == 0x060E2B34 ) &&
- ( GetUns32BE(&buffer[4]) == 0x02050101 ) &&
- ( GetUns32BE(&buffer[8]) == 0x0D010201 ) &&
- ( ( GetUns32BE(&buffer[12]) & 0xFFFF00FF ) == 0x01020000 )
- )
- {
- std::string pathtomxfclip=Host_IO::GetCasePreservedName(mxfFilePath);
- if ( pathtomxfclip != "" )
- {
- std::string ext;
- XIO::SplitFileExtension( &pathtomxfclip, &ext , false);
- ext="."+ext;
- MakeClipFilePath ( &mxfFilePath , ext.c_str() , false );
- this->sidecarPath = mxfFilePath + ".xmp";
- }
- }
- }
- }
- }
- }
- }
- catch( ... )
- {
- // Use new side car name.
- }
- if(this->sidecarPath.empty())
- {
- MakeClipFilePath ( &this->sidecarPath , "M01.XMP", false ) ;
- }
-}// XDCAM_MetaHandler::SetSidecarPath
-
// =================================================================================================
// XDCAM_MetaHandler::XDCAM_MetaHandler
// ====================================
-
-XDCAM_MetaHandler::XDCAM_MetaHandler ( XMPFiles * _parent ) : isFAM(false), expat(0),clipMetadata(NULL)
+XDCAM_MetaHandler::XDCAM_MetaHandler ( XMPFiles * _parent ) : expat(0), clipMetadata(NULL)
{
this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kXDCAM_HandlerFlags;
this->stdCharForm = kXMP_Char8Bit;
- // Extract the root path, clip name, and FAM/SAM flag from tempPtr.
-
- if ( this->parent->tempPtr == 0 ) {
- // The CheckFormat call might have been skipped.
- this->parent->tempPtr = CreatePseudoClipPath ( this->parent->GetFilePath() );
- }
-
- this->rootPath.assign ( (char*) this->parent->tempPtr );
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- XIO::SplitLeafName ( &this->rootPath, &this->clipName );
-
- std::string temp;
- XIO::SplitLeafName ( &this->rootPath, &temp );
- XMP_Assert ( (temp == "FAM") || (temp == "SAM") );
- if ( temp == "FAM" ) this->isFAM = true;
- // backward compatibility ensured for XMPilot Clips
- // XMPilot is FAM
- this->SetSidecarPath();
- XMP_Assert ( this->isFAM ? (this->parent->format == kXMP_XDCAM_FAMFile) : (this->parent->format == kXMP_XDCAM_SAMFile) );
-
} // XDCAM_MetaHandler::XDCAM_MetaHandler
// =================================================================================================
@@ -564,35 +221,6 @@ XDCAM_MetaHandler::~XDCAM_MetaHandler()
} // XDCAM_MetaHandler::~XDCAM_MetaHandler
// =================================================================================================
-// XDCAM_MetaHandler::MakeClipFilePath
-// ===================================
-
-bool XDCAM_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ )
-{
-
- *path = this->rootPath;
- *path += kDirChar;
-
- if ( this->isFAM ) {
- *path += "Clip"; // ! Yes, mixed case.
- } else {
- *path += "PROAV";
- *path += kDirChar;
- *path += "CLPR";
- *path += kDirChar;
- *path += this->clipName;
- }
-
- *path += kDirChar;
- *path += this->clipName;
- *path += suffix;
-
- if ( ! checkFile ) return true;
- return Host_IO::Exists ( path->c_str() );
-
-} // XDCAM_MetaHandler::MakeClipFilePath
-
-// =================================================================================================
// XDCAM_MetaHandler::MakeMediaproPath
// ===================================
@@ -616,6 +244,10 @@ bool XDCAM_MetaHandler::MakeMediaproPath ( std::string * path, bool checkFile /*
#define kHexDigits "0123456789ABCDEF"
+// =================================================================================================
+// XDCAM_MetaHandler::MakeLegacyDigest
+// ================================
+
void XDCAM_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
{
digestStr->erase();
@@ -664,7 +296,7 @@ void XDCAM_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
} // XDCAM_MetaHandler::MakeLegacyDigest
// =================================================================================================
-// P2_MetaHandler::CleanupLegacyXML
+// XDCAM_MetaHandler::CleanupLegacyXML
// ================================
void XDCAM_MetaHandler::CleanupLegacyXML()
@@ -676,6 +308,10 @@ void XDCAM_MetaHandler::CleanupLegacyXML()
} // XDCAM_MetaHandler::CleanupLegacyXML
+// =================================================================================================
+// XDCAM_MetaHandler::readXMLFile
+// ================================
+
void XDCAM_MetaHandler::readXMLFile( XMP_StringPtr filePath, ExpatAdapter* &expat )
{
Host_IO::FileRef hostRef = Host_IO::Open ( filePath, Host_IO::openReadOnly );
@@ -705,27 +341,25 @@ static inline bool operator< ( const XMP_DateTime & left, const XMP_DateTime & r
return (compare < 0);
}
+// =================================================================================================
+// XDCAM_MetaHandler::GetFileModDate
+// ================================
+
bool XDCAM_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
{
- // The XDCAM FAM locations of metadata:
- // MEDIAPRO.XML // Has non-XMP metadata.
- // Clip:
- // C0001_50i_DVCAM_43_4chM01.XML // Has non-XMP metadata.
- // C0001_50i_DVCAM_43_4chM01.XMP
-
- // The XDCAM SAM locations of metadata:
- // PROAV:
- // CLPR:
- // C0001:
- // C0001M01.XML // Has non-XMP metadata.
- // C0001M01.XMP
+ // Modify date is found in the increasing priority order
+ //
+ // MEDIAPRO.XML
+ // Non-Real time metadata file
+ // XMP file
bool ok, haveDate = false;
std::string fullPath;
XMP_DateTime oneDate, junkDate;
if ( modDate == 0 ) modDate = &junkDate;
+ // MEDIAPRO.XML
std::string mediaproPath;
ok = MakeMediaproPath ( &mediaproPath, true /* checkFile */ );
if ( ok ) ok = Host_IO::GetModifyDate ( mediaproPath.c_str(), &oneDate );
@@ -734,15 +368,19 @@ bool XDCAM_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
haveDate = true;
}
- ok = this->MakeClipFilePath ( &fullPath, "M01.XML", true /* checkFile */ );
- if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
+ // Non-Real time metadata file
+ ok = Host_IO::Exists( this->mNRTFilePath.c_str() );
+ //ok = this->MakeClipFilePath ( &fullPath, "M01.XML", true /* checkFile */ );
+ if ( ok ) ok = Host_IO::GetModifyDate ( this->mNRTFilePath.c_str(), &oneDate );
if ( ok ) {
if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
haveDate = true;
}
- ok = this->MakeClipFilePath ( &fullPath, "M01.XMP", true /* checkFile */ );
- if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
+ // XMP file
+ ok = Host_IO::Exists( this->sidecarPath.c_str() );
+ //ok = this->MakeClipFilePath ( &fullPath, "M01.XMP", true /* checkFile */ );
+ if ( ok ) ok = Host_IO::GetModifyDate ( this->sidecarPath.c_str(), &oneDate );
if ( ok ) {
if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
haveDate = true;
@@ -752,140 +390,6 @@ bool XDCAM_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
} // XDCAM_MetaHandler::GetFileModDate
-
-// =================================================================================================
-// XDCAM_MetaHandler::GetClipUmid
-// ==============================
-bool XDCAM_MetaHandler::GetClipUmid ( std::string &clipUmid )
-{
- std::string clipInfoPath;
- ExpatAdapter* clipInfoExpat = 0 ;
- bool umidFound = false;
- XMP_StringPtr nameSpace = 0;
- try {
- this->MakeClipFilePath ( &clipInfoPath, "C01.SMI" ) ;
- readXMLFile( clipInfoPath.c_str(), clipInfoExpat );
- if ( clipInfoExpat != 0 )
- {
- XML_Node & xmlTree = clipInfoExpat->tree;
- XML_NodePtr rootElem = 0;
-
- for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
- if ( xmlTree.content[i]->kind == kElemNode ) {
- rootElem = xmlTree.content[i];
- }
- }
- if ( rootElem != 0 )
- {
- XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
-
- if ( XMP_LitMatch ( rootLocalName, "smil" ) )
- {
- XMP_StringPtr umidValue = rootElem->GetAttrValue ( "umid" );
- if ( umidValue != 0 ) {
- clipUmid = umidValue;
- umidFound = true;
- }
- }
- }
- }
- if( ! umidFound )
- { //try to get the umid from the NRT metadata
- delete ( clipInfoExpat ) ; clipInfoExpat = 0;
- this->MakeClipFilePath ( &clipInfoPath, "M01.XML" ) ;
- readXMLFile( clipInfoPath.c_str(), clipInfoExpat ) ;
- if ( clipInfoExpat != 0 )
- {
- XML_Node & xmlTree = clipInfoExpat->tree;
- XML_NodePtr rootElem = 0;
- for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
- if ( xmlTree.content[i]->kind == kElemNode ) {
- rootElem = xmlTree.content[i];
- }
- }
- if ( rootElem != 0 )
- {
- XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
-
- if ( XMP_LitMatch ( rootLocalName, "NonRealTimeMeta" ) )
- {
- nameSpace = rootElem->ns.c_str() ;
- XML_NodePtr targetProp = rootElem->GetNamedElement ( nameSpace, "TargetMaterial" );
- if ( (targetProp != 0) && targetProp->IsEmptyLeafNode() ) {
- XMP_StringPtr umidValue = targetProp->GetAttrValue ( "umidRef" );
- if ( umidValue != 0 ) {
- clipUmid = umidValue;
- umidFound = true;
- }
- }
- }
- }
- }
- }
- } catch ( ... ) {
- }
- delete ( clipInfoExpat ) ;
- return umidFound;
-}// XDCAM_MetaHandler::GetClipUmid
-
-// =================================================================================================
-// XDCAM_MetaHandler::IsClipsPlanning
-// ==================================
-bool XDCAM_MetaHandler::IsClipsPlanning ( std::string clipUmid , XMP_StringPtr planPath )
-{
- ExpatAdapter* planniingExpat = 0 ;
- XMP_StringPtr nameSpace = 0 ;
- try {
- readXMLFile( planPath, planniingExpat );
- if ( planniingExpat != 0 )
- {
- XML_Node & xmlTree = planniingExpat->tree;
- XML_NodePtr rootElem = 0;
-
- for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
- if ( xmlTree.content[i]->kind == kElemNode ) {
- rootElem = xmlTree.content[i];
- }
- }
- if ( rootElem != 0 )
- {
- XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
-
- if ( XMP_LitMatch ( rootLocalName, "PlanningMetadata" ) )
- {
- nameSpace = rootElem->ns.c_str() ;
- size_t noOfMaterialGroups = rootElem->CountNamedElements ( nameSpace, "MaterialGroup" ) ;
- while( noOfMaterialGroups-- )
- {
- XML_NodePtr mgNode = rootElem->GetNamedElement( nameSpace, "MaterialGroup" );
- size_t noOfMaterialElements = mgNode->CountNamedElements ( nameSpace, "Material" ) ;
- while( noOfMaterialElements-- )
- {
- XML_NodePtr materialNode = mgNode->GetNamedElement( nameSpace, "Material" );
- XMP_StringPtr materialType = materialNode->GetAttrValue ( "type" );
- if ( materialType && XMP_LitMatch( materialType , "clip" ) )
- {
- XMP_StringPtr umidValue = materialNode->GetAttrValue ( "umidRef" );
- if ( umidValue != 0 && XMP_LitMatch( umidValue , clipUmid.c_str() ) )
- {
- delete ( planniingExpat ) ;
- return true;
- }
- }
-
- }
- }
- }
- }
- }
-
- } catch ( ... ) {
- }
- delete ( planniingExpat ) ;
- return false;
-} // XDCAM_MetaHandler::IsClipsPlanning
-
-
// =================================================================================================
// XDCAM_MetaHandler::RefersClipUmid
// ==================================
@@ -948,144 +452,9 @@ bool XDCAM_MetaHandler::RefersClipUmid ( std::string clipUmid , XMP_StringPtr ed
return false;
} // XDCAM_MetaHandler::RefersClipUmid
-inline bool IsDigit( char c )
-{
- return c >= '0' && c <= '9';
-}
-
-
-// =================================================================================================
-// XDCAM_MetaHandler::GetEditInfoFilesSAM
-// ======================================
-bool XDCAM_MetaHandler::GetEditInfoFilesSAM ( std::vector<std::string> &editInfoList )
-{
- std::string clipUmid;
- bool found = false;
-
- if( GetClipUmid ( clipUmid ) )
- {
- std::string editFolderPath = this->rootPath + kDirChar + "PROAV" + kDirChar + "EDTR" + kDirChar ;
- if ( Host_IO::Exists( editFolderPath.c_str() ) &&
- Host_IO::GetFileMode( editFolderPath.c_str() ) == Host_IO::kFMode_IsFolder
- )
- {
- Host_IO::AutoFolder edtrFolder, editFolder;
- std::string edtrChildName, edlistChild;
-
- edtrFolder.folder = Host_IO::OpenFolder ( editFolderPath.c_str() );
- while ( Host_IO::GetNextChild ( edtrFolder.folder, &edtrChildName ) ) {
- size_t childLen = edtrChildName.size();
- std::string editListFolderPath = editFolderPath + edtrChildName + kDirChar ;
- if ( ! ( childLen == 5 &&
- edtrChildName[0] == 'E' &&
- IsDigit( edtrChildName[1] ) &&
- IsDigit( edtrChildName[2] ) &&
- IsDigit( edtrChildName[3] ) &&
- IsDigit( edtrChildName[4] ) &&
- Host_IO::GetFileMode( editListFolderPath.c_str() ) == Host_IO::kFMode_IsFolder
- ) ) continue;
-
- editFolder.folder = Host_IO::OpenFolder ( editListFolderPath.c_str() );
- while ( Host_IO::GetNextChild ( editFolder.folder, &edlistChild ) ) {
- size_t filenamelen = edlistChild.size();
- std::string editListFilePath = editListFolderPath + edlistChild ;
- if ( ! ( filenamelen == 12 &&
- edlistChild.compare ( filenamelen - 4, 4 , ".SMI" ) == 0 &&
- edlistChild.compare ( 0, edtrChildName.size(), edtrChildName ) == 0 &&
- Host_IO::GetFileMode( editListFilePath.c_str() ) == Host_IO::kFMode_IsFile
- ) ) continue;
- if( RefersClipUmid ( clipUmid , editListFilePath.c_str() ) )
- {
- found = true ;
- editInfoList.push_back( editListFilePath );
- }
- }
- }
- }
- }
- return found;
-} // XDCAM_MetaHandler::GetEditInfoFilesSAM
-
-// =================================================================================================
-// XDCAM_MetaHandler::GetInfoFilesFAM
-// ==================================
-bool XDCAM_MetaHandler::GetInfoFilesFAM ( std::vector<std::string> &editInfoList, std::string pathToFolder)
-{
- std::string clipUmid;
- bool found = false;
-
- if( GetClipUmid ( clipUmid ) )
- {
- if ( Host_IO::Exists( pathToFolder.c_str() ) &&
- Host_IO::GetFileMode( pathToFolder.c_str() ) == Host_IO::kFMode_IsFolder
- )
- {
- Host_IO::AutoFolder editFolder;
- std::string edlistChild;
-
- editFolder.folder = Host_IO::OpenFolder ( pathToFolder.c_str() );
- while ( Host_IO::GetNextChild ( editFolder.folder, &edlistChild ) ) {
- size_t filenamelen = edlistChild.size();
- std::string editListFilePath = pathToFolder + edlistChild ;
- if ( ! ( filenamelen > 7 &&
- edlistChild.compare ( filenamelen - 4, 4 , ".SMI" ) == 0 &&
- Host_IO::GetFileMode( editListFilePath.c_str() ) == Host_IO::kFMode_IsFile
- ) ) continue;
- if( RefersClipUmid ( clipUmid , editListFilePath.c_str() ) )
- {
- found = true ;
- editInfoList.push_back( editListFilePath );
- }
- }
- }
- }
- return found;
-} // XDCAM_MetaHandler::GetInfoFilesFAM
-
-// =================================================================================================
-// XDCAM_MetaHandler::GetPlanningFilesFAM
-// ======================================
-bool XDCAM_MetaHandler::GetPlanningFilesFAM ( std::vector<std::string> &planInfoList, std::string pathToFolder)
-{
- std::string clipUmid;
- bool found = false;
-
- if( GetClipUmid ( clipUmid ) )
- {
- if ( Host_IO::Exists( pathToFolder.c_str() ) &&
- Host_IO::GetFileMode( pathToFolder.c_str() ) == Host_IO::kFMode_IsFolder
- )
- {
- Host_IO::AutoFolder planFolder;
- std::string listChild;
-
- planFolder.folder = Host_IO::OpenFolder ( pathToFolder.c_str() );
- while ( Host_IO::GetNextChild ( planFolder.folder, &listChild ) ) {
- size_t filenamelen = listChild.size();
- std::string listFilePath = pathToFolder + listChild ;
- if ( ! ( filenamelen > 4 &&
- ( listChild.compare ( filenamelen - 4, 4 , ".XML" ) == 0
- ||
- listChild.compare ( filenamelen - 4, 4 , ".xml" ) == 0
- )
- &&
- Host_IO::GetFileMode( listFilePath.c_str() ) == Host_IO::kFMode_IsFile
- ) ) continue;
- if( IsClipsPlanning ( clipUmid , listFilePath.c_str() ) )
- {
- found = true ;
- planInfoList.push_back( listFilePath );
- }
- }
- }
- }
- return found;
-} // XDCAM_MetaHandler::GetPlanningFilesFAM
-
// =================================================================================================
// XDCAM_MetaHandler::IsMetadataWritable
// =======================================
-
bool XDCAM_MetaHandler::IsMetadataWritable ( )
{
std::vector<std::string> metadataFiles;
@@ -1099,310 +468,12 @@ bool XDCAM_MetaHandler::IsMetadataWritable ( )
}// XDCAM_MetaHandler::IsMetadataWritable
// =================================================================================================
-// XDCAM_MetaHandler::FillFAMAssociatedResources
-// =============================================
-void XDCAM_MetaHandler::FillFAMAssociatedResources ( std::vector<std::string> * resourceList )
-{
- // The possible associated resources:
- // .../MyMovie/
- // ALIAS.XML
- // INDEX.XML
- // DISCMETA.XML
- // MEDIAPRO.XML
- // MEDIAPRO.BUP
- // CUEUP.XML
- // CUEUP.BUP
- // Clip/
- // AAAAA.MXF AAAAA is the clipname with clipserial
- // XX is a counter which will start from from 01 and can go upto 99 based
- // on number of files present in this folder with same extension and same clipname/editListName/Takename.
- // AAAAAMXX.XML
- // AAAAAMXX.XMP
- // AAAAARXX.BIM
- // Sub/
- // AAAAASXX.MXF
- // Local/
- // AAAAACXX.SMI
- // AAAAACXX.PPN
- // Edit/ DDDDD is the editListName
- // DDDDDEXX.SMI
- // DDDDDMXX.XML
- // Take/ TTTTT is the Takename
- // TTTTT.SMI
- // TTTTTUNN.SMI NN is a counter which goes from 01 to N-1 where N is number of media, this
- // take is divided into. For Nth, TTTTT.SMI shall be picked up.
- // TTTTTMXX.XML
- // General/
- // Sony/
- // Planning/ AAAAA is the clipname without clipserial
- // YYYYMMDDHHMISS is DateTime
- // BBBBB_YYYYMMDDHHMISS.xml
- // UserData/
- //
-
- //Add RootPath
- std::string filePath = rootPath + kDirChar;
- PackageFormat_Support::AddResourceIfExists( resourceList, filePath );
-
- // Get the files present directly inside root folder.
- filePath = rootPath + kDirChar + "ALIAS.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = rootPath + kDirChar + "INDEX.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = rootPath + kDirChar + "DISCMETA.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = rootPath + kDirChar + "MEDIAPRO.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
- filePath = rootPath + kDirChar + "MEDIAPRO.BUP";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = rootPath + kDirChar + "CUEUP.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
- filePath = rootPath + kDirChar + "CUEUP.BUP";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- // Add the UserData folder which is used to identify the format in any way
- filePath = rootPath + kDirChar + "UserData" + kDirChar;
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- XMP_VarString clipPath = rootPath + kDirChar + "Clip" + kDirChar ;
-
- size_t oldCount = resourceList->size();
- // Get the files present inside clip folder.
- XMP_VarString regExp;
- XMP_StringVector regExpVec;
-
- regExp = "^" + clipName + ".MXF$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "M\\d\\d.XML$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "R\\d\\d.BIM$";
- regExpVec.push_back ( regExp );
- IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
- PackageFormat_Support::AddResourceIfExists(resourceList, this->sidecarPath);
- if ( resourceList->size() <= oldCount )
- {
- PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
- }
-
- //Get the files Under Sub folder
- clipPath = rootPath + kDirChar + "Sub" + kDirChar ;
- regExpVec.clear();
- regExp = "^" + clipName + "S\\d\\d.MXF$";
- regExpVec.push_back ( regExp );
- oldCount = resourceList->size();
- IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
- // Add Sub folder if no file inside this, was added.
- if ( resourceList->size() <= oldCount )
- {
- PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
- }
-
- //Get the files Under Local folder
- clipPath = rootPath + kDirChar + "Local" + kDirChar ;
- regExpVec.clear();
- regExp = "^" + clipName + "C\\d\\d.SMI$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "I\\d\\d.PPN$";
- regExpVec.push_back ( regExp );
- oldCount = resourceList->size();
- IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
-
- //Add the Edit lists associated to this clip
- XMP_StringVector editInfoList;
- bool atLeastOneFileAdded = false;
- clipPath = rootPath + kDirChar + "Edit" + kDirChar ;
- if ( GetInfoFilesFAM ( editInfoList , clipPath ) )
- {
- size_t noOfEditInfoFiles = editInfoList.size() ;
- for( size_t count = 0; count < noOfEditInfoFiles; count++ )
- {
- atLeastOneFileAdded = PackageFormat_Support::AddResourceIfExists(resourceList, editInfoList[count]) ? true : atLeastOneFileAdded;
- std::string editNRTFile = editInfoList[count] ;
- size_t filenamelen = editInfoList[count].length() ;
- editNRTFile[ filenamelen - 7 ] = 'M';
- editNRTFile[ filenamelen - 3 ] = 'X';
- editNRTFile[ filenamelen - 2 ] = 'M';
- editNRTFile[ filenamelen - 1 ] = 'L';
- atLeastOneFileAdded = PackageFormat_Support::AddResourceIfExists(resourceList, editNRTFile ) ? true : atLeastOneFileAdded;
- }
- }
- // Add Edit folder if no file inside this, was added.
- if ( !atLeastOneFileAdded )
- {
- PackageFormat_Support::AddResourceIfExists(resourceList, clipPath);
- }
-
- atLeastOneFileAdded = false;
-
- //Add the Takes associated to this clip
- XMP_StringVector takeList;
- clipPath = rootPath + kDirChar + "Take" + kDirChar ;
- if( GetInfoFilesFAM ( takeList , clipPath ) )
- {
- size_t noOfTakes = takeList.size() ;
- for( size_t count = 0; count < noOfTakes; count++ )
- {
- atLeastOneFileAdded = PackageFormat_Support::AddResourceIfExists(resourceList, takeList[count]) ? true : atLeastOneFileAdded;
- XMP_VarString takeNRTFile = takeList[count] ;
- size_t filenamelen = takeList[count].length() ;
- if ( takeNRTFile[ filenamelen - 7 ] == 'U'
- && IsDigit( takeNRTFile[ filenamelen - 6 ] )
- && IsDigit( takeNRTFile[ filenamelen - 5 ] ) )
- {
- takeNRTFile.erase( takeNRTFile.begin() + filenamelen - 7, takeNRTFile.end() ) ;
- }
- else
- {
- takeNRTFile.erase( takeNRTFile.begin() + filenamelen - 4, takeNRTFile.end() ) ;
- }
-
- XMP_VarString fileName;
- size_t pos = takeNRTFile.find_last_of ( kDirChar );
- fileName = takeNRTFile.substr ( pos + 1 );
- XMP_VarString regExp = "^" + fileName + "M\\d\\d.XML$";
- oldCount = resourceList->size();
- IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExp, false, true, true );
- atLeastOneFileAdded = resourceList->size() > oldCount;
- }
- }
- // Add Take folder if no file inside this, was added.
- if(!atLeastOneFileAdded)
- {
- filePath = rootPath + kDirChar + "Take" + kDirChar;
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
- }
-
- //Add the Planning Metadata Files associated to this clip
- XMP_StringVector planList;
- clipPath = rootPath + kDirChar + "General" + kDirChar + "Sony" + kDirChar+ "Planning" + kDirChar;
- if( GetPlanningFilesFAM ( planList , clipPath ) )
- {
- size_t noOfPlans = planList.size() ;
- for( size_t count = 0; count < noOfPlans; count++ )
- {
- resourceList->push_back( planList[count] );
- }
- }
-} // XDCAM_MetaHandler::FillFAMAssociatedResources
-
-// =================================================================================================
-// XDCAM_MetaHandler::FillSAMAssociatedResources
-// =============================================
-void XDCAM_MetaHandler::FillSAMAssociatedResources ( std::vector<std::string> * resourceList )
-{
- // The possible associated resources:
- // .../MyMovie/
- // PROAV/
- // INDEX.XML
- // INDEX.BUP
- // DISCMETA.XML
- // DISCINFO.XML
- // DISCINFO.BUP
- // CLPR/
- // CXXXX/ XXXX is ClipSerial and NN is a counter which will start from from 01 and can go upto 99 based
- // on number of files present in this folder with same extension.
- // CXXXXCNN.SMI
- // CXXXXVNN.MXF
- // CXXXXANN.MXF
- // CXXXXRNN.BIM
- // CXXXXINN.PPN
- // CXXXXMNN.XML
- // CXXXXSNN.MXF
- // EDTR/
- // EXXXX:
- // EXXXXENN.SMI
- // EXXXXMNN.XML
- //
- std::string proavPath = rootPath + kDirChar + "PROAV" + kDirChar;
- std::string filePath;
- //Add RootPath
- filePath = rootPath + kDirChar;
- PackageFormat_Support::AddResourceIfExists( resourceList, filePath );
-
- // Get the files present directly inside PROAV folder.
- filePath = proavPath + "INDEX.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
- filePath = proavPath + "INDEX.BUP";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = proavPath + "DISCINFO.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
- filePath = proavPath + "DISCINFO.BUP";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- filePath = proavPath + "DISCMETA.XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, filePath);
-
- XMP_VarString clipPath = proavPath + "CLPR" + kDirChar + clipName + kDirChar;
- XMP_VarString regExp;
- XMP_StringVector regExpVec;
-
- regExp = "^" + clipName + "C\\d\\d.SMI$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "M\\d\\d.XML$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "V\\d\\d.MXF$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "A\\d\\d.MXF$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "R\\d\\d.BIM$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "I\\d\\d.PPN$";
- regExpVec.push_back ( regExp );
- regExp = "^" + clipName + "S\\d\\d.MXF$";
- regExpVec.push_back ( regExp );
- IOUtils::GetMatchingChildren ( *resourceList, clipPath, regExpVec, false, true, true );
- PackageFormat_Support::AddResourceIfExists(resourceList, this->sidecarPath);
- //Add the Edit lists that refer this clip
- std::vector<std::string> editInfoList;
- if( GetEditInfoFilesSAM ( editInfoList ) )
- {
- size_t noOfEditInfoFiles = editInfoList.size() ;
- for( size_t count = 0; count < noOfEditInfoFiles; count++ )
- {
- PackageFormat_Support::AddResourceIfExists(resourceList, editInfoList[count]);
- std::string editNRTFile = editInfoList[count].c_str() ;
- size_t filenamelen = editInfoList[count].length() ;
- editNRTFile[ filenamelen - 7 ] = 'M';
- editNRTFile[ filenamelen - 3 ] = 'X';
- editNRTFile[ filenamelen - 2 ] = 'M';
- editNRTFile[ filenamelen - 1 ] = 'L';
- PackageFormat_Support::AddResourceIfExists(resourceList, editNRTFile );
- }
- }
-}// XDCAM_MetaHandler::FillSAMAssociatedResources
-
-// =================================================================================================
-// XDCAM_MetaHandler::FillAssociatedResources
-// ======================================
-void XDCAM_MetaHandler::FillAssociatedResources ( std::vector<std::string> * resourceList )
-{
- if( this->isFAM )
- FillFAMAssociatedResources ( resourceList );
- else
- FillSAMAssociatedResources ( resourceList );
-}
-// =================================================================================================
// XDCAM_MetaHandler::FillMetadataFiles
// ====================================
void XDCAM_MetaHandler::FillMetadataFiles ( std::vector<std::string> * metadataFiles )
{
- std::string noExtPath, filePath;
-
- if(this->isFAM) {
- noExtPath = rootPath + kDirChar + "Clip" + kDirChar + clipName;
- } else {
- noExtPath = rootPath + kDirChar + "PROAV" + kDirChar + "CLPR" +
- kDirChar + clipName + kDirChar + clipName;
- }
-
- metadataFiles->push_back ( this->sidecarPath );
- filePath = noExtPath + "M01.XML";
- metadataFiles->push_back ( filePath );
+ metadataFiles->push_back( this->sidecarPath );
+ metadataFiles->push_back( this->mNRTFilePath );
} // XDCAM_MetaHandler::FillMetadataFiles
@@ -1419,7 +490,6 @@ void XDCAM_MetaHandler::CacheFileData()
}
// See if the clip's .XMP file exists.
-
if ( ! Host_IO::Exists ( this->sidecarPath.c_str() ) ) return; // No XMP.
// Read the entire .XMP file. We know the XMP exists, New_XMPFiles_IO is supposed to return 0
@@ -1428,6 +498,7 @@ void XDCAM_MetaHandler::CacheFileData()
bool readOnly = XMP_OptionIsClear ( this->parent->openFlags, kXMPFiles_OpenForUpdate );
XMP_Assert ( this->parent->ioRef == 0 );
+
XMPFiles_IO* xmpFile = XMPFiles_IO::New_XMPFiles_IO ( this->sidecarPath.c_str(), readOnly );
if ( xmpFile == 0 ) XMP_Throw ( "XDCAM XMP file open failure", kXMPErr_InternalFailure );
this->parent->ioRef = xmpFile;
@@ -1454,20 +525,6 @@ void XDCAM_MetaHandler::CacheFileData()
// XDCAM_MetaHandler::GetMediaProMetadata
// ======================================
-bool XDCAM_MetaHandler::GetMediaProMetadata ( SXMPMeta * xmpObjPtr,
- const std::string& clipUMID,
- bool digestFound )
-{
- if (!this->isFAM) return false;
-
- // Build a directory string to the MEDIAPRO file.
-
- std::string mediaproPath;
- MakeMediaproPath ( &mediaproPath );
- return XDCAM_Support::GetMediaProLegacyMetadata ( xmpObjPtr, clipUMID, mediaproPath, digestFound );
-
-}
-
// =================================================================================================
// XDCAM_MetaHandler::ProcessXMP
// =============================
@@ -1492,10 +549,10 @@ void XDCAM_MetaHandler::ProcessXMP()
}
// NonRealTimeMeta -> XMP by schema
- std::string xmlPath, umid;
- this->MakeClipFilePath ( &xmlPath, "M01.XML" );
+ std::string xmlPath = this->mNRTFilePath;
+ std::string umid;
- readXMLFile( xmlPath.c_str(),this->expat );
+ readXMLFile( xmlPath.c_str(), this->expat );
if ( this->expat == 0 ) return;
// The root element should be NonRealTimeMeta in some namespace. Take whatever this file uses.
@@ -1590,7 +647,7 @@ void XDCAM_MetaHandler::UpdateFile ( bool doSafeUpdate )
std::string legacyXML, xmlPath;
this->expat->tree.Serialize ( &legacyXML );
- this->MakeClipFilePath ( &xmlPath, "M01.XML" );
+ xmlPath = this->mNRTFilePath;
bool haveXML = Host_IO::Exists ( xmlPath.c_str() );
if ( ! haveXML ) Host_IO::Create ( xmlPath.c_str() );
diff --git a/XMPFiles/source/FileHandlers/XDCAM_Handler.hpp b/XMPFiles/source/FileHandlers/XDCAM_Handler.hpp
index f03ada8..e70621a 100644
--- a/XMPFiles/source/FileHandlers/XDCAM_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/XDCAM_Handler.hpp
@@ -24,25 +24,10 @@
///
// =================================================================================================
-extern XMPFileHandler * XDCAM_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool XDCAM_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kXDCAM_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_FolderBasedFormat);
+inline bool IsDigit( char c )
+{
+ return c >= '0' && c <= '9';
+}
class XDCAM_MetaHandler : public XMPFileHandler
{
@@ -50,8 +35,7 @@ public:
bool GetFileModDate ( XMP_DateTime * modDate );
- void FillMetadataFiles ( std::vector<std::string> * metadataFiles );
- void FillAssociatedResources ( std::vector<std::string> * resourceList );
+ virtual void FillAssociatedResources ( std::vector<std::string> * resourceList ) {};
bool IsMetadataWritable ( ) ;
void CacheFileData();
@@ -66,31 +50,31 @@ public:
XDCAM_MetaHandler ( XMPFiles * _parent );
virtual ~XDCAM_MetaHandler();
-private:
+protected:
- XDCAM_MetaHandler() : isFAM(false), expat(0), clipMetadata(0) {}; // Hidden on purpose.
+ XDCAM_MetaHandler() : expat(0), clipMetadata(0) {}; // Hidden on purpose.
- bool MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false );
+ virtual bool MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false ) { return false; }
+ virtual void SetPathVariables ( const std::string & clientPath ) { }
+ virtual bool GetMediaProMetadata ( SXMPMeta * xmpObjPtr, const std::string& clipUMID, bool digestFound ) {
+ return false;
+ }
bool MakeMediaproPath ( std::string * path, bool checkFile = false );
- void MakeLegacyDigest ( std::string * digestStr );
- void CleanupLegacyXML();
- void SetSidecarPath();
-
+ virtual bool GetClipUmid ( std::string &clipUmid ) { return false; }
void readXMLFile( XMP_StringPtr filePath,ExpatAdapter* &expat );
- bool GetClipUmid ( std::string &clipUmid ) ;
- bool IsClipsPlanning ( std::string clipUmid , XMP_StringPtr planPath ) ;
bool RefersClipUmid ( std::string clipUmid , XMP_StringPtr editInfoPath ) ;
- bool GetInfoFilesFAM ( std::vector<std::string> &InfoList, std::string pathToFolder) ;
- bool GetPlanningFilesFAM ( std::vector<std::string> &planInfoList, std::string pathToFolder) ;
- bool GetEditInfoFilesSAM ( std::vector<std::string> &editInfoList ) ;
- void FillFAMAssociatedResources ( std::vector<std::string> * resourceList );
- void FillSAMAssociatedResources ( std::vector<std::string> * resourceList );
+ std::string rootPath, clipName, sidecarPath;
+
+ std::string mNRTFilePath;
+ std::string oldSidecarPath;
- bool GetMediaProMetadata ( SXMPMeta * xmpObjPtr, const std::string& clipUMID, bool digestFound );
+private:
- std::string rootPath, clipName, xdcNS, legacyNS, sidecarPath;
+ void FillMetadataFiles ( std::vector<std::string> * metadataFiles );
+ void MakeLegacyDigest ( std::string * digestStr );
+ void CleanupLegacyXML();
- bool isFAM;
+ std::string xdcNS, legacyNS;
ExpatAdapter * expat;
XML_Node * clipMetadata; // ! Don't delete, points into the Expat tree.
diff --git a/XMPFiles/source/FormatSupport/ID3_Support.cpp b/XMPFiles/source/FormatSupport/ID3_Support.cpp
index dd19c16..528609c 100644
--- a/XMPFiles/source/FormatSupport/ID3_Support.cpp
+++ b/XMPFiles/source/FormatSupport/ID3_Support.cpp
@@ -468,50 +468,53 @@ void ID3v2Frame::release()
// =================================================================================================
-void ID3v2Frame::setFrameValue ( const std::string& rawvalue, bool needDescriptor,
- bool utf16, bool isXMPPRIVFrame, bool needEncodingByte )
+void ID3v2Frame::setFrameValue( const std::string& rawvalue, bool needDescriptor,
+ bool utf16, bool isXMPPRIVFrame, bool needEncodingByte, bool isAlreadyEncoded /* = false */ )
{
std::string value;
if ( isXMPPRIVFrame ) {
- XMP_Assert ( (! needDescriptor) && (! utf16) );
+ XMP_Assert( ( !needDescriptor ) && ( !utf16 ) );
- value.append ( "XMP\0", 4 );
- value.append ( rawvalue );
- value.append ( "\0", 1 ); // final zero byte
+ value.append( "XMP\0", 4 );
+ value.append( rawvalue );
+ value.append( "\0", 1 ); // final zero byte
- } else {
+ }
+ else if ( !isAlreadyEncoded ) {
if ( needEncodingByte ) {
if ( utf16 ) {
- value.append ( "\x1", 1 );
- } else {
- value.append ( "\x0", 1 );
+ value.append( "\x1", 1 );
+ }
+ else {
+ value.append( "\x0", 1 );
}
}
- if ( needDescriptor ) value.append ( "eng", 3 );
+ if ( needDescriptor ) value.append( "eng", 3 );
if ( utf16 ) {
- if ( needDescriptor ) value.append ( "\xFF\xFE\0\0", 4 );
+ if ( needDescriptor ) value.append( "\xFF\xFE\0\0", 4 );
- value.append ( "\xFF\xFE", 2 );
+ value.append( "\xFF\xFE", 2 );
std::string utf16str;
- ToUTF16 ( (XMP_Uns8*) rawvalue.c_str(), rawvalue.size(), &utf16str, false );
- value.append ( utf16str );
- value.append ( "\0\0", 2 );
+ ToUTF16( ( XMP_Uns8* ) rawvalue.c_str(), rawvalue.size(), &utf16str, false );
+ value.append( utf16str );
+ value.append( "\0\0", 2 );
- } else {
+ }
+ else {
std::string convertedValue;
- ReconcileUtils::UTF8ToLatin1 ( rawvalue.c_str(), rawvalue.size(), &convertedValue );
+ ReconcileUtils::UTF8ToLatin1( rawvalue.c_str(), rawvalue.size(), &convertedValue );
- if ( needDescriptor ) value.append ( "\0", 1 );
- value.append ( convertedValue );
- value.append ( "\0", 1 );
+ if ( needDescriptor ) value.append( "\0", 1 );
+ value.append( convertedValue );
+ value.append( "\0", 1 );
}
@@ -520,10 +523,19 @@ void ID3v2Frame::setFrameValue ( const std::string& rawvalue, bool needDescripto
this->changed = true;
this->release();
- this->contentSize = (XMP_Int32) value.size();
- XMP_Validate ( (this->contentSize < 20*1024*1024), "XMP Property exceeds 20MB in size", kXMPErr_InternalFailure );
- this->content = new char [ this->contentSize ];
- memcpy ( this->content, value.c_str(), this->contentSize );
+ if ( isAlreadyEncoded )
+ {
+ XMP_Assert( ( !needDescriptor ) && ( !utf16 ) && value.empty() );
+ this->contentSize = ( XMP_Int32 ) rawvalue.size();
+ }
+ else
+ this->contentSize = ( XMP_Int32 ) value.size();
+ XMP_Validate( ( this->contentSize < 20 * 1024 * 1024 ), "XMP Property exceeds 20MB in size", kXMPErr_InternalFailure );
+ this->content = new char[ this->contentSize ];
+ if ( isAlreadyEncoded )
+ memcpy( this->content, rawvalue.c_str(), this->contentSize );
+ else
+ memcpy( this->content, value.c_str(), this->contentSize );
} // ID3v2Frame::setFrameValue
@@ -871,7 +883,7 @@ void ID3v1Tag::write ( XMP_IO* file, SXMPMeta* meta )
}
- if ( meta->GetProperty ( kXMP_NS_DM, "trackNumber", &utf8, 0 ) ) {
+ if ( meta->GetProperty ( kXMP_NS_DM, "trackNumber", &utf8, (XMP_OptionBits *) kXMP_NoOptions ) ) {
XMP_Uns8 trackNo = 0;
try {
diff --git a/XMPFiles/source/FormatSupport/ID3_Support.hpp b/XMPFiles/source/FormatSupport/ID3_Support.hpp
index 1ca3107..dda6bfc 100644
--- a/XMPFiles/source/FormatSupport/ID3_Support.hpp
+++ b/XMPFiles/source/FormatSupport/ID3_Support.hpp
@@ -120,7 +120,7 @@ namespace ID3_Support {
void release();
void setFrameValue ( const std::string& rawvalue, bool needDescriptor = false,
- bool utf16 = false, bool isXMPPRIVFrame = false, bool needEncodingByte = true );
+ bool utf16 = false, bool isXMPPRIVFrame = false, bool needEncodingByte = true, bool isAlreadyEncoded = false );
XMP_Int64 read ( XMP_IO* file, XMP_Uns8 majorVersion );
void write ( XMP_IO* file, XMP_Uns8 majorVersion );
diff --git a/XMPFiles/source/FormatSupport/IPTC_Support.cpp b/XMPFiles/source/FormatSupport/IPTC_Support.cpp
index fece006..3df7726 100644
--- a/XMPFiles/source/FormatSupport/IPTC_Support.cpp
+++ b/XMPFiles/source/FormatSupport/IPTC_Support.cpp
@@ -250,8 +250,10 @@ void IPTC_Manager::ParseMemoryDataSets ( const void* data, XMP_Uns32 length, boo
if ( (dsLen == 3) && (memcmp ( iptcPtr, "\x1B\x25\x47", 3 ) == 0) ) this->utf8Encoding = true;
}
- XMP_Uns16 mapID = recNum*1000 + dsNum;
- DataSetInfo dsInfo ( recNum, dsNum, dsLen, iptcPtr );
+ XMP_Uns16 mapID = recNum*1000 + dsNum;
+ DataSetInfo dsInfo( recNum, dsNum, dsLen );
+ if ( dsLen != 0 )
+ dsInfo.dataPtr = iptcPtr;
DataSetMap::iterator dsPos = this->dataSets.find ( mapID );
bool repeatable = false;
@@ -405,6 +407,10 @@ IPTC_Writer::~IPTC_Writer()
void IPTC_Writer::SetDataSet_UTF8 ( XMP_Uns8 dsNum, const void* utf8Ptr, XMP_Uns32 utf8Len, long which /* = -1 */ )
{
+ // No need to process if data is of zero length
+ if ( utf8Len == 0 )
+ return;
+
const DataSetCharacteristics* knownDS = FindKnownDataSet ( dsNum );
if ( knownDS == 0 ) XMP_Throw ( "Can only set known IPTC DataSets", kXMPErr_InternalFailure );
@@ -413,7 +419,10 @@ void IPTC_Writer::SetDataSet_UTF8 ( XMP_Uns8 dsNum, const void* utf8Ptr, XMP_Uns
XMP_Uns8 * tempPtr;
XMP_Uns32 dataLen;
std::string localStr;
-
+#if XMP_MacBuild
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
if ( kUTF8_Mode == kUTF8_AlwaysMode ) {
// Always use UTF-8.
@@ -463,6 +472,9 @@ void IPTC_Writer::SetDataSet_UTF8 ( XMP_Uns8 dsNum, const void* utf8Ptr, XMP_Uns
}
}
+#if XMP_MacBuild
+#pragma clang diagnostic pop
+#endif
// Set the value for this DataSet, making a non-transient copy of the value. Respect UTF-8 character
// boundaries when truncating. This is easy to check. If the first truncated byte has 10 in the
@@ -674,15 +686,16 @@ void IPTC_Writer::ConvertToUTF8()
for ( ; dsPos != dsEnd; ++dsPos ) {
DataSetInfo & dsInfo = dsPos->second;
-
- ReconcileUtils::LocalToUTF8 ( dsInfo.dataPtr, dsInfo.dataLen, &utf8Str );
- this->DisposeLooseValue ( dsInfo );
-
- dsInfo.dataLen = (XMP_Uns32)utf8Str.size();
- dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
- if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( dsInfo.dataPtr, utf8Str.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
-
+ if ( dsInfo.dataLen != 0 )
+ {
+ ReconcileUtils::LocalToUTF8( dsInfo.dataPtr, dsInfo.dataLen, &utf8Str );
+ this->DisposeLooseValue( dsInfo );
+
+ dsInfo.dataLen = ( XMP_Uns32 ) utf8Str.size();
+ dsInfo.dataPtr = ( XMP_Uns8* ) malloc( dsInfo.dataLen );
+ if ( dsInfo.dataPtr == 0 ) XMP_Throw( "Out of memory", kXMPErr_NoMemory );
+ memcpy( dsInfo.dataPtr, utf8Str.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+ }
}
this->utf8Encoding = true;
@@ -706,15 +719,16 @@ void IPTC_Writer::ConvertToLocal()
for ( ; dsPos != dsEnd; ++dsPos ) {
DataSetInfo & dsInfo = dsPos->second;
-
- ReconcileUtils::UTF8ToLocal ( dsInfo.dataPtr, dsInfo.dataLen, &localStr );
- this->DisposeLooseValue ( dsInfo );
-
- dsInfo.dataLen = (XMP_Uns32)localStr.size();
- dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
- if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( dsInfo.dataPtr, localStr.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
-
+ if ( dsInfo.dataLen != 0 )
+ {
+ ReconcileUtils::UTF8ToLocal( dsInfo.dataPtr, dsInfo.dataLen, &localStr );
+ this->DisposeLooseValue( dsInfo );
+
+ dsInfo.dataLen = ( XMP_Uns32 ) localStr.size();
+ dsInfo.dataPtr = ( XMP_Uns8* ) malloc( dsInfo.dataLen );
+ if ( dsInfo.dataPtr == 0 ) XMP_Throw( "Out of memory", kXMPErr_NoMemory );
+ memcpy( dsInfo.dataPtr, localStr.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+ }
}
this->utf8Encoding = false;
diff --git a/XMPFiles/source/FormatSupport/IPTC_Support.hpp b/XMPFiles/source/FormatSupport/IPTC_Support.hpp
index 4c2d2bc..e81f1e0 100644
--- a/XMPFiles/source/FormatSupport/IPTC_Support.hpp
+++ b/XMPFiles/source/FormatSupport/IPTC_Support.hpp
@@ -156,6 +156,8 @@ public:
XMP_Uns32 dataLen;
XMP_Uns8 * dataPtr; // ! The data is read-only. Raw data pointer, beware of character encoding.
DataSetInfo() : recNum(0), dsNum(0), dataLen(0), dataPtr(0) {};
+ DataSetInfo( XMP_Uns8 _recNum, XMP_Uns8 _dsNum, XMP_Uns32 _dataLen )
+ : recNum( _recNum ), dsNum( _dsNum ), dataLen( _dataLen ), dataPtr( 0 ) {};
DataSetInfo ( XMP_Uns8 _recNum, XMP_Uns8 _dsNum, XMP_Uns32 _dataLen, XMP_Uns8 * _dataPtr )
: recNum(_recNum), dsNum(_dsNum), dataLen(_dataLen), dataPtr(_dataPtr) {};
};
diff --git a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
index d4a8076..b1ee77c 100644
--- a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
+++ b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
@@ -55,7 +55,8 @@ const XMP_Uns8 * GetBoxInfo ( const XMP_Uns8 * boxPtr, const XMP_Uns8 * boxLimit
if ( info == 0 ) info = &voidInfo;
info->boxType = info->headerSize = 0;
info->contentSize = 0;
-
+ memset( info->idUUID, 0, 16 );
+
if ( boxPtr >= boxLimit ) XMP_Throw ( "Bad offset to GetBoxInfo", kXMPErr_InternalFailure );
if ( (boxLimit - boxPtr) < 8 ) { // Is there enough space for a standard box header?
@@ -68,8 +69,22 @@ const XMP_Uns8 * GetBoxInfo ( const XMP_Uns8 * boxPtr, const XMP_Uns8 * boxLimit
info->boxType = GetUns32BE ( boxPtr+4 );
if ( u32Size >= 8 ) {
- info->headerSize = 8; // Normal explicit size case.
- info->contentSize = u32Size - 8;
+ if( info->boxType == ISOMedia::k_uuid )
+ {
+ if ( (boxLimit - boxPtr) < 24 )
+ { // Is there enough space for a uuid box header?
+ if ( throwErrors ) XMP_Throw ( "No space for UUID box header", kXMPErr_BadFileFormat );
+ info->headerSize = (XMP_Uns32) (boxLimit - boxPtr);
+ return boxLimit;
+ }
+ info->headerSize = 8 + 16; // 16 for ID in UUID
+ memcpy( info->idUUID, boxPtr + 8, 16 );
+ }
+ else
+ {
+ info->headerSize = 8; // Normal explicit size case.
+ }
+ info->contentSize = u32Size - info->headerSize;
} else if ( u32Size == 0 ) {
info->headerSize = 8; // The box goes to EoF - treat it as "to limit".
info->contentSize = (boxLimit - boxPtr) - 8;
@@ -115,6 +130,7 @@ XMP_Uns64 GetBoxInfo ( XMP_IO* fileRef, const XMP_Uns64 boxOffset, const XMP_Uns
if ( info == 0 ) info = &voidInfo;
info->boxType = info->headerSize = 0;
info->contentSize = 0;
+ memset( info->idUUID, 0, 16 );
if ( boxOffset >= boxLimit ) XMP_Throw ( "Bad offset to GetBoxInfo", kXMPErr_InternalFailure );
@@ -131,8 +147,22 @@ XMP_Uns64 GetBoxInfo ( XMP_IO* fileRef, const XMP_Uns64 boxOffset, const XMP_Uns
info->boxType = GetUns32BE ( &buffer[4] );
if ( u32Size >= 8 ) {
- info->headerSize = 8; // Normal explicit size case.
- info->contentSize = u32Size - 8;
+ if( info->boxType == ISOMedia::k_uuid )
+ {
+ if ( (boxLimit - boxOffset) < 24 )
+ { // Is there enough space for a uuid box header?
+ if ( throwErrors ) XMP_Throw ( "No space for UUID box header", kXMPErr_BadFileFormat );
+ info->headerSize = (XMP_Uns32) (boxLimit - boxOffset);
+ return boxLimit;
+ }
+ info->headerSize = 8 + 16; // 16 for ID in UUID
+ (void) fileRef->ReadAll ( info->idUUID, 16 );
+ }
+ else
+ {
+ info->headerSize = 8; // Normal explicit size case.
+ }
+ info->contentSize = u32Size - info->headerSize;
} else if ( u32Size == 0 ) {
info->headerSize = 8; // The box goes to EoF.
info->contentSize = fileRef->Length() - (boxOffset + 8);
diff --git a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
index 728293f..a7c8feb 100644
--- a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
+++ b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
@@ -37,6 +37,11 @@ namespace ISOMedia {
ISOboxType(k_f4v ,0x66347620UL)SEPARATOR \
ISOboxType(k_avc1,0x61766331UL)SEPARATOR \
ISOboxType(k_qt ,0x71742020UL)SEPARATOR \
+ ISOboxType(k_isom,0x69736F6DUL)SEPARATOR \
+ ISOboxType(k_3gp4,0x33677034UL)SEPARATOR \
+ ISOboxType(k_3g2a,0x33673261UL)SEPARATOR \
+ ISOboxType(k_3g2b,0x33673262UL)SEPARATOR \
+ ISOboxType(k_3g2c,0x33673263UL)SEPARATOR \
\
ISOboxType(k_moov,0x6D6F6F76UL)SEPARATOR /* Container Box, no version/flags. */ \
ISOboxType(k_mvhd,0x6D766864UL)SEPARATOR /* Data FullBox, has version/flags. */ \
@@ -93,16 +98,17 @@ namespace ISOMedia {
bool IsKnownBoxType(XMP_Uns32 boxType) ;
void TerminateGlobals();
- static XMP_Uns32 k_xmpUUID [4] = { MakeUns32BE ( 0xBE7ACFCBUL ),
- MakeUns32BE ( 0x97A942E8UL ),
- MakeUns32BE ( 0x9C719994UL ),
- MakeUns32BE ( 0x91E3AFACUL ) };
+ static XMP_Uns8 k_xmpUUID [16] = { 0xBE, 0x7A, 0xCF, 0xCB, 0x97, 0xA9, 0x42, 0xE8, 0x9C, 0x71, 0x99, 0x94, 0x91, 0xE3, 0xAF, 0xAC };
struct BoxInfo {
XMP_Uns32 boxType; // In memory as native endian!
XMP_Uns32 headerSize; // Normally 8 or 16, less than 8 if available space is too small.
XMP_Uns64 contentSize; // Always the real size, never 0 for "to EoF".
- BoxInfo() : boxType(0), headerSize(0), contentSize(0) {};
+ XMP_Uns8 idUUID[16]; // ID of the uuid atom if present
+ BoxInfo() : boxType(0), headerSize(0), contentSize(0)
+ {
+ memset( idUUID, 0, 16 );
+ };
};
// Get basic info about a box in memory, returning a pointer to the following box.
diff --git a/XMPFiles/source/FormatSupport/MOOV_Support.cpp b/XMPFiles/source/FormatSupport/MOOV_Support.cpp
index 959df44..50b02eb 100644
--- a/XMPFiles/source/FormatSupport/MOOV_Support.cpp
+++ b/XMPFiles/source/FormatSupport/MOOV_Support.cpp
@@ -59,6 +59,8 @@ void MOOV_Manager::FillBoxInfo ( const BoxNode & node, BoxInfo * info ) const
info->childCount = (XMP_Uns32)node.children.size();
info->contentSize = node.contentSize;
info->content = PickContentPtr ( node );
+ if( node.boxType == ISOMedia::k_uuid )
+ memcpy( info->idUUID, node.idUUID, 16);
} // MOOV_Manager::FillBoxInfo
@@ -249,7 +251,10 @@ void MOOV_Manager::ParseNestedBoxes ( BoxNode * parentNode, const std::string &
(isoInfo.contentSize == 0) ) continue; // Skip trailing padding that QT sometimes writes.
XMP_Uns32 childOffset = (XMP_Uns32) (currChild - moovOrigin);
- parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns32)isoInfo.contentSize ) );
+ if( isoInfo.boxType == ISOMedia::k_uuid )
+ parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns8 *)isoInfo.idUUID, (XMP_Uns32)isoInfo.contentSize ) );
+ else
+ parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns32)isoInfo.contentSize ) );
BoxNode * newChild = &parentNode->children.back();
#if TraceParseMoovTree
@@ -300,13 +305,17 @@ void MOOV_Manager::NoteChange()
//
// Save the new data, set this box's changed flag, and set the top changed flag.
-void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size )
+void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID )
{
XMP_Enforce ( size < moovBoxSizeLimit );
BoxNode * node = (BoxNode*)theBox;
if ( node->contentSize == size ) {
-
+ if( node->boxType == ISOMedia::k_uuid && idUUID != 0 )
+ {
+ memcpy ( node->idUUID, idUUID, 16 );
+ this->moovNode.changed = true;
+ }
XMP_Uns8 * oldContent = PickContentPtr ( *node );
if ( memcmp ( oldContent, dataPtr, size ) == 0 ) return; // No change.
memcpy ( oldContent, dataPtr, size ); // Update the old content in-place
@@ -323,6 +332,8 @@ void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size )
memcpy ( &node->changedContent[0], dataPtr, size );
node->contentSize = size;
node->changed = true;
+ if( node->boxType == ISOMedia::k_uuid && idUUID != 0)
+ memcpy ( node->idUUID, idUUID, 16 );
this->moovNode.changed = true;
#if TraceUpdateMoovTree
@@ -342,7 +353,7 @@ void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size )
//
// Like above, but create the path to the box if necessary.
-void MOOV_Manager::SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size )
+void MOOV_Manager::SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID )
{
XMP_Enforce ( size < moovBoxSizeLimit );
@@ -363,11 +374,11 @@ void MOOV_Manager::SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32
parentRef = currRef;
currRef = this->GetTypeChild ( parentRef, boxType, 0 );
- if ( currRef == 0 ) currRef = this->AddChildBox ( parentRef, boxType, 0, 0 );
+ if ( currRef == 0 ) currRef = this->AddChildBox ( parentRef, boxType, 0, 0 , idUUID );
}
- this->SetBox ( currRef, dataPtr, size );
+ this->SetBox ( currRef, dataPtr, size, idUUID );
} // MOOV_Manager::SetBox
@@ -375,12 +386,15 @@ void MOOV_Manager::SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32
// MOOV_Manager::AddChildBox
// =========================
-MOOV_Manager::BoxRef MOOV_Manager::AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void* dataPtr, XMP_Uns32 size )
+MOOV_Manager::BoxRef MOOV_Manager::AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID )
{
BoxNode * parent = (BoxNode*)parentRef;
XMP_Assert ( parent != 0 );
- parent->children.push_back ( BoxNode ( 0, childType, 0, 0 ) );
+ if( childType == ISOMedia::k_uuid && idUUID != 0)
+ parent->children.push_back ( BoxNode ( 0, childType, 0, idUUID, 0 ) );
+ else
+ parent->children.push_back ( BoxNode ( 0, childType, 0, 0 ) );
BoxNode * newNode = &parent->children.back();
this->SetBox ( newNode, dataPtr, size );
@@ -436,6 +450,8 @@ XMP_Uns32 MOOV_Manager::NewSubtreeSize ( const BoxNode & node, const std::string
{
XMP_Uns32 subtreeSize = 8 + node.contentSize; // All boxes will have 8 byte headers.
+ if( node.boxType == ISOMedia::k_uuid )
+ subtreeSize += 16; // id of uuid is 16 bytes long
if ( (node.boxType == ISOMedia::k_free) || (node.boxType == ISOMedia::k_wide) ) {
}
@@ -493,7 +509,12 @@ XMP_Uns8 * MOOV_Manager::AppendNewSubtree ( const BoxNode & node, const std::str
XMP_Uns8 * boxOrigin = newPtr; // Save origin to fill in the final size.
PutUns32BE ( node.boxType, (newPtr + 4) );
IncrNewPtr ( 8 );
-
+ if( node.boxType == ISOMedia::k_uuid ) // For uuid, additional 16 bytes is stored for ID
+ {
+ XMP_Enforce ( (XMP_Uns32)(newEnd - newPtr) >= ( 16 + node.contentSize ) );
+ memcpy( newPtr, node.idUUID, 16 );
+ IncrNewPtr ( 16 );
+ }
if ( node.contentSize != 0 ) {
const XMP_Uns8 * content = PickContentPtr( node );
memcpy ( newPtr, content, node.contentSize );
diff --git a/XMPFiles/source/FormatSupport/MOOV_Support.hpp b/XMPFiles/source/FormatSupport/MOOV_Support.hpp
index 7d34ca2..9dc785c 100644
--- a/XMPFiles/source/FormatSupport/MOOV_Support.hpp
+++ b/XMPFiles/source/FormatSupport/MOOV_Support.hpp
@@ -44,7 +44,11 @@ public:
XMP_Uns32 childCount; // ! A 'meta' box has both content (version/flags) and children!
XMP_Uns32 contentSize; // Does not include the size of nested boxes.
const XMP_Uns8 * content; // Null if contentSize is zero.
- BoxInfo() : boxType(0), childCount(0), contentSize(0), content(0) {};
+ XMP_Uns8 idUUID[16]; // ID of the uuid atom if present
+ BoxInfo() : boxType(0), childCount(0), contentSize(0), content(0)
+ {
+ memset ( idUUID ,0, 16 );
+ };
};
// ---------------------------------------------------------------------------------------------
@@ -73,10 +77,10 @@ public:
void NoteChange();
- void SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size );
- void SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size );
+ void SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID = 0 );
+ void SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID = 0 );
- BoxRef AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void * dataPtr, XMP_Uns32 size );
+ BoxRef AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void * dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID = 0 );
// ---------------------------------------------------------------------------------------------
// DeleteNthChild - Delete the overall n-th child, return true if there was one.
@@ -195,15 +199,26 @@ private:
XMP_Uns32 offset; // The offset in the fullSubtree, 0 if not in the parse.
XMP_Uns32 boxType;
XMP_Uns32 headerSize; // The actual header size in the fullSubtree, 0 if not in the parse.
- XMP_Uns32 contentSize; // The current content size, does not include nested boxes.
+ XMP_Uns32 contentSize; // The current content size, does not include nested boxes or id.
BoxList children;
+ XMP_Uns8 idUUID[16];
RawDataBlock changedContent; // Might be empty even if changed is true.
bool changed; // If true, the content is in changedContent, else in fullSubtree.
- BoxNode() : offset(0), boxType(0), headerSize(0), contentSize(0), changed(false) {};
+ BoxNode() : offset(0), boxType(0), headerSize(0), contentSize(0), changed(false)
+ {
+ memset ( idUUID, 0, 16 );
+ };
BoxNode ( XMP_Uns32 _offset, XMP_Uns32 _boxType, XMP_Uns32 _headerSize, XMP_Uns32 _contentSize )
- : offset(_offset), boxType(_boxType), headerSize(_headerSize), contentSize(_contentSize), changed(false) {};
-
+ : offset(_offset), boxType(_boxType), headerSize(_headerSize), contentSize(_contentSize), changed(false)
+ {
+ memset ( idUUID, 0, 16 );
+ };
+ BoxNode ( XMP_Uns32 _offset, XMP_Uns32 _boxType, XMP_Uns32 _headerSize, const XMP_Uns8 * _idUUID, XMP_Uns32 _contentSize )
+ : offset(_offset), boxType(_boxType), headerSize(_headerSize), contentSize(_contentSize), changed(false)
+ {
+ memcpy ( idUUID, _idUUID, 16 );
+ };
};
XMP_Uns8 fileMode;
diff --git a/XMPFiles/source/FormatSupport/RIFF.cpp b/XMPFiles/source/FormatSupport/RIFF.cpp
index 4d9a0c1..6930190 100644
--- a/XMPFiles/source/FormatSupport/RIFF.cpp
+++ b/XMPFiles/source/FormatSupport/RIFF.cpp
@@ -52,21 +52,20 @@ Chunk* getChunk ( ContainerChunk* parent, RIFF_MetaHandler* handler )
return new ContainerChunk( parent, handler );
case kChunk_LIST:
{
- if ( level != 1 ) break; // only care on this level
+ if ( level != 1 ) break; // only care on this level
// look further (beyond 4+4 = beyond id+size) to check on relevance
file->Seek ( 8, kXMP_SeekFromCurrent );
XMP_Uns32 containerType = XIO::PeekUns32_LE ( file );
file->Seek ( -8, kXMP_SeekFromCurrent );
- bool isRelevantList = ( containerType== kType_INFO || containerType == kType_Tdat );
- if ( !isRelevantList ) break;
-
- return new ContainerChunk( parent, handler );
+ bool isRelevantList = ( containerType== kType_INFO || containerType == kType_Tdat || containerType == kType_hdrl );
+ if ( !isRelevantList ) break;
+ return new ContainerChunk( parent, handler );
}
case kChunk_XMP:
- if ( level != 1 ) break; // ignore on inappropriate levels (might be compound metadata?)
- return new XMPChunk( parent, handler );
+ if ( level != 1 ) break; // ignore on inappropriate levels (might be compound metadata?)
+ return new XMPChunk( parent, handler );
case kChunk_DISP:
{
if ( level != 1 ) break; // only care on this level
@@ -114,6 +113,13 @@ Chunk* getChunk ( ContainerChunk* parent, RIFF_MetaHandler* handler )
JunkChunk* r = new JunkChunk( parent, handler );
return r;
}
+ case kChunk_IDIT:
+ {
+ if ( level != 2 ) break; // only care on this level
+ ValueChunk* r = new ValueChunk( parent, handler );
+ handler->iditChunk = r;
+ return r;
+ }
}
// this "default:" section must be ouside switch bracket, to be
// reachable by all those break statements above:
@@ -267,7 +273,8 @@ ContainerChunk::ContainerChunk( ContainerChunk* parent, RIFF_MetaHandler* handle
// has *relevant* subChunks? (there might be e.g. non-INFO LIST chunks we don't care about)
bool hasSubChunks = ( ( this->id == kChunk_RIFF ) ||
( this->id == kChunk_LIST && this->containerType == kType_INFO ) ||
- ( this->id == kChunk_LIST && this->containerType == kType_Tdat )
+ ( this->id == kChunk_LIST && this->containerType == kType_Tdat ) ||
+ ( this->id == kChunk_LIST && this->containerType == kType_hdrl )
);
XMP_Int64 endOfChunk = this->oldPos + this->oldSize;
@@ -330,6 +337,8 @@ ContainerChunk::ContainerChunk( ContainerChunk* parent, RIFF_MetaHandler* handle
handler->listInfoChunk = this;
if ( level==1 && this->id==kChunk_LIST && this->containerType == kType_Tdat )
handler->listTdatChunk = this;
+ if ( level == 1 && this->id == kChunk_LIST && this->containerType == kType_hdrl )
+ handler->listHdlrChunk = this;
}
else // skip non-interest container chunk
{
@@ -814,8 +823,6 @@ chunkVectIter ContainerChunk::getChild( Chunk* needle )
chunkVectIter iter;
for( iter = this->children.begin(); iter != this->children.end(); iter++ )
{
- Chunk* temp1 = *iter;
- Chunk* temp2 = needle;
if ( (*iter) == needle ) return iter;
}
return this->children.end();
diff --git a/XMPFiles/source/FormatSupport/RIFF.hpp b/XMPFiles/source/FormatSupport/RIFF.hpp
index e2451e5..4bb1f6e 100644
--- a/XMPFiles/source/FormatSupport/RIFF.hpp
+++ b/XMPFiles/source/FormatSupport/RIFF.hpp
@@ -70,6 +70,7 @@ namespace RIFF {
// other relevant chunks
const XMP_Uns32 kChunk_XMP = 0x584D505F; // "_PMX"
+ const XMP_Uns32 kChunk_IDIT = 0x54494449; // "TIDI"
// relevant for Index Correction
// LIST:
diff --git a/XMPFiles/source/FormatSupport/RIFF_Support.cpp b/XMPFiles/source/FormatSupport/RIFF_Support.cpp
index 152a53b..a64c98e 100644
--- a/XMPFiles/source/FormatSupport/RIFF_Support.cpp
+++ b/XMPFiles/source/FormatSupport/RIFF_Support.cpp
@@ -22,6 +22,8 @@
#include "XMPFiles/source/FormatSupport/RIFF_Support.hpp"
#include "XMPFiles/source/FormatSupport/Reconcile_Impl.hpp"
+#include <sstream>
+
#define MIN(a, b) ((a) < (b) ? (a) : (b))
using namespace RIFF;
@@ -37,6 +39,9 @@ XMP_Int32 MAX_BEXT_SIZE = 100 * 1024 * 1024;
XMP_Int32 CR8R_SIZE = 0x5C;
XMP_Int32 PRML_SIZE = 0x122;
+// IDIT chunk size
+XMP_Int32 IDIT_SIZE = 0x1A;
+
static const char* sHexChars = "0123456789ABCDEF";
// Encode a string of raw data bytes into a HexString (w/o spaces, i.e. "DEADBEEF").
@@ -290,6 +295,89 @@ static void importBextChunkToXMP( RIFF_MetaHandler* handler, ValueChunk* bextChu
}
} // importBextChunkToXMP
+static XMP_Int32 GetMonth( const char * valuePtr )
+{
+ // This will check 3 characters (4,5,6) of the input and return corresponding months as 1,2,...,12
+ // else it will return 0
+ // Input should as follows : wda mon dd hh:mm:ss yyyy\n\0
+ char firstChar = tolower( valuePtr[ 4 ] );
+ char secondChar = tolower( valuePtr[ 5 ] );
+ char thirdChar = tolower( valuePtr[ 6 ] );
+ if ( firstChar == 'j' && secondChar == 'a' && thirdChar == 'n' )
+ return 1;
+ if ( firstChar == 'f' && secondChar == 'e' && thirdChar == 'b' )
+ return 2;
+ if ( firstChar == 'm' && secondChar == 'a' )
+ {
+ if ( thirdChar == 'r' )
+ return 3;
+ if ( thirdChar == 'y' )
+ return 5;
+ }
+ if ( firstChar == 'a' && secondChar == 'p' && thirdChar == 'r' )
+ return 4;
+ if ( firstChar == 'j' && secondChar == 'u' )
+ {
+ if ( thirdChar == 'n' )
+ return 6;
+ if ( thirdChar == 'l' )
+ return 7;
+ }
+ if ( firstChar == 'a' && secondChar == 'u' && thirdChar == 'g' )
+ return 8;
+ if ( firstChar == 's' && secondChar == 'e' && thirdChar == 'p' )
+ return 9;
+ if ( firstChar == 'o' && secondChar == 'c' && thirdChar == 't' )
+ return 10;
+ if ( firstChar == 'n' && secondChar == 'o' && thirdChar == 'v' )
+ return 11;
+ if ( firstChar == 'd' && secondChar == 'e' && thirdChar == 'c' )
+ return 12;
+ return 0;
+}
+
+static XMP_Uns32 GatherUnsignedInt ( const char * strPtr, size_t count )
+{
+ XMP_Uns32 value = 0;
+ const char * strEnd = strPtr + count;
+
+ while ( strPtr < strEnd ) {
+ if ( *strPtr == ' ' ) ++strPtr;
+ else break;
+ }
+
+ while ( strPtr < strEnd ) {
+ char ch = *strPtr;
+ if ( (ch < '0') || (ch > '9') ) break;
+ value = value*10 + (ch - '0');
+ ++strPtr;
+ }
+
+ return value;
+
+} // GatherUnsignedInt
+
+static void importIditChunkToXMP( RIFF_MetaHandler* handler, ValueChunk* iditChunk )
+{
+ // if there iss a IDIT chunk, there is data...
+ handler->containsXMP = true; // very important for treatment on caller level
+
+ // Size has been already checked in calling function
+ XMP_Enforce( iditChunk->oldSize == IDIT_SIZE + 8 );
+ const char * valuePtr = iditChunk->oldValue.c_str();
+ XMP_Enforce( valuePtr[ IDIT_SIZE - 2 ] == 0x0A );
+ XMP_Enforce( valuePtr[ 13 ] == ':' && valuePtr[ 16 ] == ':' );
+ XMP_DateTime dateTime;
+ dateTime.month = GetMonth( valuePtr );
+ dateTime.day = GatherUnsignedInt( valuePtr + 8, 2 );
+ dateTime.hour = GatherUnsignedInt( valuePtr + 11, 2 );
+ dateTime.minute = GatherUnsignedInt( valuePtr + 14, 2 );
+ dateTime.second = GatherUnsignedInt( valuePtr + 17, 2 );
+ dateTime.year = GatherUnsignedInt( valuePtr + 20, 4 );
+ handler->xmpObj.SetProperty_Date( kXMP_NS_EXIF, "DateTimeOriginal", dateTime );
+
+} // importIditChunkToXMP
+
static void importPrmLToXMP( RIFF_MetaHandler* handler, ValueChunk* prmlChunk )
{
bool haveXMP = false;
@@ -540,6 +628,13 @@ void importProperties( RIFF_MetaHandler* handler )
} // if size sufficient
} // handler->dispChunk
+ // IDIT chunk --------------------------------------------------------------
+ if ( handler->parent->format == kXMP_AVIFile && // Only for AVI file
+ handler->iditChunk != 0 && handler->iditChunk->oldSize == IDIT_SIZE + 8 ) // Including header size i.e, ID + size
+ {
+ importIditChunkToXMP( handler, handler->iditChunk );
+ }
+
} // importProperties
////////////////////////////////////////////////////////////////////////////////
@@ -613,7 +708,7 @@ static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextCh
// prepare buffer, need to know CodingHistory size as the only variable
XMP_Int32 bextBufferSize = MIN_BEXT_SIZE - 8; // -8 because of header
std::string value;
- if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, 0 ))
+ if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ))
{
bextBufferSize += ((XMP_StringLen)value.size()) + 1 ; // add to size (and a trailing zero)
}
@@ -625,35 +720,35 @@ static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextCh
// grab props, write into buffer, remove from XMP ///////////////////////////
// bextDescription ------------------------------------------------
- if ( xmp->GetProperty( bextDescription.ns, bextDescription.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextDescription.ns, bextDescription.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
setBextField( &value, (XMP_Uns8*) buffer, 0, 256 );
xmp->DeleteProperty( bextDescription.ns, bextDescription.prop) ;
chunkUsed = true;
}
// bextOriginator -------------------------------------------------
- if ( xmp->GetProperty( bextOriginator.ns , bextOriginator.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextOriginator.ns , bextOriginator.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
setBextField( &value, (XMP_Uns8*) buffer, 256, 32 );
xmp->DeleteProperty( bextOriginator.ns , bextOriginator.prop );
chunkUsed = true;
}
// bextOriginatorRef ----------------------------------------------
- if ( xmp->GetProperty( bextOriginatorRef.ns , bextOriginatorRef.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextOriginatorRef.ns , bextOriginatorRef.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
setBextField( &value, (XMP_Uns8*) buffer, 256+32, 32 );
xmp->DeleteProperty( bextOriginatorRef.ns , bextOriginatorRef.prop );
chunkUsed = true;
}
// bextOriginationDate --------------------------------------------
- if ( xmp->GetProperty( bextOriginationDate.ns , bextOriginationDate.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextOriginationDate.ns , bextOriginationDate.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
setBextField( &value, (XMP_Uns8*) buffer, 256+32+32, 10 );
xmp->DeleteProperty( bextOriginationDate.ns , bextOriginationDate.prop );
chunkUsed = true;
}
// bextOriginationTime --------------------------------------------
- if ( xmp->GetProperty( bextOriginationTime.ns , bextOriginationTime.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextOriginationTime.ns , bextOriginationTime.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
setBextField( &value, (XMP_Uns8*) buffer, 256+32+32+10, 8 );
xmp->DeleteProperty( bextOriginationTime.ns , bextOriginationTime.prop );
@@ -661,7 +756,7 @@ static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextCh
}
// bextTimeReference ----------------------------------------------
// thanx to friendly byte order, all 8 bytes can be written in one go:
- if ( xmp->GetProperty( bextTimeReference.ns, bextTimeReference.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextTimeReference.ns, bextTimeReference.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
try
{
@@ -684,7 +779,7 @@ static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextCh
xmp->DeleteProperty( bextVersion.ns, bextVersion.prop );
// bextUMID -------------------------------------------------------
- if ( xmp->GetProperty( bextUMID.ns, bextUMID.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextUMID.ns, bextUMID.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
std::string rawStr;
@@ -703,7 +798,7 @@ static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextCh
}
// bextCodingHistory ----------------------------------------------
- if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, 0 ) )
+ if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, (XMP_OptionBits *) kXMP_NoOptions ) )
{
std::string ascii;
convertToASCII( value.data(), (XMP_StringLen) value.size() , &ascii, (XMP_StringLen) value.size() );
@@ -809,6 +904,237 @@ static void exportXMPtoCr8rChunk ( RIFF_MetaHandler* handler, ValueChunk** cr8rC
}
+// Returns numbers of leap years between 1800 and provided year value. Both end values will be inclusive for getting this field.
+// For leap year this will be handled later in GetIDITString() function
+static XMP_Uns32 GetLeapYearsNumber( const XMP_Uns32 & year )
+{
+
+ XMP_Uns32 numLeapYears = ( year / 4 );
+ numLeapYears -= ( year / 100 );
+ numLeapYears += ( ( year + 200 ) / 400 ); // 200 is added becuase our base is 1800 which give modulas 200 by divinding with 400
+ return numLeapYears;
+
+} //GetLeapYearsNumber
+
+static XMP_Uns32 GetDays( const XMP_Int32 & month, const bool &isLeapYear )
+{
+ // Adding number of days as per last month of the provided year
+ // Leap year case is handled later
+ XMP_Uns32 numDays = 0;
+ switch ( month )
+ {
+ case 2:
+ numDays = 31;
+ break;
+ case 3:
+ numDays = 31 + 28;
+ break;
+ case 4:
+ numDays = 31 + 28 + 31;
+ break;
+ case 5:
+ numDays = 31 + 28 + 31 + 30;
+ break;
+ case 6:
+ numDays = 31 + 28 + 31 + 30 + 31;
+ break;
+ case 7:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30;
+ break;
+ case 8:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30 + 31;
+ break;
+ case 9:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
+ break;
+ case 10:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
+ break;
+ case 11:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
+ break;
+ case 12:
+ numDays = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
+ break;
+ default:
+ break;
+ }
+
+ // Adding one day for leap year and month above than feb
+ if ( isLeapYear == true && month > 2 )
+ numDays += 1;
+
+ return numDays;
+
+} // GetDays
+
+static const std::string GetIDITString( const XMP_DateTime & targetDate )
+{
+ // Date 1 Jan 1800 is treating as base date for handling this issue
+ // 1800 is chosen becuase of consistency in calender after 1752
+
+ XMP_Uns64 numOfDays = 0; // Specifies number of days after 1 jan 1800
+ XMP_Uns32 year = targetDate.year - 1800;
+
+ // 2000 was the first exception when year dividing by 100 was still a leap year
+ bool isLeapYear = ( year % 4 != 0 ) ? false : ( year % 100 != 0 ) ? true : ( ( year % 400 != 200 ) ? false : true );
+
+ // Adding days according to normal year and adjusting days for leap years
+ numOfDays = 365 * year;
+ numOfDays += GetLeapYearsNumber( year );
+
+ // Adding days according to the month
+ numOfDays += GetDays( targetDate.month, isLeapYear );
+
+ // GetLeapYearsNumber() function is also considering provided year for calculating number of leap numbers between provided year
+ // and 1800. This consideration is done by inclusive both end values. So both GetLeapYearsNumber() and GetDays() would have added
+ // extra day for higher end year for leap year.
+ // So, we need to decrease one day from number of days field
+ if ( isLeapYear )
+ --numOfDays;
+
+ // Adding days according to provided month
+ numOfDays += targetDate.day;
+
+ // Weekday starting from Wednesday i.e., Wed will be the first day of the week.
+ // This day was choosen because 1 Jan 1800 was Wednesday
+ XMP_Uns8 weekDayNum = numOfDays % 7;
+ std::string weekDay;
+ switch ( weekDayNum )
+ {
+ case 0:
+ weekDay = "Tue";
+ break;
+ case 1:
+ weekDay = "Wed";
+ break;
+ case 2:
+ weekDay = "Thu";
+ break;
+ case 3:
+ weekDay = "Fri";
+ break;
+ case 4:
+ weekDay = "Sat";
+ break;
+ case 5:
+ weekDay = "Sun";
+ break;
+ case 6:
+ weekDay = "Mon";
+ break;
+ default:
+ break;
+ }
+
+ // Stream to convert into IDIT format
+ std::stringstream iditStream;
+ iditStream << weekDay;
+ iditStream.put( ' ' );
+
+ // IDIT needs 3 character codes for month
+ const char * monthArray[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ iditStream << monthArray[ targetDate.month - 1 ];
+ iditStream.put( ' ' );
+
+ if ( targetDate.day < 10 )
+ iditStream.put( '0' );
+ iditStream << targetDate.day;
+ iditStream.put( ' ' );
+
+ if ( targetDate.hour < 10 )
+ iditStream.put( '0' );
+ iditStream << targetDate.hour;
+ iditStream.put( ':' );
+
+ if ( targetDate.minute < 10 )
+ iditStream.put( '0' );
+ iditStream << targetDate.minute;
+ iditStream.put( ':' );
+
+ if ( targetDate.second < 10 )
+ iditStream.put( '0' );
+ iditStream << targetDate.second;
+ iditStream.put( ' ' );
+
+ // No need to handle casese for year 1 to 999
+ /*
+ if ( targetDate.year < 10 )
+ iditStream << " ";
+ else if ( targetDate.year < 100 )
+ iditStream << " ";
+ else if ( targetDate.year < 1000 )
+ iditStream << " ";
+ */
+ // Year will be in the range of 1800-3999
+ iditStream << targetDate.year;
+
+ // Adding new line charcter for IDIT
+ iditStream.put( '\n' );
+
+ return iditStream.str();
+
+} // GetIDITString
+
+static void exportXMPtoIDITChunk( RIFF_MetaHandler* handler )
+{
+ // exif:DateTimeOriginal -> IDIT chunk
+ ContainerChunk * hdlrChunk = handler->listHdlrChunk;
+ if ( hdlrChunk == 0 )
+ XMP_Throw( "Header of AVI file (hdlr chunk) must exists", kXMPErr_BadFileFormat );
+
+ XMP_DateTime dateTime;
+ bool propExists = handler->xmpObj.GetProperty_Date( kXMP_NS_EXIF, "DateTimeOriginal", &dateTime, 0 );
+ if ( !propExists )
+ {
+ if ( handler->iditChunk != 0 )
+ {
+ // Exception would have thrown if we don't find hdlr chunk for AVI file
+ XMP_Assert( hdlrChunk != 0 );
+ bool isSuccess = hdlrChunk->removeValue( kChunk_IDIT );
+ if ( !isSuccess )
+ XMP_Throw( "Removal of IDIT block fails", kXMPErr_InternalFailure );
+ handler->iditChunk = 0;
+ hdlrChunk->hasChange = true;
+ }
+ // Else no need to do anything
+ }
+ else
+ {
+ if ( dateTime.year < 1800 || dateTime.year > 3999 )
+ XMP_Throw( "For IDIT block, XMP currently supports years in between 1800 and 3999 (Both inclusive).", kXMPErr_InternalFailure );
+
+ /*
+ Conversion need to be done from XMP date time to IDIT structure.
+ XMP_DateTime accepts any value but IDIT needs to have weekday, month-day, month, year and time.
+ */
+
+ // Silently modifying dateTime for invalid dates.
+ if ( dateTime.month < 1 )
+ dateTime.month = 1;
+ if ( dateTime.month > 12 )
+ dateTime.month = 12;
+ if ( dateTime.day < 1 )
+ dateTime.day = 1;
+ if ( dateTime.day > 31 )
+ dateTime.day = 31;
+
+ const std::string iditString = GetIDITString( dateTime );
+
+ // If no IDIT exits then create one
+ if ( handler->iditChunk == 0 )
+ handler->iditChunk = new ValueChunk( hdlrChunk, std::string(), kChunk_IDIT );
+ else if ( strncmp( iditString.c_str(), handler->iditChunk->oldValue.c_str(), IDIT_SIZE ) == 0 ) // Equal
+ return;
+
+ // Setting the IDIT value
+ handler->iditChunk->hasChange = true;
+ handler->iditChunk->SetValue( iditString, true );
+
+ }
+
+} // exportXMPtoIDITChunk
+
static void exportXMPtoListChunk( XMP_Uns32 id, XMP_Uns32 containerType,
RIFF_MetaHandler* handler, ContainerChunk** listChunk, Mapping mapping[])
{
@@ -887,12 +1213,12 @@ void exportAndRemoveProperties ( RIFF_MetaHandler* handler )
exportXMPtoCr8rChunk ( handler, &handler->cr8rChunk );
- // 1/4 BWF Bext extension chunk -----------------------------------------------
+ // 1/5 BWF Bext extension chunk -----------------------------------------------
if ( handler->parent->format == kXMP_WAVFile ) { // applies only to WAV
exportXMPtoBextChunk ( handler, &handler->bextChunk );
}
- // 2/4 DISP chunk
+ // 2/5 DISP chunk
if ( handler->parent->format == kXMP_WAVFile ) { // create for WAVE only
std::string actualLang, xmpValue;
@@ -928,12 +1254,16 @@ void exportAndRemoveProperties ( RIFF_MetaHandler* handler )
}
- // 3/4 LIST:INFO
+ // 3/5 LIST:INFO
exportXMPtoListChunk ( kChunk_LIST, kType_INFO, handler, &handler->listInfoChunk, listInfoProps );
- // 4/4 LIST:Tdat
+ // 4/5 LIST:Tdat
exportXMPtoListChunk ( kChunk_LIST, kType_Tdat, handler, &handler->listTdatChunk, listTdatProps );
+ // 5/5 LIST:HDRL:IDIT
+ if ( handler->parent->format == kXMP_AVIFile )
+ exportXMPtoIDITChunk ( handler );
+
}
} // namespace RIFF
diff --git a/XMPFiles/source/FormatSupport/ReconcileIPTC.cpp b/XMPFiles/source/FormatSupport/ReconcileIPTC.cpp
index df9d676..142cdd6 100644
--- a/XMPFiles/source/FormatSupport/ReconcileIPTC.cpp
+++ b/XMPFiles/source/FormatSupport/ReconcileIPTC.cpp
@@ -193,7 +193,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
IPTC_Manager::DataSetInfo dsInfo;
size_t count = iptc.GetDataSet ( dateID, &dsInfo );
- if ( count == 0 ) return;
+ if ( count == 0 || dsInfo.dataLen == 0 ) return;
size_t chPos, digits;
XMP_DateTime xmpDate;
@@ -205,7 +205,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
xmpDate.year = (xmpDate.year * 10) + (dsInfo.dataPtr[chPos] - '0');
}
- if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
+ if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == '-' ) ++chPos;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
xmpDate.month = (xmpDate.month * 10) + (dsInfo.dataPtr[chPos] - '0');
@@ -213,7 +213,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
if ( xmpDate.month < 1 ) xmpDate.month = 1;
if ( xmpDate.month > 12 ) xmpDate.month = 12;
- if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
+ if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == '-' ) ++chPos;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
xmpDate.day = (xmpDate.day * 10) + (dsInfo.dataPtr[chPos] - '0');
@@ -227,7 +227,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
// Now add the time portion if present.
count = iptc.GetDataSet ( timeID, &dsInfo );
- if ( count != 0 ) {
+ if ( count != 0 && dsInfo.dataLen > 0 ) {
chPos = 0;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
@@ -237,7 +237,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
if ( xmpDate.hour < 0 ) xmpDate.hour = 0;
if ( xmpDate.hour > 23 ) xmpDate.hour = 23;
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == ':' ) ++chPos;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
xmpDate.minute = (xmpDate.minute * 10) + (dsInfo.dataPtr[chPos] - '0');
@@ -245,7 +245,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
if ( xmpDate.minute < 0 ) xmpDate.minute = 0;
if ( xmpDate.minute > 59 ) xmpDate.minute = 59;
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == ':' ) ++chPos;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
xmpDate.second = (xmpDate.second * 10) + (dsInfo.dataPtr[chPos] - '0');
@@ -255,11 +255,11 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
xmpDate.hasTime = true;
- if ( (dsInfo.dataPtr[chPos] != ' ') && (dsInfo.dataPtr[chPos] != 0) ) { // Tolerate a missing TZ.
+ if ( ( chPos < dsInfo.dataLen ) && (dsInfo.dataPtr[chPos] != ' ') && (dsInfo.dataPtr[chPos] != 0) ) { // Tolerate a missing TZ.
- if ( dsInfo.dataPtr[chPos] == '+' ) {
+ if ( ( chPos < dsInfo.dataLen ) && ( dsInfo.dataPtr[chPos] == '+' ) ) {
xmpDate.tzSign = kXMP_TimeEastOfUTC;
- } else if ( dsInfo.dataPtr[chPos] == '-' ) {
+ } else if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == '-' ) {
xmpDate.tzSign = kXMP_TimeWestOfUTC;
} else if ( chPos != dsInfo.dataLen ) {
return; // The DataSet is ill-formed.
@@ -273,7 +273,7 @@ void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & ipt
if ( xmpDate.tzHour < 0 ) xmpDate.tzHour = 0;
if ( xmpDate.tzHour > 23 ) xmpDate.tzHour = 23;
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ if ( ( chPos < dsInfo.dataLen ) && dsInfo.dataPtr[chPos] == ':' ) ++chPos;
for ( digits = 0; digits < 2; ++digits, ++chPos ) {
if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
xmpDate.tzMinute = (xmpDate.tzMinute * 10) + (dsInfo.dataPtr[chPos] - '0');
@@ -367,8 +367,6 @@ static void ImportIPTC_SubjectCode ( const IPTC_Manager & iptc, SXMPMeta * xmp )
void PhotoDataUtils::Import2WayIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp, int iptcDigestState )
{
- if ( iptcDigestState == kDigestMatches ) return; // Ignore the IPTC if the digest matches.
-
std::string oldStr, newStr;
IPTC_Writer oldIPTC;
@@ -386,9 +384,9 @@ void PhotoDataUtils::Import2WayIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp,
bool haveXMP = xmp->DoesPropertyExist ( thisDS.xmpNS, thisDS.xmpProp );
newCount = PhotoDataUtils::GetNativeInfo ( iptc, thisDS.dsNum, iptcDigestState, haveXMP, &newInfo );
- if ( newCount == 0 ) continue; // GetNativeInfo returns 0 for ignored local text.
-
- if ( iptcDigestState == kDigestMissing ) {
+ if ( ( newCount == 0 ) || ( newInfo.dataLen == 0 ) ) continue; // GetNativeInfo returns 0 for ignored local text.
+ // For no data in dataset, don't import or delete anything
+ if ( iptcDigestState == kDigestMissing || iptcDigestState == kDigestMatches ) {
if ( haveXMP ) continue; // Keep the existing XMP.
} else if ( ! PhotoDataUtils::IsValueDifferent ( iptc, oldIPTC, thisDS.dsNum ) ) {
continue; // Don't import values that match the previous export.
diff --git a/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp b/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
index aa4aea6..ee58379 100644
--- a/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
+++ b/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
@@ -306,9 +306,7 @@ size_t PhotoDataUtils::GetNativeInfo ( const IPTC_Manager & iptc, XMP_Uns8 id, i
{
size_t iptcCount = 0;
- if ( (digestState == kDigestDiffers) || ((digestState == kDigestMissing) && (! haveXMP)) ) {
- iptcCount = iptc.GetDataSet ( id, info );
- }
+ iptcCount = iptc.GetDataSet ( id, info );
if ( ignoreLocalText && (iptcCount > 0) && (! iptc.UsingUTF8()) ) {
// Check to see if the new value(s) should be ignored.
@@ -2283,11 +2281,10 @@ static void Import3WayDateTime ( XMP_Uns16 exifTag, const TIFF_Manager & exif, c
haveXMP = xmp->GetProperty ( xmpNS, xmpProp, &xmpValue, 0 );
iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, iptcDS, iptcDigestState, haveXMP, &iptcInfo );
haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_ExifIFD, exifTag, &exifInfo );
XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
- if ( haveIPTC ) {
+ if ( haveIPTC && ((iptcDigestState == kDigestDiffers) || (!haveXMP && !haveExif)) ) {
PhotoDataUtils::ImportIPTC_Date ( iptcDS, iptc, xmp );
@@ -2360,7 +2357,6 @@ void PhotoDataUtils::Import3WayItems ( const TIFF_Manager & exif, const IPTC_Man
haveXMP = xmp->GetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", 0, &xmpValue, 0 );
iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_CopyrightNotice, iptcDigestState, haveXMP, &iptcInfo );
haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Copyright, &exifInfo );
XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
@@ -2370,7 +2366,7 @@ void PhotoDataUtils::Import3WayItems ( const TIFF_Manager & exif, const IPTC_Man
}
}
- if ( haveIPTC ) {
+ if ( haveIPTC && ((iptcDigestState == kDigestDiffers) || (!haveXMP && !haveExif)) ) {
PhotoDataUtils::ImportIPTC_LangAlt ( iptc, xmp, kIPTC_CopyrightNotice, kXMP_NS_DC, "rights" );
} else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", exifValue.c_str() );
@@ -2383,11 +2379,10 @@ void PhotoDataUtils::Import3WayItems ( const TIFF_Manager & exif, const IPTC_Man
haveXMP = xmp->GetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", 0, &xmpValue, 0 );
iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_Description, iptcDigestState, haveXMP, &iptcInfo );
haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_ImageDescription, &exifInfo );
XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
- if ( haveIPTC ) {
+ if ( haveIPTC && ((iptcDigestState == kDigestDiffers) || (!haveXMP && !haveExif)) ) {
PhotoDataUtils::ImportIPTC_LangAlt ( iptc, xmp, kIPTC_Description, kXMP_NS_DC, "description" );
} else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
xmp->SetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", exifValue.c_str() );
@@ -2401,11 +2396,10 @@ void PhotoDataUtils::Import3WayItems ( const TIFF_Manager & exif, const IPTC_Man
haveExif = PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Artist, &exifInfo );
iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_Creator, iptcDigestState, haveXMP, &iptcInfo );
haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Artist, &exifInfo );
XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
- if ( haveIPTC ) {
+ if ( haveIPTC && ((iptcDigestState == kDigestDiffers) || (!haveXMP && !haveExif)) ) {
PhotoDataUtils::ImportIPTC_Array ( iptc, xmp, kIPTC_Creator, kXMP_NS_DC, "creator" );
} else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
SXMPUtils::SeparateArrayItems ( xmp, kXMP_NS_DC, "creator",
diff --git a/XMPFiles/source/FormatSupport/SVG_Adapter.cpp b/XMPFiles/source/FormatSupport/SVG_Adapter.cpp
new file mode 100644
index 0000000..750848d
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/SVG_Adapter.cpp
@@ -0,0 +1,464 @@
+// =================================================================================================
+// Copyright 2015 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.
+//
+// This file includes implementation of SVG metadata, according to Scalable Vector Graphics (SVG) 1.1 Specification.
+// "https://www.w3.org/TR/2003/REC-SVG11-20030114/"
+// Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology,
+// Institut National de Recherche en Informatique et en Automatique, Keio University).
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
+//
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+
+#include "XMPFiles/source/FormatSupport/SVG_Adapter.hpp"
+
+#include "third-party/expat/lib/expat.h"
+#include <string.h>
+
+using namespace std;
+
+#if XMP_WinBuild
+#pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#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 ProcessingInstructionHandler( void * userData, XMP_StringPtr target, XMP_StringPtr data );
+static void DeclarationHandler( void *userData, const XML_Char *version, const XML_Char *encoding, int standalone );
+
+static bool isRequireData = false;
+static XMP_Uns32 reqDepth = 0;
+
+// Flag is provided to support behaviour like Expat Adapter
+#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 (&amp;, &lt;, &gt;, &quot;, &apos;, 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
+
+// =================================================================================================
+
+SVG_Adapter::SVG_Adapter() : parser(0), registeredNamespaces(0), firstSVGElementOffset(-1), depth(0)
+{
+
+ this->parser = XML_ParserCreateNS( 0, FullNameSeparator );
+
+ if ( this->parser == 0 ) {
+ XMP_Error error( kXMPErr_NoMemory, "Failure creating Expat parser" );
+ this->NotifyClient( kXMPErrSev_ProcessFatal, error );
+ }
+ else
+ {
+ this->registeredNamespaces = new XMP_NamespaceTable();
+
+ XML_SetUserData( this->parser, this );
+ XML_SetNamespaceDeclHandler( this->parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler );
+ XML_SetElementHandler( this->parser, StartElementHandler, EndElementHandler );
+ XML_SetCharacterDataHandler( this->parser, CharacterDataHandler );
+ XML_SetProcessingInstructionHandler( this->parser, ProcessingInstructionHandler );
+ XML_SetXmlDeclHandler( this->parser, DeclarationHandler );
+
+#if BanAllEntityUsage
+ XML_SetStartDoctypeDeclHandler( this->parser, StartDoctypeDeclHandler );
+ isAborted = false;
+#endif
+
+ this->parseStack.push_back( &this->tree ); // Push the XML root node.
+ }
+} // SVG_Adapter::SVG_Adapter
+
+// =================================================================================================
+
+SVG_Adapter::~SVG_Adapter()
+{
+ if ( this->parser != 0 ) XML_ParserFree( this->parser );
+ this->parser = 0;
+
+ if ( this->registeredNamespaces != 0 ) delete ( this->registeredNamespaces );
+ this->registeredNamespaces = 0;
+
+} // SVG_Adapter::~SVG_Adapter
+
+// =================================================================================================
+
+OffsetStruct SVG_Adapter::GetElementOffsets( std::string elementName )
+{
+ IteratorStringOffsetStruct iterator = this->mOffsetsMap.find( elementName );
+ if ( iterator != mOffsetsMap.end() )
+ return iterator->second;
+
+ return OffsetStruct();
+} // SVG_Adapter::GetElementOffset
+
+// =================================================================================================
+
+void SVG_Adapter::RegisterElement( std::string elementName, std::string reqParent )
+{
+ IteratorStringOffsetStruct iterator = this->mOffsetsMap.find( elementName );
+ if ( iterator == mOffsetsMap.end() )
+ {
+ this->mOffsetsMap.insert( iterator, std::pair<std::string, OffsetStruct>( elementName, OffsetStruct( reqParent ) ) );
+ }
+} // SVG_Adapter::RegisterElement
+
+// =================================================================================================
+
+XMP_Int64 SVG_Adapter::GetPIOffset( std::string PIName, XMP_Uns32 requiredIndex /* = 1 */ )
+{
+ if ( this->parser != 0 )
+ {
+ std::pair<IteratorStringXMP_Int64, IteratorStringXMP_Int64> iterator = this->mPIWithOffsetMap.equal_range( PIName );
+ if ( iterator.first != iterator.second )
+ {
+ XMP_Uns32 index = 0;
+ IteratorStringXMP_Int64 indexIterator = iterator.first;
+ for ( ; index < ( requiredIndex - 1 ) && indexIterator != iterator.second; ++indexIterator, ++index );
+ if ( index == requiredIndex - 1 )
+ return indexIterator->second;
+ }
+ }
+ return -1;
+} // SVG_Adapter::GetPIOffset
+
+// =================================================================================================
+
+void SVG_Adapter::RegisterPI( std::string PIName )
+{
+ IteratorStringXMP_Int64 iterator = this->mPIWithOffsetMap.find( PIName );
+ if ( iterator == mPIWithOffsetMap.end() )
+ {
+ this->mPIWithOffsetMap.insert( iterator, std::pair<std::string, XMP_Int64>( PIName, -1 ) );
+ }
+} // SVG_Adapter::RegisterPI
+
+// =================================================================================================
+
+XMP_Bool SVG_Adapter::IsParsingRequire( )
+{
+ for ( IteratorStringOffsetStruct iterator = this->mOffsetsMap.begin(); iterator != this->mOffsetsMap.end(); ++iterator )
+ {
+ if ( iterator->second.startOffset == -1 || iterator->second.endOffset == -1 || iterator->second.nextOffset == -1 )
+ return true;
+ }
+ return false;
+} // SVG_Adapter::IsParsingRequire
+
+// =================================================================================================
+
+// This version of parsing throw an error
+void SVG_Adapter::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;
+ const char * kOneSpace = " ";
+ buffer = kOneSpace;
+ length = 1;
+ }
+
+ status = XML_Parse( this->parser, ( const char * ) buffer, static_cast< XMP_StringLen >( length ), last );
+
+#if BanAllEntityUsage
+ if ( this->isAborted ) {
+ XMP_Error error( kXMPErr_BadXML, "DOCTYPE is not allowed" )
+ this->NotifyClient( kXMPErrSev_Recoverable, error );
+ }
+#endif
+
+ if ( status != XML_STATUS_OK ) {
+
+ XMP_Error error( kXMPErr_BadXML, "Invalid SVG file" );
+ this->NotifyClient( kXMPErrSev_OperationFatal, error );
+
+ }
+
+} // SVG_Adapter::ParseBuffer
+
+// =================================================================================================
+
+// This version of parsing doesn't throw error but returns false if any error is encountered
+// This is required just for checkformat
+XMP_Bool SVG_Adapter::ParseBufferNoThrow( 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 false;
+ const char * kOneSpace = " ";
+ buffer = kOneSpace;
+ length = 1;
+ }
+
+ status = XML_Parse( this->parser, ( const char * ) buffer, static_cast< XMP_StringLen >( length ), last );
+
+#if BanAllEntityUsage
+ if ( this->isAborted ) {
+ XMP_Error error( kXMPErr_BadXML, "DOCTYPE is not allowed" )
+ this->NotifyClient( kXMPErrSev_Recoverable, error );
+ }
+#endif
+
+ if ( status != XML_STATUS_OK )
+ return false;
+ else
+ return true;
+
+} // SVG_Adapter::ParseBufferNoThrow
+
+// =================================================================================================
+
+static void ParseFullNS( XMP_StringPtr fullName, string & NS, string &localName )
+{
+ // Expat delivers the full name as a catenation of namespace URI, separator, and local name.
+ size_t sepPos = strlen( fullName );
+ for ( --sepPos; sepPos > 0; --sepPos ) {
+ if ( fullName[ sepPos ] == FullNameSeparator ) break;
+ }
+
+ if ( fullName[ sepPos ] == FullNameSeparator )
+ {
+ localName = fullName + sepPos + 1;
+ NS.assign( fullName, sepPos );
+ }
+ else
+ localName = fullName;
+
+} // ParseFullNS
+
+// =================================================================================================
+
+static void StartNamespaceDeclHandler( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri )
+{
+
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+ if ( uri == 0 ) return; // Ignore, have xmlns:pre="", no URI to register.
+
+ ( void ) thiz->registeredNamespaces->Define( uri, prefix, 0, 0 );
+
+} // StartNamespaceDeclHandler
+
+// =================================================================================================
+
+static void EndNamespaceDeclHandler( void * userData, XMP_StringPtr prefix )
+{
+ IgnoreParam( userData );
+ IgnoreParam( prefix );
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+
+} // EndNamespaceDeclHandler
+
+// =================================================================================================
+
+static void StartElementHandler( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs )
+{
+ // In case, if name is NULL then ParseBuffer would return with error status
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+ thiz->depth++;
+ if ( thiz->depth > 3 )
+ return;
+ else if ( thiz->firstSVGElementOffset == -1 && thiz->depth == 2 )
+ thiz->firstSVGElementOffset = XML_GetCurrentByteIndex( thiz->parser );
+ else
+ {
+ if ( !thiz->mPrevRequiredElement.empty() )
+ {
+ IteratorStringOffsetStruct iterator = thiz->mOffsetsMap.find( thiz->mPrevRequiredElement );
+ if ( iterator != thiz->mOffsetsMap.end() )
+ iterator->second.nextOffset = XML_GetCurrentByteIndex( thiz->parser );
+ thiz->mPrevRequiredElement.clear();
+ }
+ }
+
+ string NS, localName;
+ ParseFullNS( name, NS, localName );
+
+ IteratorStringOffsetStruct iterator = thiz->mOffsetsMap.find( localName );
+ if ( iterator == thiz->mOffsetsMap.end() && localName != "svg" )
+ return;
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * elemNode = new XML_Node( parentNode, "", kElemNode );
+
+ if ( strncmp( localName.c_str(), name, localName.length() ) != 0 )
+ {
+ XMP_StringPtr prefix;
+ XMP_StringLen prefixLen;
+ bool found = thiz->registeredNamespaces->GetPrefix( NS.c_str(), &prefix, &prefixLen );
+ if ( !found ) {
+ XMP_Error error( kXMPErr_ExternalFailure, "Unknown URI in Expat full name" );
+ thiz->NotifyClient( kXMPErrSev_OperationFatal, error );
+ }
+ elemNode->ns = NS;
+ elemNode->nsPrefixLen = prefixLen; // ! Includes the ':'.
+
+ if ( strcmp( prefix, "_dflt_:" ) == 0 )
+ {
+ elemNode->name = localName;
+ elemNode->nsPrefixLen = 0;
+ }
+ else
+ {
+ elemNode->name = prefix;
+ elemNode->name += localName;
+ }
+ }
+ else
+ {
+ elemNode->name = localName; // The name is not in a namespace.
+ }
+
+ parentNode->content.push_back( elemNode );
+ thiz->parseStack.push_back( elemNode );
+
+ if ( iterator != thiz->mOffsetsMap.end() && iterator->second.parent == parentNode->name )
+ {
+ reqDepth = thiz->depth;
+ isRequireData = true;
+ if ( iterator->second.startOffset == -1 )
+ iterator->second.startOffset = XML_GetCurrentByteIndex( thiz->parser );
+ }
+ else
+ {
+ isRequireData = false;
+ }
+
+} // StartElementHandler
+
+// =================================================================================================
+
+static void EndElementHandler( void * userData, XMP_StringPtr name )
+{
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+
+ thiz->depth--;
+ if ( thiz->depth > 2 )
+ return;
+
+ string NS, localName;
+ ParseFullNS( name, NS, localName );
+
+ IteratorStringOffsetStruct iterator = thiz->mOffsetsMap.find( localName );
+ if ( iterator != thiz->mOffsetsMap.end() )
+ {
+ // StartOffset flag is provided to reject the elements of non-required namespace
+ // Endoffset flag is provided to maintain state of first available element
+ // Depth flag is provided to support for workflow like <title><title>...</title></title>
+ if ( iterator->second.startOffset != -1 && iterator->second.endOffset == -1 && thiz->depth == reqDepth - 1 )
+ {
+ iterator->second.endOffset = XML_GetCurrentByteIndex( thiz->parser );
+ thiz->mPrevRequiredElement = localName;
+ }
+ }
+ else if ( localName != "svg" )
+ return;
+
+ ( void ) thiz->parseStack.pop_back();
+
+} // EndElementHandler
+
+// =================================================================================================
+
+static void CharacterDataHandler( void * userData, XMP_StringPtr cData, int len )
+{
+ if ( !isRequireData )
+ return;
+ isRequireData = false;
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+
+ if ( ( cData == 0 ) || ( len == 0 ) ) { cData = ""; len = 0; }
+
+ 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 ProcessingInstructionHandler( void * userData, XMP_StringPtr target, XMP_StringPtr data )
+{
+
+ if ( target == NULL || strncmp( target, "xpacket", 7 ) != 0 )
+ return; // Ignore all PIs except the XMP packet wrapper.
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+ XML_Node * parentNode = thiz->parseStack.back();
+ if ( parentNode->name != "metadata" )
+ return;
+ IteratorStringXMP_Int64 iterator = thiz->mPIWithOffsetMap.find( target );
+ if ( iterator != thiz->mPIWithOffsetMap.end() )
+ {
+ if ( iterator->second == -1 )
+ iterator->second = XML_GetCurrentByteIndex( thiz->parser );
+ else
+ thiz->mPIWithOffsetMap.insert( std::pair<std::string, XMP_Int64>( target, XML_GetCurrentByteIndex( thiz->parser ) ) );
+ }
+
+ if ( data == 0 ) data = "";
+ XML_Node * piNode = new XML_Node( parentNode, target, kPINode );
+
+ piNode->value.assign( data );
+ parentNode->content.push_back( piNode );
+
+} // ProcessingInstructionHandler
+
+// =================================================================================================
+
+static void DeclarationHandler( void *userData, const XML_Char *version, const XML_Char *encoding, int standalone )
+{
+ if ( encoding == NULL || strlen( encoding ) != 5 ||
+ ( tolower( encoding[ 0 ] ) == 'u'
+ && tolower( encoding[ 1 ] ) == 't'
+ && tolower( encoding[ 2 ] ) == 'f'
+ && encoding[ 3 ] == '-'
+ && encoding[ 4 ] == '8' ) )
+ return;
+ else
+ {
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+ ( void ) ( XML_StopParser( thiz->parser, false ) );
+ }
+} // DeclarationHandler
+
+// =================================================================================================
+
+#if BanAllEntityUsage
+static void StartDoctypeDeclHandler( void * userData, XMP_StringPtr doctypeName,
+ XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset )
+{
+ IgnoreParam( userData );
+
+ SVG_Adapter * thiz = ( SVG_Adapter* ) userData;
+
+ 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/XMPFiles/source/FormatSupport/SVG_Adapter.hpp b/XMPFiles/source/FormatSupport/SVG_Adapter.hpp
new file mode 100644
index 0000000..0c325a5
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/SVG_Adapter.hpp
@@ -0,0 +1,79 @@
+#ifndef __SVG_Adapter_hpp__
+#define __SVG_Adapter_hpp__
+
+// =================================================================================================
+// Copyright 2015 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.
+//
+// This file includes implementation of SVG metadata, according to Scalable Vector Graphics (SVG) 1.1 Specification.
+// "https://www.w3.org/TR/2003/REC-SVG11-20030114/"
+// Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology,
+// Institut National de Recherche en Informatique et en Automatique, Keio University).
+// All Rights Reserved . http://www.w3.org/Consortium/Legal
+//
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "source/XMLParserAdapter.hpp"
+
+// =================================================================================================
+// Derived SVG 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;
+typedef std::map<std::string, XMP_Int64>::iterator IteratorStringXMP_Int64;
+
+struct OffsetStruct
+{
+ XMP_Int64 startOffset;
+ XMP_Int64 nextOffset;
+ XMP_Int64 endOffset;
+ std::string parent;
+ OffsetStruct() : startOffset( -1 ), nextOffset( -1 ), endOffset( -1 ) {}
+ OffsetStruct( std::string reqParent ) : startOffset( -1 ), nextOffset( -1 ), endOffset( -1 ), parent( reqParent ) {}
+};
+
+typedef std::map<std::string, OffsetStruct>::iterator IteratorStringOffsetStruct;
+
+class SVG_Adapter : public XMLParserAdapter {
+public:
+
+ XML_Parser parser;
+ XMP_NamespaceTable * registeredNamespaces;
+
+#if BanAllEntityUsage
+ bool isAborted;
+#endif
+
+ SVG_Adapter( );
+ virtual ~SVG_Adapter();
+
+ virtual void ParseBuffer( const void * buffer, size_t length, bool last = true );
+ virtual XMP_Bool ParseBufferNoThrow( const void * buffer, size_t length, bool last = true );
+
+ virtual OffsetStruct GetElementOffsets( std::string elementName );
+ virtual void RegisterElement( std::string elementName, std::string reqParent );
+
+ virtual XMP_Int64 GetPIOffset( std::string PIName, XMP_Uns32 requiredIndex = 1 );
+ virtual void RegisterPI( std::string PIName );
+ virtual XMP_Bool IsParsingRequire();
+
+ std::multimap<std::string, XMP_Int64> mPIWithOffsetMap;
+ std::map<std::string, OffsetStruct> mOffsetsMap;
+ XMP_Int64 firstSVGElementOffset;
+
+ std::string mPrevRequiredElement;
+ XMP_Uns32 depth;
+};
+
+// =================================================================================================
+
+#endif // __SVG_Adapter_hpp__
diff --git a/XMPFiles/source/FormatSupport/TIFF_FileWriter.cpp b/XMPFiles/source/FormatSupport/TIFF_FileWriter.cpp
index da4d260..ec92c8e 100644
--- a/XMPFiles/source/FormatSupport/TIFF_FileWriter.cpp
+++ b/XMPFiles/source/FormatSupport/TIFF_FileWriter.cpp
@@ -571,7 +571,7 @@ bool TIFF_FileWriter::IsLegacyChanged()
// TIFF_FileWriter::ParseMemoryStream
// ==================================
-void TIFF_FileWriter::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+void TIFF_FileWriter::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */, bool isAlreadyLittle /*= false */ )
{
this->DeleteExistingInfo();
this->memParsed = true;
@@ -733,7 +733,18 @@ XMP_Uns32 TIFF_FileWriter::ProcessMemoryIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd
ifdPtr += (2 + tagCount*12);
ifdInfo.origNextIFD = this->GetUns32 ( ifdPtr );
-
+// The following code modifies a file in case it is invalid, we should keep this fix so that we can track this issue if we receive client bugs for this
+#if 0
+ if (ifdInfo.origNextIFD != 0) {
+ if ( (ifdInfo.origNextIFD < 8) || (ifdInfo.origNextIFD > (this->tiffLength - kEmptyIFDLength)) ) {
+ // Next IFD offset is invalid. Ignore it.
+ ifdInfo.origNextIFD = 0;
+ // Should we try to patch it?
+ ifdInfo.changed = true;
+ this->changed = true;
+ }
+ }
+#endif
return ifdInfo.origNextIFD;
} // TIFF_FileWriter::ProcessMemoryIFD
@@ -780,13 +791,13 @@ void TIFF_FileWriter::ParseFileStream ( XMP_IO* fileRef )
}
const InternalTagInfo* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
- if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->count == 1) ) {
+ if ( ( exifIFDTag != 0 ) && ( ( exifIFDTag->type == kTIFF_LongType || exifIFDTag->type == kTIFF_IFDType ) && ( exifIFDTag->count == 1 ) ) ) {
XMP_Uns32 exifOffset = this->GetUns32 ( exifIFDTag->dataPtr );
(void) this->ProcessFileIFD ( kTIFF_ExifIFD, exifOffset, fileRef );
}
const InternalTagInfo* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
- if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->count == 1) ) {
+ if ( ( gpsIFDTag != 0 ) && ( ( gpsIFDTag->type == kTIFF_LongType || gpsIFDTag->type == kTIFF_IFDType ) && ( gpsIFDTag->count == 1 ) ) ) {
XMP_Uns32 gpsOffset = this->GetUns32 ( gpsIFDTag->dataPtr );
if ( IsOffsetValid (gpsOffset, 8, ifdLimit ) ) { // Remove a bad GPS IFD offset.
(void) this->ProcessFileIFD ( kTIFF_GPSInfoIFD, gpsOffset, fileRef );
@@ -798,7 +809,7 @@ void TIFF_FileWriter::ParseFileStream ( XMP_IO* fileRef )
}
const InternalTagInfo* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
- if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->dataLen == 4) ) {
+ if ( ( interopIFDTag != 0 ) && ( ( interopIFDTag->type == kTIFF_LongType || interopIFDTag->type == kTIFF_IFDType ) && ( interopIFDTag->dataLen == 4 ) ) ) {
XMP_Uns32 interopOffset = this->GetUns32 ( interopIFDTag->dataPtr );
if ( IsOffsetValid (interopOffset, 8, ifdLimit ) ) { // Remove a bad Interoperability IFD offset.
(void) this->ProcessFileIFD ( kTIFF_InteropIFD, interopOffset, fileRef );
diff --git a/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp b/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
index ea1b686..c1a0d44 100644
--- a/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
+++ b/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
@@ -528,8 +528,8 @@ bool TIFF_MemoryReader::GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::
// ====================================
// *** Need to tell TIFF/Exif from TIFF/EP, DNG files are the latter.
-
-void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+// isAlredyLittle is provided for case when data contain no information about Endianess, So need not to check for header
+void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */, bool isAlredyLittle /* = false */ )
{
// Get rid of any current TIFF.
@@ -560,13 +560,31 @@ void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length,
this->tiffLength = length;
XMP_Uns32 ifdLimit = this->tiffLength - 6; // An IFD must start before this offset.
-
- // Find and process the primary, Exif, GPS, and Interoperability IFDs.
-
- XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->tiffStream, length );
+ XMP_Uns32 primaryIFDOffset = 0;
XMP_Uns32 tnailIFDOffset = 0;
+ // Find and process the primary, Exif, GPS, and Interoperability IFDs.
+
+ // If already is in little Endian then no need to check for Check TIFF header
+ if ( isAlredyLittle )
+ {
+ this->nativeEndian = ! kBigEndianHost;
+ this->GetUns16 = GetUns16LE;
+ this->GetUns32 = GetUns32LE;
+ this->GetFloat = GetFloatLE;
+ this->GetDouble = GetDoubleLE;
+
+ this->PutUns16 = PutUns16LE;
+ this->PutUns32 = PutUns32LE;
+ this->PutFloat = PutFloatLE;
+ this->PutDouble = PutDoubleLE;
+ tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD, true );
+ }
+ else
+ {
+ primaryIFDOffset = this->CheckTIFFHeader ( this->tiffStream, length );
- if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
+ if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
+ }
// ! Need the thumbnail IFD for checking full Exif APP1 in some JPEG files!
if ( tnailIFDOffset != 0 ) {
@@ -611,14 +629,25 @@ void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length,
// =================================================================================================
// TIFF_MemoryReader::ProcessOneIFD
// ================================
+// ModifiedInitialCheck is provided for case when data contain no header
-XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
+XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd, bool ModifiedInitialCheck /* = false */ )
{
TweakedIFDInfo& ifdInfo = this->containedIFDs[ifd];
- if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
- XMP_Error error(kXMPErr_BadTIFF, "Bad IFD offset" );
- this->NotifyClient ( kXMPErrSev_FileFatal, error );
+ if( ModifiedInitialCheck )
+ {
+ if ((ifdOffset > (this->tiffLength)) ) {
+ XMP_Error error(kXMPErr_BadTIFF, "Bad IFD offset" );
+ this->NotifyClient ( kXMPErrSev_FileFatal, error );
+ }
+ }
+ else
+ {
+ if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
+ XMP_Error error(kXMPErr_BadTIFF, "Bad IFD offset" );
+ this->NotifyClient ( kXMPErrSev_FileFatal, error );
+ }
}
XMP_Uns8* ifdPtr = this->tiffStream + ifdOffset;
diff --git a/XMPFiles/source/FormatSupport/TIFF_Support.hpp b/XMPFiles/source/FormatSupport/TIFF_Support.hpp
index d4e2f4d..5ed5965 100644
--- a/XMPFiles/source/FormatSupport/TIFF_Support.hpp
+++ b/XMPFiles/source/FormatSupport/TIFF_Support.hpp
@@ -91,10 +91,11 @@ enum { // Constants for the type field of a tag, as defined by TIFF.
kTIFF_SRationalType = 10,
kTIFF_FloatType = 11,
kTIFF_DoubleType = 12,
- kTIFF_LastType = 12
+ kTIFF_IFDType = 13,
+ kTIFF_LastType = kTIFF_IFDType
};
-static const size_t kTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
+static const size_t kTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4 };
static const bool kTIFF_IsIntegerType[] = { 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0 };
static const bool kTIFF_IsRationalType[] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 };
@@ -639,8 +640,9 @@ public:
// The condenseStream parameter to UpdateMemoryStream can be used to rewrite the full stream
// instead of appending. This will discard any MakerNote tags and risks breaking offsets that
// are hidden. This can be necessary though to try to make the TIFF fit in a JPEG file.
-
- virtual void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true ) = 0;
+
+ // isAlredyLittle is provided for case when data contain no information about Endianess, So need not to check for header
+ virtual void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true, bool isAlreadyLittle = false ) = 0;
virtual void ParseFileStream ( XMP_IO* fileRef ) = 0;
virtual void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) = 0;
@@ -736,7 +738,8 @@ public:
bool IsChanged() { return false; };
bool IsLegacyChanged() { return false; };
- void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
+ // isAlredyLittle is provided for case when data contain no information about Endianess, So need not to check for header
+ void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true, bool isAlreadyLittle = false );
void ParseFileStream ( XMP_IO* fileRef ) { NotAppropriate(); };
void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) { NotAppropriate(); };
@@ -778,7 +781,8 @@ private:
static void SortIFD ( TweakedIFDInfo* thisIFD );
- XMP_Uns32 ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd );
+ // ModifiedInitialCheck is provided for case when data contain no header
+ XMP_Uns32 ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd, bool ModifiedInitialCheck = false );
const TweakedIFDEntry* FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
@@ -846,7 +850,8 @@ public:
enum { kDoNotCopyData = false };
- void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
+ // isAlredyLittle is provided for case when data contain no information about Endianess, So need not to check for header
+ void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true, bool isAlreadyLittle = false );
void ParseFileStream ( XMP_IO* fileRef );
void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen );
diff --git a/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp b/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp
index bf7ed04..73ba9ff 100644
--- a/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp
+++ b/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp
@@ -12,7 +12,10 @@
#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
#include "public/include/XMP_Const.h"
-
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
#include "XMPFiles/source/XMPFiles_Impl.hpp"
namespace TimeConversionUtils {
diff --git a/XMPFiles/source/FormatSupport/WAVE/CartMetadata.h b/XMPFiles/source/FormatSupport/WAVE/CartMetadata.h
index 29266a7..b007afc 100644
--- a/XMPFiles/source/FormatSupport/WAVE/CartMetadata.h
+++ b/XMPFiles/source/FormatSupport/WAVE/CartMetadata.h
@@ -58,6 +58,14 @@ public:
struct StoredCartTimer {
XMP_Uns32 usage;
XMP_Uns32 value;
+
+ bool operator == (const StoredCartTimer & other ) const {
+ return usage == other.usage && value == other.value;
+ }
+
+ bool operator != ( const StoredCartTimer & other ) const {
+ return usage != other.usage || value != other.value;
+ }
};
enum { kPostTimerLength = 8 };
diff --git a/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
index 335acd7..9bdeb94 100644
--- a/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
@@ -152,7 +152,7 @@ XMP_Uns64 INFOMetadata::serialize( XMP_Uns8** outBuffer )
{
TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(iter->second);
- XMP_Uns32 chunkSize = kChunkHeaderSize + strObj->getValue().length();
+ XMP_Uns32 chunkSize = kChunkHeaderSize + strObj->getValue().length() + 1; // 1 byte is added for NULL termination string
if( chunkSize & 1 )
{
@@ -194,7 +194,7 @@ XMP_Uns64 INFOMetadata::serialize( XMP_Uns8** outBuffer )
TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(iter->second);
std::string value = strObj->getValue();
XMP_Uns32 id = iter->first;
- XMP_Uns32 size = value.length();
+ XMP_Uns32 size = value.length() + 1; // Null terminated string
if( size & 1 && strObj->hasChanged() )
{
@@ -221,7 +221,7 @@ XMP_Uns64 INFOMetadata::serialize( XMP_Uns8** outBuffer )
memcpy( buffer+offset+kSizeChunkID, &size, kSizeChunkSize );
//size has been changed in little endian format. Change it back to bigendina
size = LE.getUns32( &size );
- memcpy( buffer+offset+kChunkHeaderSize, value.c_str(), size );
+ memcpy( buffer+offset+kChunkHeaderSize, value.c_str(), value.length() );
//
// update pointer
diff --git a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
index 8c3067b..db15dab 100644
--- a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
@@ -10,6 +10,8 @@
#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
#include "public/include/XMP_Const.h"
+#include <string.h>
+
#include "XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h"
#include "XMPFiles/source/FormatSupport/WAVE/DISPMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/INFOMetadata.h"
@@ -26,6 +28,7 @@
#include "XMPFiles/source/FormatSupport/Reconcile_Impl.hpp"
+
using namespace IFF_RIFF;
// ************** legacy Mappings ***************** //
@@ -57,7 +60,7 @@ static const MetadataPropertyInfo kBextProperties[] =
{ NULL }
};
-static const char * kDM_takeNumber = "takeNumber";
+static const char * kDM_shotNumber = "shotNumber";
static const char * kDM_audioSampleType = "audioSampleType";
static const char * kDM_scene = "scene";
static const char * kDM_tapeName = "tapeName";
@@ -68,12 +71,17 @@ static const char * kDM_startTimecode = "startTimecode";
static const char * kDM_timeFormat = "timeFormat";
static const char * kDM_timeValue = "timeValue";
static const char * kDM_good = "good";
+static const char * kIXML_trackList = "trackList";
+static const char * kIXML_channelIndex = "channelIndex";
+static const char * kIXML_interleaveIndex = "interleaveIndex";
+static const char * kIXML_Name = "name";
+static const char * kIXML_Function = "function";
static const MetadataPropertyInfo kiXMLProperties[] =
{
// XMP NS XMP Property Name Native Metadata Identifier Native Datatype XMP Datatype Delete Priority ExportPolicy
{ kXMP_NS_DM, kDM_tapeName, iXMLMetadata::kTape, kNativeType_StrUTF8, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:tapeName <-> iXML:TAPE
- { kXMP_NS_DM, kDM_takeNumber, iXMLMetadata::kTake, kNativeType_Uns64, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:tapeName <-> iXML:TAPE
+ { kXMP_NS_DM, kDM_shotNumber, iXMLMetadata::kTake, kNativeType_StrUTF8, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:shotNumber <-> iXML:TAKE
{ kXMP_NS_DM, kDM_scene, iXMLMetadata::kScene, kNativeType_StrUTF8, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:scene <-> iXML:SCENE
{ kXMP_NS_DM, kDM_logComment, iXMLMetadata::kNote, kNativeType_StrUTF8, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:logComment <-> iXML:NOTE
{ kXMP_NS_DM, kDM_projectName, iXMLMetadata::kProject, kNativeType_StrUTF8, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:project <-> iXML:PROJECT
@@ -93,6 +101,7 @@ static const MetadataPropertyInfo kiXMLProperties[] =
// special case for timeReference // bext:timeReference <-> iXML:TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HO and iXML:TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI
// special case for startTimeCode // xmpDM:startTimecode <-> iXML:TIMECODE_RATE, iXML:TIMECODE_FLAG and bext:timeReference.
{ kXMP_NS_BWF, kBWF_timeStampSampleRate, iXMLMetadata::kTimeStampSampleRate, kNativeType_Uns64, kXMPType_Simple, false, false, kExport_NoDelete }, // bext::timeStampSampleRate <-> iXML
+ // special case for TRACK_LIST // ixml:Track_List <-> ixml:trackList
{ NULL }
};
@@ -985,6 +994,37 @@ void IFF_RIFF::WAVEReconcile::exportSpecialXMPToiXML( SXMPMeta & inXMP, IMetadat
outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceHigh );
outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceLow );
}
+
+ // track list
+ try {
+ if ( inXMP.DoesPropertyExist( kXMP_NS_iXML, kIXML_trackList ) ) {
+ XMP_OptionBits options( 0 );
+ if ( inXMP.GetProperty( kXMP_NS_iXML, kIXML_trackList, NULL, &options ) &&
+ XMP_OptionIsSet( options, kXMP_PropArrayIsOrdered ) )
+ {
+ XMP_Index count = inXMP.CountArrayItems( kXMP_NS_iXML, kIXML_trackList );
+ std::vector< iXMLMetadata::TrackListInfo > trackListInfo( count );
+ for ( XMP_Index i = 0; i < count; i++ ) {
+ iXMLMetadata::TrackListInfo & trackRef = trackListInfo[i];
+ std::string trackPath;
+ SXMPUtils::ComposeArrayItemPath( kXMP_NS_iXML, kIXML_trackList, i + 1, &trackPath );
+ std::string fieldPath;
+ SXMPUtils::ComposeStructFieldPath( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_channelIndex, &fieldPath );
+ XMP_Int64 int64Value;
+ inXMP.GetProperty_Int64( kXMP_NS_iXML, fieldPath.c_str(), &int64Value, &options );
+ trackRef.mChannelIndex = int64Value;
+ inXMP.GetStructField( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_Name, &trackRef.mName, &options );
+ inXMP.GetStructField( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_Function, &trackRef.mFunction, &options );
+ }
+ outNativeMeta.setArray< iXMLMetadata::TrackListInfo >( iXMLMetadata::kTrackList, trackListInfo.data(), count );
+ inXMP.DeleteProperty( kXMP_NS_iXML, kIXML_trackList );
+ }
+ } else {
+ outNativeMeta.deleteValue( iXMLMetadata::kTrackList );
+ }
+ } catch( ... ) {
+ // do nothing
+ }
}
bool IFF_RIFF::WAVEReconcile::exportSpecialiXMLToXMP( IMetadata & inNativeMeta, SXMPMeta & outXMP )
@@ -1063,5 +1103,30 @@ bool IFF_RIFF::WAVEReconcile::exportSpecialiXMLToXMP( IMetadata & inNativeMeta,
}
}
+ // special case for iXML:trackList
+ if ( inNativeMeta.valueExists( iXMLMetadata::kTrackList ) )
+ {
+ XMP_Uns32 countOfTracks( 0 );
+ const iXMLMetadata::TrackListInfo * trackInfoArray =
+ inNativeMeta.getArray< iXMLMetadata::TrackListInfo >( iXMLMetadata::kTrackList, countOfTracks );
+ if ( countOfTracks > 0 && trackInfoArray != NULL ) {
+ outXMP.DeleteProperty( kXMP_NS_iXML, kIXML_trackList );
+ outXMP.SetProperty( kXMP_NS_iXML, kIXML_trackList, 0, kXMP_PropArrayIsOrdered );
+ for ( XMP_Uns32 i = 0; i < countOfTracks; i++ ) {
+ std::string trackPath;
+ SXMPUtils::ComposeArrayItemPath( kXMP_NS_iXML, kIXML_trackList, i + 1, &trackPath );
+ const iXMLMetadata::TrackListInfo & ref = trackInfoArray[i];
+ std::string value;
+ SXMPUtils::ConvertFromInt64( ref.mChannelIndex, "%llu", &value );
+ outXMP.SetStructField( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_channelIndex, value );
+ if ( ref.mName.size() > 0 )
+ outXMP.SetStructField( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_Name, ref.mName );
+ if ( ref.mFunction.size() > 0 )
+ outXMP.SetStructField( kXMP_NS_iXML, trackPath.c_str(), kXMP_NS_iXML, kIXML_Function, ref.mFunction );
+ }
+ changed = true;
+ }
+ }
+
return changed;
}
diff --git a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp
index d6ea068..a153bc7 100644
--- a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp
@@ -21,7 +21,7 @@ namespace IFF_RIFF {
static const char * tagNames[ iXMLMetadata::kLastEntry ] = {
"TAPE", //kTape, // std::string
- "TAKE", //kTake, // XMP_Uns64
+ "TAKE", //kTake, // std::string
"SCENE", //kScene, // std::string
"NOTE", //kNote, // std::string
"PROJECT", //kProject, // std::string
@@ -44,11 +44,18 @@ namespace IFF_RIFF {
"TIMESTAMP_SAMPLE_RATE", //kTimeStampSampleRate, // XMP_Uns64
"TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO", //kTimeStampSampleSinceMidnightLow, // XMP_Uns32
"TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI", //kTimeStampSampleSinceMidnightHi, // XMP_Uns32
+ "TRACK_LIST", //kTrackList // std::vector< TrackListInfo >
};
static const char * rootTagName = "BWFXML";
static const char * speedTagName = "SPEED";
static const char * bextTagName = "BEXT";
+ static const char * trackCountTagName = "TRACK_COUNT";
+ static const char * trackTagName = "TRACK";
+ static const char * trackChannelIndexTagName = "CHANNEL_INDEX";
+ static const char * trackInterleaveIndexTagName = "INTERLEAVE_INDEX";
+ static const char * trackNameTagName = "NAME";
+ static const char * trackFunctionTagName = "FUNCTION";
iXMLMetadata::iXMLMetadata()
: mExpatAdapter( NULL )
@@ -194,6 +201,7 @@ namespace IFF_RIFF {
switch( id )
{
case kTape:
+ case kTake:
case kScene:
case kNote:
case kProject:
@@ -213,7 +221,6 @@ namespace IFF_RIFF {
}
break;
- case kTake:
case kFileSampleRate:
case kAudioBitDepth:
case kBWFTimeReferenceLow:
@@ -230,6 +237,19 @@ namespace IFF_RIFF {
ret = false;
break;
+ case kTrackList:
+ ret = true;
+ {
+ TArrayObject< TrackListInfo > * trackListInfoArrayObj = dynamic_cast< TArrayObject< TrackListInfo > *>( &valueObj );
+ if ( trackListInfoArrayObj ) {
+ XMP_Uns32 nElements ( 0 );
+ const TrackListInfo * trackListInfoPtr = trackListInfoArrayObj->getArray( nElements );
+ if ( nElements > 0 && trackListInfoPtr != NULL )
+ ret = false;
+ }
+ }
+ break;
+
default:
ret = true;
}
@@ -252,6 +272,15 @@ namespace IFF_RIFF {
XMPFileHandler::NotifyClient( mErrorCallback, severity, error );
}
+ static std::string & Trim( std::string & str ) {
+ static const char * whiteSpaceChars = " \t\n\r\v";
+ size_t pos = str.find_last_not_of( whiteSpaceChars );
+ if ( pos != std::string::npos ) {
+ str.erase( pos + 1 );
+ }
+ return str;
+ }
+
static XMP_Uns64 ConvertStringToUns64( const std::string & strValue ) {
int count;
char nextCh;
@@ -269,7 +298,7 @@ namespace IFF_RIFF {
if ( strValue.size() > 0 ) {
XMP_Uns64 uValue;
try {
- uValue = ConvertStringToUns64( strValue );
+ uValue = ConvertStringToUns64( Trim( strValue ) );
} catch( ... ) {
// some nodes like tape can be non integer also. Treat it as warning
XMP_Error error( kXMPErr_BadFileFormat, "iXML Metadata reconciliation failure: node is supposed to have integer value" );
@@ -298,7 +327,7 @@ namespace IFF_RIFF {
// top level properties
ParseAndSetStringProperty( mRootNode, kTape );
- ParseAndSetIntegerProperty( mRootNode, kTake );
+ ParseAndSetStringProperty( mRootNode, kTake );
ParseAndSetStringProperty( mRootNode, kScene );
ParseAndSetStringProperty( mRootNode, kNote );
ParseAndSetStringProperty( mRootNode, kProject );
@@ -331,6 +360,12 @@ namespace IFF_RIFF {
ParseAndSetStringProperty( bextNode, kBWFHistory );
ParseAndSetStringProperty( bextNode, kBWFUMID );
}
+
+ // TRACK_LIST
+ XML_Node * trackListNode = mRootNode->GetNamedElement( "", tagNames[ kTrackList ] );
+ if ( trackListNode ) {
+ ParseAndSetTrackListInfo( trackListNode );
+ }
}
void iXMLMetadata::UpdateStringProperty( XML_Node * parentNode, XMP_Uns32 id ) {
@@ -431,10 +466,67 @@ namespace IFF_RIFF {
}
}
+ void iXMLMetadata::UpdateTrackListInfo( XML_Node * parentNode ) {
+ if ( valueExists( kTrackList ) ) {
+ XMP_Uns32 size;
+ const TrackListInfo * arrayObj( NULL );
+ try {
+ arrayObj = this->getArray< TrackListInfo >( kTrackList, size );
+ } catch( ... ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected the array of TrackListInfo type" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ if ( size > 0 ) {
+ XML_Node * node = parentNode->GetNamedElement( "", tagNames[ kTrackList ] );
+
+ if ( node == NULL ) {
+ node = new XML_Node( parentNode, tagNames[ kTrackList ], kElemNode );
+ if ( node == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "Unable to create new objects" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return;
+ }
+ parentNode->content.push_back( node );
+ }
+
+ // add count
+ std::string count = ConvertUns64ToString( size );
+ UpdateXMLNode( node, trackCountTagName, count );
+
+ for ( XMP_Uns32 i = 0; i < size; i++ ) {
+ XML_Node * track = node->GetNamedElement( "", trackTagName, i );
+ if ( track == NULL ) {
+ track = new XML_Node( parentNode, trackTagName, kElemNode );
+ if ( track == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "Unable to create new objects" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return;
+ }
+ node->content.push_back( track );
+ }
+ const TrackListInfo & ref = arrayObj[i];
+ count = ConvertUns64ToString( ref.mChannelIndex );
+ UpdateXMLNode( track, trackChannelIndexTagName, count );
+ if ( ref.mChannelIndex != i + 1 )
+ count = ConvertUns64ToString( i + 1 );
+ UpdateXMLNode( track, trackInterleaveIndexTagName, count );
+ UpdateXMLNode( track, trackNameTagName, ref.mName );
+ UpdateXMLNode( track, trackFunctionTagName, ref.mFunction );
+ }
+ } else {
+ RemoveXMLNode( parentNode, tagNames[ kTrackList ] );
+ }
+ } else {
+ RemoveXMLNode( parentNode, tagNames[ kTrackList ] );
+ }
+ }
+
void iXMLMetadata::UpdateProperties() {
// top level properties
UpdateStringProperty( mRootNode, kTape );
- UpdateIntegerProperty( mRootNode, kTake );
+ UpdateStringProperty( mRootNode, kTake );
UpdateStringProperty( mRootNode, kScene );
UpdateStringProperty( mRootNode, kNote );
UpdateStringProperty( mRootNode, kProject );
@@ -468,6 +560,7 @@ namespace IFF_RIFF {
UpdateStringProperty( bextNode, kBWFUMID );
}
+ UpdateTrackListInfo( mRootNode );
}
bool iXMLMetadata::valueValid( XMP_Uns32 id, ValueObject * valueObj ) {
@@ -477,7 +570,7 @@ namespace IFF_RIFF {
break;
case kTake:
- return validateInt( valueObj );
+ return validateStringSize( valueObj );
break;
case kScene:
@@ -752,8 +845,12 @@ namespace IFF_RIFF {
}
std::string iXMLMetadata::ParseStringValue( XML_Node * parentNode, XMP_Uns32 id ) {
+ return ParseStringValue( parentNode, tagNames[ id ] );
+ }
+
+ std::string iXMLMetadata::ParseStringValue( XML_Node * parentNode, const char * tagName, bool recoverable ) {
std::string nodeValue;
- XML_Node * node = parentNode->GetNamedElement( "", tagNames[ id ] );
+ XML_Node * node = parentNode->GetNamedElement( "", tagName );
if ( node ) {
if ( node->IsLeafContentNode() && node->content.size() != 0 ) {
size_t lengthOfValue = node->content[0]->value.size();
@@ -762,12 +859,84 @@ namespace IFF_RIFF {
}
} else {
XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: node was supposed to be a leaf node" );
- NotifyClient( kXMPErrSev_Recoverable, error );
+ NotifyClient( recoverable ? kXMPErrSev_Recoverable : kXMPErrSev_OperationFatal, error );
}
+ } else {
+ XMP_Error error ( recoverable ? kXMPErrSev_Recoverable : kXMPErrSev_OperationFatal, "iXML Metadata reconciliation failure: node not present" );
}
return nodeValue;
}
+ XMP_Uns64 iXMLMetadata::ParseUns64Value( XML_Node * parentNode, const char * tagName ) {
+ std::string strValue = ParseStringValue( parentNode, tagName, false );
+
+ if ( strValue.size() > 0 ) {
+ XMP_Uns64 uValue;
+ try {
+ uValue = ConvertStringToUns64( Trim( strValue ) );
+ } catch( ... ) {
+ // some nodes like tape can be non integer also. Treat it as warning
+ XMP_Error error( kXMPErr_BadFileFormat, "iXML Metadata reconciliation failure: node is supposed to have integer value" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ }
+ return uValue;
+ }
+ return Max_XMP_Uns64;
+ }
+
+ void iXMLMetadata::ParseAndSetTrackListInfo( XML_Node * parentNode ) {
+ XMP_Uns64 trackCount( 0 );
+ try {
+ trackCount = ParseUns64Value( parentNode, trackCountTagName );
+ } catch( ... ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: failed parsing track list" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ std::vector< TrackListInfo > trackInfoListVector( trackCount );
+
+ for ( size_t i = 0; i < trackCount; i++ ) {
+ XML_Node * trackElement = parentNode->GetNamedElement( "", trackTagName, i );
+ if ( trackElement ) {
+ XMP_Uns64 channelIndex( 0 ), interleaveIndex( 0 );
+ std::string name, function;
+
+ try {
+ channelIndex = ParseUns64Value( trackElement, trackChannelIndexTagName );
+ interleaveIndex = ParseUns64Value( trackElement, trackInterleaveIndexTagName );
+ name = ParseStringValue( trackElement, trackNameTagName );
+ function = ParseStringValue( trackElement, trackFunctionTagName );
+ } catch( ... ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: failed parsing track list" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ // check value of interleave index it should be between 1 and trackCount.
+ if ( interleaveIndex > 0 && interleaveIndex <= trackCount
+ && trackInfoListVector[ interleaveIndex - 1 ].mChannelIndex == 0 )
+ {
+ TrackListInfo & currentElement = trackInfoListVector[ interleaveIndex - 1 ];
+ currentElement.mChannelIndex = channelIndex;
+ currentElement.mName = name;
+ currentElement.mFunction = function;
+ } else {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: interleave index is not correct" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ } else {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: number of track elements is less than expected" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ }
+
+ if ( trackCount > 0 ) {
+ this->setArray( kTrackList, trackInfoListVector.data(), ( XMP_Uns32 ) trackInfoListVector.size() );
+ }
+ }
+
bool iXMLMetadata::validateTimeCodeFlag( ValueObject * value ) {
bool returnValue = validateStringSize( value, 2, 3 );
if ( returnValue ) {
@@ -812,4 +981,8 @@ namespace IFF_RIFF {
return false;
}
+ bool iXMLMetadata::validateTrackListInfo( ValueObject * value ) {
+ return true;
+ }
+
}
diff --git a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h
index 815fe85..5c18268 100644
--- a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h
+++ b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h
@@ -28,10 +28,35 @@ namespace IFF_RIFF {
class iXMLMetadata : public IMetadata
{
public:
+
+ class TrackListInfo {
+ public:
+ TrackListInfo() : mChannelIndex( 0 ) {}
+
+ TrackListInfo( XMP_Uns64 channelIndex, const std::string & name, const std::string & function )
+ : mChannelIndex( channelIndex )
+ , mName( name )
+ , mFunction( function ) {}
+
+ bool operator == ( const TrackListInfo & other ) const {
+ return mChannelIndex == other.mChannelIndex &&
+ mName.compare( other.mName ) == 0 &&
+ mFunction.compare( other.mFunction ) == 0;
+ }
+
+ bool operator != ( const TrackListInfo & other ) const {
+ return !( this->operator==( other ) );
+ }
+
+ XMP_Uns64 mChannelIndex;
+ std::string mName;
+ std::string mFunction;
+ };
+
enum
{
kTape, // std::string
- kTake, // XMP_Uns64
+ kTake, // std::string
kScene, // std::string
kNote, // std::string
kProject, // std::string
@@ -54,6 +79,7 @@ namespace IFF_RIFF {
kTimeStampSampleRate, // XMP_Uns64
kTimeStampSampleSinceMidnightLow, // XMP_Uns32
kTimeStampSampleSinceMidnightHigh, // XMP_Uns32
+ kTrackList, // std::vector< TrackListInfo >
kLastEntry
};
@@ -118,6 +144,10 @@ namespace IFF_RIFF {
void UpdateProperties();
std::string ParseStringValue( XML_Node * parentNode, XMP_Uns32 id );
+ std::string ParseStringValue( XML_Node * parentNode, const char * tagName, bool recoverableError = true );
+ XMP_Uns64 ParseUns64Value( XML_Node * parentNode, const char * tagName );
+
+ void ParseAndSetTrackListInfo( XML_Node * parentNode );
void ParseAndSetStringProperty( XML_Node * parentNode, XMP_Uns32 id );
void ParseAndSetIntegerProperty( XML_Node * parentNode, XMP_Uns32 id );
void ParseAndSetBoolProperty( XML_Node * parentNode, XMP_Uns32 id );
@@ -125,6 +155,7 @@ namespace IFF_RIFF {
void UpdateStringProperty( XML_Node * parentNode, XMP_Uns32 id );
void UpdateIntegerProperty( XML_Node * parentNode, XMP_Uns32 id );
void UpdateBoolProperty( XML_Node * parentNode, XMP_Uns32 id );
+ void UpdateTrackListInfo( XML_Node * parentNode );
void UpdateXMLNode( XML_Node * parentNode, const char * localName, const std::string & value );
void RemoveXMLNode( XML_Node * parentNode, const char * localName );
@@ -140,7 +171,7 @@ namespace IFF_RIFF {
bool validateUMID( ValueObject * value );
bool validateTimeCodeFlag( ValueObject * value );
bool validateRational( ValueObject * value );
-
+ bool validateTrackListInfo( ValueObject * value );
private:
// Operators hidden on purpose
iXMLMetadata( const iXMLMetadata& ) {};
diff --git a/XMPFiles/source/FormatSupport/XMPScanner.cpp b/XMPFiles/source/FormatSupport/XMPScanner.cpp
index 0dd34ae..22726d0 100644
--- a/XMPFiles/source/FormatSupport/XMPScanner.cpp
+++ b/XMPFiles/source/FormatSupport/XMPScanner.cpp
@@ -20,11 +20,7 @@
#include "public/include/XMP_Const.h"
-#if TestRunnerBuild
- #define EnablePacketScanning 1
-#else
- #include "XMPFiles/source/XMPFiles_Impl.hpp"
-#endif
+
#include "XMPFiles/source/FormatSupport/XMPScanner.hpp"
@@ -38,6 +34,12 @@
#include <fstream>
#endif
+#if TestRunnerBuild
+#define EnablePacketScanning 1
+#else
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#endif
+
#ifndef UseStringPushBack // VC++ 6.x does not provide push_back for strings!
#define UseStringPushBack 0
#endif
diff --git a/XMPFiles/source/HandlerRegistry.cpp b/XMPFiles/source/HandlerRegistry.cpp
index 69aed6e..60547fc 100644
--- a/XMPFiles/source/HandlerRegistry.cpp
+++ b/XMPFiles/source/HandlerRegistry.cpp
@@ -22,6 +22,7 @@
#include "XMPFiles/source/FileHandlers/JPEG_Handler.hpp"
#include "XMPFiles/source/FileHandlers/PSD_Handler.hpp"
#include "XMPFiles/source/FileHandlers/TIFF_Handler.hpp"
+ #include "XMPFiles/source/FileHandlers/GIF_Handler.hpp"
#endif
#if EnableDynamicMediaHandlers
@@ -36,8 +37,9 @@
#include "XMPFiles/source/FileHandlers/RIFF_Handler.hpp"
#include "XMPFiles/source/FileHandlers/SonyHDV_Handler.hpp"
#include "XMPFiles/source/FileHandlers/SWF_Handler.hpp"
- #include "XMPFiles/source/FileHandlers/XDCAM_Handler.hpp"
#include "XMPFiles/source/FileHandlers/XDCAMEX_Handler.hpp"
+ #include "XMPFiles/source/FileHandlers/XDCAMFAM_Handler.hpp"
+ #include "XMPFiles/source/FileHandlers/XDCAMSAM_Handler.hpp"
#include "XMPFiles/source/FileHandlers/WEBP_Handler.hpp"
#endif
@@ -46,7 +48,7 @@
#include "XMPFiles/source/FileHandlers/PNG_Handler.hpp"
#include "XMPFiles/source/FileHandlers/PostScript_Handler.hpp"
#include "XMPFiles/source/FileHandlers/UCF_Handler.hpp"
- #include "XMPFiles/source/FileHandlers/GIF_Handler.hpp"
+ #include "XMPFiles/source/FileHandlers/SVG_Handler.hpp"
#endif
//#if EnablePacketScanning
@@ -123,8 +125,8 @@ void HandlerRegistry::initialize()
#if EnableDynamicMediaHandlers
allOK &= this->registerFolderHandler ( kXMP_P2File, kP2_HandlerFlags, P2_CheckFormat, P2_MetaHandlerCTor );
allOK &= this->registerFolderHandler ( kXMP_SonyHDVFile, kSonyHDV_HandlerFlags, SonyHDV_CheckFormat, SonyHDV_MetaHandlerCTor );
- allOK &= this->registerFolderHandler ( kXMP_XDCAM_FAMFile, kXDCAM_HandlerFlags, XDCAM_CheckFormat, XDCAM_MetaHandlerCTor );
- allOK &= this->registerFolderHandler ( kXMP_XDCAM_SAMFile, kXDCAM_HandlerFlags, XDCAM_CheckFormat, XDCAM_MetaHandlerCTor );
+ allOK &= this->registerFolderHandler ( kXMP_XDCAM_FAMFile, kXDCAMFAM_HandlerFlags, XDCAMFAM_CheckFormat, XDCAMFAM_MetaHandlerCTor );
+ allOK &= this->registerFolderHandler ( kXMP_XDCAM_SAMFile, kXDCAMSAM_HandlerFlags, XDCAMSAM_CheckFormat, XDCAMSAM_MetaHandlerCTor );
allOK &= this->registerFolderHandler ( kXMP_XDCAM_EXFile, kXDCAMEX_HandlerFlags, XDCAMEX_CheckFormat, XDCAMEX_MetaHandlerCTor );
#endif
@@ -135,6 +137,7 @@ void HandlerRegistry::initialize()
allOK &= this->registerNormalHandler ( kXMP_JPEGFile, kJPEG_HandlerFlags, JPEG_CheckFormat, JPEG_MetaHandlerCTor );
allOK &= this->registerNormalHandler ( kXMP_PhotoshopFile, kPSD_HandlerFlags, PSD_CheckFormat, PSD_MetaHandlerCTor );
allOK &= this->registerNormalHandler ( kXMP_TIFFFile, kTIFF_HandlerFlags, TIFF_CheckFormat, TIFF_MetaHandlerCTor );
+ allOK &= this->registerNormalHandler( kXMP_GIFFile, kGIF_HandlerFlags, GIF_CheckFormat, GIF_MetaHandlerCTor );
#endif
#if EnableDynamicMediaHandlers
@@ -158,6 +161,7 @@ void HandlerRegistry::initialize()
// ! EPS and PostScript have the same handler, EPS is a proper subset of PostScript.
allOK &= this->registerNormalHandler ( kXMP_EPSFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
allOK &= this->registerNormalHandler ( kXMP_PostScriptFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
+ allOK &= this->registerNormalHandler ( kXMP_SVGFile, kSVG_HandlerFlags, SVG_CheckFormat, SVG_MetaHandlerCTor );
#endif
// ------------------------------------------------------------------------------------
diff --git a/XMPFiles/source/NativeMetadataSupport/IMetadata.h b/XMPFiles/source/NativeMetadataSupport/IMetadata.h
index b85239b..608d4a2 100644
--- a/XMPFiles/source/NativeMetadataSupport/IMetadata.h
+++ b/XMPFiles/source/NativeMetadataSupport/IMetadata.h
@@ -237,7 +237,7 @@ template<class T> void IMetadata::setValue( XMP_Uns32 id, const T& value )
//
// check if the value is "empty"
//
- if( this->isEmptyValue( id, *valueObj ) )
+ if( valueObj == NULL || this->isEmptyValue( id, *valueObj ) )
{
//
// value is "empty", delete it
diff --git a/XMPFiles/source/NativeMetadataSupport/IReconcile.h b/XMPFiles/source/NativeMetadataSupport/IReconcile.h
index 16a0109..d28d5c4 100644
--- a/XMPFiles/source/NativeMetadataSupport/IReconcile.h
+++ b/XMPFiles/source/NativeMetadataSupport/IReconcile.h
@@ -11,6 +11,7 @@
#define _IReconcile_h_
#include <string>
+#include <vector>
#ifndef TXMP_STRING_TYPE
#define TXMP_STRING_TYPE std::string
diff --git a/XMPFiles/source/NativeMetadataSupport/ValueObject.h b/XMPFiles/source/NativeMetadataSupport/ValueObject.h
index cfd0c49..4ef2f50 100644
--- a/XMPFiles/source/NativeMetadataSupport/ValueObject.h
+++ b/XMPFiles/source/NativeMetadataSupport/ValueObject.h
@@ -110,7 +110,13 @@ template<class T> inline void TArrayObject<T>::setArray( const T* buffer, XMP_Un
if( mArray != NULL && mSize == numElements )
{
- doSet = ( memcmp( mArray, buffer, numElements*sizeof(T) ) != 0 );
+ doSet = false;
+ for( size_t i = 0; i < mSize; i++ ) {
+ if ( mArray[i] != buffer[i] ) {
+ doSet = true;
+ break;
+ }
+ }
}
if( doSet )
@@ -123,7 +129,9 @@ template<class T> inline void TArrayObject<T>::setArray( const T* buffer, XMP_Un
mArray = new T[numElements];
mSize = numElements;
- memcpy( mArray, buffer, numElements*sizeof(T) );
+ for ( size_t i = 0; i < mSize; i++ ) {
+ mArray[i] = buffer[i];
+ }
mDirty = true;
}
diff --git a/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp b/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp
index 3d2ffd8..c70a794 100644
--- a/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp
+++ b/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp
@@ -49,70 +49,116 @@ void FileHandlerInstance::CacheFileData()
if( error.mErrorID != kXMPErr_NoError )
{
if ( xmpStr != 0 ) free( (void*) xmpStr );
- throw XMP_Error( kXMPErr_InternalFailure, error.mErrorMsg );
+ if ( error.mErrorID == kXMPErr_FilePermission )
+ throw XMP_Error( kXMPErr_FilePermission, error.mErrorMsg );
+ else
+ throw XMP_Error( kXMPErr_InternalFailure, error.mErrorMsg );
}
if( xmpStr != NULL )
{
this->xmpPacket.assign( xmpStr );
free( (void*) xmpStr ); // It should be freed as documentation of mCacheFileDataProc says so.
+ this->containsXMP = true;
}
- this->containsXMP = true;
+ else
+ this->containsXMP = false;
}
void FileHandlerInstance::ProcessXMP()
{
- if( !this->containsXMP || this->processedXMP ) return;
+ if( this->processedXMP ) return;
this->processedXMP = true;
SXMPUtils::RemoveProperties ( &this->xmpObj, 0, 0, kXMPUtil_DoAllProperties );
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
+ if ( this->xmpPacket.size() != 0 )
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
WXMP_Error error;
- if( mHandler->getModule()->getPluginAPIs()->mImportToXMPStringProc )
+ if ( mHandler->getModule()->getPluginAPIs()->mVersion >= 4 && mHandler->getModule()->getPluginAPIs()->mImportToXMPStringWithPacketProc )
+ {
+ XMP_StringPtr xmpStr = this->xmpPacket.c_str();
+ XMP_StringPtr oldPacketPtr = NULL;
+ XMP_PacketInfo packetInfo;
+ mHandler->getModule()->getPluginAPIs()->mImportToXMPStringWithPacketProc( this->mObject, &xmpStr, &error, &oldPacketPtr, &packetInfo );
+
+ if( xmpStr != NULL && xmpStr != this->xmpPacket.c_str() )
+ {
+ XMP_StringLen newLen = static_cast<XMP_StringLen>(strlen( xmpStr ));
+ this->xmpObj.Erase();
+ this->xmpObj.ParseFromBuffer( xmpStr, newLen, 0 );
+
+ // Note: Freeing memory would not create any problem as plugin would have allocated memory using Host library function
+ free( ( void * ) xmpStr );
+ this->containsXMP = true;
+ }
+
+ if( oldPacketPtr != NULL )
+ {
+ this->xmpPacket.resize( strlen( oldPacketPtr ) );
+ this->xmpPacket.assign( oldPacketPtr );
+ this->packetInfo = packetInfo;
+
+ // Note: Freeing memory would not create any problem as plugin would have allocated memory using Host library function
+ free( ( void * ) oldPacketPtr );
+ this->containsXMP = true;
+ }
+ }
+ else if( mHandler->getModule()->getPluginAPIs()->mVersion >= 2 && mHandler->getModule()->getPluginAPIs()->mImportToXMPStringProc )
{
- std::string xmp;
- this->xmpObj.SerializeToBuffer(&xmp, kXMP_NoOptions, 0);
- XMP_StringPtr xmpStr=xmp.c_str();
+ XMP_StringPtr xmpStr = this->xmpPacket.c_str();
mHandler->getModule()->getPluginAPIs()->mImportToXMPStringProc( this->mObject, &xmpStr, &error );
- if( xmpStr!= NULL && xmpStr != xmp.c_str() )
+
+ if( xmpStr != NULL && xmpStr != this->xmpPacket.c_str() )
{
- xmp.resize(0);
- xmp.assign(xmpStr);
- SXMPMeta newMeta(xmp.c_str(),xmp.length());
- this->xmpObj=newMeta;
- free( (void*) xmpStr ); // It should be freed as documentation of mImportToXMPStringProc says so.
+ XMP_StringLen newLen = static_cast<XMP_StringLen>(strlen( xmpStr ));
+ this->xmpObj.Erase();
+ this->xmpObj.ParseFromBuffer( xmpStr, newLen, 0 );
+
+ // Note: Freeing memory would not create any problem as plugin would have allocated memory using Host library function
+ free( ( void * ) xmpStr );
+ this->containsXMP = true;
}
}
else
{
if( mHandler->getModule()->getPluginAPIs()->mImportToXMPProc )
mHandler->getModule()->getPluginAPIs()->mImportToXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error );
+ this->containsXMP = true;
}
CheckError( error );
}
void FileHandlerInstance::UpdateFile ( bool doSafeUpdate )
{
- if ( !this->needsUpdate || this->xmpPacket.size() == 0 ) return;
-
+ bool optimizeFileLayout = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OptimizeFileLayout );
+ this->needsUpdate |= optimizeFileLayout;
+ if( !this->needsUpdate ) return;
WXMP_Error error;
- if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPStringProc )
- {
- std::string xmp;
- this->xmpObj.SerializeToBuffer(&xmp, kXMP_NoOptions, 0);
- XMP_StringPtr xmpStr=xmp.c_str();
- mHandler->getModule()->getPluginAPIs()->mExportFromXMPStringProc( this->mObject, xmpStr, &error );
- }
- else
+
+ if ( xmpPacket.size() != 0 )
{
- if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc )
- mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error );
- }
- CheckError( error );
+ if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPStringProc )
+ {
+ std::string xmp;
+ this->xmpObj.SerializeToBuffer( &xmp, kXMP_NoOptions, 0 );
+ XMP_StringPtr xmpStr = xmp.c_str();
+ mHandler->getModule()->getPluginAPIs()->mExportFromXMPStringProc( this->mObject, xmpStr, &error );
+ if ( xmpStr != xmp.c_str() )
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, mHandler->getSerializeOption() );
+ }
+ else
+ {
+ if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc )
+ {
+ mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error );
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, mHandler->getSerializeOption() );
+ }
+ }
+ CheckError( error );
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, mHandler->getSerializeOption() );
-
+
+ }
mHandler->getModule()->getPluginAPIs()->mUpdateFileProc( this->mObject, this->parent->ioRef, doSafeUpdate, this->xmpPacket.c_str(), &error );
CheckError( error );
this->needsUpdate = false;
@@ -141,7 +187,6 @@ static void SetStringVector ( StringVectorRef clientPtr, XMP_StringPtr * arrayPt
}
}
-
void FileHandlerInstance::FillMetadataFiles( std::vector<std::string> * metadataFiles )
{
WXMP_Error error;
@@ -180,4 +225,28 @@ bool FileHandlerInstance::IsMetadataWritable( )
return ConvertXMP_BoolToBool( result );
}
+void FileHandlerInstance::SetErrorCallback ( ErrorCallbackBox errorCallbackBox )
+{
+ WXMP_Error error;
+ SetErrorCallbackproc wSetErrorCallbackproc = mHandler->getModule()->getPluginAPIs()->mSetErrorCallbackproc ;
+ if( wSetErrorCallbackproc ) {
+ wSetErrorCallbackproc( this->mObject, errorCallbackBox, &error );
+ CheckError( error );
+ } else {
+ XMP_Throw ( "This version of plugin does not support IsMetadataWritable API", kXMPErr_Unimplemented );
+ }
+}
+
+void FileHandlerInstance::SetProgressCallback ( XMP_ProgressTracker::CallbackInfo * progCBInfoPtr )
+{
+ WXMP_Error error;
+ SetProgressCallbackproc wSetProgressCallbackproc = mHandler->getModule()->getPluginAPIs()->mSetProgressCallbackproc ;
+ if( wSetProgressCallbackproc ) {
+ wSetProgressCallbackproc( this->mObject, progCBInfoPtr, &error );
+ CheckError( error );
+ } else {
+ XMP_Throw ( "This version of plugin does not support IsMetadataWritable API", kXMPErr_Unimplemented );
+ }
+}
+
} //namespace XMP_PLUGIN
diff --git a/XMPFiles/source/PluginHandler/FileHandlerInstance.h b/XMPFiles/source/PluginHandler/FileHandlerInstance.h
index 9810831..b1c2a7b 100644
--- a/XMPFiles/source/PluginHandler/FileHandlerInstance.h
+++ b/XMPFiles/source/PluginHandler/FileHandlerInstance.h
@@ -37,6 +37,8 @@ public:
virtual void FillMetadataFiles ( std::vector<std::string> * metadataFiles );
virtual void FillAssociatedResources ( std::vector<std::string> * resourceList );
virtual bool IsMetadataWritable ( );
+ virtual void SetErrorCallback ( ErrorCallbackBox errorCallbackBox );
+ virtual void SetProgressCallback ( XMP_ProgressTracker::CallbackInfo * progCBInfoPtr );
inline SessionRef GetSession() const { return mObject; }
inline FileHandlerSharedPtr GetHandlerInfo() const { return mHandler; }
diff --git a/XMPFiles/source/PluginHandler/HostAPIImpl.cpp b/XMPFiles/source/PluginHandler/HostAPIImpl.cpp
index cf6a389..dd7031e 100644
--- a/XMPFiles/source/PluginHandler/HostAPIImpl.cpp
+++ b/XMPFiles/source/PluginHandler/HostAPIImpl.cpp
@@ -376,7 +376,7 @@ static void GetAbortAPI( Abort_API* abortAPI )
// StandardHandler_API
//
-static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_Bool & checkOK, WXMP_Error* wError )
+static XMPErrorID CheckFormatStandardHandlerInternal( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_Bool & checkOK, WXMP_Error* wError, XMPFiles * standardClient = NULL )
{
if( wError == NULL ) return kXMPErr_BadParam;
@@ -400,14 +400,23 @@ static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat
{
if( hdlInfo->checkProc != NULL )
{
+ bool xmpFilesCreated = false;
+ if ( standardClient == NULL )
+ {
+ standardClient = new XMPFiles();
+ xmpFilesCreated = true;
+ }
+
try
{
//
// setup temporary XMPFiles instance
//
- XMPFiles standardClient;
- standardClient.format = format;
- standardClient.SetFilePath( path );
+ if ( xmpFilesCreated )
+ {
+ standardClient->format = format;
+ standardClient->SetFilePath( path );
+ }
if( hdlInfo->flags & kXMPFiles_FolderBasedFormat )
{
@@ -447,7 +456,7 @@ static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat
// The case that a logical path to a clip has been passed, which does not point to a real file
if( Host_IO::GetFileMode( path ) == Host_IO::kFMode_DoesNotExist )
{
- checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, &standardClient );
+ checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, standardClient );
}
else
{
@@ -463,7 +472,7 @@ static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat
gpName = origGPName; // ! XDCAM-FAM has just 1 level of inner folder, preserve the "MyMovie" case.
}
- checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, &standardClient );
+ checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, standardClient );
}
}
else
@@ -483,14 +492,24 @@ static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat
//
CheckFileFormatProc CheckProc = (CheckFileFormatProc) (hdlInfo->checkProc);
XMPFiles_IO* io = XMPFiles_IO::New_XMPFiles_IO ( path, true );
- checkOK = CheckProc( hdlInfo->format, path, io, &standardClient );
+ checkOK = CheckProc( hdlInfo->format, path, io, standardClient );
delete io;
}
wError->mErrorID = kXMPErr_NoError;
+ if ( xmpFilesCreated )
+ {
+ delete standardClient;
+ standardClient = NULL;
+ }
}
catch( ... )
{
+ if ( xmpFilesCreated )
+ {
+ delete standardClient;
+ standardClient = NULL;
+ }
HandleException( wError );
}
}
@@ -508,7 +527,12 @@ static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat
return wError->mErrorID;
}
-static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMPMetaRef xmpRef, XMP_Bool * xmpExists, WXMP_Error* wError )
+static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_Bool & checkOK, WXMP_Error* wError )
+{
+ return CheckFormatStandardHandlerInternal( session, format, path, checkOK, wError );
+}
+
+static XMPErrorID GetXMPStandardHandlerInternal( SessionRef session, XMP_FileFormat format, StringPtr path, XMPMetaRef xmpRef, XMP_Bool * xmpExists, WXMP_Error* wError, XMP_OptionBits flags = 0, XMP_StringPtr *packet = NULL, XMP_PacketInfo *packetInfo = NULL, ErrorCallbackBox * errorCallback = NULL, XMP_ProgressTracker::CallbackInfo * progCBInfoPtr = NULL )
{
if( wError == NULL ) return kXMPErr_BadParam;
@@ -533,34 +557,58 @@ static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat form
// check format first
//
XMP_Bool suc = kXMP_Bool_False;
+ if( flags == 0 )
+ flags = kXMPFiles_OpenForRead;
+ //
+ // setup temporary XMPFiles instance
+ //
+ XMPFiles standardClient;
+ standardClient.format = format;
+ standardClient.SetFilePath( path );
+ standardClient.openFlags = flags;
+
+ if ( errorCallback != NULL )
+ {
+ standardClient.SetErrorCallback( errorCallback->wrapperProc, errorCallback->clientProc, errorCallback->context, errorCallback->limit );
+ }
+ if ( progCBInfoPtr != NULL && progCBInfoPtr->wrapperProc != NULL )
+ {
+ standardClient.SetProgressCallback( *progCBInfoPtr );
+ }
- XMPErrorID errorID = CheckFormatStandardHandler( session, format, path, suc, wError );
+ XMPErrorID errorID = kXMPErr_NoError;
+ if ( flags & kXMPFiles_ForceGivenHandler )
+ {
+ suc = ConvertBoolToXMP_Bool( true );
+ wError->mErrorID = kXMPErr_NoError;
+ }
+ else
+ errorID = CheckFormatStandardHandlerInternal( session, format, path, suc, wError, &standardClient );
if( errorID == kXMPErr_NoError && ConvertXMP_BoolToBool( suc ) )
{
- //
- // setup temporary XMPFiles instance
- //
- XMPFiles standardClient;
- standardClient.format = format;
- standardClient.SetFilePath( path );
-
SXMPMeta meta( xmpRef );
-
+
try
{
- //
- // open with passed handler info
- //
- suc = standardClient.OpenFile( *hdlInfo, path, kXMPFiles_OpenForRead );
+ suc = standardClient.OpenFile( *hdlInfo, path, flags );
if( suc )
{
- //
- // read meta data
- //
- suc = standardClient.GetXMP( &meta );
-
+ XMP_StringPtr oldStr;
+ XMP_StringLen length = 0;
+ suc = standardClient.GetXMP( &meta, &oldStr, &length, packetInfo );
+ if( length != 0 && packet != NULL )
+ {
+ StringPtr buffer = NULL;
+ CreateBuffer( &buffer, length + 1, wError);
+ if( wError->mErrorID != kXMPErr_NoError )
+ return wError->mErrorID;
+
+ memcpy( buffer, oldStr, length );
+ buffer[length] = '\0';
+ *packet = buffer;
+ }
if( xmpExists != NULL ) *xmpExists = suc;
}
}
@@ -569,9 +617,6 @@ static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat form
HandleException( wError );
}
- //
- // close and cleanup
- //
try
{
standardClient.CloseFile();
@@ -601,6 +646,11 @@ static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat form
return wError->mErrorID;
}
+static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMPMetaRef xmpRef, XMP_Bool * xmpExists, WXMP_Error* wError )
+{
+ return GetXMPStandardHandlerInternal( session, format, path, xmpRef, xmpExists, wError );
+}
+
static XMPErrorID GetXMPStandardHandler_V2( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_StringPtr* xmpStr, XMP_Bool * xmpExists, WXMP_Error* wError )
{
SXMPMeta meta;
@@ -621,6 +671,334 @@ static XMPErrorID GetXMPStandardHandler_V2( SessionRef session, XMP_FileFormat f
return wError->mErrorID ;
}
+static XMPErrorID GetXMPStandardHandler_V3( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_StringPtr* xmpStr, XMP_Bool * xmpExists, WXMP_Error* wError, XMP_OptionBits flags, XMP_StringPtr* packet, XMP_PacketInfo* packetInfo, ErrorCallbackBox * errorCallback, XMP_ProgressTracker::CallbackInfo * progCBInfoPtr )
+{
+ SXMPMeta meta;
+ std::string xmp;
+ GetXMPStandardHandlerInternal( session, format, path, meta.GetInternalRef(), xmpExists, wError, flags, packet, packetInfo, errorCallback, progCBInfoPtr ) ;
+ if( wError->mErrorID != kXMPErr_NoError )
+ return wError->mErrorID;
+
+ meta.SerializeToBuffer( &xmp, kXMP_NoOptions, 0);
+ XMP_Uns32 length = (XMP_Uns32)xmp.size() + 1 ;
+ StringPtr buffer = NULL;
+ CreateBuffer( &buffer, length , wError);
+ if( wError->mErrorID != kXMPErr_NoError )
+ return wError->mErrorID;
+
+ memcpy( buffer, xmp.c_str(), length );
+ *xmpStr = buffer; // callee function should free the memory.
+ return wError->mErrorID ;
+}
+
+static XMPErrorID PutXMPStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, const XMP_StringPtr xmpStr, WXMP_Error* wError , XMP_OptionBits flags, ErrorCallbackBox * errorCallback, XMP_ProgressTracker::CallbackInfo * progCBInfoPtr )
+{
+ if( wError == NULL ) return kXMPErr_BadParam;
+
+ wError->mErrorID = kXMPErr_InternalFailure;
+ wError->mErrorMsg = NULL;
+
+ //
+ // find FileHandlerInstance associated to session reference
+ //
+ FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session );
+
+ if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler )
+ {
+ //
+ // find previous file handler for file format identifier
+ //
+ XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format );
+
+ if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) )
+ {
+ //
+ // check format first
+ //
+ XMP_Bool suc = kXMP_Bool_False;
+ if( flags == 0 )
+ flags = kXMPFiles_OpenForUpdate;
+ XMPFiles standardClient;
+ standardClient.format = format;
+ standardClient.SetFilePath( path );
+ standardClient.openFlags = flags ;
+
+ if ( errorCallback != NULL )
+ {
+ standardClient.SetErrorCallback( errorCallback->wrapperProc, errorCallback->clientProc, errorCallback->context, errorCallback->limit );
+ }
+ if ( progCBInfoPtr != NULL && progCBInfoPtr->wrapperProc != NULL )
+ {
+ standardClient.SetProgressCallback( *progCBInfoPtr );
+ }
+
+ XMPErrorID errorID = kXMPErr_NoError;
+ if ( flags & kXMPFiles_ForceGivenHandler )
+ {
+ suc = ConvertBoolToXMP_Bool( true );
+ wError->mErrorID = kXMPErr_NoError;
+ }
+ else
+ errorID = CheckFormatStandardHandlerInternal( session, format, path, suc, wError, &standardClient );
+
+ if( errorID == kXMPErr_NoError && ConvertXMP_BoolToBool( suc ) )
+ {
+ try
+ {
+ // open with passed handler info
+ suc = standardClient.OpenFile( *hdlInfo, path, flags );
+ size_t length = strnlen( xmpStr, Max_XMP_Uns32 );
+
+ if( suc && length != 0 && length <= Max_XMP_Uns32 )
+ {
+ // insert xmp into file
+ SXMPMeta meta( xmpStr, static_cast<XMP_Uns32>( length ));
+ standardClient.PutXMP( meta );
+ }
+ // close and cleanup
+ standardClient.CloseFile();
+ }
+ catch( ... )
+ {
+ HandleException( wError );
+ }
+
+ }
+ else if( errorID == kXMPErr_NoError )
+ {
+ wError->mErrorID = kXMPErr_BadFileFormat;
+ wError->mErrorMsg = "Standard handler can't process file format";
+ }
+ }
+ else
+ {
+ wError->mErrorID = kXMPErr_NoFileHandler;
+ wError->mErrorMsg = "No standard handler available";
+ }
+ }
+ else
+ {
+ wError->mErrorMsg = "Standard file handler can't call prior handler";
+ }
+
+ return wError->mErrorID;
+}
+
+static XMPErrorID GetFileModDateStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_DateTime * modDate, XMP_Bool * isSuccess, WXMP_Error* wError, XMP_OptionBits flags )
+{
+ *isSuccess = false;
+ if( wError == NULL ) return kXMPErr_BadParam;
+
+ wError->mErrorID = kXMPErr_InternalFailure;
+ wError->mErrorMsg = NULL;
+
+ //
+ // find FileHandlerInstance associated to session reference
+ //
+ FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session );
+
+ if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler )
+ {
+ //
+ // find previous file handler for file format identifier
+ //
+ XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format );
+
+ if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) )
+ {
+ //
+ // check format first
+ //
+ XMP_Bool suc = kXMP_Bool_False;
+
+ XMPErrorID errorID = kXMPErr_NoError;
+ if ( flags & kXMPFiles_ForceGivenHandler )
+ {
+ suc = ConvertBoolToXMP_Bool( true );
+ wError->mErrorID = kXMPErr_NoError;
+ }
+ else
+ errorID = CheckFormatStandardHandlerInternal( session, format, path, suc, wError );
+
+ if( errorID == kXMPErr_NoError && ConvertXMP_BoolToBool( suc ) )
+ {
+
+ try
+ {
+ *isSuccess = XMPFiles::GetFileModDate( *hdlInfo, path, modDate, flags );
+ }
+ catch( ... )
+ {
+ HandleException( wError );
+ }
+ }
+ else if( errorID == kXMPErr_NoError )
+ {
+ wError->mErrorID = kXMPErr_BadFileFormat;
+ wError->mErrorMsg = "Standard handler can't process file format";
+ }
+ }
+ else
+ {
+ wError->mErrorID = kXMPErr_NoFileHandler;
+ wError->mErrorMsg = "No standard handler available";
+ }
+ }
+ else
+ {
+ wError->mErrorMsg = "Standard file handler can't call prior handler";
+ }
+
+ return wError->mErrorID;
+}
+
+static XMPErrorID IsMetadataWritableStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMP_Bool * isWritable, WXMP_Error* wError, XMP_OptionBits flags )
+{
+ if( wError == NULL ) return kXMPErr_BadParam;
+
+ wError->mErrorID = kXMPErr_InternalFailure;
+ wError->mErrorMsg = NULL;
+
+ //
+ // find FileHandlerInstance associated to session reference
+ //
+ FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session );
+
+ if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler )
+ {
+ //
+ // find previous file handler for file format identifier
+ //
+ XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format );
+
+ if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) )
+ {
+ //
+ // check format first
+ //
+ XMP_Bool suc = kXMP_Bool_False;
+
+ XMPErrorID errorID = kXMPErr_NoError;
+ if ( flags & kXMPFiles_ForceGivenHandler )
+ {
+ suc = ConvertBoolToXMP_Bool( true );
+ wError->mErrorID = kXMPErr_NoError;
+ }
+ else
+ errorID = CheckFormatStandardHandlerInternal( session, format, path, suc, wError );
+
+ if( errorID == kXMPErr_NoError && ConvertXMP_BoolToBool( suc ) )
+ {
+ try
+ {
+ (void)XMPFiles::IsMetadataWritable( *hdlInfo, path, isWritable, flags );
+ }
+ catch( ... )
+ {
+ HandleException( wError );
+ }
+ }
+ else if( errorID == kXMPErr_NoError )
+ {
+ wError->mErrorID = kXMPErr_BadFileFormat;
+ wError->mErrorMsg = "Standard handler can't process file format";
+ }
+ }
+ else
+ {
+ wError->mErrorID = kXMPErr_NoFileHandler;
+ wError->mErrorMsg = "No standard handler available";
+ }
+ }
+ else
+ {
+ wError->mErrorMsg = "Standard file handler can't call prior handler";
+ }
+
+ return wError->mErrorID;
+}
+
+static XMPErrorID GetAssociatedResourcesStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, void * resourceList, SetClientStringVectorProc SetClientStringVector, WXMP_Error* wError, XMP_OptionBits flags )
+{
+ if( wError == NULL ) return kXMPErr_BadParam;
+
+ wError->mErrorID = kXMPErr_InternalFailure;
+ wError->mErrorMsg = NULL;
+
+ //
+ // find FileHandlerInstance associated to session reference
+ //
+ FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session );
+
+ if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler )
+ {
+ //
+ // find previous file handler for file format identifier
+ //
+ XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format );
+
+ if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) )
+ {
+ //
+ // check format first
+ //
+ XMP_Bool suc = kXMP_Bool_False;
+
+ XMPErrorID errorID = kXMPErr_NoError;
+ if ( flags & kXMPFiles_ForceGivenHandler )
+ {
+ suc = ConvertBoolToXMP_Bool( true );
+ wError->mErrorID = kXMPErr_NoError;
+ }
+ else
+ errorID = CheckFormatStandardHandlerInternal( session, format, path, suc, wError );
+
+ if( errorID == kXMPErr_NoError && ConvertXMP_BoolToBool( suc ) )
+ {
+ try
+ {
+ bool isSuccess;
+
+ // Host XMPFile library is providing a new vector of string and will use that for getting list of associated resources using standard handler
+ std::vector<std::string> resList;
+ ( *SetClientStringVector )( resourceList, 0, 0 );
+ isSuccess = XMPFiles::GetAssociatedResources( *hdlInfo, path, &resList, flags );
+ if ( isSuccess && (! resList.empty()) )
+ {
+ const size_t fileCount = resList.size();
+ std::vector<XMP_StringPtr> ptrArray;
+ ptrArray.reserve ( fileCount );
+ for ( size_t index = 0; index < fileCount; ++index )
+ ptrArray.push_back( resList[ index ].c_str() );
+
+ // Filling list of resources into plugin provided vector of strings using plugin provided method of creating vector of strings
+ ( *SetClientStringVector ) ( resourceList, ptrArray.data(), static_cast<XMP_Uns32>( fileCount ) );
+ }
+ }
+ catch( ... )
+ {
+ HandleException( wError );
+ }
+ }
+ else if( errorID == kXMPErr_NoError )
+ {
+ wError->mErrorID = kXMPErr_BadFileFormat;
+ wError->mErrorMsg = "Standard handler can't process file format";
+ }
+ }
+ else
+ {
+ wError->mErrorID = kXMPErr_NoFileHandler;
+ wError->mErrorMsg = "No standard handler available";
+ }
+ }
+ else
+ {
+ wError->mErrorMsg = "Standard file handler can't call prior handler";
+ }
+
+ return wError->mErrorID;
+}
static void GetStandardHandlerAPI( StandardHandler_API* standardHandlerAPI )
{
@@ -632,6 +1010,10 @@ static void GetStandardHandlerAPI( StandardHandler_API* standardHandlerAPI )
}
+//
+//
+//
+///////////////////////////////////////////////////////////////////////////////
static XMPErrorID RequestAPISuite( const char* apiName, XMP_Uns32 apiVersion, void** apiSuite, WXMP_Error* wError )
{
@@ -655,14 +1037,39 @@ static XMPErrorID RequestAPISuite( const char* apiName, XMP_Uns32 apiVersion, vo
{
*apiSuite = (void*) &RequestAPISuite;
}
- else if ( ! strcmp( apiName, "StandardHandler" ) && apiVersion == 2 )
+ else if ( ! strcmp( apiName, "StandardHandler" ) )
{
- static const StandardHandler_API_V2 standardHandlerAPI =
- {
+ static const StandardHandler_API_V3 standardHandlerAPI(
&CheckFormatStandardHandler,
- &GetXMPStandardHandler_V2
- };
- *apiSuite=(void*)&standardHandlerAPI;
+ &GetXMPStandardHandler_V2,
+ &GetXMPStandardHandler_V3,
+ &PutXMPStandardHandler,
+ &GetFileModDateStandardHandler,
+ &GetAssociatedResourcesStandardHandler,
+ &IsMetadataWritableStandardHandler
+ );
+
+ switch ( apiVersion )
+ {
+ case 2:
+ {
+ const StandardHandler_API_V2 * ptr = &standardHandlerAPI;
+ *apiSuite = (void *) ptr;
+ }
+ break;
+
+ case 3:
+ {
+ *apiSuite = (void *) &standardHandlerAPI;
+ }
+ break;
+
+ default:
+ *apiSuite = NULL;
+ wError->mErrorID = kXMPErr_Unimplemented;
+ break;
+
+ }
}
else
{
diff --git a/XMPFiles/source/PluginHandler/ModuleUtils.h b/XMPFiles/source/PluginHandler/ModuleUtils.h
index e261271..b4c2d71 100644
--- a/XMPFiles/source/PluginHandler/ModuleUtils.h
+++ b/XMPFiles/source/PluginHandler/ModuleUtils.h
@@ -16,6 +16,7 @@
typedef HMODULE OS_ModuleRef;
#elif XMP_MacBuild
#include <CoreFoundation/CFBundle.h>
+#include <memory>
typedef CFBundleRef OS_ModuleRef;
#elif XMP_UNIXBuild
#include <tr1/memory>
diff --git a/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp b/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp
index e9c2b46..e29084e 100644
--- a/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp
+++ b/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp
@@ -267,27 +267,27 @@ bool GetResourceDataFromModule(
if ( !url.IsNull() )
{
- typedef AutoCFRef<CFDataRef> AutoCFData;
typedef AutoCFRef<CFNumberRef> AutoCFNumber;
- AutoCFData resourceData;
- SInt32 errorCode = 0;
+ typedef AutoCFRef<CFErrorRef> AutoCFError;
+ typedef AutoCFRef<CFReadStreamRef> AutoCFReadStream;
+ AutoCFError cfError;
AutoCFNumber length;
- *length = reinterpret_cast<CFNumberRef> ( ::CFURLCreatePropertyFromResource( kCFAllocatorDefault, *url, kCFURLFileLength, &errorCode ) );
- if ( !errorCode )
+ if ( ::CFURLCopyResourcePropertyForKey(*url, kCFURLFileSizeKey, &length, &(*cfError)) && !length.IsNull())
{
SInt64 sizeOfFile = 0;
success = ::CFNumberGetValue( *length, kCFNumberSInt64Type, &sizeOfFile );
+
// presumingly we don't want to load more than 2GByte at once (!)
- if ( success && sizeOfFile < std::numeric_limits<XMP_Int32>::max() )
+ if ( success && sizeOfFile != 0 && sizeOfFile < std::numeric_limits<XMP_Int32>::max() )
{
- success = ::CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, *url, &(*resourceData), NULL, NULL, &errorCode );
- if ( success && errorCode == 0 )
+ AutoCFReadStream readStream(::CFReadStreamCreateWithFile(kCFAllocatorDefault, *url));
+ if( *readStream != NULL && CFReadStreamOpen(*readStream) )
{
- outBuffer.resize( sizeOfFile );
- CFRange range = CFRangeMake (0, sizeOfFile );
- ::CFDataGetBytes( *resourceData, range, reinterpret_cast< UInt8 * > (&outBuffer[0]) );
- return true;
+ outBuffer.assign(sizeOfFile, NULL);
+ success = ( ::CFReadStreamRead(*readStream,reinterpret_cast< UInt8 * > (&outBuffer[0]), sizeOfFile) != -1 );
+ ::CFReadStreamClose(*readStream);
+ return success;
}
}
}
diff --git a/XMPFiles/source/PluginHandler/PluginManager.cpp b/XMPFiles/source/PluginHandler/PluginManager.cpp
index 0f47300..6bcea90 100644
--- a/XMPFiles/source/PluginHandler/PluginManager.cpp
+++ b/XMPFiles/source/PluginHandler/PluginManager.cpp
@@ -56,8 +56,11 @@ static XMPFileHandler* Plugin_MetaHandlerCTor ( FileHandlerSharedPtr handler, XM
{
XMP_Throw ( "Plugin not loaded", kXMPErr_InternalFailure );
}
-
- handler->getModule()->getPluginAPIs()->mInitializeSessionProc ( handler->getUID().c_str(), parent->GetFilePath().c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error );
+
+ if( handler->getModule()->getPluginAPIs()->mInitializeSessionV2Proc )
+ handler->getModule()->getPluginAPIs()->mInitializeSessionV2Proc ( handler->getUID().c_str(), parent->GetFilePath().c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error, ErrorCallbackBox( parent->errorCallback.wrapperProc, parent->errorCallback.clientProc, parent->errorCallback.context, parent->errorCallback.limit ), parent->progressTracker->GetCallbackInfo() );
+ else
+ handler->getModule()->getPluginAPIs()->mInitializeSessionProc ( handler->getUID().c_str(), parent->GetFilePath().c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error );
CheckError ( error );
FileHandlerInstance* instance = new FileHandlerInstance ( object, handler, parent );
diff --git a/XMPFiles/source/PluginHandler/PluginManager.h b/XMPFiles/source/PluginHandler/PluginManager.h
index 85ec785..a7ea17d 100644
--- a/XMPFiles/source/PluginHandler/PluginManager.h
+++ b/XMPFiles/source/PluginHandler/PluginManager.h
@@ -12,26 +12,39 @@
#include "PluginHandler.h"
#include "ModuleUtils.h"
-#if XMP_WinBuild && _MSC_VER >= 1700
- // Visual Studio 2012 or newer supports C++11 (mostly)
+#include "XMPCommon/XMPCommonDefines.h"
+
+
+#if SUPPORT_SHARED_POINTERS_IN_STD
#include <memory>
#include <functional>
- #define XMP_SHARED_PTR std::shared_ptr
-#elif XMP_MacBuild
- #include <memory>
- #define XMP_SHARED_PTR std::shared_ptr
+#elif SUPPORT_SHARED_POINTERS_IN_TR1
+ #if XMP_WinBuild
+ #include <memory>
+ #include <functional>
+ #else
+ #include <tr1/memory>
+ #include <tr1/functional>
+ #endif
#else
- #define XMP_SHARED_PTR std::tr1::shared_ptr
+ #error "location of shared pointer stuff is unknown"
#endif
+
namespace XMP_PLUGIN
{
+#if SUPPORT_SHARED_POINTERS_IN_STD
+ using std::shared_ptr;
+#elif SUPPORT_SHARED_POINTERS_IN_TR1
+ using std::tr1::shared_ptr;
+#endif
+
typedef XMP_Uns32 XMPAtom;
typedef XMPAtom FileHandlerType;
-typedef XMP_SHARED_PTR<class Module> ModuleSharedPtr;
-typedef XMP_SHARED_PTR<class FileHandler> FileHandlerSharedPtr;
+typedef shared_ptr<class Module> ModuleSharedPtr;
+typedef shared_ptr<class FileHandler> FileHandlerSharedPtr;
class FileHandlerInstance;
typedef FileHandlerInstance* FileHandlerInstancePtr;
diff --git a/XMPFiles/source/WXMPFiles.cpp b/XMPFiles/source/WXMPFiles.cpp
index 26fdcac..8ffd214 100644
--- a/XMPFiles/source/WXMPFiles.cpp
+++ b/XMPFiles/source/WXMPFiles.cpp
@@ -201,7 +201,7 @@ void WXMPFiles_GetAssociatedResources_1 ( XMP_StringPtr filePath,
std::vector<XMP_StringPtr> ptrArray;
ptrArray.reserve ( fileCount );
for ( size_t i = 0; i < fileCount; ++i ) ptrArray.push_back ( resList[i].c_str() );
- (*SetClientStringVector) ( resourceList, ptrArray.data(), fileCount );
+ (*SetClientStringVector) ( resourceList, ptrArray.data(), static_cast<XMP_Uns32>(fileCount ));
}
XMP_EXIT
}
@@ -219,7 +219,6 @@ void WXMPFiles_IsMetadataWritable_1 ( XMP_StringPtr filePath,
XMP_EXIT
}
-
// =================================================================================================
void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpObjRef,
diff --git a/XMPFiles/source/XMPFiles.cpp b/XMPFiles/source/XMPFiles.cpp
index ae8f701..db1fc8b 100644
--- a/XMPFiles/source/XMPFiles.cpp
+++ b/XMPFiles/source/XMPFiles.cpp
@@ -36,6 +36,14 @@
#include "XMPFiles/source/FileHandlers/Generic_Handler.hpp"
#endif
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+ #include "XMPCore/Interfaces/IMetadata.h"
+ #include "XMPCore/Interfaces/INodeIterator.h"
+ #include "XMPCommon/Interfaces/IUTF8String.h"
+ #include "XMPCore/Interfaces/ICoreObjectFactory.h"
+#endif
+
// =================================================================================================
/// \file XMPFiles.cpp
/// \brief High level support to access metadata in files of interest to Adobe applications.
@@ -81,12 +89,12 @@ const char * kXMPFiles_EmbeddedVersion = kXMPFiles_VersionMessage;
const char * kXMPFiles_EmbeddedCopyright = kXMPFilesName " " kXMP_CopyrightStr;
#define EMPTY_FILE_PATH ""
-#define XMP_FILES_STATIC_START try { int a;
-#define XMP_FILES_STATIC_END1(severity) a = 1; } catch ( XMP_Error & error ) { sDefaultErrorCallback.NotifyClient ( (severity), error, EMPTY_FILE_PATH ); }
-#define XMP_FILES_STATIC_END2(filePath, severity) a = 1; } catch ( XMP_Error & error ) { sDefaultErrorCallback.NotifyClient ( (severity), error, (filePath) ); }
-#define XMP_FILES_START try { int b;
-#define XMP_FILES_END1(severity) b = 1; } catch ( XMP_Error & error ) { errorCallback.NotifyClient ( (severity), error, this->filePath.c_str() ); }
-#define XMP_FILES_END2(filePath, severity) b = 1; } catch ( XMP_Error & error ) { errorCallback.NotifyClient ( (severity), error, (filePath) ); }
+#define XMP_FILES_STATIC_START try { /*int a;*/
+#define XMP_FILES_STATIC_END1(severity) /*a = 1;*/ } catch ( XMP_Error & error ) { sDefaultErrorCallback.NotifyClient ( (severity), error, EMPTY_FILE_PATH ); }
+#define XMP_FILES_STATIC_END2(filePath, severity) /*a = 1;*/ } catch ( XMP_Error & error ) { sDefaultErrorCallback.NotifyClient ( (severity), error, (filePath) ); }
+#define XMP_FILES_START try { /*int b;*/
+#define XMP_FILES_END1(severity) /*b = 1;*/ } catch ( XMP_Error & error ) { errorCallback.NotifyClient ( (severity), error, this->filePath.c_str() ); }
+#define XMP_FILES_END2(filePath, severity) /*b = 1;*/ } catch ( XMP_Error & error ) { errorCallback.NotifyClient ( (severity), error, (filePath) ); }
#define XMP_FILES_STATIC_NOTIFY_ERROR(errorCallbackPtr, filePath, severity, error) \
if ( (errorCallbackPtr) != NULL ) (errorCallbackPtr)->NotifyClient ( (severity), (error), (filePath) );
@@ -574,6 +582,7 @@ XMPFiles::GetFileModDate ( XMP_StringPtr clientPath,
dummyParent.format = handlerInfo->format;
if ( format ) *format = handlerInfo->format;
+ dummyParent.openFlags = handlerInfo->flags;
dummyParent.handler = handlerInfo->handlerCTor ( &dummyParent );
@@ -618,6 +627,64 @@ XMPFiles::GetFileModDate ( XMP_StringPtr clientPath,
/* class static */
bool
+XMPFiles::GetFileModDate ( const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr clientPath,
+ XMP_DateTime * modDate,
+ XMP_OptionBits options /* = 0 */ )
+{
+ XMP_FILES_STATIC_START
+ Host_IO::FileMode clientMode;
+ std::string fileExt; // Used to check for excluded files.
+ bool excluded = FileIsExcluded ( clientPath, &fileExt, &clientMode, &sDefaultErrorCallback ); // ! Fills in fileExt and clientMode.
+ if ( excluded ) return false;
+
+ XMPFiles dummyParent; // GetFileModDate is static, but the handler needs a parent.
+ dummyParent.SetFilePath ( clientPath );
+ dummyParent.format = hdlInfo.format;
+ dummyParent.openFlags = hdlInfo.flags;
+ dummyParent.handler = hdlInfo.handlerCTor ( &dummyParent );
+
+ bool ok = false;
+
+ std::vector <std::string> resourceList;
+ try{
+ XMP_DateTime lastModDate;
+ XMP_DateTime junkDate;
+ if ( modDate == 0 ) modDate = &junkDate;
+ dummyParent.handler->FillAssociatedResources ( &resourceList );
+ size_t countRes = resourceList.size();
+ for ( size_t index = 0; index < countRes ; ++index ){
+ XMP_StringPtr curFilePath = resourceList[index].c_str();
+ if( Host_IO::GetFileMode ( curFilePath ) != Host_IO::kFMode_IsFile ) continue;// only interested in files
+ if (!Host_IO::GetModifyDate ( curFilePath, &lastModDate ) ) continue;
+ if ( ! ok || ( SXMPUtils::CompareDateTime ( *modDate , lastModDate ) < 0 ) )
+ {
+ *modDate = lastModDate;
+ ok = true;
+ }
+ }
+ }
+ catch(...){
+ // Fallback to the old way
+ // eventually this method would go away as
+ // soon as the implementation for
+ // GetAssociatedResources is added to all
+ // the file/Plugin Handlers
+ ok = dummyParent.handler->GetFileModDate ( modDate );
+ }
+ delete dummyParent.handler;
+ dummyParent.handler = 0;
+
+ return ok;
+ XMP_FILES_STATIC_END2 ( clientPath, kXMPErrSev_OperationFatal )
+ return false;
+
+} // XMPFiles::GetFileModDate
+
+// =================================================================================================
+
+/* class static */
+bool
XMPFiles::GetAssociatedResources (
XMP_StringPtr filePath,
std::vector<std::string> * resourceList,
@@ -661,6 +728,7 @@ XMPFiles::GetAssociatedResources (
// Fill in the format output. Call the handler to get the Associated Resources.
dummyParent.format = handlerInfo->format;
+ dummyParent.openFlags = handlerInfo->flags;
dummyParent.handler = handlerInfo->handlerCTor ( &dummyParent );
@@ -686,6 +754,53 @@ XMPFiles::GetAssociatedResources (
} // XMPFiles::GetAssociatedResources
+// =================================================================================================
+
+/* class static */
+bool
+XMPFiles::GetAssociatedResources (
+ const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr filePath,
+ std::vector<std::string> * resourceList,
+ XMP_OptionBits options /* = 0 */ )
+{
+ XMP_FILES_STATIC_START
+ Host_IO::FileMode clientMode;
+ std::string fileExt; // Used to check for excluded files.
+ bool excluded = FileIsExcluded ( filePath, &fileExt, &clientMode, &sDefaultErrorCallback ); // ! Fills in fileExt and clientMode.
+ if ( excluded ) return false;
+
+ XMPFiles dummyParent; // GetFileModDate is static, but the handler needs a parent.
+ dummyParent.SetFilePath ( filePath );
+ dummyParent.format = hdlInfo.format;
+ dummyParent.openFlags = hdlInfo.flags;
+ dummyParent.handler = hdlInfo.handlerCTor ( &dummyParent );
+
+ try {
+ dummyParent.handler->FillAssociatedResources ( resourceList );
+ } catch ( XMP_Error& error ) {
+ if ( error.GetID() == kXMPErr_Unimplemented ) {
+ XMP_FILES_STATIC_NOTIFY_ERROR ( &sDefaultErrorCallback, filePath, kXMPErrSev_Recoverable, error );
+ return false;
+ } else {
+ throw;
+ }
+ }
+ XMP_Assert ( ! resourceList->empty() );
+
+ delete dummyParent.handler;
+ dummyParent.handler = 0;
+
+ return true;
+
+ XMP_FILES_STATIC_END2 ( filePath, kXMPErrSev_OperationFatal )
+ return false;
+
+} // XMPFiles::GetAssociatedResources
+
+// =================================================================================================
+
+/* class static */
bool
XMPFiles::IsMetadataWritable (
XMP_StringPtr filePath,
@@ -732,6 +847,7 @@ XMPFiles::IsMetadataWritable (
dummyParent.format = handlerInfo->format;
+ dummyParent.openFlags = handlerInfo->flags;
dummyParent.handler = handlerInfo->handlerCTor ( &dummyParent );
// We don't require any of the files to be opened at this point.
@@ -759,6 +875,58 @@ XMPFiles::IsMetadataWritable (
return true;
} // XMPFiles::IsMetadataWritable
+// =================================================================================================
+
+/* class static */
+bool
+XMPFiles::IsMetadataWritable (
+ const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr filePath,
+ XMP_Bool * writable,
+ XMP_OptionBits options /* = 0 */ )
+{
+ XMP_FILES_STATIC_START
+ Host_IO::FileMode clientMode;
+ std::string fileExt; // Used to check for excluded files.
+ bool excluded = FileIsExcluded ( filePath, &fileExt, &clientMode, &sDefaultErrorCallback ); // ! Fills in fileExt and clientMode.
+ if ( excluded ) return false;
+
+ if ( writable == 0 ) {
+ XMP_Throw("Boolean parameter is required for IsMetadataWritable() API.", kXMPErr_BadParam);
+ } else {
+ *writable = kXMP_Bool_False;
+ }
+
+ XMPFiles dummyParent; // GetFileModDate is static, but the handler needs a parent.
+ dummyParent.SetFilePath ( filePath );
+ dummyParent.format = hdlInfo.format;
+ dummyParent.openFlags = hdlInfo.flags;
+ dummyParent.handler = hdlInfo.handlerCTor ( &dummyParent );
+
+ // We don't require any of the files to be opened at this point.
+ // Also, if We don't close them then this will be a problem for embedded handlers because we will be checking
+ // write permission on the same file which could be open (in some mode) already.
+ CloseLocalFile(&dummyParent);
+
+ try {
+ *writable = ConvertBoolToXMP_Bool( dummyParent.handler->IsMetadataWritable() );
+ } catch ( XMP_Error& error ) {
+ delete dummyParent.handler;
+ dummyParent.handler = 0;
+ if ( error.GetID() == kXMPErr_Unimplemented ) {
+ XMP_FILES_STATIC_NOTIFY_ERROR ( &sDefaultErrorCallback, filePath, kXMPErrSev_Recoverable, error );
+ return false;
+ } else {
+ throw;
+ }
+ }
+ if ( dummyParent.handler ) {
+ delete dummyParent.handler;
+ dummyParent.handler = 0;
+ }
+ XMP_FILES_STATIC_END2 ( filePath, kXMPErrSev_OperationFatal )
+ return true;
+} // XMPFiles::IsMetadataWritable
// =================================================================================================
@@ -1086,7 +1254,7 @@ XMPFiles::CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
XMP_Throw ( "XMPFiles::CloseFile - Safe update not supported", kXMPErr_Unavailable );
}
- if ( (this->progressTracker != 0) && this->UsesLocalIO() ) {
+ if ( (this->progressTracker != 0) && this->UsesLocalIO() && this->ioRef != NULL ) {
XMPFiles_IO * localFile = (XMPFiles_IO*)this->ioRef;
localFile->SetProgressTracker ( this->progressTracker );
}
@@ -1306,7 +1474,7 @@ XMPFiles::GetXMP ( SXMPMeta * xmpObj /* = 0 */,
if ( xmpObj != 0 ) {
// ! Don't use Clone, that replaces the internal ref in the local xmpObj, leaving the client unchanged!
xmpObj->Erase();
- SXMPUtils::ApplyTemplate ( xmpObj, this->handler->xmpObj, applyTemplateFlags );
+ SXMPUtils::ApplyTemplate(xmpObj, this->handler->xmpObj, applyTemplateFlags);
}
if ( xmpPacket != 0 ) *xmpPacket = this->handler->xmpPacket.c_str();
if ( xmpPacketLen != 0 ) *xmpPacketLen = (XMP_StringLen) this->handler->xmpPacket.size();
@@ -1322,9 +1490,8 @@ XMPFiles::GetXMP ( SXMPMeta * xmpObj /* = 0 */,
if ( xmpObj != 0 ) *xmpObj = this->handler->xmpObj.Clone();
#else
if ( xmpObj != 0 ) {
- // ! Don't use Clone, that replaces the internal ref in the local xmpObj, leaving the client unchanged!
xmpObj->Erase();
- SXMPUtils::ApplyTemplate ( xmpObj, this->handler->xmpObj, applyTemplateFlags );
+ SXMPUtils::ApplyTemplate(xmpObj, this->handler->xmpObj, applyTemplateFlags);
}
#endif
@@ -1482,6 +1649,7 @@ XMPFiles::CanPutXMP ( XMP_StringPtr xmpPacket,
} // XMPFiles::CanPutXMP
+
// =================================================================================================
/* class-static */
@@ -1513,6 +1681,11 @@ XMPFiles::SetProgressCallback ( const XMP_ProgressTracker::CallbackInfo & cbInfo
if ( cbInfo.clientProc != 0 ) {
this->progressTracker = new XMP_ProgressTracker ( cbInfo );
+ if ( this->handler != 0 ) { // Provided to support ProgressTracker in Plugins
+ XMP_ProgressTracker::CallbackInfo * callbackInfo = new XMP_ProgressTracker::CallbackInfo(cbInfo);
+ this->handler->SetProgressCallback( callbackInfo ) ;
+ delete callbackInfo;
+ }
}
XMP_FILES_END1 ( kXMPErrSev_OperationFatal )
@@ -1559,6 +1732,8 @@ void XMPFiles::SetErrorCallback ( XMPFiles_ErrorCallbackWrapper wrapperProc,
this->errorCallback.clientProc = clientProc;
this->errorCallback.context = context;
this->errorCallback.limit = limit;
+ if ( this->handler != 0 ) // Provided to support ErrroCallback in Plugins
+ this->handler->SetErrorCallback( ErrorCallbackBox( errorCallback.wrapperProc, errorCallback.clientProc, errorCallback.context, errorCallback.limit ) );
XMP_FILES_END1 ( kXMPErrSev_OperationFatal )
} // SetErrorCallback
@@ -1571,6 +1746,8 @@ void XMPFiles::ResetErrorCallbackLimit ( XMP_Uns32 limit ) {
this->errorCallback.limit = limit;
this->errorCallback.notifications = 0;
this->errorCallback.topSeverity = kXMPErrSev_Recoverable;
+ if ( this->handler != 0 ) // Provided to support ErrroCallback in Plugins
+ this->handler->SetErrorCallback( ErrorCallbackBox( errorCallback.wrapperProc, errorCallback.clientProc, errorCallback.context, errorCallback.limit ) );
XMP_FILES_END1 ( kXMPErrSev_OperationFatal )
} // ResetErrorCallbackLimit
diff --git a/XMPFiles/source/XMPFiles.hpp b/XMPFiles/source/XMPFiles.hpp
index e3ecb8b..2cb15aa 100644
--- a/XMPFiles/source/XMPFiles.hpp
+++ b/XMPFiles/source/XMPFiles.hpp
@@ -173,6 +173,12 @@ public:
XMP_FileFormat * format = 0,
XMP_OptionBits options = 0);
+ static bool GetFileModDate(
+ const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr clientPath,
+ XMP_DateTime * modDate,
+ XMP_OptionBits options = 0 );
+
static XMP_FileFormat CheckFileFormat(XMP_StringPtr filePath);
static XMP_FileFormat CheckPackageFormat(XMP_StringPtr folderPath);
@@ -182,12 +188,24 @@ public:
XMP_FileFormat format = kXMP_UnknownFile ,
XMP_OptionBits options = 0 );
+ static bool GetAssociatedResources (
+ const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr filePath,
+ std::vector<std::string> * resourceList,
+ XMP_OptionBits options = 0 );
+
static bool IsMetadataWritable (
XMP_StringPtr filePath,
XMP_Bool * writable,
XMP_FileFormat format = kXMP_UnknownFile ,
XMP_OptionBits options = 0 );
+ static bool IsMetadataWritable (
+ const Common::XMPFileHandlerInfo& hdlInfo,
+ XMP_StringPtr filePath,
+ XMP_Bool * writable,
+ XMP_OptionBits options = 0 );
+
static void SetDefaultProgressCallback(const XMP_ProgressTracker::CallbackInfo & cbInfo);
static void SetDefaultErrorCallback(XMPFiles_ErrorCallbackWrapper wrapperProc,
XMPFiles_ErrorCallbackProc clientProc,
@@ -225,7 +243,6 @@ public:
bool CanPutXMP(const SXMPMeta & xmpObj);
bool CanPutXMP(XMP_StringPtr xmpPacket, XMP_StringLen xmpPacketLen = kXMP_UseNullTermination);
-
void SetAbortProc(XMP_AbortProc abortProc, void * abortArg);
void SetProgressCallback(const XMP_ProgressTracker::CallbackInfo & cbInfo);
diff --git a/XMPFiles/source/XMPFiles_Impl.cpp b/XMPFiles/source/XMPFiles_Impl.cpp
index cf4c768..febb790 100644
--- a/XMPFiles/source/XMPFiles_Impl.cpp
+++ b/XMPFiles/source/XMPFiles_Impl.cpp
@@ -98,6 +98,8 @@ const FileExtMapping kFileExtMap[] =
{ "m4v", kXMP_MPEG4File },
{ "m4a", kXMP_MPEG4File },
{ "f4v", kXMP_MPEG4File },
+ { "3gp", kXMP_MPEG4File },
+ { "3g2", kXMP_MPEG4File },
{ "ses", kXMP_SESFile },
{ "cel", kXMP_CELFile },
{ "wma", kXMP_WMAVFile },
@@ -124,6 +126,7 @@ const FileExtMapping kFileExtMap[] =
{ "xml", kXMP_XMLFile },
{ "txt", kXMP_TextFile },
{ "text", kXMP_TextFile },
+ { "svg", kXMP_SVGFile },
{ "psd", kXMP_PhotoshopFile },
{ "ai", kXMP_IllustratorFile },
@@ -147,10 +150,8 @@ const FileExtMapping kFileExtMap[] =
// Files known to contain XMP but have no smart handling, here or elsewhere.
const char * kKnownScannedFiles[] =
- {
- "ai", // Illustrator, actually a PDF file.
+ { "ai", // Illustrator, actually a PDF file.
"ait", // Illustrator template, actually a PDF file.
- "svg", // SVG, an XML file.
"aet", // After Effects template project file.
"ffx", // After Effects filter preset file.
"aep", // After Effects project file in proprietary format
diff --git a/XMPFiles/source/XMPFiles_Impl.hpp b/XMPFiles/source/XMPFiles_Impl.hpp
index c67d391..f8bc5ac 100644
--- a/XMPFiles/source/XMPFiles_Impl.hpp
+++ b/XMPFiles/source/XMPFiles_Impl.hpp
@@ -279,7 +279,7 @@ public:
#define DefaultCTorPresets \
handlerFlags(0), stdCharForm(kXMP_CharUnknown), \
- containsXMP(false), processedXMP(false), needsUpdate(false)
+ containsXMP(false), processedXMP(false), needsUpdate(false), needsArtUpdate (false)
XMPFileHandler() : parent(0), DefaultCTorPresets {};
XMPFileHandler (XMPFiles * _parent) : parent(_parent), DefaultCTorPresets
@@ -287,7 +287,7 @@ public:
xmpObj.SetErrorCallback(ErrorCallbackForXMPMeta, &parent->errorCallback);
};
- virtual ~XMPFileHandler() {}; // ! The specific handler is responsible for tnailInfo.tnailImage.
+ virtual ~XMPFileHandler() {}; // ! The specific handler is responsible for tnailInfo.tnailImage or AlbumArt.
virtual bool GetFileModDate ( XMP_DateTime * modDate ); // The default implementation is for embedding handlers.
virtual void FillMetadataFiles ( std::vector<std::string> * metadataFiles );
@@ -296,12 +296,17 @@ public:
virtual void CacheFileData() = 0;
virtual void ProcessXMP(); // The default implementation just parses the XMP.
-
virtual XMP_OptionBits GetSerializeOptions(); // The default is compact.
virtual void UpdateFile ( bool doSafeUpdate ) = 0;
virtual void WriteTempFile ( XMP_IO* tempRef ) = 0;
+ // Currently, FileHandleInstance needs to implement Error and progress callback because of plugins,
+ // Rest handlers need not to implement them because handlers can access them parent
+ virtual void SetErrorCallback ( ErrorCallbackBox errorCallbackBox ) {}
+ virtual void SetProgressCallback ( XMP_ProgressTracker::CallbackInfo * progCBInfoPtr ) {}
+
+
static void NotifyClient(GenericErrorCallback * errCBptr, XMP_ErrorSeverity severity, XMP_Error & error);
// ! Leave the data members public so common code can see them.
@@ -313,11 +318,12 @@ public:
bool containsXMP; // True if the file has XMP or PutXMP has been called.
bool processedXMP; // True if the XMP is parsed and reconciled.
bool needsUpdate; // True if the file needs to be updated.
+
+ bool needsArtUpdate; // True if Album arts need to be updated.
- XMP_PacketInfo packetInfo; // ! This is always info about the packet in the file, if any!
- std::string xmpPacket; // ! This is the current XMP, updated by XMPFiles::PutXMP.
- SXMPMeta xmpObj;
-
+ XMP_PacketInfo packetInfo; // ! This is always info about the packet in the file, if any!
+ std::string xmpPacket; // ! This is the current XMP, updated by XMPFiles::PutXMP.
+ SXMPMeta xmpObj;
}; // XMPFileHandler
typedef XMPFileHandler * (* XMPFileHandlerCTor) ( XMPFiles * parent );