summaryrefslogtreecommitdiff
path: root/XMPFiles
diff options
context:
space:
mode:
authorHubert Figuière <hub@figuiere.net>2015-03-06 11:11:01 +0100
committerHubert Figuière <hub@figuiere.net>2015-03-06 11:11:01 +0100
commit606a7df73750084a36fe69651e7b672333a76412 (patch)
treee337e53680715d69be570ccfcf8757ca898ea124 /XMPFiles
parent4652015fe779e12fb06ff8fa56bf70e373cd3894 (diff)
Update to XMP SDK CC 2014.12
Diffstat (limited to 'XMPFiles')
-rw-r--r--XMPFiles/build/CMakeLists.txt315
-rw-r--r--XMPFiles/build/CMakeListsCommon.txt318
-rw-r--r--XMPFiles/source/FileHandlers/AVCHD_Handler.cpp4
-rw-r--r--XMPFiles/source/FileHandlers/JPEG_Handler.cpp44
-rw-r--r--XMPFiles/source/FileHandlers/MP3_Handler.cpp49
-rw-r--r--XMPFiles/source/FileHandlers/MPEG4_Handler.cpp446
-rw-r--r--XMPFiles/source/FileHandlers/MPEG4_Handler.hpp2
-rw-r--r--XMPFiles/source/FileHandlers/P2_Handler.cpp691
-rw-r--r--XMPFiles/source/FileHandlers/P2_Handler.hpp17
-rw-r--r--XMPFiles/source/FileHandlers/PSD_Handler.cpp6
-rw-r--r--XMPFiles/source/FileHandlers/SonyHDV_Handler.cpp2
-rw-r--r--XMPFiles/source/FileHandlers/UCF_Handler.cpp30
-rw-r--r--XMPFiles/source/FileHandlers/UCF_Handler.hpp4
-rw-r--r--XMPFiles/source/FileHandlers/WAVE_Handler.cpp26
-rw-r--r--XMPFiles/source/FileHandlers/WAVE_Handler.hpp10
-rw-r--r--XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp2
-rw-r--r--XMPFiles/source/FileHandlers/XDCAM_Handler.cpp25
-rw-r--r--XMPFiles/source/FormatSupport/IFF/ChunkController.cpp10
-rw-r--r--XMPFiles/source/FormatSupport/IFF/ChunkPath.h1
-rw-r--r--XMPFiles/source/FormatSupport/IPTC_Support.cpp4
-rw-r--r--XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp19
-rw-r--r--XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp137
-rw-r--r--XMPFiles/source/FormatSupport/MOOV_Support.hpp4
-rw-r--r--XMPFiles/source/FormatSupport/P2_Support.cpp566
-rw-r--r--XMPFiles/source/FormatSupport/P2_Support.hpp135
-rw-r--r--XMPFiles/source/FormatSupport/PostScript_Support.cpp9
-rw-r--r--XMPFiles/source/FormatSupport/QuickTime_Support.cpp194
-rw-r--r--XMPFiles/source/FormatSupport/RIFF.cpp1
-rw-r--r--XMPFiles/source/FormatSupport/ReconcileTIFF.cpp13
-rw-r--r--XMPFiles/source/FormatSupport/Reconcile_Impl.cpp40
-rw-r--r--XMPFiles/source/FormatSupport/Reconcile_Impl.hpp2
-rw-r--r--XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp4
-rw-r--r--XMPFiles/source/FormatSupport/TIFF_Support.hpp4
-rw-r--r--XMPFiles/source/FormatSupport/TimeConversionUtils.cpp599
-rw-r--r--XMPFiles/source/FormatSupport/TimeConversionUtils.hpp35
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/Cr8rMetadata.cpp2
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp2
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/PrmLMetadata.cpp2
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.cpp5
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp515
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h6
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp815
-rw-r--r--XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h157
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IMetadata.cpp25
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IMetadata.h36
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IReconcile.cpp52
-rw-r--r--XMPFiles/source/NativeMetadataSupport/IReconcile.h7
-rw-r--r--XMPFiles/source/PluginHandler/FileHandler.h2
-rw-r--r--XMPFiles/source/PluginHandler/Module.cpp4
-rw-r--r--XMPFiles/source/PluginHandler/PluginManager.cpp6
-rw-r--r--XMPFiles/source/XMPFiles.cpp146
-rw-r--r--XMPFiles/source/XMPFiles.hpp2
-rw-r--r--XMPFiles/source/XMPFiles_Impl.cpp15
-rw-r--r--XMPFiles/source/XMPFiles_Impl.hpp2
54 files changed, 4535 insertions, 1034 deletions
diff --git a/XMPFiles/build/CMakeLists.txt b/XMPFiles/build/CMakeLists.txt
index 28dc36a..76bdae0 100644
--- a/XMPFiles/build/CMakeLists.txt
+++ b/XMPFiles/build/CMakeLists.txt
@@ -39,6 +39,10 @@ set(XMP_THIS_PROJECT_RELATIVEPATH "../..")
include(${CMAKE_CURRENT_SOURCE_DIR}/${XMP_THIS_PROJECT_RELATIVEPATH}/build/XMP_Config.cmake)
+
+set(TP_ZUID_PATH "${XMPROOT_DIR}/third-party/zuid/interfaces")
+set(LIB_ADOBEXMP XMPCore)
+
# ==============================================================================
# platform specific config
# ==============================================================================
@@ -69,314 +73,5 @@ else(UNIX)
endif(WIN32)
endif(UNIX)
-# ==============================================================================
-# For convenience we define the sources as a variable. You can add
-# header files and cpp/c files and CMake will sort them out
-# ==============================================================================
-
-#file (GLOB INTERNAL_HEADER_FILES ${PRODUCT_ROOT}/source/*.hpp ${PRODUCT_ROOT}/source/*.incl_cpp ${PRODUCT_ROOT}/build/*.h)
-file (GLOB INTERNAL_HEADER_COMMONCODE_NMDS ${PRODUCT_ROOT}/XMPFiles/source/NativeMetadataSupport/*.h)
-source_group("Header Files\\Internal Headers\\Common Code\\NativeMetadataSupport" FILES ${INTERNAL_HEADER_COMMONCODE_NMDS})
-
-list (APPEND INTERNAL_HEADER_COMMONCODE
- ${XMPROOT_DIR}/source/Endian.h
- ${XMPROOT_DIR}/build/XMP_BuildInfo.h
- ${SOURCE_ROOT}/XMPFiles.hpp
- ${SOURCE_ROOT}/XMPFiles_Impl.hpp
- )
-source_group("Header Files\\Internal Headers\\Common Code" FILES ${INTERNAL_HEADER_COMMONCODE})
-
-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})
-
-file (GLOB INTERNAL_HEADER_FORMATSUPPORT_AIFF ${SOURCE_ROOT}/FormatSupport/AIFF/*.h)
-source_group("Header Files\\Internal Headers\\Format Support\\AIFF" FILES ${INTERNAL_HEADER_FORMATSUPPORT_AIFF})
-
-file (GLOB INTERNAL_HEADER_FORMATSUPPORT_IFF ${SOURCE_ROOT}/FormatSupport/IFF/*.h)
-source_group("Header Files\\Internal Headers\\Format Support\\IFF" FILES ${INTERNAL_HEADER_FORMATSUPPORT_IFF})
-
-file (GLOB INTERNAL_HEADER_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/*.h)
-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
- )
-source_group("Header Files\\Internal Headers\\Format Support" FILES ${INTERNAL_HEADER_FORMATSUPPORT})
-
-file (GLOB INTERNAL_HEADER_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/*.h)
-source_group("Header Files\\Internal Headers\\PluginHandler" FILES ${INTERNAL_HEADER_PLUGINHANDLER})
-
-list (APPEND PUBLIC_HEADER_CLIENTGLUE
- ${XMPROOT_DIR}/public/include/client-glue/TXMPFiles.incl_cpp
- ${XMPROOT_DIR}/public/include/client-glue/WXMP_Common.hpp
- ${XMPROOT_DIR}/public/include/client-glue/WXMPFiles.hpp
- )
-source_group("Header Files\\Public Headers\\Client Glue" FILES ${PUBLIC_HEADER_CLIENTGLUE})
-list (APPEND PUBLIC_HEADER
- ${XMPROOT_DIR}/public/include/TXMPFiles.hpp
- ${XMPROOT_DIR}/public/include/TXMPIterator.hpp
- ${XMPROOT_DIR}/public/include/TXMPMeta.hpp
- ${XMPROOT_DIR}/public/include/TXMPUtils.hpp
- ${XMPROOT_DIR}/public/include/XMP.hpp
- ${XMPROOT_DIR}/public/include/XMP.incl_cpp
- ${XMPROOT_DIR}/public/include/XMP_Const.h
- ${XMPROOT_DIR}/public/include/XMP_Environment.h
- ${XMPROOT_DIR}/public/include/XMP_IO.hpp
- ${XMPROOT_DIR}/public/include/XMP_Version.h
- )
-source_group("Header Files\\Public Headers" FILES ${PUBLIC_HEADER})
-
-file (GLOB HEADERFILES_THIRDPARTY_ZLIB ${XMPROOT_DIR}/third-party/zlib/*.h)
-list (REMOVE_ITEM HEADERFILES_THIRDPARTY_ZLIB
- ${CMAKE_CURRENT_SOURCE_DIR}/${XMPROOT_DIR}/third-party/zlib/gzguts.h
- )
-source_group("Header Files\\ThirdParty\\zlib" FILES ${HEADERFILES_THIRDPARTY_ZLIB})
-
-list (APPEND HEADERFILES
- ${XMPROOT_DIR}/source/Host_IO.hpp
- ${XMPROOT_DIR}/source/XIO.hpp
- ${XMPROOT_DIR}/source/IOUtils.hpp
- ${XMPROOT_DIR}/source/XMPFiles_IO.hpp
- )
-source_group("Header Files" FILES ${HEADERFILES})
-
-#resource files
-file (GLOB RESOURCE_FILES ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.*)
-if(WIN32 AND ${XMP_BUILD_STATIC})
- list (REMOVE_ITEM RESOURCE_FILES ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.rc)
-endif()
-source_group("Resource Files" FILES ${RESOURCE_FILES})
-
-#source files
-file (GLOB SOURCEFILES_COMMONCODE_NMDS ${SOURCE_ROOT}/NativeMetadataSupport/*.cpp)
-source_group("Source Files\\Common Code\\NativeMetadataSupport" FILES ${SOURCEFILES_COMMONCODE_NMDS})
-
-list (APPEND SOURCEFILES_COMMONCODE
- ${XMPROOT_DIR}/third-party/zuid/interfaces/MD5.cpp
- ${XMPROOT_DIR}/source/UnicodeConversions.cpp
- ${SOURCE_ROOT}/HandlerRegistry.cpp
- ${XMPROOT_DIR}/source/PerfUtils.cpp
- ${SOURCE_ROOT}/WXMPFiles.cpp
- ${XMPROOT_DIR}/source/XIO.cpp
- ${XMPROOT_DIR}/source/IOUtils.cpp
- ${XMPROOT_DIR}/source/XML_Node.cpp
- ${XMPROOT_DIR}/source/XMP_LibUtils.cpp
- ${XMPROOT_DIR}/source/XMP_ProgressTracker.cpp
- ${SOURCE_ROOT}/XMPFiles.cpp
- ${SOURCE_ROOT}/XMPFiles_Impl.cpp
- ${XMPROOT_DIR}/source/XMPFiles_IO.cpp
- )
-if(UNIX)
- list(APPEND SOURCEFILES_COMMONCODE ${XMPROOT_DIR}/source/Host_IO-POSIX.cpp)
-else()
- list(APPEND SOURCEFILES_COMMONCODE ${XMPROOT_DIR}/source/Host_IO-Win.cpp)
-endif()
-source_group("Source Files\\Common Code" FILES ${SOURCEFILES_COMMONCODE})
-
-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)
-source_group("Source Files\\Format Support\\AIFF" FILES ${SOURCEFILES_FORMATSUPPORT_AIFF})
-
-file (GLOB SOURCEFILES_FORMATSUPPORT_IFF ${SOURCE_ROOT}/FormatSupport/IFF/*.cpp)
-source_group("Source Files\\Format Support\\IFF" FILES ${SOURCEFILES_FORMATSUPPORT_IFF})
-
-file (GLOB SOURCEFILES_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/*.cpp)
-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})
-
-file (GLOB SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/*.cpp)
-list (REMOVE_ITEM SOURCEFILES_PLUGINHANDLER
- ${SOURCE_ROOT}/PluginHandler/OS_Utils_Linux.cpp
- ${SOURCE_ROOT}/PluginHandler/OS_Utils_WIN.cpp
- ${SOURCE_ROOT}/PluginHandler/OS_Utils_Mac.cpp
- )
-if (UNIX)
- if (APPLE)
- list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_Mac.cpp)
- else()
- list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_Linux.cpp)
- endif()
-else()
- list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_WIN.cpp)
-endif()
-
-source_group("Source Files\\PluginHandler" FILES ${SOURCEFILES_PLUGINHANDLER})
-
-list (APPEND HEADERFILES_THIRDPARTY_ZLIB
- ${XMPROOT_DIR}/third-party/zlib/adler32.c
- ${XMPROOT_DIR}/third-party/zlib/compress.c
- ${XMPROOT_DIR}/third-party/zlib/crc32.c
- ${XMPROOT_DIR}/third-party/zlib/deflate.c
- ${XMPROOT_DIR}/third-party/zlib/infback.c
- ${XMPROOT_DIR}/third-party/zlib/inffast.c
- ${XMPROOT_DIR}/third-party/zlib/inflate.c
- ${XMPROOT_DIR}/third-party/zlib/inftrees.c
- ${XMPROOT_DIR}/third-party/zlib/trees.c
- ${XMPROOT_DIR}/third-party/zlib/uncompr.c
- ${XMPROOT_DIR}/third-party/zlib/zutil.c
- )
-source_group("Source Files\\ThirdParty\\zlib" FILES ${HEADERFILES_THIRDPARTY_ZLIB})
-
-list(APPEND SOURCE_FILES
- ${INTERNAL_HEADER_COMMONCODE_NMDS}
- ${INTERNAL_HEADER_COMMONCODE}
- ${INTERNAL_HEADER_FILEHANDLERS}
- ${INTERNAL_HEADER_FORMATSUPPORT_AIFF}
- ${INTERNAL_HEADER_FORMATSUPPORT_IFF}
- ${INTERNAL_HEADER_FORMATSUPPORT_WAVE}
- ${INTERNAL_HEADER_FORMATSUPPORT}
- ${INTERNAL_HEADER_PLUGINHANDLER}
- ${PUBLIC_HEADER_CLIENTGLUE}
- ${PUBLIC_HEADER}
- ${HEADERFILES_THIRDPARTY_ZLIB}
- ${HEADERFILES}
- ${RESOURCE_FILES}
- ${SOURCEFILES_COMMONCODE_NMDS}
- ${SOURCEFILES_COMMONCODE}
- ${SOURCEFILES_FILEHANDLERS}
- ${SOURCEFILES_FORMATSUPPORT_AIFF}
- ${SOURCEFILES_FORMATSUPPORT_IFF}
- ${SOURCEFILES_FORMATSUPPORT_WAVE}
- ${SOURCEFILES_FORMATSUPPORT}
- ${SOURCEFILES_PLUGINHANDLER}
- ${HEADERFILES_THIRDPARTY_ZLIB}
- )
-
-# include directories
-include_directories(${XMPROOT_DIR})
-include_directories(${XMPROOT_DIR}/public/include)
-include_directories(${XMPROOT_DIR}/third-party/expat/zlib)
-include_directories(${XMPROOT_DIR}/XMPFilesPlugins/api/source)
-include_directories(${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT})
-
-#additional link directory
-set(LIB_ADOBEXMP XMPCore)
-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"
- )
- set(DEPENDENCY_LIST "ALL:${TARGET_NAME}InfoPlist" "DLL:XMPCore")
-else ()
- set(DEPENDENCY_LIST "DLL:XMPCore")
-endif()
-
-AddLibraryAndDependencies(${TARGET_NAME} ${XMP_BUILD_STATIC} YES "SHARED" SOURCE_FILES DEPENDENCY_LIST)
-
-# ==============================================================================
-# Link dependencies
-
-if(WIN32)
- target_link_libraries(
- ${TARGET_NAME}
- ${LIB_ADOBEXMP}
- ${XMP_PLATFORM_LINK}
- )
-else(WIN32)
- if(UNIX AND NOT APPLE)
- target_link_libraries(
- ${TARGET_NAME}
- ${LIB_ADOBEXMP}
- )
- endif()
-endif()
-
-set(FRAMEWORK_LIST "Mac:CoreFoundation" "Mac:CoreServices" "Mac:${LIB_ADOBEXMP}" "Mac:${XMP_PLATFORM_LINK}")
-AddMacFramework(${TARGET_NAME} FRAMEWORK_LIST)
-
-if(UNIX)
- if (NOT APPLE)
- SetWinLinkFlags(${TARGET_NAME} "-Xlinker --version-script -Xlinker \"${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.exp\"" "")
- else()
- set_target_properties(${TARGET_NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH ON INSTALL_NAME_DIR "@executable_path/../Frameworks")
- SetWinLinkFlags(${TARGET_NAME} "-exported_symbols_list \"${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.exp\"" "${XMPFILES_LIB}")
- endif()
-else()
- SetWinLinkFlags(${TARGET_NAME} "" "${XMPFILES_LIB}")
-endif()
-
-set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${XMPFILES_LIB})
-
-# ==============================================================================
-# Define output for this project
-SetOutputPath(${OUTPUT_DIR} 0)
-
-# ==============================================================================
-# Post build
-# ==============================================================================
-
-if(UNIX)
- #hack for unix to rename the output static library. cmake add lib and extenstion as .a, rename it
- if (NOT APPLE)
- if (${XMP_BUILD_STATIC})
- add_custom_command (TARGET ${TARGET_NAME}
- POST_BUILD
- COMMAND mv ${OUTPUT_DIR}/lib${XMPFILES_LIB}.a ${OUTPUT_DIR}/${XMPFILES_LIB}.ar
- )
- else()
- if((${CMAKE_BUILD_TYPE} MATCHES "Debug") OR (${CMAKE_BUILD_TYPE} MATCHES "debug") )
- add_custom_command (TARGET ${TARGET_NAME}
- POST_BUILD
- COMMAND ls -l ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
- )
- else()
- add_custom_command (TARGET ${TARGET_NAME}
- POST_BUILD
- COMMAND strip ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
- COMMAND ls -l ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
- )
- endif()
- endif()
- endif()
-
-else()
- set_target_properties(${TARGET_NAME} PROPERTIES PROJECT_LABEL ${PROJECT_LABEL_STR})
-
-endif()
-message (STATUS "===========================================================================")
-message (STATUS " ${PROJECT_NAME} ")
-message (STATUS "===========================================================================")
-message (STATUS " OUTPUT_DIR = ${OUTPUT_DIR}")
+include(${CMAKE_CURRENT_SOURCE_DIR}/${XMP_THIS_PROJECT_RELATIVEPATH}/XMPFiles/build/CMakeListsCommon.txt) \ No newline at end of file
diff --git a/XMPFiles/build/CMakeListsCommon.txt b/XMPFiles/build/CMakeListsCommon.txt
new file mode 100644
index 0000000..2f116d0
--- /dev/null
+++ b/XMPFiles/build/CMakeListsCommon.txt
@@ -0,0 +1,318 @@
+
+# ==============================================================================
+# For convenience we define the sources as a variable. You can add
+# header files and cpp/c files and CMake will sort them out
+# ==============================================================================
+
+#file (GLOB INTERNAL_HEADER_FILES ${PRODUCT_ROOT}/source/*.hpp ${PRODUCT_ROOT}/source/*.incl_cpp ${PRODUCT_ROOT}/build/*.h)
+file (GLOB INTERNAL_HEADER_COMMONCODE_NMDS ${PRODUCT_ROOT}/XMPFiles/source/NativeMetadataSupport/*.h)
+source_group("Header Files\\Internal Headers\\Common Code\\NativeMetadataSupport" FILES ${INTERNAL_HEADER_COMMONCODE_NMDS})
+
+list (APPEND INTERNAL_HEADER_COMMONCODE
+ ${XMPROOT_DIR}/source/Endian.h
+ ${XMPROOT_DIR}/source/SafeStringAPIs.h
+ ${XMPROOT_DIR}/source/SafeTypes.h
+ ${XMPROOT_DIR}/source/SuppressSAL.h
+ ${XMPROOT_DIR}/build/XMP_BuildInfo.h
+ ${SOURCE_ROOT}/XMPFiles.hpp
+ ${SOURCE_ROOT}/XMPFiles_Impl.hpp
+ )
+source_group("Header Files\\Internal Headers\\Common Code" FILES ${INTERNAL_HEADER_COMMONCODE})
+
+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})
+
+file (GLOB INTERNAL_HEADER_FORMATSUPPORT_AIFF ${SOURCE_ROOT}/FormatSupport/AIFF/*.h)
+source_group("Header Files\\Internal Headers\\Format Support\\AIFF" FILES ${INTERNAL_HEADER_FORMATSUPPORT_AIFF})
+
+file (GLOB INTERNAL_HEADER_FORMATSUPPORT_IFF ${SOURCE_ROOT}/FormatSupport/IFF/*.h)
+source_group("Header Files\\Internal Headers\\Format Support\\IFF" FILES ${INTERNAL_HEADER_FORMATSUPPORT_IFF})
+
+file (GLOB INTERNAL_HEADER_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/*.h)
+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
+ )
+source_group("Header Files\\Internal Headers\\Format Support" FILES ${INTERNAL_HEADER_FORMATSUPPORT})
+
+file (GLOB INTERNAL_HEADER_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/*.h)
+source_group("Header Files\\Internal Headers\\PluginHandler" FILES ${INTERNAL_HEADER_PLUGINHANDLER})
+
+list (APPEND PUBLIC_HEADER_CLIENTGLUE
+ ${XMPROOT_DIR}/public/include/client-glue/TXMPFiles.incl_cpp
+ ${XMPROOT_DIR}/public/include/client-glue/WXMP_Common.hpp
+ ${XMPROOT_DIR}/public/include/client-glue/WXMPFiles.hpp
+ )
+source_group("Header Files\\Public Headers\\Client Glue" FILES ${PUBLIC_HEADER_CLIENTGLUE})
+list (APPEND PUBLIC_HEADER
+ ${XMPROOT_DIR}/public/include/TXMPFiles.hpp
+ ${XMPROOT_DIR}/public/include/TXMPIterator.hpp
+ ${XMPROOT_DIR}/public/include/TXMPMeta.hpp
+ ${XMPROOT_DIR}/public/include/TXMPUtils.hpp
+ ${XMPROOT_DIR}/public/include/XMP.hpp
+ ${XMPROOT_DIR}/public/include/XMP.incl_cpp
+ ${XMPROOT_DIR}/public/include/XMP_Const.h
+ ${XMPROOT_DIR}/public/include/XMP_Environment.h
+ ${XMPROOT_DIR}/public/include/XMP_IO.hpp
+ ${XMPROOT_DIR}/public/include/XMP_Version.h
+ )
+source_group("Header Files\\Public Headers" FILES ${PUBLIC_HEADER})
+
+file (GLOB HEADERFILES_THIRDPARTY_ZLIB ${XMPROOT_DIR}/third-party/zlib/*.h)
+list (REMOVE_ITEM HEADERFILES_THIRDPARTY_ZLIB
+ ${CMAKE_CURRENT_SOURCE_DIR}/${XMPROOT_DIR}/third-party/zlib/gzguts.h
+ )
+source_group("Header Files\\ThirdParty\\zlib" FILES ${HEADERFILES_THIRDPARTY_ZLIB})
+
+list (APPEND HEADERFILES
+ ${XMPROOT_DIR}/source/Host_IO.hpp
+ ${XMPROOT_DIR}/source/XIO.hpp
+ ${XMPROOT_DIR}/source/IOUtils.hpp
+ ${XMPROOT_DIR}/source/XMPFiles_IO.hpp
+ )
+source_group("Header Files" FILES ${HEADERFILES})
+
+#resource files
+file (GLOB RESOURCE_FILES ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.*)
+if(WIN32 AND ${XMP_BUILD_STATIC})
+ list (REMOVE_ITEM RESOURCE_FILES ${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT}/${TARGET_NAME}.rc)
+endif()
+source_group("Resource Files" FILES ${RESOURCE_FILES})
+
+#source files
+file (GLOB SOURCEFILES_COMMONCODE_NMDS ${SOURCE_ROOT}/NativeMetadataSupport/*.cpp)
+source_group("Source Files\\Common Code\\NativeMetadataSupport" FILES ${SOURCEFILES_COMMONCODE_NMDS})
+
+list (APPEND SOURCEFILES_COMMONCODE
+ ${TP_ZUID_PATH}/MD5.cpp
+ ${XMPROOT_DIR}/source/UnicodeConversions.cpp
+ ${SOURCE_ROOT}/HandlerRegistry.cpp
+ ${XMPROOT_DIR}/source/SafeStringAPIs.cpp
+ ${XMPROOT_DIR}/source/PerfUtils.cpp
+ ${SOURCE_ROOT}/WXMPFiles.cpp
+ ${XMPROOT_DIR}/source/XIO.cpp
+ ${XMPROOT_DIR}/source/IOUtils.cpp
+ ${XMPROOT_DIR}/source/XML_Node.cpp
+ ${XMPROOT_DIR}/source/XMP_LibUtils.cpp
+ ${XMPROOT_DIR}/source/XMP_ProgressTracker.cpp
+ ${SOURCE_ROOT}/XMPFiles.cpp
+ ${SOURCE_ROOT}/XMPFiles_Impl.cpp
+ ${XMPROOT_DIR}/source/XMPFiles_IO.cpp
+ )
+if(UNIX)
+ list(APPEND SOURCEFILES_COMMONCODE ${XMPROOT_DIR}/source/Host_IO-POSIX.cpp)
+else()
+ list(APPEND SOURCEFILES_COMMONCODE ${XMPROOT_DIR}/source/Host_IO-Win.cpp)
+endif()
+source_group("Source Files\\Common Code" FILES ${SOURCEFILES_COMMONCODE})
+
+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)
+source_group("Source Files\\Format Support\\AIFF" FILES ${SOURCEFILES_FORMATSUPPORT_AIFF})
+
+file (GLOB SOURCEFILES_FORMATSUPPORT_IFF ${SOURCE_ROOT}/FormatSupport/IFF/*.cpp)
+source_group("Source Files\\Format Support\\IFF" FILES ${SOURCEFILES_FORMATSUPPORT_IFF})
+
+file (GLOB SOURCEFILES_FORMATSUPPORT_WAVE ${SOURCE_ROOT}/FormatSupport/WAVE/*.cpp)
+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)
+ file (GLOB SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/*.cpp)
+ list (REMOVE_ITEM SOURCEFILES_PLUGINHANDLER
+ ${SOURCE_ROOT}/PluginHandler/OS_Utils_Linux.cpp
+ ${SOURCE_ROOT}/PluginHandler/OS_Utils_WIN.cpp
+ ${SOURCE_ROOT}/PluginHandler/OS_Utils_Mac.cpp
+ )
+ if (UNIX)
+ if (APPLE)
+ list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_Mac.cpp)
+ else()
+ list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_Linux.cpp)
+ endif()
+ else()
+ list (APPEND SOURCEFILES_PLUGINHANDLER ${SOURCE_ROOT}/PluginHandler/OS_Utils_WIN.cpp)
+ endif()
+
+ source_group("Source Files\\PluginHandler" FILES ${SOURCEFILES_PLUGINHANDLER})
+endif()
+
+list (APPEND HEADERFILES_THIRDPARTY_ZLIB
+ ${XMPROOT_DIR}/third-party/zlib/adler32.c
+ ${XMPROOT_DIR}/third-party/zlib/compress.c
+ ${XMPROOT_DIR}/third-party/zlib/crc32.c
+ ${XMPROOT_DIR}/third-party/zlib/deflate.c
+ ${XMPROOT_DIR}/third-party/zlib/infback.c
+ ${XMPROOT_DIR}/third-party/zlib/inffast.c
+ ${XMPROOT_DIR}/third-party/zlib/inflate.c
+ ${XMPROOT_DIR}/third-party/zlib/inftrees.c
+ ${XMPROOT_DIR}/third-party/zlib/trees.c
+ ${XMPROOT_DIR}/third-party/zlib/uncompr.c
+ ${XMPROOT_DIR}/third-party/zlib/zutil.c
+ )
+source_group("Source Files\\ThirdParty\\zlib" FILES ${HEADERFILES_THIRDPARTY_ZLIB})
+
+list(APPEND SOURCE_FILES
+ ${INTERNAL_HEADER_COMMONCODE_NMDS}
+ ${INTERNAL_HEADER_COMMONCODE}
+ ${INTERNAL_HEADER_FILEHANDLERS}
+ ${INTERNAL_HEADER_FORMATSUPPORT_AIFF}
+ ${INTERNAL_HEADER_FORMATSUPPORT_IFF}
+ ${INTERNAL_HEADER_FORMATSUPPORT_WAVE}
+ ${INTERNAL_HEADER_FORMATSUPPORT}
+ ${INTERNAL_HEADER_PLUGINHANDLER}
+ ${PUBLIC_HEADER_CLIENTGLUE}
+ ${PUBLIC_HEADER}
+ ${HEADERFILES_THIRDPARTY_ZLIB}
+ ${HEADERFILES}
+ ${RESOURCE_FILES}
+ ${SOURCEFILES_COMMONCODE_NMDS}
+ ${SOURCEFILES_COMMONCODE}
+ ${SOURCEFILES_FILEHANDLERS}
+ ${SOURCEFILES_FORMATSUPPORT_AIFF}
+ ${SOURCEFILES_FORMATSUPPORT_IFF}
+ ${SOURCEFILES_FORMATSUPPORT_WAVE}
+ ${SOURCEFILES_FORMATSUPPORT}
+ ${SOURCEFILES_PLUGINHANDLER}
+ ${HEADERFILES_THIRDPARTY_ZLIB}
+ )
+
+# include directories
+include_directories(${XMPROOT_DIR})
+include_directories(${XMPROOT_DIR}/public/include)
+include_directories(${XMPROOT_DIR}/third-party/expat/zlib)
+include_directories(${XMPROOT_DIR}/XMPFilesPlugins/api/source)
+include_directories(${RESOURCE_ROOT}/${XMP_PLATFORM_SHORT})
+
+#additional link directory
+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"
+ )
+ set(DEPENDENCY_LIST "ALL:${TARGET_NAME}InfoPlist" "DLL:XMPCore")
+else ()
+ set(DEPENDENCY_LIST "DLL:XMPCore")
+endif()
+
+AddLibraryAndDependencies(${TARGET_NAME} ${XMP_BUILD_STATIC} YES "SHARED" SOURCE_FILES DEPENDENCY_LIST)
+
+# ==============================================================================
+# Link dependencies
+
+if(WIN32)
+ target_link_libraries(
+ ${TARGET_NAME}
+ ${LIB_ADOBEXMP}
+ ${XMP_PLATFORM_LINK}
+ )
+else(WIN32)
+ if(UNIX AND NOT APPLE)
+ target_link_libraries(
+ ${TARGET_NAME}
+ ${LIB_ADOBEXMP}
+ )
+ endif()
+endif()
+
+set(FRAMEWORK_LIST "Mac:CoreFoundation" "Mac:CoreServices" "Mac:${LIB_ADOBEXMP}" "Mac:${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()
+ 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()
+else()
+ SetPlatformLinkFlags(${TARGET_NAME} "" "${XMPFILES_LIB}")
+endif()
+
+set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${XMPFILES_LIB})
+
+# ==============================================================================
+# Define output for this project
+SetOutputPath(${OUTPUT_DIR} 0)
+
+# ==============================================================================
+# Post build
+# ==============================================================================
+
+if(UNIX)
+ #hack for unix to rename the output static library. cmake add lib and extenstion as .a, rename it
+ if (NOT APPLE)
+ if (${XMP_BUILD_STATIC})
+ add_custom_command (TARGET ${TARGET_NAME}
+ POST_BUILD
+ COMMAND mv ${OUTPUT_DIR}/lib${XMPFILES_LIB}.a ${OUTPUT_DIR}/${XMPFILES_LIB}.ar
+ )
+ else()
+ if((${CMAKE_BUILD_TYPE} MATCHES "Debug") OR (${CMAKE_BUILD_TYPE} MATCHES "debug") )
+ add_custom_command (TARGET ${TARGET_NAME}
+ POST_BUILD
+ COMMAND ls -l ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
+ )
+ else()
+ add_custom_command (TARGET ${TARGET_NAME}
+ POST_BUILD
+ COMMAND strip ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
+ COMMAND ls -l ${OUTPUT_DIR}/lib${XMPFILES_LIB}.so
+ )
+ endif()
+ endif()
+ endif()
+
+
+else()
+ set_target_properties(${TARGET_NAME} PROPERTIES PROJECT_LABEL ${PROJECT_LABEL_STR})
+
+endif()
+
+message (STATUS "===========================================================================")
+message (STATUS " ${PROJECT_NAME} ")
+message (STATUS "===========================================================================")
+message (STATUS " OUTPUT_DIR = ${OUTPUT_DIR}")
diff --git a/XMPFiles/source/FileHandlers/AVCHD_Handler.cpp b/XMPFiles/source/FileHandlers/AVCHD_Handler.cpp
index a58594f..95d4f1b 100644
--- a/XMPFiles/source/FileHandlers/AVCHD_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/AVCHD_Handler.cpp
@@ -1979,7 +1979,7 @@ bool AVCHD_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
ok = this->MakeClipInfoPath ( &fullPath, ".clpi", true /* checkFile */ );
if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
+ if ( *modDate < oneDate ) *modDate = oneDate;
haveDate = true;
}
@@ -2270,7 +2270,7 @@ void AVCHD_MetaHandler::ProcessXMP()
if ( has2_2pulldown )
xmpValue = "29.97p";
else
- xmpValue = has3_2pulldown ? "23.98p" : "59.94i";
+ xmpValue = "59.94i";
break;
default: break;
diff --git a/XMPFiles/source/FileHandlers/JPEG_Handler.cpp b/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
index ea025bd..bdc5505 100644
--- a/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/JPEG_Handler.cpp
@@ -276,6 +276,9 @@ void JPEG_MetaHandler::CacheFileData()
static const size_t kBufferSize = 64*1024; // Enough for maximum segment contents.
XMP_Uns8 buffer [kBufferSize];
+ psirContents.clear();
+ exifContents.clear();
+
XMP_AbortProc abortProc = this->parent->abortProc;
void * abortArg = this->parent->abortArg;
const bool checkAbort = (abortProc != 0);
@@ -333,7 +336,7 @@ void JPEG_MetaHandler::CacheFileData()
size_t psirLen = contentLen - kPSIRSignatureLength;
fileRef->Seek ( (contentOrigin + kPSIRSignatureLength), kXMP_SeekFromStart );
fileRef->ReadAll ( buffer, psirLen );
- this->psirContents.assign ( (char*)buffer, psirLen );
+ this->psirContents.append( (char *) buffer, psirLen );
continue; // Move on to the next marker.
}
@@ -354,7 +357,7 @@ void JPEG_MetaHandler::CacheFileData()
size_t exifLen = contentLen - kExifSignatureLength;
fileRef->Seek ( (contentOrigin + kExifSignatureLength), kXMP_SeekFromStart );
fileRef->ReadAll ( buffer, exifLen );
- this->exifContents.assign ( (char*)buffer, exifLen );
+ this->exifContents.append ( (char*)buffer, exifLen );
continue; // Move on to the next marker.
}
@@ -535,8 +538,10 @@ void JPEG_MetaHandler::ProcessXMP()
XMP_Assert ( (this->psirMgr == 0) && (this->iptcMgr == 0) ); // ProcessTNail might create the exifMgr.
- bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
-
+ bool readOnly = false;
+ if ( this->parent ){
+ readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+ }
if ( readOnly ) {
if ( this->exifMgr == 0 ) this->exifMgr = new TIFF_MemoryReader();
this->psirMgr = new PSIR_MemoryReader();
@@ -826,19 +831,16 @@ void JPEG_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
void* exifPtr;
XMP_Uns32 exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr );
if ( exifLen > kExifMaxDataLength ) exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr, true /* compact */ );
- if ( exifLen > kExifMaxDataLength ) {
- // XMP_Throw ( "Overflow of Exif APP1 data", kXMPErr_BadJPEG ); ** Used to throw, now rewrite original Exif.
- exifPtr = (void*)this->exifContents.c_str();
- exifLen = this->exifContents.size();
- }
- if ( exifLen > 0 ) {
- first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + exifLen );
+ while ( exifLen > 0 ) {
+ XMP_Uns32 count = std::min ( exifLen, (XMP_Uns32) kExifMaxDataLength );
+ first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + count );
tempRef->Write ( &first4, 4 );
tempRef->Write ( kExifSignatureString, kExifSignatureLength );
- tempRef->Write ( exifPtr, exifLen );
+ tempRef->Write ( exifPtr, count );
+ exifPtr = (XMP_Uns8 *) exifPtr + count;
+ exifLen -= count;
}
-
}
// Write the new XMP APP1 marker segment, with possible extension marker segments.
@@ -878,25 +880,23 @@ void JPEG_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
}
- // Write the new PSIR APP13 marker segment.
-
+ // Write the new PSIR APP13 marker segments.
if ( this->psirMgr != 0 ) {
void* psirPtr;
XMP_Uns32 psirLen = this->psirMgr->UpdateMemoryResources ( &psirPtr );
- if ( psirLen > kPSIRMaxDataLength ) XMP_Throw ( "Overflow of PSIR APP13 data", kXMPErr_BadJPEG );
-
- if ( psirLen > 0 ) {
- first4 = MakeUns32BE ( 0xFFED0000 + 2 + kPSIRSignatureLength + psirLen );
+ while ( psirLen > 0 ) {
+ XMP_Uns32 count = std::min ( psirLen, (XMP_Uns32) kPSIRMaxDataLength );
+ first4 = MakeUns32BE ( 0xFFED0000 + 2 + kPSIRSignatureLength + count );
tempRef->Write ( &first4, 4 );
tempRef->Write ( kPSIRSignatureString, kPSIRSignatureLength );
- tempRef->Write ( psirPtr, psirLen );
+ tempRef->Write ( psirPtr, count );
+ psirPtr = (XMP_Uns8 *) psirPtr + count;
+ psirLen -= count;
}
-
}
// Copy remaining marker segments, skipping old metadata, to the first SOS marker or to EOI.
-
origRef->Seek ( -2, kXMP_SeekFromCurrent ); // Back up to the marker from the end of the APP0 copy loop.
while ( true ) {
diff --git a/XMPFiles/source/FileHandlers/MP3_Handler.cpp b/XMPFiles/source/FileHandlers/MP3_Handler.cpp
index a568c1a..3215e72 100644
--- a/XMPFiles/source/FileHandlers/MP3_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/MP3_Handler.cpp
@@ -119,6 +119,20 @@ bool MP3_CheckFormat ( XMP_FileFormat format,
MP3_MetaHandler::MP3_MetaHandler ( XMPFiles * _parent )
{
+ this->oldTagSize = 0;
+ this->oldPadding = 0;
+ this->oldFramesSize = 0;
+ this->newTagSize = 0;
+ this->newPadding = 0;
+ this->newFramesSize = 0;
+ this->tagIsDirty = false;
+ this->mustShift = false;
+ this->majorVersion = 2.3;
+ this->minorVersion = 2.3;
+ this->hasID3Tag = false;
+ this->hasFooter = false;
+ this->extHeaderSize = 0;
+ this->hasExtHeader = false;
this->parent = _parent;
this->handlerFlags = kMP3_HandlerFlags;
this->stdCharForm = kXMP_Char8Bit;
@@ -423,23 +437,26 @@ void MP3_MetaHandler::ProcessXMP()
}//for reconProps
// import DateTime
- XMP_DateTime oldDateTime;
- xmpObj.GetProperty_Date ( kXMP_NS_XMP, "CreateDate", &oldDateTime, 0 );
+ XMP_DateTime oldDateTime;
+ bool haveNewDateTime = newDateTime.year != 0 ;
+ 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) ) ) );
+ }
+ // NOTE: no further validation nessesary the function "SetProperty_Date" will care about validating date and time
+ // any exception will be caught and block import
+ try {
+ if ( haveNewDateTime ) {
+ this->xmpObj.SetProperty_Date ( kXMP_NS_XMP, "CreateDate", newDateTime );
+ }
+ } catch ( ... ) {
+ // Dont import invalid dates from ID3
+ }
- // NOTE: no further validation nessesary the function "SetProperty_Date" will care about validating date and time
- // any exception will be caught and block import
- try {
- bool haveNewDateTime = (newDateTime.year != 0) &&
- ( (newDateTime.year != oldDateTime.year) ||
- ( (newDateTime.month != 0 ) && ( (newDateTime.day != oldDateTime.day) || (newDateTime.month != oldDateTime.month) ) ) ||
- ( newDateTime.hasTime && ( (newDateTime.hour != oldDateTime.minute) || (newDateTime.hour != oldDateTime.minute) ) ) );
- if ( haveNewDateTime ) {
- this->xmpObj.SetProperty_Date ( kXMP_NS_XMP, "CreateDate", newDateTime );
- }
- } catch ( ... ) {
- // Dont import invalid dates from ID3
- }
-
}
// very important to avoid multiple runs! (in which case I'd need to clean certain
diff --git a/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp b/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
index 2dfe088..905f19f 100644
--- a/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/MPEG4_Handler.cpp
@@ -24,6 +24,7 @@
#include "source/XMP_ProgressTracker.hpp"
#include "source/UnicodeConversions.hpp"
#include "third-party/zuid/interfaces/MD5.h"
+#include <math.h>
#if XMP_WinBuild
#pragma warning ( disable : 4996 ) // '...' was declared deprecated
@@ -142,6 +143,31 @@ static inline XMP_StringPtr Lookup3LetterLang ( XMP_StringPtr lang2 )
return "";
}
+
+#define IsTolerableBoxChar(ch) ( ((0x20 <= (ch)) && ((ch) <= 0x7E)) || ((ch) == 0xA9) )
+
+static inline bool IsTolerableBox ( XMP_Uns32 boxType )
+{
+ // Make sure the box type is 4 ASCII characters or 0xA9 (MacRoman copyright).
+ XMP_Uns8 b1 = (XMP_Uns8) (boxType >> 24);
+ XMP_Uns8 b2 = (XMP_Uns8) ((boxType >> 16) & 0xFF);
+ XMP_Uns8 b3 = (XMP_Uns8) ((boxType >> 8) & 0xFF);
+ XMP_Uns8 b4 = (XMP_Uns8) (boxType & 0xFF);
+ bool ok = IsTolerableBoxChar(b1) && IsTolerableBoxChar(b2) &&
+ IsTolerableBoxChar(b3) && IsTolerableBoxChar(b4);
+ return ok;
+}
+
+static inline bool IsXMPUUID ( XMP_IO * fileRef,XMP_Uns64 contentSize, bool unmovedFilePtr=false )
+{
+ if ( contentSize < 16 ) return false;
+ XMP_Uns8 uuid [16];
+ fileRef->ReadAll ( uuid, 16 );
+ if (unmovedFilePtr) fileRef->Seek ( -16, kXMP_SeekFromCurrent );
+ if ( memcmp ( uuid, ISOMedia::k_xmpUUID, 16 ) != 0 ) return false; // Check for the XMP GUID.
+ return true;
+}
+
// =================================================================================================
// MPEG4_CheckFormat
// =================
@@ -184,8 +210,6 @@ bool MPEG4_CheckFormat ( XMP_FileFormat format,
XMP_Uns64 fileSize, nextOffset;
ISOMedia::BoxInfo currBox;
- #define IsTolerableBoxChar(ch) ( ((0x20 <= (ch)) && ((ch) <= 0x7E)) || ((ch) == 0xA9) )
-
XMP_AbortProc abortProc = parent->abortProc;
void * abortArg = parent->abortArg;
const bool checkAbort = (abortProc != 0);
@@ -256,14 +280,7 @@ bool MPEG4_CheckFormat ( XMP_FileFormat format,
while ( currBox.boxType != ISOMedia::k_moov ) {
if ( ! IsClassicQuickTimeBox ( currBox.boxType ) ) {
- // Make sure the box type is 4 ASCII characters or 0xA9 (MacRoman copyright).
- XMP_Uns8 b1 = (XMP_Uns8) (currBox.boxType >> 24);
- XMP_Uns8 b2 = (XMP_Uns8) ((currBox.boxType >> 16) & 0xFF);
- XMP_Uns8 b3 = (XMP_Uns8) ((currBox.boxType >> 8) & 0xFF);
- XMP_Uns8 b4 = (XMP_Uns8) (currBox.boxType & 0xFF);
- bool ok = IsTolerableBoxChar(b1) && IsTolerableBoxChar(b2) &&
- IsTolerableBoxChar(b3) && IsTolerableBoxChar(b4);
- if ( ! ok ) return false;
+ if ( ! IsTolerableBox(currBox.boxType) ) return false;
}
if ( nextOffset >= fileSize ) return false;
if ( checkAbort && abortProc(abortArg) ) {
@@ -1721,7 +1738,6 @@ static QTErrorMode CheckAtomList ( XMP_IO* qtFile, XMP_Int64 spanSize, int nesti
if ( spanSize != 0 ) {
qtFile->Seek ( spanSize, kXMP_SeekFromCurrent ); // ! Skip the trailing garbage of this span.
status = kBadQT_SmallInner;
- if ( spanSize >= 8 ) status = kBadQT_LargeInner;
if ( nesting == 0 ) status += 2; // Convert to "outer".
}
@@ -1733,16 +1749,28 @@ static QTErrorMode CheckAtomList ( XMP_IO* qtFile, XMP_Int64 spanSize, int nesti
// AttemptFileRepair
// =================
-static void AttemptFileRepair ( XMP_IO* qtFile, XMP_Int64 fileSpace, QTErrorMode status )
+static void AttemptFileRepair ( XMP_IO* qtFile, XMP_Int64 fileSpace, QTErrorMode status, GenericErrorCallback * ec )
{
switch ( status ) {
case kBadQT_NoError : return; // Sanity check.
case kBadQT_SmallInner : return; // Fixed in normal update code for the 'udta' box.
- case kBadQT_LargeInner : XMP_Throw ( "Can't repair QuickTime file", kXMPErr_BadFileFormat );
- case kBadQT_SmallOuter : break; // Truncate file below.
- case kBadQT_LargeOuter : break; // Truncate file below.
- default : XMP_Throw ( "Invalid QuickTime error mode", kXMPErr_InternalFailure );
+ case kBadQT_LargeInner :
+ {
+ XMP_Error error ( kXMPErr_BadFileFormat,"Can't repair QuickTime file" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_FileFatal, error);
+ break;// will never be here
+ }
+ case kBadQT_SmallOuter : // Truncate file below.
+ case kBadQT_LargeOuter : // Truncate file below.
+ {
+ break;
+ }
+ default :
+ {
+ XMP_Error error ( kXMPErr_InternalFailure, "Invalid QuickTime error mode" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_FileFatal, error);
+ }
}
AtomInfo info;
@@ -1760,19 +1788,37 @@ static void AttemptFileRepair ( XMP_IO* qtFile, XMP_Int64 fileSpace, QTErrorMode
if ( info.hasLargeSize ) headerSize = 16;
if ( atomStatus != kBadQT_NoError ) break;
- if ( (info.atomSize < headerSize) || (info.atomSize > fileSpace) ) break;
+ // If the atom size is less than header -case of kBadQT_SmallOuter
+ // If the atom size is more than left filespace -case of kBadQT_LargeOuter
+ if ( (info.atomSize < headerSize) || (info.atomSize > fileSpace ) ) break;
XMP_Int64 dataSize = info.atomSize - headerSize;
qtFile->Seek ( dataSize, kXMP_SeekFromCurrent );
}
+ // Truncate only if the last box type was XMP boxes
+ // Refrain from truncating a known box as it
+ // might have some useful data which is incomplete
+ if ( fileSpace < 8 ||
+ ! ISOMedia::IsKnownBoxType ( info.atomType ) ||
+ ((info.atomType == ISOMedia::k_uuid) && IsXMPUUID(qtFile,info.atomSize-headerSize,true)) ||
+ (info.atomType == ISOMedia::k_XMP_)
+ ){
+
+ XMP_Error error ( kXMPErr_BadFileFormat,"Truncate outer EOF Garbage" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_Recoverable, error);
+ // Truncate the file. If fileSpace >= 8 then the loop exited early due to a bad atom, seek back
+ // to the atom's start. Otherwise, the loop exited because no more atoms are possible, no seek.
- // Truncate the file. If fileSpace >= 8 then the loop exited early due to a bad atom, seek back
- // to the atom's start. Otherwise, the loop exited because no more atoms are possible, no seek.
+ if ( fileSpace >= 8 ) qtFile->Seek ( -headerSize, kXMP_SeekFromCurrent );
+ XMP_Int64 currPos = qtFile->Offset();
+ qtFile->Truncate ( currPos );
+ }
+ else{
- if ( fileSpace >= 8 ) qtFile->Seek ( -headerSize, kXMP_SeekFromCurrent );
- XMP_Int64 currPos = qtFile->Offset();
- qtFile->Truncate ( currPos );
+ XMP_Error error ( kXMPErr_BadFileFormat,"Missing box Data at EOF" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_FileFatal, error);
+ }
} // AttemptFileRepair
@@ -1780,7 +1826,7 @@ static void AttemptFileRepair ( XMP_IO* qtFile, XMP_Int64 fileSpace, QTErrorMode
// CheckQTFileStructure
// ====================
-static void CheckQTFileStructure ( XMPFileHandler * thiz, bool doRepair )
+static void CheckQTFileStructure ( XMPFileHandler * thiz,bool doRepair, GenericErrorCallback * ec )
{
XMPFiles * parent = thiz->parent;
XMP_IO* fileRef = parent->ioRef;
@@ -1793,13 +1839,13 @@ static void CheckQTFileStructure ( XMPFileHandler * thiz, bool doRepair )
if ( status != kBadQT_NoError ) {
if ( doRepair || (status == kBadQT_SmallInner) || (status == kBadQT_SmallOuter) ) {
- AttemptFileRepair ( fileRef, fileSize, status ); // Will throw if the attempt fails.
+ AttemptFileRepair ( fileRef, fileSize, status,ec ); // Will throw if the attempt fails.
} else if ( status != kBadQT_SmallInner ) {
- XMP_Throw ( "Ill-formed QuickTime file", kXMPErr_BadFileFormat );
- } else {
- return; // ! Ignore these, QT seems to be able to handle them.
- // *** Might want to throw for check-only, ignore when repairing.
- }
+ //don't truncate Large Outer EOF garbage unless the client wants it to
+ // Clients can pass their intent by setting the flag kXMPFiles_OpenRepairFile
+ XMP_Error error ( kXMPErr_BadFileFormat,"Ill-formed QuickTime file" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_FileFatal, error);
+ }
}
} // CheckQTFileStructure;
@@ -1946,7 +1992,7 @@ typedef std::vector<SpaceInfo> FreeSpaceList;
static void CreateFreeSpaceList ( XMP_IO* fileRef, XMP_Uns64 fileSize,
XMP_Uns64 oldOffset, XMP_Uns32 oldSize, FreeSpaceList * spaceList )
{
- XMP_Uns64 boxPos, boxNext, adjacentFree;
+ XMP_Uns64 boxPos=0, boxNext=0, adjacentFree=0;
ISOMedia::BoxInfo currBox;
fileRef->Rewind();
@@ -2002,8 +2048,8 @@ void MPEG4_MetaHandler::CacheFileData()
const bool isUpdate = XMP_OptionIsSet ( openFlags, kXMPFiles_OpenForUpdate );
const bool doRepair = XMP_OptionIsSet ( openFlags, kXMPFiles_OpenRepairFile );
- if ( isUpdate && (parent->format == kXMP_MOVFile) ) {
- CheckQTFileStructure ( this, doRepair ); // Will throw for failure.
+ if ( isUpdate ) {
+ CheckQTFileStructure ( this, doRepair, &parent->errorCallback ); // Will throw for failure.
}
// Cache the top level 'moov' and 'uuid'/XMP boxes.
@@ -2045,13 +2091,7 @@ void MPEG4_MetaHandler::CacheFileData()
moovFound = true;
if ( uuidFound ) break; // Exit the loop when both are found.
- } else if ( (! uuidFound) && (currBox.boxType == ISOMedia::k_uuid) ) {
-
- if ( currBox.contentSize < 16 ) continue;
-
- XMP_Uns8 uuid [16];
- fileRef->ReadAll ( uuid, 16 );
- if ( memcmp ( uuid, ISOMedia::k_xmpUUID, 16 ) != 0 ) continue; // Check for the XMP GUID.
+ } else if ( (! uuidFound) && (currBox.boxType == ISOMedia::k_uuid) && IsXMPUUID(fileRef,currBox.contentSize) ) {
XMP_Uns64 fullUuidSize = currBox.headerSize + currBox.contentSize;
if ( fullUuidSize > moovBoxSizeLimit ) { // From here on we know 32-bit offsets are safe.
@@ -2073,7 +2113,10 @@ void MPEG4_MetaHandler::CacheFileData()
}
- if ( (! moovFound) && (! moovIgnored) ) XMP_Throw ( "No 'moov' box", kXMPErr_BadFileFormat );
+ if ( (! moovFound) && (! moovIgnored) ){
+ XMP_Error error ( kXMPErr_BadFileFormat,"No 'moov' box" );
+ XMPFileHandler::NotifyClient(&parent->errorCallback, kXMPErrSev_FileFatal, error);
+ }
} // MPEG4_MetaHandler::CacheFileData
@@ -2110,7 +2153,10 @@ void MPEG4_MetaHandler::ProcessXMP()
// Parse the cached 'moov' subtree, parse the preferred XMP.
- if ( this->moovMgr.fullSubtree.empty() ) XMP_Throw ( "No 'moov' box", kXMPErr_BadFileFormat );
+ if ( this->moovMgr.fullSubtree.empty() ) {
+ XMP_Error error ( kXMPErr_BadFileFormat,"No 'moov' box" );
+ XMPFileHandler::NotifyClient(&parent->errorCallback, kXMPErrSev_FileFatal, error);
+ }
this->moovMgr.ParseMemoryTree ( this->fileMode );
if ( (this->xmpBoxPos == 0) || (! haveISOFile) ) {
@@ -2168,6 +2214,7 @@ void MPEG4_MetaHandler::ProcessXMP()
if ( mvhdFound ) this->containsXMP |= ImportMVHDItems ( mvhdInfo, &this->xmpObj );
if ( cprtFound ) this->containsXMP |= ImportISOCopyrights ( cprtBoxes, &this->xmpObj );
+ if ( tmcdFound ) this->containsXMP |= ImportTimecodeItems ( this->tmcdInfo, this->tradQTMgr, &this->xmpObj );
} else { // This is a QuickTime file, either traditional or modern.
if ( mvhdFound ) this->containsXMP |= ImportMVHDItems ( mvhdInfo, &this->xmpObj );
@@ -2251,11 +2298,16 @@ bool MPEG4_MetaHandler::ParseTimecodeTrack()
XMP_Uns32 stsdEntryFormat = GetUns32BE ( &stsdRawEntry->format );
if ( stsdEntryFormat != ISOMedia::k_tmcd ) return false;
+ // If frame duration is zero it means tmcd sample is invalid
+ if(GetUns32BE(&stsdRawEntry->frameDuration)==0)
+ return false;
+
this->tmcdInfo.timeScale = GetUns32BE ( &stsdRawEntry->timeScale );
this->tmcdInfo.frameDuration = GetUns32BE ( &stsdRawEntry->frameDuration );
double floatCount = (double)this->tmcdInfo.timeScale / (double)this->tmcdInfo.frameDuration;
XMP_Uns8 expectedCount = (XMP_Uns8) (floatCount + 0.5);
+ if( expectedCount == 0 ) return false;
if ( expectedCount != stsdRawEntry->frameCount ) {
double countRatio = (double)stsdRawEntry->frameCount / (double)expectedCount;
this->tmcdInfo.timeScale = (XMP_Uns32) (((double)this->tmcdInfo.timeScale * countRatio) + 0.5);
@@ -2541,6 +2593,305 @@ void MPEG4_MetaHandler::UpdateTopLevelBox ( XMP_Uns64 oldOffset, XMP_Uns32 oldSi
} // MPEG4_MetaHandler::UpdateTopLevelBox
// =================================================================================================
+// AdjustOffset
+// ============
+//
+// A utility for OptimizeFileLayout, adjusts a 'stco' or 'co64' table entry for the new layout. The
+// map is keyed by the original box's last content offset, so that map.lower_bound does what we want.
+
+struct LayoutInfo {
+ XMP_Uns32 boxType;
+ XMP_Uns64 boxSize; // The full size, including the header.
+ XMP_Uns64 oldOffset, newOffset;
+ LayoutInfo() : boxType(0), boxSize(0), oldOffset(0), newOffset(0) {};
+ LayoutInfo ( XMP_Uns32 type, XMP_Uns64 size, XMP_Uns64 offset )
+ : boxType(type), boxSize(size), oldOffset(offset), newOffset(0) {};
+};
+
+typedef std::vector < LayoutInfo > LayoutVector;
+typedef std::map < XMP_Uns64, LayoutInfo* > LayoutMap;
+
+static XMP_Uns64 AdjustOffset ( XMP_Uns64 oldOffset, const LayoutMap & newMap , GenericErrorCallback * ec)
+{
+
+ LayoutMap::const_iterator mapEntry = newMap.lower_bound ( oldOffset );
+ if ( (mapEntry == newMap.end()) || (oldOffset < mapEntry->second->oldOffset) ) {
+ XMP_Error error ( kXMPErr_BadFileFormat,"Offset from 'stco' or 'co64' is not into kept box" );
+ XMPFileHandler::NotifyClient(ec, kXMPErrSev_FileFatal, error);
+ }
+
+ XMP_Assert ( (mapEntry->second->oldOffset <= oldOffset) &&
+ (oldOffset <= (mapEntry->second->oldOffset + mapEntry->second->boxSize)) );
+
+ return mapEntry->second->newOffset + (oldOffset - mapEntry->second->oldOffset);
+
+} // AdjustOffset
+
+// =================================================================================================
+// MPEG4_MetaHandler::OptimizeFileLayout
+// =====================================
+//
+// Make sure the file is acceptable for streaming use: the 'moov' and XMP 'uuid' boxes must be
+// before any 'mdat' box, other top level boxes after 'mdat' are accepted. If the file needs
+// optimization, it is fully rewritten in this order: 'ftyp' (if ISO), 'moov', XMP 'uuid', other
+// non-'mdat', all 'mdat' boxes. Top level 'free' and 'skip' boxes will be removed. Offsets in the
+// 'stco' and 'co64' boxes will be adjusted.
+
+void MPEG4_MetaHandler::OptimizeFileLayout()
+{
+ XMP_IO* originalFile = this->parent->ioRef;
+ XMP_Uns64 originalSize = originalFile->Length();
+
+ XMP_AbortProc abortProc = parent->abortProc;
+ void * abortArg = parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Uns64 currPos, nextPos;
+ ISOMedia::BoxInfo currBox;
+
+ size_t boxCount = 0;
+ size_t moovIndex = 0, xmpIndex = 0;
+
+ // Go through the top level boxes to see if the file layout needs to be optimized. Look until
+ // we find both the 'moov' and XMP 'uuid' boxes, saving their relative index in the file.
+
+ bool needsOptimization = false;
+ bool moovFound = false, xmpFound = false, mdatFound = false;
+
+ for ( currPos = 0; currPos < originalSize; currPos = nextPos ) {
+
+ nextPos = ISOMedia::GetBoxInfo ( originalFile, currPos, originalSize, &currBox );
+ if ( (currBox.boxType == ISOMedia::k_free) ||
+ (currBox.boxType == ISOMedia::k_skip) ||
+ (currBox.boxType == ISOMedia::k_wide) ) continue;
+
+ ++boxCount; // ! Must be counted for all, continue statements below skip an end of loop increment.
+
+ if ( currBox.boxType == ISOMedia::k_mdat ) {
+
+ mdatFound = true;
+ XMP_Assert ( (! moovFound) | (! xmpFound) ); // The other cases should be exiting.
+
+ } else if ( currBox.boxType == ISOMedia::k_moov ) {
+
+ moovFound = true;
+ moovIndex = boxCount-1; // Need later for optimization.
+ needsOptimization = mdatFound;
+ if ( xmpFound ) break; // Don't need to look further.
+
+ } else if ( currBox.boxType == ISOMedia::k_uuid && IsXMPUUID(originalFile,currBox.contentSize) ) {
+
+ xmpFound = true;
+ xmpIndex = boxCount-1; // Need later for optimization.
+ needsOptimization = mdatFound;
+ if ( moovFound ) break; // Don't need to look further.
+
+ }
+
+ }
+
+ if ( ! needsOptimization ) return;
+
+ // The file needs to be optimized. Make sure that a file over 4 GB has 'co64', not 'stco' boxes.
+ // These are needed to hold 64-bit offsets. We don't go to the effort of changing from 'stco'
+ // to 'co64', the file needs to be OK from the start. (Yes, this eliminates a marginal case of
+ // a file growing beyond 4 GB due to metadata growth.)
+
+ if ( originalSize >= 0xFFFFFFFF ) {
+
+ MOOV_Manager::BoxRef moovRef, trakRef, tempRef, stcoRef;
+ MOOV_Manager::BoxInfo boxInfo;
+
+ moovRef = this->moovMgr.GetBox ( "moov", &boxInfo );
+ XMP_Enforce ( moovRef != 0 );
+
+ for ( size_t i = 0, limit = boxInfo.childCount; i < limit; ++i ) {
+
+ trakRef = this->moovMgr.GetNthChild ( moovRef, i, &boxInfo );
+ if ( boxInfo.boxType != ISOMedia::k_trak ) continue;
+
+ tempRef = this->moovMgr.GetTypeChild ( trakRef, ISOMedia::k_mdia, 0 );
+ if ( tempRef == 0 ) continue;
+ tempRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_minf, 0 );
+ if ( tempRef == 0 ) continue;
+ tempRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_stbl, 0 );
+ if ( tempRef == 0 ) continue;
+
+ stcoRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_stco, 0 );
+ if ( stcoRef != 0 ) {
+ XMP_Error error ( kXMPErr_BadFileFormat,"Large MPEG-4 file must use 'co64' boxes" );
+ XMPFileHandler::NotifyClient(&parent->errorCallback, kXMPErrSev_FileFatal, error);
+ }
+
+ }
+
+ }
+
+ // Build a vector of info for the top level boxes, ignoring 'free', 'skip', and 'wide' boxes.
+ // Then determine the new offsets and create a map keyed by the new offset.
+
+ // ! The box indices saved in the prior loop must match those in the vector built here!
+
+ LayoutVector fileBoxes;
+ LayoutMap optLayout;
+
+ for ( currPos = 0; currPos < originalSize; currPos = nextPos ) {
+ nextPos = ISOMedia::GetBoxInfo ( originalFile, currPos, originalSize, &currBox );
+ if ( (currBox.boxType == ISOMedia::k_free) ||
+ (currBox.boxType == ISOMedia::k_skip) ||
+ (currBox.boxType == ISOMedia::k_wide) ) continue;
+ --boxCount; // For sanity check below.
+ fileBoxes.push_back ( LayoutInfo ( currBox.boxType, (currBox.headerSize + currBox.contentSize), currPos ) );
+ }
+
+ XMP_Assert ( boxCount == 0 ); // Must get the same count in both loops.
+ XMP_Assert ( fileBoxes.size() >= 2 ); // At least 'mdat', and 'moov' or XMP 'uuid'.
+ XMP_Assert ( (!moovFound) || (fileBoxes[moovIndex].boxType == ISOMedia::k_moov) );
+ XMP_Assert ( (!xmpFound) || (fileBoxes[xmpIndex].boxType == ISOMedia::k_uuid) );
+
+ size_t currIndex = 0, limit = fileBoxes.size();
+ XMP_Uns64 newSize = 0;
+
+ if ( fileBoxes[0].boxType == ISOMedia::k_ftyp ) {
+ optLayout.insert ( optLayout.end(), LayoutMap::value_type ( 0, &fileBoxes[0] ) );
+ newSize = fileBoxes[0].boxSize;
+ currIndex = 1; // Keep the 'ftyp' box in front.
+ }
+
+ if ( moovFound ) {
+ optLayout.insert ( optLayout.end(), LayoutMap::value_type ( newSize, &fileBoxes[moovIndex] ) );
+ fileBoxes[moovIndex].newOffset = newSize;
+ newSize += fileBoxes[moovIndex].boxSize;
+ }
+
+ if ( xmpFound ) {
+ optLayout.insert ( optLayout.end(), LayoutMap::value_type ( newSize, &fileBoxes[xmpIndex] ) );
+ fileBoxes[xmpIndex].newOffset = newSize;
+ newSize += fileBoxes[xmpIndex].boxSize;
+ }
+
+ for ( ; currIndex < limit; ++currIndex ) { // Add all of the other non-'mdat' boxes to the map.
+ if ( moovFound && (currIndex == moovIndex) ) continue;
+ if ( xmpFound && (currIndex == xmpIndex) ) continue;
+ if ( fileBoxes[currIndex].boxType == ISOMedia::k_mdat ) continue;
+ optLayout.insert ( optLayout.end(), LayoutMap::value_type ( newSize, &fileBoxes[currIndex] ) );
+ fileBoxes[currIndex].newOffset = newSize;
+ newSize += fileBoxes[currIndex].boxSize;
+ }
+
+ for ( currIndex = 0; currIndex < limit; ++currIndex ) { // Add all of the 'mdat' boxes to the map.
+ if ( fileBoxes[currIndex].boxType != ISOMedia::k_mdat ) continue;
+ optLayout.insert ( optLayout.end(), LayoutMap::value_type ( newSize, &fileBoxes[currIndex] ) );
+ fileBoxes[currIndex].newOffset = newSize;
+ newSize += fileBoxes[currIndex].boxSize;
+ }
+
+ // Adjust the progress tracking if necessary.
+
+ XMP_ProgressTracker * progressTracker = this->parent->progressTracker;
+ if ( progressTracker != 0 ) {
+ XMP_Assert ( progressTracker->WorkInProgress() );
+ progressTracker->AddTotalWork ( (float) newSize );
+ }
+
+ // Create a temp file for the optimized layout, write it, update the offset tables.
+
+ XMP_IO* tempFile = originalFile->DeriveTemp();
+ XMP_Enforce ( tempFile != 0 );
+
+ // Iterate the map and write the new layout.
+
+ LayoutMap::iterator layoutPos = optLayout.begin();
+ LayoutMap::iterator layoutEnd = optLayout.end();
+
+ for ( ; layoutPos != layoutEnd; ++layoutPos ) {
+ LayoutInfo * currBox = layoutPos->second;
+ XMP_Assert ( (XMP_Int64)currBox->newOffset == tempFile->Length() );
+ originalFile->Seek ( currBox->oldOffset, kXMP_SeekFromStart );
+ XIO::Copy ( originalFile, tempFile, currBox->boxSize, abortProc, abortArg );
+ }
+
+ // Update the offset tables in the temp file. Create a layout map ordered by the last actual
+ // offset of the old box's content to enable fast lookup within AdjustOffset.
+
+ LayoutMap oldEndMap;
+ for ( size_t i = 0, limit = fileBoxes.size(); i < limit; ++i ) {
+ XMP_Uns64 oldEnd = fileBoxes[i].oldOffset + fileBoxes[i].boxSize - 1; // ! Want the last actual offset!
+ oldEndMap.insert ( oldEndMap.end(), LayoutMap::value_type ( oldEnd, &fileBoxes[i] ) );
+ }
+
+ MOOV_Manager::BoxRef moovRef, trakRef, tempRef, stcoRef, co64Ref;
+ MOOV_Manager::BoxInfo boxInfo;
+
+ moovRef = this->moovMgr.GetBox ( "moov", &boxInfo );
+ XMP_Enforce ( moovRef != 0 );
+
+ for ( size_t i = 0, limit = boxInfo.childCount; i < limit; ++i ) {
+
+ trakRef = this->moovMgr.GetNthChild ( moovRef, i, &boxInfo );
+ if ( boxInfo.boxType != ISOMedia::k_trak ) continue;
+
+ tempRef = this->moovMgr.GetTypeChild ( trakRef, ISOMedia::k_mdia, 0 );
+ if ( tempRef == 0 ) continue;
+ tempRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_minf, 0 );
+ if ( tempRef == 0 ) continue;
+ tempRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_stbl, 0 );
+ if ( tempRef == 0 ) continue;
+
+ co64Ref = 0;
+ XMP_Uns32 entrySize = 4;
+ stcoRef = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_stco, &boxInfo );
+ if ( stcoRef == 0 ) {
+ co64Ref = this->moovMgr.GetTypeChild ( tempRef, ISOMedia::k_co64, &boxInfo );
+ if ( co64Ref == 0 ) continue;
+ entrySize = 8;
+ }
+
+ XMP_Uns32 offsetCount = GetUns32BE ( boxInfo.content + 4 );
+ if ( boxInfo.contentSize < (4+4 + entrySize*offsetCount) ) {
+ XMP_Error error ( kXMPErr_BadFileFormat, "Bad 'stco' size or count" );
+ XMPFileHandler::NotifyClient(&parent->errorCallback, kXMPErrSev_FileFatal, error);
+ }
+
+ if ( stcoRef != 0 ) {
+
+ XMP_Uns64 stcoTableOffset = fileBoxes[moovIndex].newOffset +
+ (XMP_Uns64) this->moovMgr.GetParsedOffset ( stcoRef ) +
+ (XMP_Uns64) this->moovMgr.GetHeaderSize ( stcoRef ) + 4+4;
+ tempFile->Seek ( stcoTableOffset, kXMP_SeekFromStart );
+
+ XMP_Uns32 * rawOldU32 = (XMP_Uns32*) (boxInfo.content + 4+4);
+ for ( XMP_Uns32 i = 0; i < offsetCount; ++i, ++rawOldU32 ) {
+ XMP_Uns64 newOffset = AdjustOffset ( (XMP_Uns64)GetUns32BE(rawOldU32), oldEndMap,&parent->errorCallback );
+ XMP_Uns32 u32 = MakeUns32BE ( (XMP_Uns32)newOffset );
+ tempFile->Write ( &u32, 4 );
+ }
+
+ } else {
+
+ XMP_Uns64 co64TableOffset = fileBoxes[moovIndex].newOffset +
+ (XMP_Uns64) this->moovMgr.GetParsedOffset ( co64Ref ) +
+ (XMP_Uns64) this->moovMgr.GetHeaderSize ( co64Ref ) + 4+4;
+ tempFile->Seek ( co64TableOffset, kXMP_SeekFromStart );
+
+ XMP_Uns64 * rawOldU64 = (XMP_Uns64*) (boxInfo.content + 4+4);
+ for ( XMP_Uns32 i = 0; i < offsetCount; ++i, ++rawOldU64 ) {
+ XMP_Uns64 newOffset = AdjustOffset ( GetUns64BE(rawOldU64), oldEndMap,&parent->errorCallback );
+ XMP_Uns64 u64 = MakeUns64BE ( newOffset );
+ tempFile->Write ( &u64, 8 );
+ }
+
+ }
+
+ }
+
+ // Swap the temp and original files.
+
+ originalFile->AbsorbTemp();
+
+} // MPEG4_MetaHandler::OptimizeFileLayout
+
+// =================================================================================================
// MPEG4_MetaHandler::UpdateFile
// =============================
//
@@ -2553,7 +2904,15 @@ void MPEG4_MetaHandler::UpdateTopLevelBox ( XMP_Uns64 oldOffset, XMP_Uns32 oldSi
void MPEG4_MetaHandler::UpdateFile ( bool doSafeUpdate )
{
+
+ bool optimizeFileLayout = false;
+ if ( this->parent)
+ {
+ optimizeFileLayout = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OptimizeFileLayout );
+ }
+
if ( ! this->needsUpdate ) { // If needsUpdate is set then at least the XMP changed.
+ if ( optimizeFileLayout ) this->OptimizeFileLayout();
return;
}
@@ -2660,6 +3019,9 @@ void MPEG4_MetaHandler::UpdateFile ( bool doSafeUpdate )
}
+ // Finally, optimize the file layout if asked.
+ if ( optimizeFileLayout ) this->OptimizeFileLayout();
+
if ( localProgressTracking ) progressTracker->WorkComplete();
} // MPEG4_MetaHandler::UpdateFile
@@ -2698,4 +3060,4 @@ void MPEG4_MetaHandler::WriteTempFile ( XMP_IO* tempRef )
} // MPEG4_MetaHandler::WriteTempFile
-// =================================================================================================
+// ================================================================================================= \ No newline at end of file
diff --git a/XMPFiles/source/FileHandlers/MPEG4_Handler.hpp b/XMPFiles/source/FileHandlers/MPEG4_Handler.hpp
index 49c749f..9ad06bb 100644
--- a/XMPFiles/source/FileHandlers/MPEG4_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/MPEG4_Handler.hpp
@@ -78,6 +78,8 @@ private:
void UpdateTopLevelBox ( XMP_Uns64 oldOffset, XMP_Uns32 oldSize, const XMP_Uns8 * newBox, XMP_Uns32 newSize );
+ void OptimizeFileLayout();
+
XMP_Uns8 fileMode;
bool havePreferredXMP;
XMP_Uns64 xmpBoxPos; // The file offset of the XMP box (the size field, not the content).
diff --git a/XMPFiles/source/FileHandlers/P2_Handler.cpp b/XMPFiles/source/FileHandlers/P2_Handler.cpp
index 8e692e9..4a2e508 100644
--- a/XMPFiles/source/FileHandlers/P2_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/P2_Handler.cpp
@@ -18,10 +18,11 @@
#include "source/IOUtils.hpp"
#include "XMPFiles/source/FileHandlers/P2_Handler.hpp"
+#include "XMPFiles/source/FormatSupport/P2_Support.hpp"
#include "XMPFiles/source/FormatSupport/PackageFormat_Support.hpp"
-#include "third-party/zuid/interfaces/MD5.h"
#include <cmath>
+#include <sstream>
using namespace std;
@@ -263,7 +264,7 @@ XMPFileHandler * P2_MetaHandlerCTor ( XMPFiles * parent )
// P2_MetaHandler::P2_MetaHandler
// ==============================
-P2_MetaHandler::P2_MetaHandler ( XMPFiles * _parent ) : expat(0), clipMetadata(0), clipContent(0)
+P2_MetaHandler::P2_MetaHandler ( XMPFiles * _parent )
{
this->parent = _parent; // Inherited, can't set in the prefix.
@@ -283,6 +284,30 @@ P2_MetaHandler::P2_MetaHandler ( XMPFiles * _parent ) : expat(0), clipMetadata(0
XIO::SplitLeafName ( &this->rootPath, &this->clipName );
+ std::string xmlPath;
+ if ( this->MakeClipFilePath ( &xmlPath, ".XML", true ) )
+ {
+ try
+ {
+
+ p2ClipManager.ProcessClip(xmlPath);
+ std::string* clipnm = p2ClipManager.GetManagedClip()->GetClipName();
+ if ( clipnm !=0 )
+ {
+ std::string newpath,leafname;
+ newpath = p2ClipManager.GetManagedClip()->GetXMPFilePath();
+ XIO::SplitLeafName(&newpath,&leafname);
+ if ( leafname == std::string(*clipnm+ ".XMP") )
+ {
+ this->clipName=*clipnm;
+ }
+ }
+ }
+ catch(...)
+ {
+ }
+ }
+
} // P2_MetaHandler::P2_MetaHandler
// =================================================================================================
@@ -292,7 +317,6 @@ P2_MetaHandler::P2_MetaHandler ( XMPFiles * _parent ) : expat(0), clipMetadata(0
P2_MetaHandler::~P2_MetaHandler()
{
- this->CleanupLegacyXML();
if ( this->parent->tempPtr != 0 ) {
free ( this->parent->tempPtr );
this->parent->tempPtr = 0;
@@ -314,79 +338,36 @@ bool P2_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix
} // P2_MetaHandler::MakeClipFilePath
-// =================================================================================================
-// P2_MetaHandler::CleanupLegacyXML
-// ================================
-
-void P2_MetaHandler::CleanupLegacyXML()
-{
- if ( this->expat != 0 ) { delete ( this->expat ); this->expat = 0; }
-
- clipMetadata = 0; // ! Was a pointer into the expat tree.
- clipContent = 0; // ! Was a pointer into the expat tree.
-
-} // P2_MetaHandler::CleanupLegacyXML
// =================================================================================================
-// P2_MetaHandler::DigestLegacyItem
-// ================================
-
-void P2_MetaHandler::DigestLegacyItem ( MD5_CTX & md5Context, XML_NodePtr legacyContext, XMP_StringPtr legacyPropName )
-{
- XML_NodePtr legacyProp = legacyContext->GetNamedElement ( this->p2NS.c_str(), legacyPropName );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &md5Context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
-} // P2_MetaHandler::DigestLegacyItem
-
-// =================================================================================================
-// P2_MetaHandler::DigestLegacyRelations
-// =====================================
+// P2_MetaHandler::SetXMPPropertyFromLegacyXML
+// ===========================================
-void P2_MetaHandler::DigestLegacyRelations ( MD5_CTX & md5Context )
+void P2_MetaHandler::SetXMPPropertyFromLegacyXML ( bool digestFound,
+ XMP_VarString* refContext,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool isLocalized )
{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_Node * legacyContext = this->clipContent->GetNamedElement ( p2NS, "Relation" );
- if ( legacyContext != 0 ) {
-
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalShotID" );
- XML_Node * legacyConnectionContext = legacyContext = this->clipContent->GetNamedElement ( p2NS, "Connection" );
-
- if ( legacyConnectionContext != 0 ) {
-
- legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Top" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalClipID" );
- }
-
- legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Previous" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalClipID" );
- }
-
- legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Next" );
+ if ( digestFound || (! this->xmpObj.DoesPropertyExist ( schemaNS, propName )) ) {
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalClipID" );
+ if ( refContext !=0 )
+ {
+ if ( isLocalized ) {
+ this->xmpObj.SetLocalizedText ( schemaNS, propName, "", "x-default", refContext->c_str(), kXMP_DeleteExisting );
+ } else {
+ this->xmpObj.SetProperty ( schemaNS, propName, refContext->c_str(), kXMP_DeleteExisting );
}
-
+ this->containsXMP = true;
}
-
}
-
-} // P2_MetaHandler::DigestLegacyRelations
+} // P2_MetaHandler::SetXMPPropertyFromLegacyXML
// =================================================================================================
// P2_MetaHandler::SetXMPPropertyFromLegacyXML
// ===========================================
-
void P2_MetaHandler::SetXMPPropertyFromLegacyXML ( bool digestFound,
XML_NodePtr legacyContext,
XMP_StringPtr schemaNS,
@@ -394,89 +375,58 @@ void P2_MetaHandler::SetXMPPropertyFromLegacyXML ( bool digestFound,
XMP_StringPtr legacyPropName,
bool isLocalized )
{
+ XMP_StringPtr p2NS = this->p2ClipManager.GetManagedClip()->GetP2RootNode()->ns.c_str();
+ XML_NodePtr legacyProp = legacyContext->GetNamedElement ( p2NS, legacyPropName );
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( schemaNS, propName )) ) {
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyProp = legacyContext->GetNamedElement ( p2NS, legacyPropName );
+ if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
+ XMP_StringPtr legacyValue = legacyProp->GetLeafContentValue();
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
+ if ( ( legacyValue != 0 ) &&
+ ( ( *legacyValue != 0 ) || (! this->xmpObj.DoesPropertyExist ( schemaNS, propName )) )) {
if ( isLocalized ) {
- this->xmpObj.SetLocalizedText ( schemaNS, propName, "", "x-default", legacyProp->GetLeafContentValue(), kXMP_DeleteExisting );
+ this->xmpObj.SetLocalizedText ( schemaNS, propName, "", "x-default", legacyValue, kXMP_DeleteExisting );
} else {
- this->xmpObj.SetProperty ( schemaNS, propName, legacyProp->GetLeafContentValue(), kXMP_DeleteExisting );
+ this->xmpObj.SetProperty ( schemaNS, propName, legacyValue, kXMP_DeleteExisting );
}
this->containsXMP = true;
}
-
}
-} // P2_MetaHandler::SetXMPPropertyFromLegacyXML
-
+}
// =================================================================================================
// P2_MetaHandler::SetRelationsFromLegacyXML
// =========================================
void P2_MetaHandler::SetRelationsFromLegacyXML ( bool digestFound )
{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyRelationContext = this->clipContent->GetNamedElement ( p2NS, "Relation" );
-
- // P2 Relation blocks are optional -- they're only present when a clip is part of a multi-clip shot.
- if ( legacyRelationContext != 0 ) {
+ P2_Clip* p2Clip=this->p2ClipManager.GetManagedClip();
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "relation" )) ) {
-
- XML_NodePtr legacyProp = legacyRelationContext->GetNamedElement ( p2NS, "GlobalShotID" );
- std::string relationString;
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
+ if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "relation" )) ) {
+
+ XMP_VarString* globalShotId = p2Clip->GetShotId() ;
+ std::string relationString ;
+ if ( ( globalShotId != 0 ) ) {
- this->xmpObj.DeleteProperty ( kXMP_NS_DC, "relation" );
- relationString = std::string("globalShotID:") + legacyProp->GetLeafContentValue();
+ this->xmpObj.DeleteProperty ( kXMP_NS_DC, "relation" );
+ relationString = std::string("globalShotID:") + *globalShotId ;
+ this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
+ this->containsXMP = true;
+
+ XMP_VarString* topId = p2Clip->GetTopClipId() ;
+ if ( topId != 0 ) {
+ relationString = std::string("topGlobalClipID:") + *topId ;
+ this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
+ }
+ XMP_VarString* prevId = p2Clip->GetPreviousClipId() ;
+ if ( prevId != 0 ) {
+ relationString = std::string("previousGlobalClipID:") + *prevId ;
+ this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
+ }
+ XMP_VarString* nextId = p2Clip->GetNextClipId() ;
+ if ( nextId != 0 ) {
+ relationString = std::string("nextGlobalClipID:") + *nextId ;
this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
- this->containsXMP = true;
-
- XML_NodePtr legacyConnectionContext = legacyRelationContext->GetNamedElement ( p2NS, "Connection" );
-
- if ( legacyConnectionContext != 0 ) {
-
- XML_NodePtr legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Top" );
-
- if ( legacyContext != 0 ) {
- legacyProp = legacyContext->GetNamedElement ( p2NS, "GlobalClipID" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- relationString = std::string("topGlobalClipID:") + legacyProp->GetLeafContentValue();
- this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
- }
- }
-
- legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Previous" );
-
- if ( legacyContext != 0 ) {
- legacyProp = legacyContext->GetNamedElement ( p2NS, "GlobalClipID" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- relationString = std::string("previousGlobalClipID:") + legacyProp->GetLeafContentValue();
- this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
- }
- }
-
- legacyContext = legacyConnectionContext->GetNamedElement ( p2NS, "Next" );
-
- if ( legacyContext != 0 ) {
- legacyProp = legacyContext->GetNamedElement ( p2NS, "GlobalClipID" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- relationString = std::string("nextGlobalClipID:") + legacyProp->GetLeafContentValue();
- this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, relationString );
- }
- }
-
- }
-
}
}
@@ -491,8 +441,9 @@ void P2_MetaHandler::SetRelationsFromLegacyXML ( bool digestFound )
void P2_MetaHandler::SetAudioInfoFromLegacyXML ( bool digestFound )
{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyAudioContext = this->clipContent->GetNamedElement ( p2NS, "EssenceList" );
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
+ XML_NodePtr legacyAudioContext = p2Clip->GetEssenceListNode();
if ( legacyAudioContext != 0 ) {
@@ -537,8 +488,9 @@ void P2_MetaHandler::SetAudioInfoFromLegacyXML ( bool digestFound )
void P2_MetaHandler::SetVideoInfoFromLegacyXML ( bool digestFound )
{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyVideoContext = this->clipContent->GetNamedElement ( p2NS, "EssenceList" );
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
+ XML_NodePtr legacyVideoContext = p2Clip->GetEssenceListNode();
if ( legacyVideoContext != 0 ) {
@@ -562,20 +514,21 @@ void P2_MetaHandler::SetDurationFromLegacyXML ( bool digestFound )
{
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "duration" )) ) {
+
+ P2_SpannedClip* p2Clip=this->p2ClipManager.GetSpannedClip();
+ XMP_Uns32 dur = p2Clip->GetDuration();
+ XMP_VarString* editunit= p2Clip->GetEditUnit();
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyDurationProp = this->clipContent->GetNamedElement ( p2NS, "Duration" );
- XML_NodePtr legacyEditUnitProp = this->clipContent->GetNamedElement ( p2NS, "EditUnit" );
-
- if ( (legacyDurationProp != 0) && ( legacyEditUnitProp != 0 ) &&
- legacyDurationProp->IsLeafContentNode() && legacyEditUnitProp->IsLeafContentNode() ) {
+ if ( ( dur != 0) && ( editunit != 0 ) ) {
+ ostringstream duration;
+ duration<<dur;
this->xmpObj.DeleteProperty ( kXMP_NS_DM, "duration" );
this->xmpObj.SetStructField ( kXMP_NS_DM, "duration",
- kXMP_NS_DM, "value", legacyDurationProp->GetLeafContentValue() );
+ kXMP_NS_DM, "value", duration.str().c_str() );
this->xmpObj.SetStructField ( kXMP_NS_DM, "duration",
- kXMP_NS_DM, "scale", legacyEditUnitProp->GetLeafContentValue() );
+ kXMP_NS_DM, "scale", editunit->c_str() );
this->containsXMP = true;
}
@@ -593,8 +546,9 @@ void P2_MetaHandler::SetVideoFrameInfoFromLegacyXML ( XML_NodePtr legacyVideoCon
// Map the P2 Codec field to various dynamic media schema fields.
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "videoFrameSize" )) ) {
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
+
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "Codec" );
if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
@@ -631,7 +585,8 @@ void P2_MetaHandler::SetVideoFrameInfoFromLegacyXML ( XML_NodePtr legacyVideoCon
// This is AVC-Intra footage. The framerate and PAR depend on the "class" attribute in the P2 XML.
const XMP_StringPtr codecClass = legacyProp->GetAttrValue( "Class" );
-
+ if ( codecClass != 0 )
+ dmVideoCompressor = "AVC-Intra"; // initializing with default value
if ( XMP_LitMatch ( codecClass, "100" ) ) {
dmVideoCompressor = "AVC-Intra 100";
@@ -735,7 +690,8 @@ void P2_MetaHandler::SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoCont
// Translate start timecode to the format specified by the dynamic media schema.
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "startTimecode" )) ) {
- XMP_StringPtr p2NS = this->p2NS.c_str();
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "StartTimecode" );
if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
@@ -821,7 +777,8 @@ void P2_MetaHandler::SetGPSPropertyFromLegacyXML ( XML_NodePtr legacyLocationCo
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_EXIF, propName )) ) {
- XMP_StringPtr p2NS = this->p2NS.c_str();
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
XML_NodePtr legacyGPSProp = legacyLocationContext->GetNamedElement ( p2NS, legacyPropName );
if ( ( legacyGPSProp != 0 ) && legacyGPSProp->IsLeafContentNode() ) {
@@ -866,7 +823,8 @@ void P2_MetaHandler::SetAltitudeFromLegacyXML ( XML_NodePtr legacyLocationConte
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_EXIF, "GPSAltitude" )) ) {
- XMP_StringPtr p2NS = this->p2NS.c_str();
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
XML_NodePtr legacyAltitudeProp = legacyLocationContext->GetNamedElement ( p2NS, "Altitude" );
if ( ( legacyAltitudeProp != 0 ) && legacyAltitudeProp->IsLeafContentNode() ) {
@@ -913,22 +871,32 @@ void P2_MetaHandler::SetAltitudeFromLegacyXML ( XML_NodePtr legacyLocationConte
XML_Node * P2_MetaHandler::ForceChildElement ( XML_Node * parent, XMP_StringPtr localName, XMP_Int32 indent , XMP_Bool insertAtFront )
{
XML_Node * wsNodeBefore, * wsNodeAfter;
- XML_Node * childNode = parent->GetNamedElement ( this->p2NS.c_str(), localName );
+ P2_Clip* p2Clip = this->p2ClipManager.GetManagedClip() ;
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
+ XML_Node * childNode = parent->GetNamedElement ( p2NS, localName );
//
if ( childNode == 0 ) {
// The indenting is a hack, assuming existing 2 spaces per level.
-
- wsNodeBefore = new XML_Node ( parent, "", kCDataNode );
- wsNodeBefore->value = " "; // Add 2 spaces to the existing WS before the parent's close tag.
-
- childNode = new XML_Node ( parent, localName, kElemNode );
- childNode->ns = parent->ns;
- childNode->nsPrefixLen = parent->nsPrefixLen;
- childNode->name.insert ( 0, parent->name, 0, parent->nsPrefixLen );
-
- wsNodeAfter = new XML_Node ( parent, "", kCDataNode );
+ try {
+ wsNodeBefore = new XML_Node ( parent, "", kCDataNode );
+ wsNodeBefore->value = " "; // Add 2 spaces to the existing WS before the parent's close tag.
+
+ childNode = new XML_Node ( parent, localName, kElemNode );
+ childNode->ns = parent->ns;
+ childNode->nsPrefixLen = parent->nsPrefixLen;
+ childNode->name.insert ( 0, parent->name, 0, parent->nsPrefixLen );
+
+ wsNodeAfter = new XML_Node ( parent, "", kCDataNode );
+ } catch (...) {
+ if (wsNodeBefore)
+ delete wsNodeBefore;
+ if (childNode)
+ delete childNode;
+
+ throw;
+ }
wsNodeAfter->value = '\n';
for ( ; indent > 1; --indent ) wsNodeAfter->value += " "; // Indent less 1, to "outdent" the parent's close.
@@ -959,184 +927,22 @@ XML_Node * P2_MetaHandler::ForceChildElement ( XML_Node * parent, XMP_StringPtr
} // P2_MetaHandler::ForceChildElement
// =================================================================================================
-// P2_MetaHandler::MakeLegacyDigest
-// =================================
-
-// *** Early hack version.
-
-#define kHexDigits "0123456789ABCDEF"
-
-void P2_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
-{
- digestStr->erase();
- if ( this->clipMetadata == 0 ) return; // Bail if we don't have any legacy XML.
- XMP_Assert ( this->expat != 0 );
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyContext;
- MD5_CTX md5Context;
- unsigned char digestBin [16];
- MD5Init ( &md5Context );
-
- legacyContext = this->clipContent;
- this->DigestLegacyItem ( md5Context, legacyContext, "ClipName" );
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalClipID" );
- this->DigestLegacyItem ( md5Context, legacyContext, "Duration" );
- this->DigestLegacyItem ( md5Context, legacyContext, "EditUnit" );
- this->DigestLegacyRelations ( md5Context );
-
- legacyContext = this->clipContent->GetNamedElement ( p2NS, "EssenceList" );
-
- if ( legacyContext != 0 ) {
-
- XML_NodePtr videoContext = legacyContext->GetNamedElement ( p2NS, "Video" );
-
- if ( videoContext != 0 ) {
- this->DigestLegacyItem ( md5Context, videoContext, "AspectRatio" );
- this->DigestLegacyItem ( md5Context, videoContext, "Codec" );
- this->DigestLegacyItem ( md5Context, videoContext, "FrameRate" );
- this->DigestLegacyItem ( md5Context, videoContext, "StartTimecode" );
- }
-
- XML_NodePtr audioContext = legacyContext->GetNamedElement ( p2NS, "Audio" );
-
- if ( audioContext != 0 ) {
- this->DigestLegacyItem ( md5Context, audioContext, "SamplingRate" );
- this->DigestLegacyItem ( md5Context, audioContext, "BitsPerSample" );
- }
-
- }
-
- legacyContext = this->clipMetadata;
- this->DigestLegacyItem ( md5Context, legacyContext, "UserClipName" );
- this->DigestLegacyItem ( md5Context, legacyContext, "ShotMark" );
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Access" );
- /* Rather return than create the digest because the "Access" element is listed as "required" in the P2 spec.
- So a P2 file without an "Access" element does not follow the spec and might be corrupt.*/
- if ( legacyContext == 0 ) return;
-
- this->DigestLegacyItem ( md5Context, legacyContext, "Creator" );
- this->DigestLegacyItem ( md5Context, legacyContext, "CreationDate" );
- this->DigestLegacyItem ( md5Context, legacyContext, "LastUpdateDate" );
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Shoot" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "Shooter" );
-
- legacyContext = legacyContext->GetNamedElement ( p2NS, "Location" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "PlaceName" );
- this->DigestLegacyItem ( md5Context, legacyContext, "Longitude" );
- this->DigestLegacyItem ( md5Context, legacyContext, "Latitude" );
- this->DigestLegacyItem ( md5Context, legacyContext, "Altitude" );
- }
- }
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Scenario" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "SceneNo." );
- this->DigestLegacyItem ( md5Context, legacyContext, "TakeNo." );
- }
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Device" );
-
- if ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "Manufacturer" );
- this->DigestLegacyItem ( md5Context, legacyContext, "SerialNo." );
- this->DigestLegacyItem ( md5Context, legacyContext, "ModelName" );
- }
-
- MD5Final ( digestBin, &md5Context );
-
- char buffer [40];
- for ( int in = 0, out = 0; in < 16; in += 1, out += 2 ) {
- XMP_Uns8 byte = digestBin[in];
- buffer[out] = kHexDigits [ byte >> 4 ];
- buffer[out+1] = kHexDigits [ byte & 0xF ];
- }
- buffer[32] = 0;
- digestStr->append ( buffer );
-
-} // P2_MetaHandler::MakeLegacyDigest
-
-// =================================================================================================
-// P2_MetaHandler::GetFileModDate
-// ==============================
-
-static inline bool operator< ( const XMP_DateTime & left, const XMP_DateTime & right ) {
- int compare = SXMPUtils::CompareDateTime ( left, right );
- return (compare < 0);
-}
-
-bool P2_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
-{
-
- // The P2 locations of metadata:
- // CONTENTS/
- // CLIP/
- // 0001AB.XML
- // 0001AB.XMP
-
- bool ok, haveDate = false;
- std::string fullPath;
- XMP_DateTime oneDate, junkDate;
- if ( modDate == 0 ) modDate = &junkDate;
-
- ok = this->MakeClipFilePath ( &fullPath, ".XML", true /* checkFile */ );
- if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
- if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
- haveDate = true;
- }
-
- ok = this->MakeClipFilePath ( &fullPath, ".XMP", true /* checkFile */ );
- if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
- if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
- haveDate = true;
- }
-
- return haveDate;
-
-} // P2_MetaHandler::GetFileModDate
-
-// =================================================================================================
-// P2_MetaHandler::FillMetadataFiles
-// =================================
-void P2_MetaHandler::FillMetadataFiles ( std::vector<std::string>* metadataFiles )
-{
- std::string noExtPath, filePath;
-
- noExtPath = rootPath + kDirChar + "CONTENTS" + kDirChar + "CLIP" + kDirChar + clipName;
-
- filePath = noExtPath + ".XMP";
- metadataFiles->push_back ( filePath );
- filePath = noExtPath + ".XML";
- metadataFiles->push_back ( filePath );
-
-} // FillMetadataFiles_P2
-
-// =================================================================================================
// P2_MetaHandler::IsMetadataWritable
// =======================================
bool P2_MetaHandler::IsMetadataWritable ( )
{
- std::vector<std::string> metadataFiles;
- FillMetadataFiles(&metadataFiles);
- std::vector<std::string>::iterator itr = metadataFiles.begin();
+ std::string noExtPath, filePath;
+ noExtPath = rootPath + kDirChar + "CONTENTS" + kDirChar + "CLIP" + kDirChar + this->clipName ;
+ filePath = noExtPath + ".XMP";
// Check whether sidecar is writable, if not then check if it can be created.
- bool xmpWritable = Host_IO::Writable( itr->c_str(), true );
+ bool writable = Host_IO::Writable( filePath.c_str(), true );
+ filePath = noExtPath + ".XML";
// Check if legacy XML is writable.
- bool xmlWritable = Host_IO::Writable( (++itr)->c_str(), false );
- return (xmlWritable && xmpWritable);
+ writable &= Host_IO::Writable( filePath.c_str(), false );
+ return writable;
}// P2_MetaHandler::IsMetadataWritable
-
// =================================================================================================
// P2_MetaHandler::FillAssociatedResources
// ======================================
@@ -1158,47 +964,54 @@ void P2_MetaHandler::FillAssociatedResources ( std::vector<std::string> * resour
// PROXY/
// XXXXXX.MP4
// XXXXXX.BIN
-
XMP_VarString contentsPath = this->rootPath + kDirChar + "CONTENTS" + kDirChar;
XMP_VarString path;
//Add RootPath
path = this->rootPath + kDirChar;
PackageFormat_Support::AddResourceIfExists(resourceList, path);
-
- std::string clipPathNoExt = contentsPath + "CLIP" + kDirChar + this->clipName;
- // Get the files present inside CLIP folder.
- path = clipPathNoExt + ".XML";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
- path = clipPathNoExt + ".XMP";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
-
- // Get the files present inside VIDEO folder.
- path = contentsPath + "VIDEO" + kDirChar + this->clipName + ".MXF";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
-
- // Get the files present inside AUDIO folder.
- path = contentsPath + "AUDIO" + kDirChar;
- XMP_VarString regExp;
- regExp = "^" + this->clipName + "\\d\\d.MXF$";
- IOUtils::GetMatchingChildren ( *resourceList, path, regExp, false, true, true );
-
- // Get the files present inside ICON folder.
- path = contentsPath + "ICON" + kDirChar + this->clipName + ".BMP";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
-
- // Get the files present inside VOICE folder.
- path = contentsPath + "VOICE" + kDirChar;
- regExp = "^" + clipName + "\\d\\d.WAV$";
- IOUtils::GetMatchingChildren ( *resourceList, path, regExp, false, true, true );
-
- // Get the files present inside PROXY folder.
- std::string proxyPathNoExt = contentsPath + "PROXY" + kDirChar + this->clipName;
-
- path = proxyPathNoExt + ".MP4";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
- path = proxyPathNoExt + ".BIN";
- PackageFormat_Support::AddResourceIfExists(resourceList, path);
+ P2_SpannedClip* p2SpanClip=p2ClipManager.GetSpannedClip();
+ if ( ! p2SpanClip ) return ;
+ std::vector<std::string> clipNameList;
+ p2SpanClip->GetAllClipNames ( clipNameList );
+ std::vector<std::string>::iterator iter = clipNameList.begin();
+ for(; iter!=clipNameList.end(); iter++)
+ {
+
+ std::string clipPathNoExt = contentsPath + "CLIP" + kDirChar + *iter;
+ // Get the files present inside CLIP folder.
+ path = clipPathNoExt + ".XML";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+ path = clipPathNoExt + ".XMP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+
+ // Get the files present inside VIDEO folder.
+ path = contentsPath + "VIDEO" + kDirChar + *iter + ".MXF";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+
+ // Get the files present inside AUDIO folder.
+ path = contentsPath + "AUDIO" + kDirChar;
+ XMP_VarString regExp;
+ regExp = "^" + *iter + "\\d\\d.MXF$";
+ IOUtils::GetMatchingChildren ( *resourceList, path, regExp, false, true, true );
+
+ // Get the files present inside ICON folder.
+ path = contentsPath + "ICON" + kDirChar + *iter + ".BMP";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+
+ // Get the files present inside VOICE folder.
+ path = contentsPath + "VOICE" + kDirChar;
+ regExp = "^" + *iter + "\\d\\d.WAV$";
+ IOUtils::GetMatchingChildren ( *resourceList, path, regExp, false, true, true );
+
+ // Get the files present inside PROXY folder.
+ std::string proxyPathNoExt = contentsPath + "PROXY" + kDirChar + *iter;
+
+ path = proxyPathNoExt + ".MP4";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+ path = proxyPathNoExt + ".BIN";
+ PackageFormat_Support::AddResourceIfExists(resourceList, path);
+ }
} // P2_MetaHandler::FillAssociatedResources
// =================================================================================================
@@ -1216,6 +1029,7 @@ void P2_MetaHandler::CacheFileData()
// Make sure the clip's .XMP file exists.
std::string xmpPath;
+
this->MakeClipFilePath ( &xmpPath, ".XMP" );
if ( ! Host_IO::Exists ( xmpPath.c_str() ) ) return; // No XMP.
@@ -1253,96 +1067,42 @@ void P2_MetaHandler::CacheFileData()
void P2_MetaHandler::ProcessXMP()
{
-
- // Some versions of gcc can't tolerate goto's across declarations.
- // *** Better yet, avoid this cruft with self-cleaning objects.
- #define CleanupAndExit \
- { \
- bool openForUpdate = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OpenForUpdate ); \
- if ( ! openForUpdate ) this->CleanupLegacyXML(); \
- return; \
- }
-
if ( this->processedXMP ) return;
this->processedXMP = true; // Make sure only called once.
if ( this->containsXMP ) {
this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
}
-
- std::string xmlPath;
- this->MakeClipFilePath ( &xmlPath, ".XML" );
-
- Host_IO::FileRef hostRef = Host_IO::Open ( xmlPath.c_str(), Host_IO::openReadOnly );
- if ( hostRef == Host_IO::noFileRef ) return; // The open failed.
- XMPFiles_IO xmlFile ( hostRef, xmlPath.c_str(), Host_IO::openReadOnly );
-
- this->expat = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
- if ( this->expat == 0 ) XMP_Throw ( "P2_MetaHandler: Can't create Expat adapter", kXMPErr_NoMemory );
-
- XMP_Uns8 buffer [64*1024];
- while ( true ) {
- XMP_Int32 ioCount = xmlFile.Read ( buffer, sizeof(buffer) );
- if ( ioCount == 0 ) break;
- this->expat->ParseBuffer ( buffer, ioCount, false /* not the end */ );
- }
- this->expat->ParseBuffer ( 0, 0, true ); // End the parse.
-
- xmlFile.Close();
-
- // The root element should be P2Main in some namespace. At least 2 different namespaces are in
- // use (ending in "v3.0" and "v3.1"). Take whatever this file uses.
-
- XML_Node & xmlTree = this->expat->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 ) CleanupAndExit
- XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
- if ( ! XMP_LitMatch ( rootLocalName, "P2Main" ) ) CleanupAndExit
-
- this->p2NS = rootElem->ns;
-
- // Now find ClipMetadata element and check the legacy digest.
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyContext, legacyProp;
-
- legacyContext = rootElem->GetNamedElement ( p2NS, "ClipContent" );
- if ( legacyContext == 0 ) CleanupAndExit
-
- this->clipContent = legacyContext; // ! Save the ClipContext pointer for other use.
-
- legacyContext = legacyContext->GetNamedElement ( p2NS, "ClipMetadata" );
- if ( legacyContext == 0 ) CleanupAndExit
-
- this->clipMetadata = legacyContext; // ! Save the ClipMetadata pointer for other use.
-
+
+ XML_NodePtr legacyContext, clipMetadata, legacyProp;
+ if ( ! this->p2ClipManager.IsValidP2() ) return;
+ P2_Clip* p2Clip=this->p2ClipManager.GetManagedClip();
+ XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str();
std::string oldDigest, newDigest;
bool digestFound = this->xmpObj.GetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "P2", &oldDigest, 0 );
if ( digestFound ) {
- this->MakeLegacyDigest ( &newDigest );
- if ( oldDigest == newDigest ) CleanupAndExit
+ p2Clip->CreateDigest ( &newDigest );
+ if ( oldDigest == newDigest ) return;
}
// If we get here we need find and import the actual legacy elements using the current namespace.
// Either there is no old digest in the XMP, or the digests differ. In the former case keep any
// existing XMP, in the latter case take new legacy values.
- this->SetXMPPropertyFromLegacyXML ( digestFound, this->clipContent, kXMP_NS_DC, "title", "ClipName", true );
- this->SetXMPPropertyFromLegacyXML ( digestFound, this->clipContent, kXMP_NS_DC, "identifier", "GlobalClipID", false );
+ std::string clipTitle= p2Clip->GetClipTitle();// needed for successful Mac Builds
+ this->SetXMPPropertyFromLegacyXML ( digestFound, &clipTitle , kXMP_NS_DC, "title", true );
+ if ( p2Clip->IsValidClip() )
+ this->SetXMPPropertyFromLegacyXML ( digestFound, p2Clip->GetClipId(), kXMP_NS_DC, "identifier", false );
this->SetDurationFromLegacyXML (digestFound );
this->SetRelationsFromLegacyXML ( digestFound );
- this->SetXMPPropertyFromLegacyXML ( digestFound, this->clipMetadata, kXMP_NS_DM, "shotName", "UserClipName", false );
+ clipMetadata = p2Clip->GetClipMetadataNode();
+ if ( clipMetadata == 0 ) return;
+ this->SetXMPPropertyFromLegacyXML ( digestFound,p2Clip->GetClipMetadataNode(), kXMP_NS_DM, "shotName", "UserClipName", false );
this->SetAudioInfoFromLegacyXML ( digestFound );
this->SetVideoInfoFromLegacyXML ( digestFound );
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Access" );
- if ( legacyContext == 0 ) CleanupAndExit
+
+ legacyContext = clipMetadata->GetNamedElement ( p2NS, "Access" );
+ if ( legacyContext == 0 ) return;
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "creator" )) ) {
legacyProp = legacyContext->GetNamedElement ( p2NS, "Creator" );
@@ -1358,7 +1118,7 @@ void P2_MetaHandler::ProcessXMP()
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_XMP, "ModifyDate", "LastUpdateDate", false );
if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "good" )) ) {
- legacyProp = this->clipMetadata->GetNamedElement ( p2NS, "ShotMark" );
+ legacyProp = clipMetadata->GetNamedElement ( p2NS, "ShotMark" );
if ( (legacyProp == 0) || (! legacyProp->IsLeafContentNode()) ) {
this->xmpObj.DeleteProperty ( kXMP_NS_DM, "good" );
} else {
@@ -1375,7 +1135,7 @@ void P2_MetaHandler::ProcessXMP()
}
}
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Shoot" );
+ legacyContext = clipMetadata->GetNamedElement ( p2NS, "Shoot" );
if ( legacyContext != 0 ) {
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_TIFF, "Artist", "Shooter", false );
legacyContext = legacyContext->GetNamedElement ( p2NS, "Location" );
@@ -1388,21 +1148,20 @@ void P2_MetaHandler::ProcessXMP()
this->SetAltitudeFromLegacyXML ( legacyContext, digestFound );
}
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Device" );
+ legacyContext = clipMetadata->GetNamedElement ( p2NS, "Device" );
if ( legacyContext != 0 ) {
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_TIFF, "Make", "Manufacturer", false );
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_EXIF_Aux, "SerialNumber", "SerialNo.", false );
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_TIFF, "Model", "ModelName", false );
}
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Scenario" );
+ legacyContext = clipMetadata->GetNamedElement ( p2NS, "Scenario" );
if ( legacyContext != 0 ) {
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_DM, "scene", "SceneNo.", false );
this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_DM, "takeNumber", "TakeNo.", false );
}
- CleanupAndExit
- #undef CleanupAndExit
+ return;
} // P2_MetaHandler::ProcessXMP
@@ -1439,47 +1198,51 @@ void P2_MetaHandler::UpdateFile ( bool doSafeUpdate )
// Update the internal legacy XML tree if we have one, and set the digest in the XMP.
bool updateLegacyXML = false;
+ P2_Clip* p2Clip = 0;
+ XML_NodePtr clipMetadata = 0;
+ if ( this->p2ClipManager.IsValidP2() )
+ {
+ p2Clip=this->p2ClipManager.GetManagedClip();
+ clipMetadata = p2Clip->GetClipMetadataNode();
+ if ( clipMetadata != 0 ) {
- if ( this->clipMetadata != 0 ) {
-
- XMP_Assert ( this->expat != 0 );
+ bool xmpFound;
+ std::string xmpValue;
+ XML_Node * xmlNode;
- bool xmpFound;
- std::string xmpValue;
- XML_Node * xmlNode;
+ xmpFound = this->xmpObj.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &xmpValue, 0 );
- xmpFound = this->xmpObj.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &xmpValue, 0 );
+ if ( xmpFound && p2Clip->GetClipContentNode()) {
- if ( xmpFound ) {
+ xmlNode = this->ForceChildElement ( p2Clip->GetClipContentNode(), "ClipName", 3, false );
- xmlNode = this->ForceChildElement ( this->clipContent, "ClipName", 3, false );
+ if ( xmpValue != xmlNode->GetLeafContentValue() ) {
+ xmlNode->SetLeafContentValue ( xmpValue.c_str() );
+ updateLegacyXML = true;
+ }
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
}
- }
-
- xmpFound = this->xmpObj.GetArrayItem ( kXMP_NS_DC, "creator", 1, &xmpValue, 0 );
+ xmpFound = this->xmpObj.GetArrayItem ( kXMP_NS_DC, "creator", 1, &xmpValue, 0 );
- if ( xmpFound ) {
- xmlNode = this->ForceChildElement ( this->clipMetadata, "Access", 3, false );
+ if ( xmpFound ) {
+ xmlNode = this->ForceChildElement ( clipMetadata , "Access", 3, false );
- // "Creator" must be first child of "Access" node else Panasonic P2 Viewer gives an error.
- xmlNode = this->ForceChildElement ( xmlNode, "Creator", 4 , true);
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
+ // "Creator" must be first child of "Access" node else Panasonic P2 Viewer gives an error.
+ xmlNode = this->ForceChildElement ( xmlNode, "Creator", 4 , true);
+ if ( xmpValue != xmlNode->GetLeafContentValue() ) {
+ xmlNode->SetLeafContentValue ( xmpValue.c_str() );
+ updateLegacyXML = true;
+ }
}
+
}
+ std::string newDigest;
+ this->p2ClipManager.GetManagedClip()->CreateDigest ( &newDigest );
+ this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "P2", newDigest.c_str(), kXMP_DeleteExisting );
}
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "P2", newDigest.c_str(), kXMP_DeleteExisting );
-
this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() );
// -----------------------------------------------------------------------
@@ -1512,8 +1275,8 @@ void P2_MetaHandler::UpdateFile ( bool doSafeUpdate )
dummy attribute with this namespace to clipContent/clipMetadata (whichever is non-null) before
serializing the XML tree. We are also undoing it below after serialization.*/
- XML_Node *parentNode = AddXSINamespace(this->clipContent, this->clipMetadata);
- this->expat->tree.Serialize ( &legacyXML );
+ XML_Node *parentNode = AddXSINamespace(p2Clip->GetClipContentNode(), clipMetadata);
+ p2Clip->SerializeP2ClipContent ( legacyXML );
if(parentNode){
// Remove the dummy attribute added to clipContent/clipMetadata.
delete parentNode->attrs[parentNode->attrs.size()-1];
diff --git a/XMPFiles/source/FileHandlers/P2_Handler.hpp b/XMPFiles/source/FileHandlers/P2_Handler.hpp
index 513e9ea..5e492ee 100644
--- a/XMPFiles/source/FileHandlers/P2_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/P2_Handler.hpp
@@ -17,6 +17,7 @@
#include "source/ExpatAdapter.hpp"
#include "third-party/zuid/interfaces/MD5.h"
+#include "XMPFiles/source/FormatSupport/P2_Support.hpp"
// =================================================================================================
/// \file P2_Handler.hpp
@@ -52,8 +53,6 @@ class P2_MetaHandler : public XMPFileHandler
{
public:
- bool GetFileModDate ( XMP_DateTime * modDate );
- void FillMetadataFiles ( std::vector<std::string> * metadataFiles );
void FillAssociatedResources ( std::vector<std::string> * resourceList );
bool IsMetadataWritable ( );
@@ -71,11 +70,10 @@ public:
private:
- P2_MetaHandler() : expat(0), clipMetadata(0), clipContent(0) {}; // Hidden on purpose.
+ P2_MetaHandler() {}; // Hidden on purpose.
bool MakeClipFilePath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false );
void MakeLegacyDigest ( std::string * digestStr );
- void CleanupLegacyXML();
void DigestLegacyItem ( MD5_CTX & md5Context, XML_NodePtr legacyContext, XMP_StringPtr legacyPropName );
void DigestLegacyRelations ( MD5_CTX & md5Context );
@@ -86,6 +84,11 @@ private:
XMP_StringPtr propName,
XMP_StringPtr legacyPropName,
bool isLocalized );
+ void SetXMPPropertyFromLegacyXML ( bool digestFound,
+ XMP_VarString* refContext,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool isLocalized );
void SetRelationsFromLegacyXML ( bool digestFound );
void SetAudioInfoFromLegacyXML ( bool digestFound );
@@ -99,11 +102,9 @@ private:
XML_Node * ForceChildElement ( XML_Node * parent, XMP_StringPtr localName, XMP_Int32 indent, XMP_Bool insertAtFront );
- std::string rootPath, clipName, p2NS;
+ std::string rootPath , clipName;
- ExpatAdapter * expat;
- XML_Node * clipMetadata; // ! Don't delete, points into the Expat tree.
- XML_Node * clipContent; // ! Don't delete, points into the Expat tree.
+ P2_Manager p2ClipManager;
}; // P2_MetaHandler
diff --git a/XMPFiles/source/FileHandlers/PSD_Handler.cpp b/XMPFiles/source/FileHandlers/PSD_Handler.cpp
index 89e1cc6..1db6ec9 100644
--- a/XMPFiles/source/FileHandlers/PSD_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/PSD_Handler.cpp
@@ -81,7 +81,7 @@ XMPFileHandler * PSD_MetaHandlerCTor ( XMPFiles * parent )
// PSD_MetaHandler::PSD_MetaHandler
// ================================
-PSD_MetaHandler::PSD_MetaHandler ( XMPFiles * _parent ) : iptcMgr(0), exifMgr(0), skipReconcile(false)
+PSD_MetaHandler::PSD_MetaHandler ( XMPFiles * _parent ) : iptcMgr(0), exifMgr(0), skipReconcile(false),imageWidth(0),imageHeight(0)
{
this->parent = _parent;
this->handlerFlags = kPSD_HandlerFlags;
@@ -185,7 +185,9 @@ void PSD_MetaHandler::ProcessXMP()
// Set up everything for the legacy import, but don't do it yet. This lets us do a forced legacy
// import if the XMP packet gets parsing errors.
- bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+ bool readOnly = false;
+ if ( this->parent )
+ readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
if ( readOnly ) {
this->iptcMgr = new IPTC_Reader();
diff --git a/XMPFiles/source/FileHandlers/SonyHDV_Handler.cpp b/XMPFiles/source/FileHandlers/SonyHDV_Handler.cpp
index 9d9a9d4..17e5baf 100644
--- a/XMPFiles/source/FileHandlers/SonyHDV_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/SonyHDV_Handler.cpp
@@ -713,7 +713,7 @@ bool SonyHDV_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
ok = this->MakeIndexFilePath ( fullPath, this->rootPath, this->clipName );
if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
+ if ( *modDate < oneDate ) *modDate = oneDate;
haveDate = true;
}
diff --git a/XMPFiles/source/FileHandlers/UCF_Handler.cpp b/XMPFiles/source/FileHandlers/UCF_Handler.cpp
index 8e1e1ff..d304bc2 100644
--- a/XMPFiles/source/FileHandlers/UCF_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/UCF_Handler.cpp
@@ -155,6 +155,32 @@ bool UCF_CheckFormat ( XMP_FileFormat format,
UCF_MetaHandler::UCF_MetaHandler ( XMPFiles * _parent )
{
+ this->cdx2 = 0 ;
+ this->z = 0;
+ this->z2 = 0;
+ this->h = 0;
+ this->h2 = 0;
+ this->al = 0;
+ this->bl = 0;
+ this->xl = 0;
+ this->x2l = 0;
+ this->cdl = 0;
+ this->cd2l = 0;
+ this->cdxl = 0;
+ this->cdx2l = 0;
+ this->z2l = 0;
+ this->hl = 0;
+ this->fl = 0;
+ this->f2l = 0;
+ this->numCF = 0;
+ this->numCF2 = 0;
+ this->wasCompressed = false;
+ this->compressXMP = false;
+ this->inPlacePossible = false;
+ this->uncomprPacketLen = 0;
+ this->uncomprPacketStr = NULL;
+ this->finalPacketStr = NULL;
+ this->finalPacketLen = 0;
this->parent = _parent;
this->handlerFlags = kUCF_HandlerFlags;
this->stdCharForm = kXMP_Char8Bit;
@@ -480,10 +506,6 @@ void UCF_MetaHandler::CacheFileData()
XMP_Enforce( file->ReadAll ( (char*)packetStr, sizeUncompressed ) );
break;
}
- default:
- {
- XMP_Throw("illegal zip compression method (not none, not flate)",kXMPErr_BadFileFormat);
- }
}
this->containsXMP = true; // do this last, after all possible failure/execptions
}
diff --git a/XMPFiles/source/FileHandlers/UCF_Handler.hpp b/XMPFiles/source/FileHandlers/UCF_Handler.hpp
index a9b9b55..3140c23 100644
--- a/XMPFiles/source/FileHandlers/UCF_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/UCF_Handler.hpp
@@ -548,7 +548,7 @@ private:
//// WRITE BACK REAL 64 BIT VALUES, CREATE EXTRA FIELD ///////////////
//may only wipe extra field after obtaining all Info from it
if (extraField) delete extraField;
- extraFieldLen=0;
+ extraFieldLen=0;
if ( ( sizeUncompressed > 0xffffffff ) ||
( sizeCompressed > 0xffffffff ) ||
@@ -593,7 +593,7 @@ private:
file ->Write ( fields , FIXED_SIZE );
if (filenameLen) file->Write ( filename , filenameLen );
if (extraFieldLen) file->Write ( extraField , extraFieldLen );
- if (commentLen) file->Write ( extraField , extraFieldLen );
+ if (commentLen) file->Write ( comment , commentLen );
}
void setXMPFilename()
diff --git a/XMPFiles/source/FileHandlers/WAVE_Handler.cpp b/XMPFiles/source/FileHandlers/WAVE_Handler.cpp
index 876234e..1695013 100644
--- a/XMPFiles/source/FileHandlers/WAVE_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/WAVE_Handler.cpp
@@ -118,6 +118,8 @@ const ChunkIdentifier WAVE_MetaHandler::kRIFFCart[2] = { { kChunk_RIFF, kType_WA
// cr8r is not yet required for WAVE
// RIFF:WAVE/Cr8r
// const ChunkIdentifier WAVE_MetaHandler::kWAVECr8r[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_Cr8r, kType_NONE } };
+// RIFF:WAVE/iXML
+const ChunkIdentifier WAVE_MetaHandler::kRIFFiXML[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_iXML, kType_NONE } };
// RF64:WAVE/PMX_
const ChunkIdentifier WAVE_MetaHandler::kRF64XMP[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_XMP, kType_NONE} };
// RF64:WAVE/LIST:INFO
@@ -131,6 +133,7 @@ const ChunkIdentifier WAVE_MetaHandler::kRF64Cart[2] = { { kChunk_RF64, kType_WA
// cr8r is not yet required for WAVE
// RF64:WAVE/Cr8r
// const ChunkIdentifier WAVE_MetaHandler::kRF64Cr8r[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_Cr8r, kType_NONE } };
+const ChunkIdentifier WAVE_MetaHandler::kRF64iXML[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_iXML, kType_NONE } };
// =================================================================================================
// WAVE_MetaHandler::WAVE_MetaHandler
@@ -138,9 +141,9 @@ const ChunkIdentifier WAVE_MetaHandler::kRF64Cart[2] = { { kChunk_RF64, kType_WA
WAVE_MetaHandler::WAVE_MetaHandler ( XMPFiles * _parent )
: mChunkBehavior(NULL), mChunkController(NULL),
- mINFOMeta(), mBEXTMeta(), mCartMeta(), mDISPMeta(),
+ mINFOMeta(), mBEXTMeta(), mCartMeta(), mDISPMeta(), miXMLMeta(),
mXMPChunk(NULL), mINFOChunk(NULL),
- mBEXTChunk(NULL), mCartChunk(NULL), mDISPChunk(NULL)
+ mBEXTChunk(NULL), mCartChunk(NULL), mDISPChunk(NULL), miXMLChunk(NULL)
{
this->parent = _parent;
this->handlerFlags = kWAVE_HandlerFlags;
@@ -148,6 +151,7 @@ WAVE_MetaHandler::WAVE_MetaHandler ( XMPFiles * _parent )
this->mChunkBehavior = new WAVEBehavior();
this->mChunkController = new ChunkController( mChunkBehavior, false );
+ miXMLMeta.SetErrorCallback( &parent->errorCallback );
} // WAVE_MetaHandler::WAVE_MetaHandler
@@ -197,6 +201,7 @@ void WAVE_MetaHandler::CacheFileData()
mWAVEXMPChunkPath.append( kRIFFXMP, SizeOfCIArray(kRIFFXMP) );
mWAVEInfoChunkPath.append( kRIFFInfo, SizeOfCIArray(kRIFFInfo) );
mWAVEDispChunkPath.append( kRIFFDisp, SizeOfCIArray(kRIFFDisp) );
+ mWAVEiXMLChunkPath.append( kRIFFiXML, SizeOfCIArray(kRIFFiXML) );
mWAVEBextChunkPath.append( kRIFFBext, SizeOfCIArray(kRIFFBext) );
mWAVECartChunkPath.append( kRIFFCart, SizeOfCIArray(kRIFFCart) );
// cr8r is not yet required for WAVE
@@ -207,6 +212,7 @@ void WAVE_MetaHandler::CacheFileData()
mWAVEXMPChunkPath.append( kRF64XMP, SizeOfCIArray(kRF64XMP) );
mWAVEInfoChunkPath.append( kRF64Info, SizeOfCIArray(kRF64Info) );
mWAVEDispChunkPath.append( kRF64Disp, SizeOfCIArray(kRF64Disp) );
+ mWAVEiXMLChunkPath.append( kRF64iXML, SizeOfCIArray(kRF64iXML) );
mWAVEBextChunkPath.append( kRF64Bext, SizeOfCIArray(kRF64Bext) );
mWAVECartChunkPath.append( kRF64Cart, SizeOfCIArray(kRF64Cart) );
// cr8r is not yet required for WAVE
@@ -216,6 +222,7 @@ void WAVE_MetaHandler::CacheFileData()
mChunkController->addChunkPath( mWAVEXMPChunkPath );
mChunkController->addChunkPath( mWAVEInfoChunkPath );
mChunkController->addChunkPath( mWAVEDispChunkPath );
+ mChunkController->addChunkPath( mWAVEiXMLChunkPath );
mChunkController->addChunkPath( mWAVEBextChunkPath );
mChunkController->addChunkPath( mWAVECartChunkPath );
// cr8r is not yet required for WAVE
@@ -341,8 +348,17 @@ void WAVE_MetaHandler::ProcessXMP()
// mCr8rMeta.parse( buffer, size );
//}
+ // Parse iXML legacy chunk
+ miXMLChunk = mChunkController->getChunk( mWAVEiXMLChunkPath, true );
+ if( miXMLChunk != NULL )
+ {
+ size = miXMLChunk->getData( &buffer );
+ miXMLMeta.parse( buffer, size );
+ }
+
// app legacy to the metadata list
metaSet.append( &mINFOMeta );
+ metaSet.append( &miXMLMeta );
metaSet.append( &mBEXTMeta );
metaSet.append( &mCartMeta );
metaSet.append( &mDISPMeta );
@@ -380,6 +396,7 @@ void WAVE_MetaHandler::UpdateFile ( bool doSafeUpdate )
WAVEReconcile recon;
metaSet.append( &mINFOMeta );
+ metaSet.append( &miXMLMeta );
metaSet.append( &mBEXTMeta );
metaSet.append( &mCartMeta );
metaSet.append( &mDISPMeta );
@@ -415,6 +432,11 @@ void WAVE_MetaHandler::UpdateFile ( bool doSafeUpdate )
//{
// updateLegacyChunk( &mCr8rChunk, kChunk_Cr8r, kType_NONE, mCr8rMeta );
//}
+
+ if ( miXMLMeta.hasChanged( ))
+ {
+ updateLegacyChunk( &miXMLChunk, kChunk_iXML, kType_NONE, miXMLMeta );
+ }
}
//update/create XMP chunk
diff --git a/XMPFiles/source/FileHandlers/WAVE_Handler.hpp b/XMPFiles/source/FileHandlers/WAVE_Handler.hpp
index f8cc31b..29c1c86 100644
--- a/XMPFiles/source/FileHandlers/WAVE_Handler.hpp
+++ b/XMPFiles/source/FileHandlers/WAVE_Handler.hpp
@@ -18,6 +18,7 @@
#include "XMPFiles/source/FormatSupport/IFF/IChunkData.h"
#include "source/Endian.h"
#include "XMPFiles/source/FormatSupport/IFF/ChunkPath.h"
+#include "XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/BEXTMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/CartMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/DISPMetadata.h"
@@ -110,6 +111,7 @@ private:
BEXTMetadata mBEXTMeta;
CartMetadata mCartMeta;
DISPMetadata mDISPMeta;
+ iXMLMetadata miXMLMeta;
// cr8r is not yet required for WAVE
// Cr8rMetadata mCr8rMeta;
@@ -121,6 +123,7 @@ private:
IChunkData *mBEXTChunk;
IChunkData *mCartChunk;
IChunkData *mDISPChunk;
+ IChunkData *miXMLChunk;
// cr8r is not yet required for WAVE
// IChunkData *mCr8rChunk;
@@ -133,7 +136,7 @@ private:
static const ChunkIdentifier kRIFFDisp[2];
static const ChunkIdentifier kRIFFBext[2];
static const ChunkIdentifier kRIFFCart[2];
-
+ static const ChunkIdentifier kRIFFiXML[2];
// cr8r is not yet required for WAVE
// static const ChunkIdentifier kWAVECr8r[2];
@@ -143,7 +146,7 @@ private:
static const ChunkIdentifier kRF64Disp[2];
static const ChunkIdentifier kRF64Bext[2];
static const ChunkIdentifier kRF64Cart[2];
-
+ static const ChunkIdentifier kRF64iXML[2];
// cr8r is not yet required for WAVE
// static const ChunkIdentifier kRF64Cr8r[2];
@@ -162,6 +165,9 @@ private:
/** Path to cart chunk */
ChunkPath mWAVECartChunkPath;
+ /** Path to IXML chunk */
+ ChunkPath mWAVEiXMLChunkPath;
+
//cr8r is not yet required for WAVE
///** Path to Cr8r chunk */
//const ChunkPath mWAVECr8rChunkPath;
diff --git a/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
index 9005fe8..826cc0b 100644
--- a/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/XDCAMEX_Handler.cpp
@@ -388,7 +388,7 @@ bool XDCAMEX_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
ok = this->MakeMediaproPath ( &fullPath, true /* checkFile */ );
if ( ok ) ok = Host_IO::GetModifyDate ( fullPath.c_str(), &oneDate );
if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
+ if ( *modDate < oneDate ) *modDate = oneDate;
haveDate = true;
}
diff --git a/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp b/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
index f455a8c..2a05be9 100644
--- a/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
+++ b/XMPFiles/source/FileHandlers/XDCAM_Handler.cpp
@@ -488,20 +488,13 @@ void XDCAM_MetaHandler::SetSidecarPath()
( ( GetUns32BE(&buffer[12]) & 0xFFFF00FF ) == 0x01020000 )
)
{
- // If cached MXF file name is present then use it otherwise
- // side car generated on case insensitive OS may not be read on case sensitive OS.
- // For example, if file name is X.MXF then windows says X.mxf is same as X.MXF so
- // we may land up generating side car name as X.mxf.xmp which will not be read on
- // Mac which will search specifically for X.MXF.xmp
- XMP_VarString filePath = this->parent->GetFilePath();
- XMP_VarString ext;
- XIO::SplitFileExtension(&filePath, &ext);
- if(ext == "MXF" || ext == "mxf")
- {
- this->sidecarPath = this->parent->GetFilePath() + ".xmp";
- }
- else
+ 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";
}
}
@@ -524,7 +517,7 @@ void XDCAM_MetaHandler::SetSidecarPath()
// XDCAM_MetaHandler::XDCAM_MetaHandler
// ====================================
-XDCAM_MetaHandler::XDCAM_MetaHandler ( XMPFiles * _parent ) : isFAM(false), expat(0)
+XDCAM_MetaHandler::XDCAM_MetaHandler ( XMPFiles * _parent ) : isFAM(false), expat(0),clipMetadata(NULL)
{
this->parent = _parent; // Inherited, can't set in the prefix.
@@ -737,7 +730,7 @@ bool XDCAM_MetaHandler::GetFileModDate ( XMP_DateTime * modDate )
ok = MakeMediaproPath ( &mediaproPath, true /* checkFile */ );
if ( ok ) ok = Host_IO::GetModifyDate ( mediaproPath.c_str(), &oneDate );
if ( ok ) {
- if ( (! haveDate) || (*modDate < oneDate) ) *modDate = oneDate;
+ if ( (! haveDate) ) *modDate = oneDate;
haveDate = true;
}
@@ -870,7 +863,7 @@ bool XDCAM_MetaHandler::IsClipsPlanning ( std::string clipUmid , XMP_StringPtr p
{
XML_NodePtr materialNode = mgNode->GetNamedElement( nameSpace, "Material" );
XMP_StringPtr materialType = materialNode->GetAttrValue ( "type" );
- if ( XMP_LitMatch( materialType , "clip" ) )
+ if ( materialType && XMP_LitMatch( materialType , "clip" ) )
{
XMP_StringPtr umidValue = materialNode->GetAttrValue ( "umidRef" );
if ( umidValue != 0 && XMP_LitMatch( umidValue , clipUmid.c_str() ) )
diff --git a/XMPFiles/source/FormatSupport/IFF/ChunkController.cpp b/XMPFiles/source/FormatSupport/IFF/ChunkController.cpp
index 2a5a322..fc7c2c6 100644
--- a/XMPFiles/source/FormatSupport/IFF/ChunkController.cpp
+++ b/XMPFiles/source/FormatSupport/IFF/ChunkController.cpp
@@ -50,6 +50,8 @@ ChunkController::ChunkController( IChunkBehavior* chunkBehavior, XMP_Bool bigEnd
ChunkController::~ChunkController()
{
+ XMP_Validate( mRoot != NULL, "ERROR inserting Chunk. mRoot is NULL.", kXMPErr_InternalFailure );
+ XMP_Assert(dynamic_cast<Chunk*>(mRoot) == static_cast<Chunk*>(mRoot));
delete dynamic_cast<Chunk*>(mRoot);
}
@@ -104,7 +106,9 @@ void ChunkController::parseChunks( XMP_IO* stream, ChunkPath& currentPath, XMP_O
XMP_Bool isRoot = (parent == mRoot);
XMP_Uns64 parseLimit = mFileSize;
XMP_Uns32 chunkCnt = 0;
-
+
+ XMP_Validate( mRoot != NULL, "ERROR inserting Chunk. mRoot is NULL.", kXMPErr_InternalFailure );
+ XMP_Assert(dynamic_cast<Chunk*>(mRoot) == static_cast<Chunk*>(mRoot));
parent = ( parent == NULL ? dynamic_cast<Chunk*>(mRoot) : parent );
//
@@ -592,6 +596,8 @@ void ChunkController::findChunks( const ChunkPath& path, ChunkPath& currentPath,
void ChunkController::cleanupTree()
{
+ XMP_Validate( mRoot != NULL, "ERROR inserting Chunk. mRoot is NULL.", kXMPErr_InternalFailure );
+ XMP_Assert(dynamic_cast<Chunk*>(mRoot) == static_cast<Chunk*>(mRoot));
delete dynamic_cast<Chunk*>(mRoot);
mRoot = Chunk::createChunk(*mEndian);
}
@@ -659,6 +665,8 @@ IChunkData* ChunkController::createChunk( XMP_Uns32 id, XMP_Uns32 type /*= kType
void ChunkController::insertChunk( IChunkData* chunk )
{
XMP_Validate( chunk != NULL, "ERROR inserting Chunk. Chunk is NULL.", kXMPErr_InternalFailure );
+ XMP_Assert(dynamic_cast<Chunk*>(chunk) == static_cast<Chunk*>(chunk));
+
Chunk* ch = dynamic_cast<Chunk*>(chunk);
mChunkBehavior->insertChunk( *mRoot, *ch );
// sets OriginalSize = Size / OriginalOffset = Offset
diff --git a/XMPFiles/source/FormatSupport/IFF/ChunkPath.h b/XMPFiles/source/FormatSupport/IFF/ChunkPath.h
index c0f149b..30ed3c0 100644
--- a/XMPFiles/source/FormatSupport/IFF/ChunkPath.h
+++ b/XMPFiles/source/FormatSupport/IFF/ChunkPath.h
@@ -57,6 +57,7 @@ enum {
kChunk_bext = 0x62657874,
kChunk_cart = 0x63617274,
kChunk_ds64 = 0x64733634,
+ kChunk_iXML = 0x69584D4C,
// AIFF
kChunk_APPL = 0x4150504C,
diff --git a/XMPFiles/source/FormatSupport/IPTC_Support.cpp b/XMPFiles/source/FormatSupport/IPTC_Support.cpp
index e8fda45..a6ff864 100644
--- a/XMPFiles/source/FormatSupport/IPTC_Support.cpp
+++ b/XMPFiles/source/FormatSupport/IPTC_Support.cpp
@@ -337,14 +337,14 @@ size_t IPTC_Manager::GetDataSet_UTF8 ( XMP_Uns8 dsNum, std::string * utf8Str, si
void IPTC_Manager::DisposeLooseValue ( DataSetInfo & dsInfo )
{
- if ( dsInfo.dataLen == 0 ) return;
+ if ( dsInfo.dataLen == 0 || dsInfo.dataPtr == NULL ) return;
XMP_Uns8* dataBegin = this->iptcContent;
XMP_Uns8* dataEnd = dataBegin + this->iptcLength;
if ( ((XMP_Uns8*)dsInfo.dataPtr < dataBegin) || ((XMP_Uns8*)dsInfo.dataPtr >= dataEnd) ) {
free ( (void*) dsInfo.dataPtr );
- dsInfo.dataPtr = 0;
+ dsInfo.dataPtr = NULL;
}
} // IPTC_Manager::DisposeLooseValue
diff --git a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
index 670b8fb..d4a8076 100644
--- a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
+++ b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.cpp
@@ -22,6 +22,25 @@
namespace ISOMedia {
+typedef std::set<XMP_Uns32> KnownBoxList;
+static KnownBoxList boxList;
+#define ISOboxType(x,y) boxList.insert(y)
+#define SEPARATOR ;
+ bool IsKnownBoxType(XMP_Uns32 boxType) {
+ if (boxList.empty()){
+ ISOBoxList ISOBoxPrivateList ;
+ }
+ if (boxList.find(boxType)!=boxList.end()){
+ return true;
+ }
+ return false;
+ }
+ void TerminateGlobals()
+ {
+ boxList.clear();
+ }
+#undef ISOboxType
+#undef SEPARATOR
static BoxInfo voidInfo;
// =================================================================================================
diff --git a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
index dd2fbea..728293f 100644
--- a/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
+++ b/XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp
@@ -1,5 +1,5 @@
#ifndef __ISOBaseMedia_Support_hpp__
-#define __ISOBaseMedia_Support_hpp__ 1
+#define __ISOBaseMedia_Support_hpp__ 1
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
@@ -10,13 +10,15 @@
// of the Adobe license agreement accompanying it.
// =================================================================================================
-#include "public/include/XMP_Environment.h" // ! This must be the first include.
+#include "public/include/XMP_Environment.h" // ! This must be the first include.
#include "public/include/XMP_Const.h"
#include "public/include/XMP_IO.hpp"
#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include <set>
+
// =================================================================================================
/// \file ISOBaseMedia_Support.hpp
/// \brief XMPFiles support for the ISO Base Media File Format.
@@ -27,82 +29,95 @@
namespace ISOMedia {
+#define ISOBoxList \
+ ISOboxType(k_ftyp,0x66747970UL)SEPARATOR /* File header Box, no version/flags.*/ \
+ \
+ ISOboxType(k_mp41,0x6D703431UL)SEPARATOR /* Compatible brand codes*/ \
+ ISOboxType(k_mp42,0x6D703432UL)SEPARATOR \
+ ISOboxType(k_f4v ,0x66347620UL)SEPARATOR \
+ ISOboxType(k_avc1,0x61766331UL)SEPARATOR \
+ ISOboxType(k_qt ,0x71742020UL)SEPARATOR \
+ \
+ ISOboxType(k_moov,0x6D6F6F76UL)SEPARATOR /* Container Box, no version/flags. */ \
+ ISOboxType(k_mvhd,0x6D766864UL)SEPARATOR /* Data FullBox, has version/flags. */ \
+ ISOboxType(k_hdlr,0x68646C72UL)SEPARATOR \
+ ISOboxType(k_udta,0x75647461UL)SEPARATOR /* Container Box, no version/flags. */ \
+ ISOboxType(k_cprt,0x63707274UL)SEPARATOR /* Data FullBox, has version/flags. */ \
+ ISOboxType(k_uuid,0x75756964UL)SEPARATOR /* Data Box, no version/flags. */ \
+ ISOboxType(k_free,0x66726565UL)SEPARATOR /* Free space Box, no version/flags.*/ \
+ ISOboxType(k_mdat,0x6D646174UL)SEPARATOR /* Media data Box, no version/flags.*/ \
+ \
+ ISOboxType(k_trak,0x7472616BUL)SEPARATOR /* Types for the QuickTime timecode track.*/ \
+ ISOboxType(k_tkhd,0x746B6864UL)SEPARATOR \
+ ISOboxType(k_edts,0x65647473UL)SEPARATOR \
+ ISOboxType(k_elst,0x656C7374UL)SEPARATOR \
+ ISOboxType(k_mdia,0x6D646961UL)SEPARATOR \
+ ISOboxType(k_mdhd,0x6D646864UL)SEPARATOR \
+ ISOboxType(k_tmcd,0x746D6364UL)SEPARATOR \
+ ISOboxType(k_mhlr,0x6D686C72UL)SEPARATOR \
+ ISOboxType(k_minf,0x6D696E66UL)SEPARATOR \
+ ISOboxType(k_stbl,0x7374626CUL)SEPARATOR \
+ ISOboxType(k_stsd,0x73747364UL)SEPARATOR \
+ ISOboxType(k_stsc,0x73747363UL)SEPARATOR \
+ ISOboxType(k_stco,0x7374636FUL)SEPARATOR \
+ ISOboxType(k_co64,0x636F3634UL)SEPARATOR \
+ ISOboxType(k_dinf,0x64696E66UL)SEPARATOR \
+ ISOboxType(k_dref,0x64726566UL)SEPARATOR \
+ ISOboxType(k_alis,0x616C6973UL)SEPARATOR \
+ \
+ ISOboxType(k_meta,0x6D657461UL)SEPARATOR /* Types for the iTunes metadata boxes.*/ \
+ ISOboxType(k_ilst,0x696C7374UL)SEPARATOR \
+ ISOboxType(k_mdir,0x6D646972UL)SEPARATOR \
+ ISOboxType(k_mean,0x6D65616EUL)SEPARATOR \
+ ISOboxType(k_name,0x6E616D65UL)SEPARATOR \
+ ISOboxType(k_data,0x64617461UL)SEPARATOR \
+ ISOboxType(k_hyphens,0x2D2D2D2DUL)SEPARATOR \
+ \
+ ISOboxType(k_skip,0x736B6970UL)SEPARATOR /* Additional classic QuickTime top level boxes.*/ \
+ ISOboxType(k_wide,0x77696465UL)SEPARATOR \
+ ISOboxType(k_pnot,0x706E6F74UL)SEPARATOR \
+ \
+ ISOboxType(k_XMP_,0x584D505FUL) /* The QuickTime variant XMP box.*/
+
+#define ISOBoxPrivateList
+#define ISOboxType(x,y) x=y
+#define SEPARATOR ,
enum {
- k_ftyp = 0x66747970UL, // File header Box, no version/flags.
-
- k_mp41 = 0x6D703431UL, // Compatible brand codes
- k_mp42 = 0x6D703432UL,
- k_f4v = 0x66347620UL,
- k_avc1 = 0x61766331UL,
- k_qt = 0x71742020UL,
-
- k_moov = 0x6D6F6F76UL, // Container Box, no version/flags.
- k_mvhd = 0x6D766864UL, // Data FullBox, has version/flags.
- k_hdlr = 0x68646C72UL,
- k_udta = 0x75647461UL, // Container Box, no version/flags.
- k_cprt = 0x63707274UL, // Data FullBox, has version/flags.
- k_uuid = 0x75756964UL, // Data Box, no version/flags.
- k_free = 0x66726565UL, // Free space Box, no version/flags.
- k_mdat = 0x6D646174UL, // Media data Box, no version/flags.
-
- k_trak = 0x7472616BUL, // Types for the QuickTime timecode track.
- k_tkhd = 0x746B6864UL,
- k_edts = 0x65647473UL,
- k_elst = 0x656C7374UL,
- k_mdia = 0x6D646961UL,
- k_mdhd = 0x6D646864UL,
- k_tmcd = 0x746D6364UL,
- k_mhlr = 0x6D686C72UL,
- k_minf = 0x6D696E66UL,
- k_stbl = 0x7374626CUL,
- k_stsd = 0x73747364UL,
- k_stsc = 0x73747363UL,
- k_stco = 0x7374636FUL,
- k_co64 = 0x636F3634UL,
- k_dinf = 0x64696E66UL,
- k_dref = 0x64726566UL,
- k_alis = 0x616C6973UL,
-
- k_meta = 0x6D657461UL, // Types for the iTunes metadata boxes.
- k_ilst = 0x696C7374UL,
- k_mdir = 0x6D646972UL,
- k_mean = 0x6D65616EUL,
- k_name = 0x6E616D65UL,
- k_data = 0x64617461UL,
- k_hyphens = 0x2D2D2D2DUL,
-
- k_skip = 0x736B6970UL, // Additional classic QuickTime top level boxes.
- k_wide = 0x77696465UL,
- k_pnot = 0x706E6F74UL,
-
- k_XMP_ = 0x584D505FUL // The QuickTime variant XMP box.
+ ISOBoxList
+ ISOBoxPrivateList
};
+#undef ISOboxType
+#undef SEPARATOR
+
+
+ bool IsKnownBoxType(XMP_Uns32 boxType) ;
+ void TerminateGlobals();
static XMP_Uns32 k_xmpUUID [4] = { MakeUns32BE ( 0xBE7ACFCBUL ),
- MakeUns32BE ( 0x97A942E8UL ),
- MakeUns32BE ( 0x9C719994UL ),
- MakeUns32BE ( 0x91E3AFACUL ) };
+ MakeUns32BE ( 0x97A942E8UL ),
+ MakeUns32BE ( 0x9C719994UL ),
+ MakeUns32BE ( 0x91E3AFACUL ) };
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".
+ 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) {};
};
// Get basic info about a box in memory, returning a pointer to the following box.
const XMP_Uns8 * GetBoxInfo ( const XMP_Uns8 * boxPtr, const XMP_Uns8 * boxLimit,
- BoxInfo * info, bool throwErrors = false );
+ BoxInfo * info, bool throwErrors = false );
// Get basic info about a box in a file, returning the offset of the following box. The I/O
// pointer is left at the start of the box's content. Returns the offset of the following box.
XMP_Uns64 GetBoxInfo ( XMP_IO* fileRef, const XMP_Uns64 boxOffset, const XMP_Uns64 boxLimit,
- BoxInfo * info, bool doSeek = true, bool throwErrors = false );
+ BoxInfo * info, bool doSeek = true, bool throwErrors = false );
-// XMP_Uns32 CountChildBoxes ( XMP_IO* fileRef, const XMP_Uns64 childOffset, const XMP_Uns64 childLimit );
+ // XMP_Uns32 CountChildBoxes ( XMP_IO* fileRef, const XMP_Uns64 childOffset, const XMP_Uns64 childLimit );
-} // namespace ISO_Media
+} // namespace ISO_Media
// =================================================================================================
-#endif // __ISOBaseMedia_Support_hpp__
+#endif // __ISOBaseMedia_Support_hpp__
diff --git a/XMPFiles/source/FormatSupport/MOOV_Support.hpp b/XMPFiles/source/FormatSupport/MOOV_Support.hpp
index 1dace2a..7d34ca2 100644
--- a/XMPFiles/source/FormatSupport/MOOV_Support.hpp
+++ b/XMPFiles/source/FormatSupport/MOOV_Support.hpp
@@ -166,9 +166,9 @@ public:
#pragma pack( pop )
-#if SUNOS_SPARC
+#if SUNOS_SPARC || XMP_IOS_ARM
#pragma pack( )
-#endif //#if SUNOS_SPARC
+#endif //#if SUNOS_SPARC || XMP_IOS_ARM
// ---------------------------------------------------------------------------------------------
diff --git a/XMPFiles/source/FormatSupport/P2_Support.cpp b/XMPFiles/source/FormatSupport/P2_Support.cpp
new file mode 100644
index 0000000..a5336d5
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/P2_Support.cpp
@@ -0,0 +1,566 @@
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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/ExpatAdapter.hpp"
+
+#include "source/IOUtils.hpp"
+
+#include "XMPFiles/source/FormatSupport/P2_Support.hpp"
+#include "third-party/zuid/interfaces/MD5.h"
+#include <sstream>
+
+P2_Clip::P2_Clip(const std::string & p2ClipMetadataFilePath)
+ try :p2XMLParser(0),p2Root(0),headContentCached(false)
+ ,p2ClipContent(0),filePath(p2ClipMetadataFilePath)
+{
+ Host_IO::FileRef hostRef = Host_IO::Open ( p2ClipMetadataFilePath.c_str(), Host_IO::openReadOnly );
+ XMPFiles_IO xmlFile ( hostRef, p2ClipMetadataFilePath.c_str(), Host_IO::openReadOnly );
+ CreateExpatParser(xmlFile);
+ xmlFile.Close();
+}
+catch(...)
+{
+ DestroyExpatParser();
+ throw;
+}
+
+P2_Clip::~P2_Clip()
+{
+ DestroyExpatParser();
+}
+
+void P2_Clip::CreateExpatParser(XMPFiles_IO &xmlFile)
+{
+ this->p2XMLParser = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
+ if ( this->p2XMLParser == 0 ) XMP_Throw ( "P2_MetaHandler: Can't create Expat adapter", kXMPErr_NoMemory );
+
+ XMP_Uns8 buffer [64*1024];
+ while ( true ) {
+ XMP_Int32 ioCount = xmlFile.Read ( buffer, sizeof(buffer) );
+ if ( ioCount == 0 ) break;
+ this->p2XMLParser->ParseBuffer ( buffer, ioCount, false /* not the end */ );
+ }
+ this->p2XMLParser->ParseBuffer ( 0, 0, true );
+}
+
+void P2_Clip::DestroyExpatParser()
+{
+ delete this->p2XMLParser;
+ this->p2XMLParser = 0;
+ p2Root=0;
+ headContent.reset();
+ headContentCached = false;
+}
+
+XML_NodePtr P2_Clip::GetP2RootNode()
+{
+ if (p2Root!=0) return p2Root;
+ // The root element should be P2Main in some namespace. At least 2 different namespaces are in
+ // use (ending in "v3.0" and "v3.1"). Take whatever this file uses.
+
+ XML_Node & xmlTree = this->p2XMLParser->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 ) return 0;
+ XMP_StringPtr rootLocalName = rootElem->name.c_str() + rootElem->nsPrefixLen;
+ if ( ! XMP_LitMatch ( rootLocalName, "P2Main" ) ) return 0;
+
+ this->p2Root = rootElem;
+ return p2Root;
+}
+static void GetElementLocation(XML_NodePtr p2node,std::string*& elemLoc )
+{
+ if ( p2node != 0 && p2node->IsLeafContentNode() )
+ {
+ elemLoc= p2node->GetLeafContentPtr();
+ }
+}
+
+static void GetElementValue(XML_NodePtr p2node, XMP_Uns32 &value)
+{
+ if ( p2node != 0 && p2node->IsLeafContentNode() )
+ {
+ value =atoi(p2node->GetLeafContentValue());
+ }
+}
+void P2_Clip::CacheClipContent()
+{
+ if (headContentCached) return;
+ headContentCached = true;
+ XMP_StringPtr p2NameSpace=GetP2RootNode()->ns.c_str();
+ p2ClipContent = GetP2RootNode()->GetNamedElement ( p2NameSpace, "ClipContent" );
+ if ( p2ClipContent == 0 ) return;
+ XML_NodePtr p2node;
+
+ p2node= p2ClipContent->GetNamedElement ( p2NameSpace, "GlobalClipID" );
+ GetElementLocation(p2node,headContent.clipId );
+
+ p2node= p2ClipContent->GetNamedElement ( p2NameSpace, "ClipName" );
+ GetElementLocation(p2node,headContent.clipTitle );
+
+ p2node= p2ClipContent->GetNamedElement ( p2NameSpace, "Duration" );
+ GetElementValue(p2node,headContent.duration );
+
+ p2node= p2ClipContent->GetNamedElement ( p2NameSpace, "EditUnit" );
+ GetElementLocation(p2node,headContent.scaleUnit );
+
+ headContent.clipMetadata= p2ClipContent->GetNamedElement ( p2NameSpace, "ClipMetadata" );
+ headContent.essenceList= p2ClipContent->GetNamedElement ( p2NameSpace, "EssenceList" );
+
+ p2node= p2ClipContent->GetNamedElement ( p2NameSpace, "Relation" );
+ if ( p2node != 0 )
+ {
+ XML_NodePtr p2Offset= p2node->GetNamedElement ( p2NameSpace, "OffsetInShot" );
+ GetElementValue(p2Offset,headContent.OffsetInShot );
+ p2Offset= p2node->GetNamedElement ( p2NameSpace, "GlobalShotID" );
+ GetElementLocation(p2Offset,headContent.shotId );
+ XML_NodePtr p2connection= p2node->GetNamedElement ( p2NameSpace, "Connection" );
+ if ( p2node != 0 )
+ {
+ p2node= p2connection->GetNamedElement ( p2NameSpace, "Top" );
+ if ( p2node != 0 )
+ {
+ p2node= p2node->GetNamedElement ( p2NameSpace, "GlobalClipID" );
+ GetElementLocation(p2node,headContent.topClipId );
+ }
+ p2node= p2connection->GetNamedElement ( p2NameSpace, "Next" );
+ if ( p2node != 0 )
+ {
+ p2node= p2node->GetNamedElement ( p2NameSpace, "GlobalClipID" );
+ GetElementLocation(p2node,headContent.nextClipId );
+ }
+ p2node= p2connection->GetNamedElement ( p2NameSpace, "Previous" );
+ if ( p2node != 0 )
+ {
+ p2node= p2node->GetNamedElement ( p2NameSpace, "GlobalClipID" );
+ GetElementLocation(p2node,headContent.prevClipId );
+ }
+ }
+ }
+}
+
+bool P2_Clip::IsValidClip()
+{
+ this->CacheClipContent();
+ return headContent.clipId != 0;
+}
+bool P2_Clip::IsSpannedClip()
+{
+ return IsValidClip() && headContent.topClipId != 0 &&( headContent.prevClipId != 0 || headContent.nextClipId!=0 );
+
+}
+
+bool P2_Clip::IsTopClip()
+{
+ return IsValidClip() && headContent.topClipId != 0 && *(headContent.topClipId) == *(headContent.clipId);
+}
+
+XMP_Uns32 P2_Clip::GetOffsetInShot()
+{
+ this->CacheClipContent();
+ return this->headContent.OffsetInShot;
+}
+
+XMP_Uns32 P2_Clip::GetDuration()
+{
+ this->CacheClipContent();
+ return this->headContent.duration;
+}
+
+std::string* P2_Clip::GetClipId()
+{
+ this->CacheClipContent();
+ return this->headContent.clipId;
+}
+
+std::string* P2_Clip::GetClipName()
+{
+ if ( this->clipName == "" )
+ {
+ std::string tempPath = this->filePath;
+ XIO::SplitLeafName(&tempPath, &this->clipName);
+ std::string ext;
+ XIO::SplitFileExtension(&this->clipName, &ext);
+ }
+ return &this->clipName;
+}
+
+std::string P2_Clip::GetClipTitle()
+{
+ this->CacheClipContent();
+ if ( ! this->headContent.clipTitle ) return std::string("");
+ return *this->headContent.clipTitle;
+}
+std::string* P2_Clip::GetNextClipId()
+{
+ this->CacheClipContent();
+ return this->headContent.nextClipId;
+}
+
+std::string* P2_Clip::GetPreviousClipId()
+{
+ this->CacheClipContent();
+ return this->headContent.prevClipId;
+}
+
+std::string* P2_Clip::GetTopClipId()
+{
+ this->CacheClipContent();
+ return this->headContent.topClipId;
+}
+
+std::string* P2_Clip::GetShotId()
+{
+ this->CacheClipContent();
+ return this->headContent.shotId;
+}
+
+std::string* P2_Clip::GetEditUnit()
+{
+ this->CacheClipContent();
+ return this->headContent.scaleUnit;
+}
+
+XML_NodePtr P2_Clip::GetClipContentNode()
+{
+ this->CacheClipContent();
+ return this->p2ClipContent;
+}
+
+XML_NodePtr P2_Clip::GetClipMetadataNode()
+{
+ this->CacheClipContent();
+ return this->headContent.clipMetadata;
+}
+
+XML_NodePtr P2_Clip::GetEssenceListNode()
+{
+ this->CacheClipContent();
+ return this->headContent.essenceList;
+}
+
+std::string P2_Clip::GetXMPFilePath()
+{
+ std::string ClipMetadataPath = this->GetClipPath();
+ std::string ignoreext;
+ XIO::SplitFileExtension(&ClipMetadataPath,&ignoreext);
+ return ClipMetadataPath+ ".XMP";
+}
+
+void P2_Clip::CreateDigest ( std::string * digestStr )
+{
+ return;
+}
+
+void P2_Clip::SerializeP2ClipContent(std::string& xmlContentData)
+{
+ this->p2XMLParser->tree.Serialize ( &xmlContentData );
+}
+
+
+P2_SpannedClip::P2_SpannedClip(const std::string & p2ClipMetadataFilePath):
+ P2_Clip(p2ClipMetadataFilePath)
+{
+ P2_Clip* p2Clip= dynamic_cast<P2_Clip*>(this);
+ spannedP2Clip.insert(p2Clip);
+ if (p2Clip->GetClipId())
+ addedClipIds.insert(*p2Clip->GetClipId());
+}
+
+bool P2_SpannedClip::AddIfRelated(P2_Clip* newClip)
+{
+ std::string* tClipId = newClip->GetTopClipId();
+ if( tClipId != 0 && *(tClipId)==*this->GetTopClipId() &&
+ newClip->IsValidClip() && addedClipIds.find(*newClip->GetClipId()) == addedClipIds.end())
+ {
+ spannedP2Clip.insert(newClip);
+ addedClipIds.insert(*newClip->GetClipId());
+ return true;
+ }
+ return false;
+}
+
+bool P2_SpannedClip::IsComplete() const
+{
+ RelatedP2ClipList::iterator iter=spannedP2Clip.begin();
+ if (! (*iter)->IsTopClip() ) return false;
+ std::string* next=(*iter)->GetNextClipId();
+ while(++iter != spannedP2Clip.end() &&
+ next != 0 && (*iter)->IsValidClip() &&
+ *next == *( (*iter)->GetClipId() )
+ )
+ next = (*iter)->GetNextClipId();
+ if ( iter != spannedP2Clip.end() || next != 0 )
+ {
+ iter=spannedP2Clip.begin();
+ std::string* prev= (*iter)->GetClipId();
+ while(++iter != spannedP2Clip.end() &&
+ prev != 0 && (*iter)->GetPreviousClipId() !=0 &&
+ *prev == *( (*iter)->GetPreviousClipId() )
+ )
+ prev= (*iter)->GetClipId();
+ if ( iter != spannedP2Clip.end() ) return false;
+ }
+ return true;
+}
+
+std::string P2_SpannedClip::GetXMPFilePath()
+{
+ if ( this->IsComplete() )
+ {
+ std::string ClipMetadataPath = (*spannedP2Clip.begin())->GetClipPath();
+ std::string ignoreext;
+ XIO::SplitFileExtension(&ClipMetadataPath,&ignoreext);
+ return ClipMetadataPath+ ".XMP";
+ }else
+ {
+ return P2_Clip::GetXMPFilePath();
+ }
+}
+
+void P2_SpannedClip::DigestElement( MD5_CTX & md5Context, XML_NodePtr legacyContext, XMP_StringPtr legacyPropName )
+{
+ XML_NodePtr legacyProp = legacyContext->GetNamedElement ( this->GetP2RootNode()->ns.c_str(), legacyPropName );
+
+ if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
+ const XML_Node * xmlValue = legacyProp->content[0];
+ MD5Update ( &md5Context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
+ }
+
+} // P2_MetaHandler::DigestLegacyItem
+#define kHexDigits "0123456789ABCDEF"
+
+void P2_SpannedClip::CreateDigest ( std::string * digestStr )
+{
+ digestStr->erase();
+ if ( this->headContent.clipMetadata == 0 ) return; // Bail if we don't have any legacy XML.
+
+ XMP_StringPtr p2NS = this->GetP2RootNode()->ns.c_str();
+ XML_NodePtr legacyContext;
+ MD5_CTX md5Context;
+ unsigned char digestBin [16];
+ MD5Init ( &md5Context );
+
+ MD5Update ( &md5Context, (XMP_Uns8*)this->GetClipTitle().c_str(), (unsigned int)this->GetClipTitle().size() );
+ if ( headContent.clipId )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.clipId->c_str(), (unsigned int)headContent.clipId->size() );
+
+ XMP_Uns32 totalDuration=this->GetDuration();
+ std::ostringstream ostr;
+ ostr << totalDuration;
+ if ( totalDuration )
+ MD5Update ( &md5Context, (XMP_Uns8*)ostr.str().c_str(), (unsigned int)ostr.str().size() );
+ if ( headContent.scaleUnit )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.scaleUnit->c_str(), (unsigned int)headContent.scaleUnit->size() );
+
+ if ( headContent.shotId )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.shotId->c_str(), (unsigned int)headContent.shotId->size() );
+ if ( headContent.topClipId )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.topClipId->c_str(), (unsigned int)headContent.topClipId->size() );
+ if ( headContent.prevClipId )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.prevClipId->c_str(), (unsigned int)headContent.prevClipId->size() );
+ if ( headContent.nextClipId )
+ MD5Update ( &md5Context, (XMP_Uns8*)headContent.nextClipId->c_str(), (unsigned int)headContent.nextClipId->size() );
+
+ if ( this->headContent.essenceList != 0 ) {
+
+ XML_NodePtr videoContext = this->headContent.essenceList->GetNamedElement ( p2NS, "Video" );
+
+ if ( videoContext != 0 ) {
+ this->DigestElement ( md5Context, videoContext, "AspectRatio" );
+ this->DigestElement ( md5Context, videoContext, "Codec" );
+ this->DigestElement ( md5Context, videoContext, "FrameRate" );
+ this->DigestElement ( md5Context, videoContext, "StartTimecode" );
+ }
+
+ XML_NodePtr audioContext = this->headContent.essenceList->GetNamedElement ( p2NS, "Audio" );
+
+ if ( audioContext != 0 ) {
+ this->DigestElement ( md5Context, audioContext, "SamplingRate" );
+ this->DigestElement ( md5Context, audioContext, "BitsPerSample" );
+ }
+
+ }
+
+ legacyContext = this->headContent.clipMetadata;
+ this->DigestElement ( md5Context, legacyContext, "UserClipName" );
+ this->DigestElement ( md5Context, legacyContext, "ShotMark" );
+
+ legacyContext = this->headContent.clipMetadata->GetNamedElement ( p2NS, "Access" );
+ /* Rather return than create the digest because the "Access" element is listed as "required" in the P2 spec.
+ So a P2 file without an "Access" element does not follow the spec and might be corrupt.*/
+ if ( legacyContext == 0 ) return;
+
+ this->DigestElement ( md5Context, legacyContext, "Creator" );
+ this->DigestElement ( md5Context, legacyContext, "CreationDate" );
+ this->DigestElement ( md5Context, legacyContext, "LastUpdateDate" );
+
+ legacyContext = this->headContent.clipMetadata->GetNamedElement ( p2NS, "Shoot" );
+
+ if ( legacyContext != 0 ) {
+ this->DigestElement ( md5Context, legacyContext, "Shooter" );
+
+ legacyContext = legacyContext->GetNamedElement ( p2NS, "Location" );
+
+ if ( legacyContext != 0 ) {
+ this->DigestElement ( md5Context, legacyContext, "PlaceName" );
+ this->DigestElement ( md5Context, legacyContext, "Longitude" );
+ this->DigestElement ( md5Context, legacyContext, "Latitude" );
+ this->DigestElement ( md5Context, legacyContext, "Altitude" );
+ }
+ }
+
+ legacyContext = this->headContent.clipMetadata->GetNamedElement ( p2NS, "Scenario" );
+
+ if ( legacyContext != 0 ) {
+ this->DigestElement ( md5Context, legacyContext, "SceneNo." );
+ this->DigestElement ( md5Context, legacyContext, "TakeNo." );
+ }
+
+ legacyContext = this->headContent.clipMetadata->GetNamedElement ( p2NS, "Device" );
+
+ if ( legacyContext != 0 ) {
+ this->DigestElement ( md5Context, legacyContext, "Manufacturer" );
+ this->DigestElement ( md5Context, legacyContext, "SerialNo." );
+ this->DigestElement ( md5Context, legacyContext, "ModelName" );
+ }
+
+ MD5Final ( digestBin, &md5Context );
+
+ char buffer [40];
+ for ( int in = 0, out = 0; in < 16; in += 1, out += 2 ) {
+ XMP_Uns8 byte = digestBin[in];
+ buffer[out] = kHexDigits [ byte >> 4 ];
+ buffer[out+1] = kHexDigits [ byte & 0xF ];
+ }
+ buffer[32] = 0;
+ digestStr->append ( buffer );
+
+}
+
+P2_SpannedClip::~P2_SpannedClip()
+{
+ RelatedP2ClipList::iterator iter = spannedP2Clip.begin();
+ for(;iter!=spannedP2Clip.end();iter++)
+ {
+ if (GetClipPath() != (*iter)->GetClipPath())
+ delete *iter;
+ }
+ spannedP2Clip.clear();
+}
+
+P2_Clip* P2_SpannedClip::TopP2Clip()
+{
+ if ( this->IsComplete() && spannedP2Clip.size() > 1 )
+ {
+ return *spannedP2Clip.begin();
+ }
+ return this;
+}
+
+XMP_Uns32 P2_SpannedClip::GetDuration()
+{
+ if ( IsComplete() )
+ {
+ RelatedP2ClipList::iterator iter = this->spannedP2Clip.begin();
+ XMP_Uns32 totalDuration=0;
+ for(;iter!=spannedP2Clip.end();iter++)
+ totalDuration+=(*iter)->GetDuration();
+ return totalDuration;
+ }
+ return P2_Clip::GetDuration();
+}
+
+void P2_SpannedClip::GetAllClipNames(std::vector <std::string> & clipNameList)
+{
+ clipNameList.clear();
+ if ( IsComplete() )
+ {
+ RelatedP2ClipList::iterator iter = this->spannedP2Clip.begin();
+ for(;iter!=spannedP2Clip.end();iter++)
+ clipNameList.push_back(*( (*iter)->GetClipName() ) );
+ }else
+ {
+ clipNameList.push_back(*( this->GetClipName() ) );
+ }
+}
+
+P2_Manager::P2_Manager():spannedClips(0)
+{
+
+}
+
+P2_Manager::~P2_Manager()
+{
+ delete this->spannedClips;
+ this->spannedClips = 0;
+}
+
+void P2_Manager::ProcessClip(std::string & clipPath)
+{
+ this->spannedClips = new P2_SpannedClip(clipPath);
+ if ( this->spannedClips->IsSpannedClip())
+ {
+ std::string clipFolder,filename,regExp;
+ XMP_StringVector clipFileList,regExpVec;
+ clipFolder=clipPath;
+ XIO::SplitLeafName ( &clipFolder, &filename );
+ regExp = "^\\d\\d\\d\\d\\d\\d.XML$";
+ regExpVec.push_back ( regExp );
+ regExp = "^\\d\\d\\d\\d\\W\\W.XML$";
+ regExpVec.push_back ( regExp );
+ regExp = "^\\d\\d\\d\\d\\d\\W.XML$";
+ regExpVec.push_back ( regExp );
+ regExp = "^\\d\\d\\d\\d\\W\\d.XML$";
+ regExpVec.push_back ( regExp );
+ IOUtils::GetMatchingChildren ( clipFileList, clipFolder, regExpVec, false, true, true );
+ for(XMP_StringVector::iterator iter=clipFileList.begin();
+ iter!=clipFileList.end();iter++)
+ {
+ P2_Clip * tempClip= new P2_Clip(*iter);
+ if ( ! spannedClips->AddIfRelated(tempClip) )
+ delete tempClip;
+ }
+ if(spannedClips->IsComplete())
+ {
+ return;
+ }
+ }
+}
+
+bool P2_Manager::IsValidP2()
+{
+ return spannedClips!= 0;
+}
+
+P2_Clip* P2_Manager::GetManagedClip()
+{
+ return spannedClips->TopP2Clip();
+}
+
+P2_SpannedClip* P2_Manager::GetSpannedClip()
+{
+ return spannedClips;
+}
+
diff --git a/XMPFiles/source/FormatSupport/P2_Support.hpp b/XMPFiles/source/FormatSupport/P2_Support.hpp
new file mode 100644
index 0000000..e16faea
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/P2_Support.hpp
@@ -0,0 +1,135 @@
+#ifndef __P2_Support_hpp__
+#define __P2_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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"
+#include "public/include/XMP_Const.h"
+
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include "source/XIO.hpp"
+#include "third-party/zuid/interfaces/MD5.h"
+#include <set>
+
+class P2_Clip {
+public:
+ P2_Clip(const std::string & p2ClipMetadataFilePath);
+ bool IsSpannedClip() ;
+ bool IsTopClip() ;
+ bool IsValidClip() ;
+ virtual void CreateDigest ( std::string * digestStr );
+ XMP_Uns32 GetOffsetInShot();
+ XMP_Uns32 GetDuration();
+ std::string* GetClipName();
+ std::string GetClipTitle();
+ std::string* GetClipId();
+ std::string* GetNextClipId();
+ std::string* GetPreviousClipId();
+ std::string* GetTopClipId();
+ std::string* GetShotId();
+ std::string* GetEditUnit();
+ std::string GetClipPath(){return filePath;}
+ virtual std::string GetXMPFilePath();
+ XML_NodePtr GetClipContentNode();
+ XML_NodePtr GetClipMetadataNode();
+ XML_NodePtr GetEssenceListNode();
+ XML_NodePtr GetP2RootNode() ;
+ void SerializeP2ClipContent(std::string& xmlContentData) ;
+ virtual ~P2_Clip();
+protected:
+ class ClipContent
+ {
+ public:
+ ClipContent():clipId(0),scaleUnit(0),
+ duration(0),OffsetInShot(0),topClipId(0),nextClipId(0),
+ prevClipId(0),shotId(0),clipMetadata(0),essenceList(0),clipTitle(0){}
+ std::string* clipTitle;
+ std::string* clipId;
+ std::string* scaleUnit;
+ XMP_Uns32 duration;
+ XMP_Uns32 OffsetInShot;
+ std::string* topClipId;
+ std::string* nextClipId;
+ std::string* prevClipId;
+ std::string* shotId;
+ XML_NodePtr clipMetadata;
+ XML_NodePtr essenceList;
+ void reset(){*this=ClipContent();}
+ };
+ ClipContent headContent;
+private:
+ void DestroyExpatParser();
+ void CreateExpatParser(XMPFiles_IO &xmlFile);
+ void CacheClipContent();
+
+ bool headContentCached;
+ ExpatAdapter * p2XMLParser;
+ XML_NodePtr p2Root;
+ XML_NodePtr p2ClipContent;
+ std::string filePath;
+ std::string clipName;
+
+}; // class P2_Clip
+struct P2SpannedClip_Order
+{
+ bool operator()( P2_Clip* lhs, P2_Clip* rhs)
+ {
+ return lhs->GetOffsetInShot() < rhs->GetOffsetInShot();
+ }
+
+};
+
+class P2_SpannedClip : public P2_Clip{
+public:
+ P2_SpannedClip(const std::string & p2ClipMetadataFilePath);
+ bool AddIfRelated(P2_Clip* openedClip);
+ bool IsComplete()const;
+ XMP_Uns32 GetDuration();
+ P2_Clip* TopP2Clip() ;
+ std::string GetXMPFilePath();
+ void CreateDigest ( std::string * digestStr );
+ void GetAllClipNames(std::vector <std::string> & clipNameList);
+ virtual ~P2_SpannedClip();
+private:
+ P2_SpannedClip(const P2_SpannedClip &);
+ P2_SpannedClip operator=(const P2_SpannedClip &);
+
+ void DigestElement( MD5_CTX & md5Context, XML_NodePtr legacyContext, XMP_StringPtr legacyPropName );
+
+ typedef std::multiset<P2_Clip*,P2SpannedClip_Order> RelatedP2ClipList;
+ std::set<std::string> addedClipIds;
+ RelatedP2ClipList spannedP2Clip;
+
+}; // class P2_SpannedClip
+
+// =================================================================================================
+class P2_Manager {
+public:
+ P2_Manager();
+ void ProcessClip(std::string & clipPath);
+ P2_Clip* GetManagedClip();
+ P2_SpannedClip* GetSpannedClip();
+ bool IsValidP2();
+ ~P2_Manager();
+
+private:
+
+ P2_SpannedClip* spannedClips;
+
+}; // class P2_Manager
+
+
+// =================================================================================================
+
+
+
+// =================================================================================================
+
+#endif // __P2_Support_hpp__
diff --git a/XMPFiles/source/FormatSupport/PostScript_Support.cpp b/XMPFiles/source/FormatSupport/PostScript_Support.cpp
index a0c13d2..fec55fb 100644
--- a/XMPFiles/source/FormatSupport/PostScript_Support.cpp
+++ b/XMPFiles/source/FormatSupport/PostScript_Support.cpp
@@ -148,10 +148,8 @@ inline static bool SearchBBoxInTrailer(XMP_IO* fileRef,IOBuffer& ioBuf)
//skip chars till newline
if ( ! PostScript_Support::SkipUntilNewline( fileRef, ioBuf ) ) return false;
}
- if (!bboxfoundintrailer)
- return false;
- else
- break;
+
+ break;
}
else if ( CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSContainsBeginDocString.c_str()), kPSContainsBeginDocString.length() ) )
{
@@ -267,7 +265,8 @@ bool PostScript_Support::IsValidPSFile(XMP_IO* fileRef,XMP_FileFormat &format
format=kXMP_PostScriptFile;
//return true if no "EPSF-" is found as it is a valid PS atleast
if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr("EPSF-"), 5 ) ) return true;
- }
+
+ }//intentional fall through for further checking of unknown files
case kXMP_EPSFile:
{
diff --git a/XMPFiles/source/FormatSupport/QuickTime_Support.cpp b/XMPFiles/source/FormatSupport/QuickTime_Support.cpp
index 5dde0c5..8e2d45a 100644
--- a/XMPFiles/source/FormatSupport/QuickTime_Support.cpp
+++ b/XMPFiles/source/FormatSupport/QuickTime_Support.cpp
@@ -12,6 +12,9 @@
#if XMP_MacBuild
#include <CoreServices/CoreServices.h>
+#elif XMP_iOSBuild
+ #include <CoreFoundation/CoreFoundation.h>
+ #include "XMPFiles/source/FormatSupport/MacScriptExtracts.h"
#else
#include "XMPFiles/source/FormatSupport/MacScriptExtracts.h"
#endif
@@ -354,7 +357,7 @@ static const char * kMacToXMPLang_128_151 [24] = {
#if XMP_WinBuild
-static UINT kMacScriptToWinCP[34] = {
+static UINT kMacScriptToWinCP[33] = {
/* smRoman (0) */ 10000, // There don't seem to be symbolic constants.
/* smJapanese (1) */ 10001, // From http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
/* smTradChinese (2) */ 10002,
@@ -383,8 +386,7 @@ static UINT kMacScriptToWinCP[34] = {
/* smSimpChinese (25) */ 10008,
/* smTibetan (26) */ 0,
/* smMongolian (27) */ 0,
- /* smEthiopic (28) */ 0,
- /* smGeez (28) */ 0,
+ /* smEthiopic/smGeez (28) */ 0,
/* smCentralEuroRoman (29) */ 10029,
/* smVietnamese (30) */ 0,
/* smExtArabic (31) */ 0,
@@ -502,6 +504,156 @@ static UINT kMacToWinCP_0_94 [95] = {
#endif
+
+#if XMP_iOSBuild
+
+static XMP_Uns32 kMacScriptToIOSEncodingCF[33] = {
+ /* smRoman (0) */ kCFStringEncodingMacRoman,
+ /* smJapanese (1) */ kCFStringEncodingMacJapanese,
+ /* smTradChinese (2) */ kCFStringEncodingMacChineseTrad,
+ /* smKorean (3) */ kCFStringEncodingMacKorean,
+ /* smArabic (4) */ kCFStringEncodingMacArabic,
+ /* smHebrew (5) */ kCFStringEncodingMacHebrew,
+ /* smGreek (6) */ kCFStringEncodingMacGreek,
+ /* smCyrillic (7) */ kCFStringEncodingMacCyrillic,
+ /* smRSymbol (8) */ kCFStringEncodingMacSymbol,
+ /* smDevanagari (9) */ kCFStringEncodingMacDevanagari,
+ /* smGurmukhi (10) */ kCFStringEncodingMacGurmukhi,
+ /* smGujarati (11) */ kCFStringEncodingMacGujarati,
+ /* smOriya (12) */ kCFStringEncodingMacOriya,
+ /* smBengali (13) */ kCFStringEncodingMacBengali,
+ /* smTamil (14) */ kCFStringEncodingMacTamil,
+ /* smTelugu (15) */ kCFStringEncodingMacTelugu,
+ /* smKannada (16) */ kCFStringEncodingMacKannada,
+ /* smMalayalam (17) */ kCFStringEncodingMacMalayalam,
+ /* smSinhalese (18) */ kCFStringEncodingMacSinhalese,
+ /* smBurmese (19) */ kCFStringEncodingMacBurmese,
+ /* smKhmer (20) */ kCFStringEncodingMacKhmer,
+ /* smThai (21) */ kCFStringEncodingMacThai,
+ /* smLao (22) */ kCFStringEncodingMacLaotian,
+ /* smGeorgian (23) */ kCFStringEncodingMacGeorgian,
+ /* smArmenian (24) */ kCFStringEncodingMacArmenian,
+ /* smSimpChinese (25) */ kCFStringEncodingMacChineseSimp,
+ /* smTibetan (26) */ kCFStringEncodingMacTibetan,
+ /* smMongolian (27) */ kCFStringEncodingMacMongolian,
+ /* smEthiopic/smGeez (28) */ kCFStringEncodingMacEthiopic,
+ /* smCentralEuroRoman (29) */ kCFStringEncodingMacCentralEurRoman,
+ /* smVietnamese (30) */ kCFStringEncodingMacVietnamese,
+ /* smExtArabic (31) */ kCFStringEncodingMacExtArabic,
+ /* smUninterp (32) */ kCFStringEncodingMacVT100
+}; // kMacScriptToIOSEncodingCF
+
+static XMP_Uns32 kMacToIOSEncodingCF_0_94 [95] = {
+
+ /* langEnglish (0) */ kCFStringEncodingMacRoman,
+ /* langFrench (1) */ kCFStringEncodingMacRoman,
+ /* langGerman (2) */ kCFStringEncodingMacRoman,
+ /* langItalian (3) */ kCFStringEncodingMacRoman,
+ /* langDutch (4) */ kCFStringEncodingMacRoman,
+ /* langSwedish (5) */ kCFStringEncodingMacRoman,
+ /* langSpanish (6) */ kCFStringEncodingMacRoman,
+ /* langDanish (7) */ kCFStringEncodingMacRoman,
+ /* langPortuguese (8) */ kCFStringEncodingMacRoman,
+ /* langNorwegian (9) */ kCFStringEncodingMacRoman,
+
+ /* langHebrew (10) */ kCFStringEncodingMacHebrew,
+ /* langJapanese (11) */ kCFStringEncodingMacJapanese,
+ /* langArabic (12) */ kCFStringEncodingMacArabic,
+ /* langFinnish (13) */ kCFStringEncodingMacRoman,
+ /* langGreek (14) */ kCFStringEncodingMacGreek,
+ /* langIcelandic (15) */ kCFStringEncodingMacIcelandic,
+ /* langMaltese (16) */ kCFStringEncodingMacRoman,
+ /* langTurkish (17) */ kCFStringEncodingMacTurkish,
+ /* langCroatian (18) */ kCFStringEncodingMacCroatian,
+ /* langTradChinese (19) */ kCFStringEncodingMacChineseTrad,
+
+ /* langUrdu (20) */ kCFStringEncodingMacArabic,
+ /* langHindi (21) */ kCFStringEncodingMacDevanagari,
+ /* langThai (22) */ kCFStringEncodingMacThai,
+ /* langKorean (23) */ kCFStringEncodingMacKorean,
+ /* langLithuanian (24) */ kCFStringEncodingMacCentralEurRoman,
+ /* langPolish (25) */ kCFStringEncodingMacCentralEurRoman,
+ /* langHungarian (26) */ kCFStringEncodingMacCentralEurRoman,
+ /* langEstonian (27) */ kCFStringEncodingMacCentralEurRoman,
+ /* langLatvian (28) */ kCFStringEncodingMacCentralEurRoman,
+ /* langSami (29) */ kCFStringEncodingInvalidId,
+
+ /* langFaroese (30) */ kCFStringEncodingMacRoman,
+ /* langFarsi (31) */ kCFStringEncodingMacFarsi,
+ /* langRussian (32) */ kCFStringEncodingMacCyrillic,
+ /* langSimpChinese (33) */ kCFStringEncodingMacChineseSimp,
+ /* langFlemish (34) */ kCFStringEncodingMacRoman,
+ /* langIrishGaelic (35) */ kCFStringEncodingMacRoman,
+ /* langAlbanian (36) */ kCFStringEncodingMacRoman,
+ /* langRomanian (37) */ kCFStringEncodingMacRomanian,
+ /* langCzech (38) */ kCFStringEncodingMacCentralEurRoman,
+ /* langSlovak (39) */ kCFStringEncodingMacCentralEurRoman,
+
+ /* langSlovenian (40) */ kCFStringEncodingMacRoman,
+ /* langYiddish (41) */ kCFStringEncodingMacHebrew,
+ /* langSerbian (42) */ kCFStringEncodingMacCyrillic,
+ /* langMacedonian (43) */ kCFStringEncodingMacCyrillic,
+ /* langBulgarian (44) */ kCFStringEncodingMacCyrillic,
+ /* langUkrainian (45) */ kCFStringEncodingMacUkrainian,
+ /* langBelorussian (46) */ kCFStringEncodingMacCyrillic,
+ /* langUzbek (47) */ kCFStringEncodingMacCyrillic,
+ /* langKazakh (48) */ kCFStringEncodingMacCyrillic,
+ /* langAzerbaijani (49) */ kCFStringEncodingMacCyrillic,
+
+ /* langAzerbaijanAr (50) */ kCFStringEncodingMacArabic,
+ /* langArmenian (51) */ kCFStringEncodingMacArmenian,
+ /* langGeorgian (52) */ kCFStringEncodingMacGeorgian,
+ /* langMoldavian (53) */ kCFStringEncodingMacCyrillic,
+ /* langKirghiz (54) */ kCFStringEncodingMacCyrillic,
+ /* langTajiki (55) */ kCFStringEncodingMacCyrillic,
+ /* langTurkmen (56) */ kCFStringEncodingMacCyrillic,
+ /* langMongolian (57) */ kCFStringEncodingMacMongolian,
+ /* langMongolianCyr (58) */ kCFStringEncodingMacCyrillic,
+ /* langPashto (59) */ kCFStringEncodingMacArabic,
+
+ /* langKurdish (60) */ kCFStringEncodingMacArabic,
+ /* langKashmiri (61) */ kCFStringEncodingMacArabic,
+ /* langSindhi (62) */ kCFStringEncodingMacArabic,
+ /* langTibetan (63) */ kCFStringEncodingMacTibetan,
+ /* langNepali (64) */ kCFStringEncodingMacDevanagari,
+ /* langSanskrit (65) */ kCFStringEncodingMacDevanagari,
+ /* langMarathi (66) */ kCFStringEncodingMacDevanagari,
+ /* langBengali (67) */ kCFStringEncodingMacBengali,
+ /* langAssamese (68) */ kCFStringEncodingMacBengali,
+ /* langGujarati (69) */ kCFStringEncodingMacGujarati,
+
+ /* langPunjabi (70) */ kCFStringEncodingMacGurmukhi,
+ /* langOriya (71) */ kCFStringEncodingMacOriya,
+ /* langMalayalam (72) */ kCFStringEncodingMacMalayalam,
+ /* langKannada (73) */ kCFStringEncodingMacKannada,
+ /* langTamil (74) */ kCFStringEncodingMacTamil,
+ /* langTelugu (75) */ kCFStringEncodingMacTelugu,
+ /* langSinhalese (76) */ kCFStringEncodingMacSinhalese,
+ /* langBurmese (77) */ kCFStringEncodingMacBurmese,
+ /* langKhmer (78) */ kCFStringEncodingMacKhmer,
+ /* langLao (79) */ kCFStringEncodingMacLaotian,
+
+ /* langVietnamese (80) */ kCFStringEncodingMacVietnamese,
+ /* langIndonesian (81) */ kCFStringEncodingMacRoman,
+ /* langTagalog (82) */ kCFStringEncodingMacRoman,
+ /* langMalayRoman (83) */ kCFStringEncodingMacRoman,
+ /* langMalayArabic (84) */ kCFStringEncodingMacArabic,
+ /* langAmharic (85) */ kCFStringEncodingMacEthiopic,
+ /* langTigrinya (86) */ kCFStringEncodingMacEthiopic,
+ /* langOromo (87) */ kCFStringEncodingMacEthiopic,
+ /* langSomali (88) */ kCFStringEncodingMacRoman,
+ /* langSwahili (89) */ kCFStringEncodingMacRoman,
+
+ /* langKinyarwanda (90) */ kCFStringEncodingMacRoman,
+ /* langRundi (91) */ kCFStringEncodingMacRoman,
+ /* langNyanja (92) */ kCFStringEncodingMacRoman,
+ /* langMalagasy (93) */ kCFStringEncodingMacRoman,
+ /* langEsperanto (94) */ kCFStringEncodingMacRoman
+
+}; // kMacToIOSEncodingCF_0_94
+
+#endif
+
// =================================================================================================
// GetMacScript
// ============
@@ -513,13 +665,35 @@ static XMP_Uns16 GetMacScript ( XMP_Uns16 macLang )
if ( macLang <= 94 ) {
macScript = kMacLangToScript_0_94[macLang];
} else if ( (128 <= macLang) && (macLang <= 151) ) {
- macScript = kMacLangToScript_0_94[macLang-128];
+ macScript = kMacLangToScript_128_151[macLang-128];
}
return macScript;
} // GetMacScript
+
+#if XMP_iOSBuild
+// =================================================================================================
+// GetIOSEncodingCF
+// ========
+
+static XMP_Uns32 GetIOSEncodingCF ( XMP_Uns16 macLang )
+{
+ XMP_Uns32 encCF = kCFStringEncodingInvalidId;
+
+ if ( macLang <= 94 ) encCF = kMacToIOSEncodingCF_0_94[macLang];
+
+ if ( encCF == kCFStringEncodingInvalidId || !CFStringIsEncodingAvailable(encCF)) {
+ XMP_Uns16 macScript = GetMacScript ( macLang );
+ if ( macScript != kNoMacScript ) encCF = kMacScriptToIOSEncodingCF[macScript];
+ }
+
+ return encCF;
+
+} // GetIOSEncodingCF
+#endif
+
// =================================================================================================
// GetWinCP
// ========
@@ -669,7 +843,10 @@ bool ConvertToMacLang ( const std::string & utf8Value, XMP_Uns16 macLang, std::s
#elif XMP_WinBuild
UINT winCP = GetWinCP ( macLang );
ReconcileUtils::UTF8ToWinEncoding ( winCP, (XMP_Uns8*)utf8Value.c_str(), utf8Value.size(), macValue );
- #endif
+ #elif XMP_iOSBuild
+ XMP_Uns32 iosEncCF = GetIOSEncodingCF(macLang);
+ ReconcileUtils::IOSConvertEncoding(kCFStringEncodingUTF8, iosEncCF, (XMP_Uns8*)utf8Value.c_str(), utf8Value.size(), macValue);
+ #endif
return true;
@@ -692,7 +869,10 @@ bool ConvertFromMacLang ( const std::string & macValue, XMP_Uns16 macLang, std::
#elif XMP_WinBuild
UINT winCP = GetWinCP ( macLang );
ReconcileUtils::WinEncodingToUTF8 ( winCP, (XMP_Uns8*)macValue.c_str(), macValue.size(), utf8Value );
- #endif
+ #elif XMP_iOSBuild
+ XMP_Uns32 iosEncCF = GetIOSEncodingCF(macLang);
+ ReconcileUtils::IOSConvertEncoding(iosEncCF, kCFStringEncodingUTF8, (XMP_Uns8*)macValue.c_str(), macValue.size(), utf8Value);
+#endif
return true;
@@ -988,7 +1168,7 @@ void TradQT_Manager::ExportLangAltXMP ( XMP_Uns32 id, const SXMPMeta & xmp, XMP_
for ( XMP_Index xmpIndex = 1; xmpIndex <= xmpCount; ++xmpIndex ) { // ! XMP index starts at 1!
SXMPUtils::ComposeArrayItemPath ( ns, langArray, xmpIndex, &xmpPath );
- xmp.GetProperty ( ns, xmpPath.c_str(), &xmpValue, 0 );
+ if ( !xmp.GetProperty ( ns, xmpPath.c_str(), &xmpValue, 0 ) ) continue;
xmp.GetQualifier ( ns, xmpPath.c_str(), kXMP_NS_XML, "lang", &xmpLang, 0 );
if ( xmpLang == "x-default" ) continue;
diff --git a/XMPFiles/source/FormatSupport/RIFF.cpp b/XMPFiles/source/FormatSupport/RIFF.cpp
index dcf55f2..4d9a0c1 100644
--- a/XMPFiles/source/FormatSupport/RIFF.cpp
+++ b/XMPFiles/source/FormatSupport/RIFF.cpp
@@ -137,6 +137,7 @@ Chunk* getChunk ( ContainerChunk* parent, RIFF_MetaHandler* handler )
// ad hoc creation
Chunk::Chunk( ContainerChunk* parent, ChunkType c, XMP_Uns32 id )
{
+ this->hasChange = false;
this->chunkType = c; // base class assumption
this->parent = parent;
this->id = id;
diff --git a/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp b/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
index 5aa4435..e43a1e5 100644
--- a/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
+++ b/XMPFiles/source/FormatSupport/ReconcileTIFF.cpp
@@ -469,12 +469,12 @@ ImportSingleTIFF_SRational ( const TIFF_Manager::TagInfo & tagInfo, const bool n
{
try { // Don't let errors with one stop the others.
-#if SUNOS_SPARC
+#if SUNOS_SPARC || XMP_IOS_ARM
XMP_Uns32 binPtr[2];
memcpy(&binPtr, tagInfo.dataPtr, sizeof(XMP_Uns32)*2);
#else
XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
-#endif //#if SUNOS_SPARC
+#endif //#if SUNOS_SPARC || XMP_IOS_ARM
XMP_Int32 binNum = GetUns32AsIs ( &binPtr[0] );
XMP_Int32 binDenom = GetUns32AsIs ( &binPtr[1] );
if ( ! nativeEndian ) {
@@ -1289,7 +1289,7 @@ static void
ImportTIFF_Date ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & dateInfo,
SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
{
- XMP_Uns16 secID;
+ XMP_Uns16 secID = 0;
switch ( dateInfo.id ) {
case kTIFF_DateTime : secID = kTIFF_SubSecTime; break;
case kTIFF_DateTimeOriginal : secID = kTIFF_SubSecTimeOriginal; break;
@@ -2584,7 +2584,8 @@ ExportArrayTIFF ( TIFF_Manager * tiff, XMP_Uns8 ifd, const TIFF_MappingToXMP & m
XMP_Uns32 num, denom;
for ( size_t i = 1; i <= arraySize; ++i, rationalPtr += 2 ) {
SXMPUtils::ComposeArrayItemPath ( xmpNS, xmpArray, (XMP_Index)i, &itemPath );
- xmp.GetProperty ( xmpNS, itemPath.c_str(), &xmpValue, 0 );
+ bool isPropoerty = xmp.GetProperty ( xmpNS, itemPath.c_str(), &xmpValue, 0 );
+ if ( ! isPropoerty ) return;
bool ok = DecodeRational ( xmpValue.c_str(), &num, &denom );
if ( ! ok ) return;
if ( ! nativeEndian ) { num = Flip4 ( num ); denom = Flip4 ( denom ); }
@@ -2680,7 +2681,7 @@ static void
ExportTIFF_Date ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp, TIFF_Manager * tiff, XMP_Uns16 mainID )
{
XMP_Uns8 mainIFD = kTIFF_ExifIFD;
- XMP_Uns16 fracID;
+ XMP_Uns16 fracID=0;
switch ( mainID ) {
case kTIFF_DateTime : mainIFD = kTIFF_PrimaryIFD; fracID = kTIFF_SubSecTime; break;
case kTIFF_DateTimeOriginal : fracID = kTIFF_SubSecTimeOriginal; break;
@@ -3086,7 +3087,7 @@ static void ExportTIFF_PhotographicSensitivity ( SXMPMeta * xmp, TIFF_Manager *
TIFF_Manager::TagInfo tagInfo;
std::string xmpValue;
XMP_OptionBits flags;
- XMP_Int32 binValue;
+ XMP_Int32 binValue = 0;
bool haveOldExif = true; // Default to old Exif if no version tag.
diff --git a/XMPFiles/source/FormatSupport/Reconcile_Impl.cpp b/XMPFiles/source/FormatSupport/Reconcile_Impl.cpp
index 9dcef3d..ca0e1a0 100644
--- a/XMPFiles/source/FormatSupport/Reconcile_Impl.cpp
+++ b/XMPFiles/source/FormatSupport/Reconcile_Impl.cpp
@@ -17,6 +17,8 @@
#if XMP_WinBuild
#elif XMP_MacBuild
#include <CoreServices/CoreServices.h>
+#elif XMP_iOSBuild
+ #include <CoreFoundation/CoreFoundation.h>
#endif
// =================================================================================================
@@ -201,6 +203,13 @@ void ReconcileUtils::UTF8ToLocal ( const void * _utf8Ptr, size_t utf8Len, std::s
#elif XMP_UNIXBuild
XMP_Throw ( "Generic UNIX does not have conversions between local and Unicode", kXMPErr_Unavailable );
+
+ #elif XMP_iOSBuild
+
+ IOSConvertEncoding(kCFStringEncodingUTF8, CFStringGetSystemEncoding(), utf8Ptr, utf8Len, local);
+
+
+
#endif
@@ -371,6 +380,11 @@ void ReconcileUtils::LocalToUTF8 ( const void * _localPtr, size_t localLen, std:
#elif XMP_UNIXBuild
XMP_Throw ( "Generic UNIX does not have conversions between local and Unicode", kXMPErr_Unavailable );
+
+ #elif XMP_iOSBuild
+
+ IOSConvertEncoding(CFStringGetSystemEncoding(), kCFStringEncodingUTF8, localPtr, localLen, utf8);
+
#endif
@@ -429,3 +443,29 @@ void ReconcileUtils::NativeToUTF8( const std::string & input, std::string & outp
output = input;
}
} // ReconcileUtils::NativeToUTF8
+
+
+#if XMP_iOSBuild
+ void ReconcileUtils::IOSConvertEncoding(XMP_Uns32 srcEncoding, XMP_Uns32 destEncoding, const XMP_Uns8 * inputPtr, size_t inputLen, std::string * output)
+ {
+ if(srcEncoding == kCFStringEncodingInvalidId || destEncoding == kCFStringEncodingInvalidId ||
+ !CFStringIsEncodingAvailable(srcEncoding) || !CFStringIsEncodingAvailable(destEncoding))
+ return;
+ CFStringRef cStrRef = CFStringCreateWithBytesNoCopy(NULL, inputPtr, inputLen, srcEncoding, false, kCFAllocatorNull);
+ if(cStrRef == NULL)
+ return;
+ CFRange inputRange = CFRangeMake(0, CFStringGetLength(cStrRef));
+ const size_t kBufferLen = 1000;
+ while(inputRange.length > 0)
+ {
+ XMP_Uns8 buffer[kBufferLen];
+ CFIndex charsWritten;
+ CFIndex charsProcessed = CFStringGetBytes(cStrRef, inputRange, destEncoding, 0, FALSE, buffer, kBufferLen, &charsWritten);
+ if (charsProcessed == 0) break;
+ output->append(reinterpret_cast<const char*>(&buffer[0]), charsWritten);
+ inputRange.location += charsProcessed;
+ inputRange.length -= charsProcessed;
+ }
+ CFRelease(cStrRef);
+ }
+#endif
diff --git a/XMPFiles/source/FormatSupport/Reconcile_Impl.hpp b/XMPFiles/source/FormatSupport/Reconcile_Impl.hpp
index ea5d407..4efcb3f 100644
--- a/XMPFiles/source/FormatSupport/Reconcile_Impl.hpp
+++ b/XMPFiles/source/FormatSupport/Reconcile_Impl.hpp
@@ -58,6 +58,8 @@ namespace ReconcileUtils {
#elif XMP_MacBuild
void UTF8ToMacEncoding ( XMP_Uns16 macScript, XMP_Uns16 macLang, const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host );
void MacEncodingToUTF8 ( XMP_Uns16 macScript, XMP_Uns16 macLang, const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 );
+ #elif XMP_iOSBuild
+ void IOSConvertEncoding(XMP_Uns32 srcEncoding, XMP_Uns32 destEncoding, const XMP_Uns8 * inputPtr, size_t inputLen, std::string * output);
#endif
}; // ReconcileUtils
diff --git a/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp b/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
index 05cd87f..a3b6ace 100644
--- a/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
+++ b/XMPFiles/source/FormatSupport/TIFF_MemoryReader.cpp
@@ -93,7 +93,7 @@ void TIFF_MemoryReader::SortIFD ( TweakedIFDInfo* thisIFD )
} else {
// Move the out of order entry to position j+1, move the middle of the array down.
- #if ! SUNOS_SPARC
+ #if ! (SUNOS_SPARC || XMP_IOS_ARM)
TweakedIFDEntry temp = ifdEntries[i];
++j; // ! So the insertion index becomes j.
memcpy ( &ifdEntries[j+1], &ifdEntries[j], 12*(i-j) ); // AUDIT: Safe, moving less than i entries to a location before i.
@@ -655,7 +655,7 @@ XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
if ( (GetUns16AsIs(&thisEntry->type) < kTIFF_ByteType) || (GetUns16AsIs(&thisEntry->type) > kTIFF_LastType) ) continue; // Bad type, skip this tag.
- #if ! SUNOS_SPARC
+ #if ! (SUNOS_SPARC || XMP_IOS_ARM)
thisEntry->bytes *= (XMP_Uns32)kTIFF_TypeSizes[thisEntry->type];
if ( thisEntry->bytes > 4 ) {
diff --git a/XMPFiles/source/FormatSupport/TIFF_Support.hpp b/XMPFiles/source/FormatSupport/TIFF_Support.hpp
index 002376b..b43fe42 100644
--- a/XMPFiles/source/FormatSupport/TIFF_Support.hpp
+++ b/XMPFiles/source/FormatSupport/TIFF_Support.hpp
@@ -25,11 +25,11 @@
#include "source/Endian.h"
-#if SUNOS_SPARC
+#if SUNOS_SPARC || XMP_IOS_ARM
static const IEndian &IE = BigEndian::getInstance();
#else
static const IEndian &IE = LittleEndian::getInstance();
-#endif //#if SUNOS_SPARC
+#endif //#if SUNOS_SPARC || XMP_IOS_ARM
// =================================================================================================
/// \file TIFF_Support.hpp
diff --git a/XMPFiles/source/FormatSupport/TimeConversionUtils.cpp b/XMPFiles/source/FormatSupport/TimeConversionUtils.cpp
new file mode 100644
index 0000000..2dbb459
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/TimeConversionUtils.cpp
@@ -0,0 +1,599 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPFiles/source/FormatSupport/TimeConversionUtils.hpp"
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+
+namespace TimeConversionUtils {
+
+ void DropFrameToHMSF(
+ XMP_Int64 inFrames,
+ XMP_Int64 inTimecodeFPS,
+ XMP_Uns32& outHours,
+ XMP_Uns32& outMinutes,
+ XMP_Uns32& outSeconds,
+ XMP_Uns32& outFrames)
+ {
+ XMP_Assert((inTimecodeFPS == 30) || (inTimecodeFPS == 60)); // No other drop frame rates are known at this time.
+
+ XMP_Int64 rateAdjustmentFactor = inTimecodeFPS / 30;
+ XMP_Int64 framesPerHour = (30 * 3600 - 108) * rateAdjustmentFactor;
+ XMP_Int64 framesPer10Minutes = (30 * 600 - 18) * rateAdjustmentFactor;
+ XMP_Int64 framesPerMinute = 30 * 60 * rateAdjustmentFactor;
+ XMP_Int64 framesPerSecond = 30 * rateAdjustmentFactor;
+ XMP_Int64 dropsPerMinute = 2 * rateAdjustmentFactor;
+
+ XMP_Int64 currentFrames = inFrames;
+ XMP_Int64 framesLeft = currentFrames;
+ if (currentFrames < 0)
+ {
+ framesLeft = -currentFrames;
+ }
+ if (framesLeft >= framesPerHour)
+ {
+ outHours = static_cast<XMP_Int32>(framesLeft / framesPerHour);
+ framesLeft = framesLeft % framesPerHour;
+ }
+ if (framesLeft >= framesPer10Minutes)
+ {
+ outMinutes = static_cast<XMP_Int32>(framesLeft / framesPer10Minutes) * 10;
+ framesLeft = framesLeft % framesPer10Minutes;
+ }
+ if (framesLeft >= framesPerMinute)
+ {
+ XMP_Int64 remainingDropMinutes = static_cast<XMP_Int64>((framesLeft - framesPerMinute) /
+ (framesPerMinute - dropsPerMinute));
+ ++remainingDropMinutes;
+
+ outMinutes += static_cast<XMP_Int32>(remainingDropMinutes);
+ framesLeft -= ((framesPerMinute - dropsPerMinute) * remainingDropMinutes);
+ }
+ if (framesLeft >= framesPerSecond)
+ {
+ outSeconds = static_cast<XMP_Int32>(framesLeft / framesPerSecond);
+ }
+ outFrames = static_cast<XMP_Int32>(framesLeft % framesPerSecond);
+ }
+
+ bool ConvertSamplesToTimecode(
+ std::string & outTimecode,
+ XMP_Int64 inSamples,
+ XMP_Uns64 inSampleRate,
+ XMP_Int64 inTimecodeFPS,
+ bool inIsDrop,
+ bool inIsNoDrop,
+ bool inShowOnlyFrames = false,
+ bool inOnlyShowSeconds = false ,
+ bool inNoZeroPrefix = false ,
+ bool inShowFractional = false ,
+ bool inNoHours = false )
+ {
+ if (!(inIsDrop ? !inIsNoDrop : true))
+ {
+ XMP_Assert( !(inIsDrop ? !inIsNoDrop : true) );
+ return false;
+ }
+
+ if (inSampleRate == 0)
+ {
+ outTimecode = "00:00:00:00";
+ return true;
+ }
+
+ std::string possibleNegStr;
+ if (inSamples < 0)
+ {
+ inSamples *= -1;
+ possibleNegStr = "-";
+ }
+
+ XMP_Int64 rateNumerator = inTimecodeFPS;
+ XMP_Int64 rateDenominator = 1;
+ if (inIsDrop || inIsNoDrop)
+ {
+ rateNumerator = 1000 * inTimecodeFPS;
+ rateDenominator = 1001;
+ }
+
+ XMP_Int64 frameNumber = (inSamples * rateNumerator) / (inSampleRate * rateDenominator);
+ XMP_Int64 hundredthsOfFrames = ((inSamples * rateNumerator * 100) / (inSampleRate * rateDenominator)) % 100;
+
+ std::stringstream stream;
+ double fSamples = static_cast<double>(inSamples);
+ double fSampleRate = static_cast<double>(inSampleRate);
+
+ if (inIsDrop)
+ {
+ if (inShowOnlyFrames)
+ {
+ double fAdjustmentFactor = static_cast<double>(inTimecodeFPS) / 30.0;
+ double fCorrectionRatio = (600.0 * static_cast<double>(inTimecodeFPS) / 1.001) / (17982.0 * fAdjustmentFactor);
+ double fValue = fSamples * fCorrectionRatio / fSampleRate;
+
+ // "%ld"
+ stream << static_cast<int>(fValue * 29.97 * fAdjustmentFactor);
+ }
+ else
+ {
+ XMP_Uns32 hours = 0;
+ XMP_Uns32 minutes = 0;
+ XMP_Uns32 seconds = 0;
+ XMP_Uns32 frames = 0;
+
+ DropFrameToHMSF(
+ frameNumber,
+ inTimecodeFPS,
+ hours,
+ minutes,
+ seconds,
+ frames);
+
+ hours = hours % 24;
+ // "%02d;%02d;%02d;%02d"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(hours)
+ << ";"
+ << std::setfill('0') << std::setw(2) << static_cast<int>(minutes)
+ << ";"
+ << std::setfill('0') << std::setw(2) << static_cast<int>(seconds)
+ << ";"
+ << std::setfill('0') << std::setw(2) << static_cast<int>(frames);
+ possibleNegStr.clear();
+ }
+ }
+ else
+ {
+ if (inShowOnlyFrames)
+ {
+ // "%ld"
+ stream << static_cast<int>(frameNumber);
+ }
+ else
+ {
+ XMP_Int64 framesPerMinute = inTimecodeFPS * 60;
+ XMP_Int64 framesPerHour = framesPerMinute * 60;
+
+ XMP_Int64 iHours = frameNumber / framesPerHour;
+ frameNumber %= framesPerHour;
+ XMP_Int64 mins = frameNumber / framesPerMinute;
+ frameNumber %= framesPerMinute;
+ XMP_Int64 seconds = frameNumber / inTimecodeFPS;
+ XMP_Int64 ss = frameNumber % inTimecodeFPS;
+ XMP_Int64 s = seconds;
+
+ if (inNoHours)
+ {
+ mins += iHours * 60;
+ iHours = 0;
+ }
+
+ if (((iHours) || (!inNoZeroPrefix)) && (!inNoHours))
+ {
+ iHours = iHours % 24;
+ // "%02ld:"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(iHours)
+ << ":";
+ possibleNegStr.clear();
+ }
+
+ if ((iHours) || (!inNoZeroPrefix))
+ {
+ // "%02ld:"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(mins)
+ << ":";
+ possibleNegStr.clear();
+ }
+ else if (mins)
+ {
+ // "%ld:"
+ stream << possibleNegStr << static_cast<int>(mins)
+ << ":";
+ possibleNegStr.clear();
+ }
+
+ if (inOnlyShowSeconds)
+ {
+ // "%02ld"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(s);
+ possibleNegStr.clear();
+ }
+ else
+ {
+ if ((iHours) || (mins) || (!inNoZeroPrefix))
+ {
+ // "%02ld:"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(s)
+ << ":";
+ possibleNegStr.clear();
+ }
+ else if (s)
+ {
+ // "%ld:"
+ stream << possibleNegStr << static_cast<int>(s)
+ << ":";
+ possibleNegStr.clear();
+ }
+
+ if ((iHours) || (mins) || (s) || (!inNoZeroPrefix))
+ {
+ if (inTimecodeFPS <= 10)
+ {
+ // "%01ld"
+ stream << possibleNegStr << std::setfill('0') << std::setw(1) << static_cast<int>(ss);
+ possibleNegStr.clear();
+ }
+ else if ((inTimecodeFPS <= 100))
+ {
+ // "%02ld"
+ stream << possibleNegStr << std::setfill('0') << std::setw(2) << static_cast<int>(ss);
+ possibleNegStr.clear();
+ }
+ else if (inTimecodeFPS <= 1000)
+ {
+ // "%03ld"
+ stream << possibleNegStr << std::setfill('0') << std::setw(3) << static_cast<int>(ss);
+ possibleNegStr.clear();
+ }
+ else
+ {
+ // "%04ld"
+ stream << possibleNegStr << std::setfill('0') << std::setw(4) << static_cast<int>(ss);
+ possibleNegStr.clear();
+ }
+ }
+ else
+ {
+ // "%ld"
+ stream << possibleNegStr << static_cast<int>(ss);
+ possibleNegStr.clear();
+ }
+
+ if (inShowFractional)
+ {
+ // ".%02d"
+ stream << possibleNegStr << "."
+ << std::setfill('0') << std::setw(2) << static_cast<int>(hundredthsOfFrames);
+ possibleNegStr.clear();
+ }
+ }
+ }
+ }
+
+ outTimecode = stream.str();
+
+ return true;
+ }
+
+ bool ConvertSamplesToSMPTETimecode(
+ std::string & outTimecode,
+ XMP_Int64 inSamples,
+ XMP_Uns64 inSampleRate,
+ const std::string & inTimecodeFormat )
+ {
+ bool result = false;
+
+ if ( inTimecodeFormat.compare( "24Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 24, false, false );
+ } else if ( inTimecodeFormat.compare( "25Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 25, false, false );
+ } else if ( inTimecodeFormat.compare( "2997DropTimecode") == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 30, true, false );
+ } else if ( inTimecodeFormat.compare( "2997NonDropTimecode") == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 30, false, true );
+ } else if ( inTimecodeFormat.compare( "30Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 30, false, false );
+ } else if ( inTimecodeFormat.compare( "50Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 50, false, false );
+ } else if ( inTimecodeFormat.compare( "5994DropTimecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 60, true, false );
+ } else if ( inTimecodeFormat.compare( "5994NonDropTimecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 60, false, true );
+ } else if ( inTimecodeFormat.compare( "60Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode( outTimecode, inSamples, inSampleRate, 60, false, false );
+ } else if ( inTimecodeFormat.compare( "23976Timecode" ) == 0 ) {
+ result = ConvertSamplesToTimecode(outTimecode, inSamples, inSampleRate, 24, false, true);
+ }
+ return result;
+ }
+
+ bool StringToNumber(
+ XMP_Int32 & outNumber,
+ const std::string & inString )
+ {
+ bool numberFound = false;
+ outNumber = 0;
+ for ( size_t i = 0, endIndex = inString.size(); i < endIndex; i++ ) {
+ XMP_Int32 digit = inString[i] - '0';
+ if ( digit >= 0 && digit <= 9 ) {
+ outNumber *= 10;
+ outNumber += digit;
+ numberFound = true;
+ } else {
+ return numberFound;
+ }
+ }
+ return numberFound;
+ }
+
+ void ParseTimeCodeString(
+ const std::string & inTimecode,
+ XMP_Int32 & outHours,
+ XMP_Int32 & outMinutes,
+ XMP_Int32 & outSeconds,
+ XMP_Int32 & outFrames,
+ XMP_Int32 & outFractionalFrameNumerator,
+ XMP_Int32 & outFractionalFrameDenominator )
+ {
+ XMP_Int32 m1 = 0;
+ XMP_Int32 m2 = 0;
+ XMP_Int32 m3 = 0;
+ XMP_Int32 m4 = 0;
+ XMP_Int32 m5 = 0;
+ bool hasFoundDecimal = false;
+ XMP_Int32 digitCount = 0;
+
+ outFractionalFrameNumerator = 0;
+ outFractionalFrameDenominator = 1;
+
+ std::string::const_iterator iter = inTimecode.begin();
+ std::string::const_iterator iterEnd = inTimecode.end();
+
+ while (1)
+ { // Skip leading white space
+ while ( iter != iterEnd && (*iter < '0' || *iter > '9') )
+ {
+ if (*iter == '.')
+ hasFoundDecimal = true;
+ iter++;
+ } // hh:mm:ss:ff.ddd
+ if (iter == iterEnd)
+ break;
+
+ if (!hasFoundDecimal)
+ {
+ // get MSB digits
+ StringToNumber(m1, std::string(iter, iterEnd));
+
+ // Skip the digits
+ while (iter != iterEnd && (*iter >= '0' && *iter <= '9'))
+ iter++;
+
+ // Skip the white space, note if "." or ":" ("." signifies decimal portion of frame)
+ while ( iter != iterEnd && (*iter < '0' || *iter > '9'))
+ {
+ if (*iter == '.')
+ hasFoundDecimal = true;
+ iter++;
+ }
+
+ if (iter == iterEnd)
+ break;
+ }
+ // shift and scan next MSB digits
+
+ if (!hasFoundDecimal)
+ {
+ m2 = m1;
+ digitCount = static_cast< XMP_Int32 >( iterEnd - iter );
+ StringToNumber(m1, std::string(iter, iterEnd));
+
+ // Skip the digits
+ while ( iter != iterEnd && (*iter >= '0' && *iter <= '9') )
+ iter++;
+
+ // Skip the white space, note if "." or ":" ("." signifies
+ // decimal portion of frame)
+ while (iter != iterEnd && (*iter < '0' || *iter > '9'))
+ {
+ if (*iter == '.')
+ hasFoundDecimal = true;
+ iter++;
+ }
+ }
+
+ if (iter == iterEnd)
+ break;
+
+ m3 = m2;
+ m2 = m1;
+ digitCount = static_cast< XMP_Int32 >( iterEnd - iter );
+ StringToNumber(m1, std::string(iter, iterEnd));
+ if (hasFoundDecimal)
+ break;
+
+ while (iter != iterEnd && (*iter >= '0' && *iter <= '9'))
+ iter++;
+
+ // Skip the white space, note if "." or ":" ("." signifies decimal portion of frame)
+ while (iter != iterEnd && (*iter < '0' || *iter > '9'))
+ {
+ if (*iter == '.')
+ hasFoundDecimal = true;
+ iter++;
+ }
+ if (iter == iterEnd)
+ break;
+
+ m4 = m3;
+ m3 = m2;
+ m2 = m1;
+ digitCount = static_cast< XMP_Int32 >( iterEnd - iter );
+ StringToNumber(m1, std::string(iter, iterEnd));
+ if (hasFoundDecimal)
+ break;
+
+ while (iter != iterEnd && (*iter >= '0' && *iter <= '9'))
+ {
+ iter++;
+ }
+
+ // Skip the white space, note if "." or ":" ("." signifies decimal portion of frame)
+ while (iter != iterEnd && (*iter < '0' || *iter > '9'))
+ {
+ if (*iter == '.')
+ hasFoundDecimal = true;
+ iter++;
+ }
+
+ if (iter == iterEnd)
+ break;
+
+ m5 = m4;
+ m4 = m3;
+ m3 = m2;
+ m2 = m1;
+ digitCount = static_cast< XMP_Int32 >( iterEnd - iter );
+ StringToNumber(m1, std::string(iter, iterEnd));
+ break;
+ }
+
+ if (hasFoundDecimal)
+ {
+ outFractionalFrameDenominator = static_cast<XMP_Int32>(pow(10.0, digitCount) + 0.5);
+ outFractionalFrameNumerator = m1;
+ m1 = m2;
+ m2 = m3;
+ m3 = m4;
+ m4 = m5;
+ m5 = 0;
+ }
+ outHours = m4;
+ outMinutes = m3;
+ outSeconds = m2;
+ outFrames = m1;
+ }
+
+ bool ConvertTimecodeToSamples(
+ XMP_Int64 & outSamples,
+ const std::string & inTimecode,
+ XMP_Uns64 inSampleRate,
+ XMP_Int64 inTimecodeFPS,
+ bool inNTSC,
+ bool inDropFrame)
+ {
+ /// @TODO: Ensure that negative and >64-bit values are OK and work as expected.
+
+ if (inTimecode.empty())
+ {
+ outSamples = static_cast<XMP_Int64>(-1);
+ return true;
+ }
+
+ XMP_Int32 hours;
+ XMP_Int32 minutes;
+ XMP_Int32 seconds;
+ XMP_Int32 frames;
+ XMP_Int32 fractionalFrameNumerator;
+ XMP_Int32 fractionalFrameDenominator;
+
+ ParseTimeCodeString(inTimecode, hours, minutes, seconds, frames, fractionalFrameNumerator, fractionalFrameDenominator);
+
+ XMP_Int64 framesPerSecond = inTimecodeFPS;
+ XMP_Int64 framesPerMinute = framesPerSecond * 60;
+ XMP_Int64 framesPerHour = framesPerMinute * 60;
+ XMP_Int64 wholeFrames = 0;
+ XMP_Int64 frameRateNumerator = inTimecodeFPS;
+ XMP_Int64 frameRateDenominator = 1;
+
+ if (inNTSC)
+ {
+ frameRateNumerator = 1000 * inTimecodeFPS;
+ frameRateDenominator = 1001;
+ }
+
+ if (inDropFrame)
+ {
+ XMP_Int64 frameGroupDropped = 2 * inTimecodeFPS / 30; // 2 or 4 frames dropped at a time.
+ XMP_Int64 framesPerHourDropped = 108 * inTimecodeFPS / 30;
+ framesPerHour -= framesPerHourDropped;
+ XMP_Int64 framesPerTenMinutes = framesPerHour / 6;
+ XMP_Assert( framesPerHour % 6 == 0 ); //, "Drop frame not supported on the given frame rate."
+ XMP_Int64 framesDroppedWithinTheLeastTenMinutes = 0;
+ if (minutes % 10 != 0)
+ {
+ if ((seconds == 0) && (frames < frameGroupDropped))
+ {
+ frames = static_cast<XMP_Int32>(frameGroupDropped); // Make sure invalid strings snap to the next higher valid frame.
+ }
+ framesDroppedWithinTheLeastTenMinutes = (minutes % 10) * frameGroupDropped;
+ }
+ wholeFrames = hours * framesPerHour + (minutes / 10) * framesPerTenMinutes + (minutes % 10) * framesPerMinute + seconds * framesPerSecond + frames - framesDroppedWithinTheLeastTenMinutes;
+ }
+ else
+ {
+ wholeFrames = hours * framesPerHour + minutes * framesPerMinute + seconds * framesPerSecond + frames;
+ }
+
+ if (frameRateNumerator * fractionalFrameDenominator == 0)
+ {
+ XMP_Assert( "Divide by zero in ConvertTimecodeToSamples" );
+ outSamples = 0;
+ return true;
+ }
+
+ //
+ // (frame count / frames per second) * samples per second = sample count.
+ //
+ // ((frame count + fractionalFrameNumerator / fractionalFrameDenominator) * samples per second / frames per second) = sample count.
+ // or in integer math:
+ // ((frame count * fractionalFrameDenominator + fractionalFrameNumerator) * samples per second / (frames per second * fractionalFrameDenominator)) = sample count.
+ // with rounding correction to give us the first sample contained entirely in the frame:
+
+ // There is a non-zero probability of rolling over this integer arithmetic.
+ double integerFailsafeNumerator = ((static_cast<double>(wholeFrames) * static_cast<double>(fractionalFrameDenominator) + fractionalFrameNumerator) * static_cast<double>(frameRateDenominator) * static_cast<double>(inSampleRate) + (frameRateNumerator * fractionalFrameDenominator - 1));
+ if (integerFailsafeNumerator > static_cast<double>(0x7000000000000000LL))
+ {
+ outSamples = static_cast<XMP_Int64>(integerFailsafeNumerator / (static_cast<double>(frameRateNumerator) * static_cast<double>(fractionalFrameDenominator)));
+ }
+ else
+ {
+ outSamples = ((wholeFrames * fractionalFrameDenominator + fractionalFrameNumerator) * frameRateDenominator * inSampleRate + (frameRateNumerator * fractionalFrameDenominator - 1)) / (frameRateNumerator * fractionalFrameDenominator);
+ }
+ return true;
+ }
+
+ bool ConvertSMPTETimecodeToSamples(
+ XMP_Int64 & outSamples,
+ const std::string & inTimecode,
+ XMP_Uns64 inSampleRate,
+ const std::string & inTimecodeFormat )
+ {
+ bool result = false;
+
+ if ( inTimecodeFormat.compare( "24Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 24, false, false );
+ } else if ( inTimecodeFormat.compare( "25Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 25, false, false );
+ } else if ( inTimecodeFormat.compare( "2997DropTimecode") == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 30, true, true );
+ } else if ( inTimecodeFormat.compare( "2997NonDropTimecode") == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 30, true, false );
+ } else if ( inTimecodeFormat.compare( "30Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 30, false, false );
+ } else if ( inTimecodeFormat.compare( "50Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 50, false, false );
+ } else if ( inTimecodeFormat.compare( "5994DropTimecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 60, true, true );
+ } else if ( inTimecodeFormat.compare( "5994NonDropTimecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 60, true, false );
+ } else if ( inTimecodeFormat.compare( "60Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 60, false, false );
+ } else if ( inTimecodeFormat.compare( "23976Timecode" ) == 0 ) {
+ result = ConvertTimecodeToSamples( outSamples, inTimecode, inSampleRate, 24, true, false );
+ }
+ return result;
+ }
+
+}
diff --git a/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp b/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp
new file mode 100644
index 0000000..bf7ed04
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/TimeConversionUtils.hpp
@@ -0,0 +1,35 @@
+#ifndef TimeConversionUtils_h__
+#define TimeConversionUtils_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPFiles/source/XMPFiles_Impl.hpp"
+
+namespace TimeConversionUtils {
+ bool ConvertSamplesToSMPTETimecode(
+ std::string & outTimecode,
+ XMP_Int64 inSamples,
+ XMP_Uns64 inSampleRate,
+ const std::string & inTimecodeFormat );
+
+ bool ConvertSMPTETimecodeToSamples(
+ XMP_Int64 & outSamples,
+ const std::string & inTimecode,
+ XMP_Uns64 inSampleRate,
+ const std::string & inTimecodeFormat
+ );
+
+
+};
+
+#endif // TimeConversionUtils_h__
diff --git a/XMPFiles/source/FormatSupport/WAVE/Cr8rMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/Cr8rMetadata.cpp
index 277924f..d085aca 100644
--- a/XMPFiles/source/FormatSupport/WAVE/Cr8rMetadata.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/Cr8rMetadata.cpp
@@ -79,8 +79,6 @@ void Cr8rMetadata::parse( const XMP_Uns8* chunkData, XMP_Uns64 size )
{
if( size >= kCr8rSizeFix )
{
- const LittleEndian& LE = LittleEndian::getInstance();
-
Cr8rBoxContent cr8r;
memset( &cr8r, 0, kCr8rSizeFix );
diff --git a/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
index 6597f2a..335acd7 100644
--- a/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/INFOMetadata.cpp
@@ -189,6 +189,8 @@ XMP_Uns64 INFOMetadata::serialize( XMP_Uns8** outBuffer )
// chunk id
// chunk size
//
+ XMP_Validate( iter->second != NULL, "ERROR inserting serialize. iter->second is NULL.", kXMPErr_InternalFailure );
+ XMP_Assert(dynamic_cast<TValueObject<std::string>*>(iter->second) == static_cast<TValueObject<std::string>*>(iter->second));
TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(iter->second);
std::string value = strObj->getValue();
XMP_Uns32 id = iter->first;
diff --git a/XMPFiles/source/FormatSupport/WAVE/PrmLMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/PrmLMetadata.cpp
index 477c31e..87d29fb 100644
--- a/XMPFiles/source/FormatSupport/WAVE/PrmLMetadata.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/PrmLMetadata.cpp
@@ -76,8 +76,6 @@ void PrmLMetadata::parse( const XMP_Uns8* chunkData, XMP_Uns64 size )
{
if( size >= kPrmlSizeFix )
{
- const LittleEndian& LE = LittleEndian::getInstance();
-
PrmlBoxContent prml;
memset( &prml, 0, kPrmlSizeFix );
diff --git a/XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.cpp b/XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.cpp
index 1e98f4f..60ce5ae 100644
--- a/XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.cpp
@@ -431,7 +431,7 @@ WAVEBehavior::DS64* WAVEBehavior::getDS64( IChunkContainer& tree, XMP_IO* stream
ds64 = NULL;
}
- if( ds64 != NULL && ds64->getID() == kChunk_ds64 )
+ if( rf64 != NULL && ds64 != NULL && ds64->getID() == kChunk_ds64 )
{
//
// Successfully read 'ds64' chunk.
@@ -439,7 +439,6 @@ WAVEBehavior::DS64* WAVEBehavior::getDS64( IChunkContainer& tree, XMP_IO* stream
// add chunk to the 'RF64' chunk
//
ds64->cacheChunkData( stream );
-
rf64->appendChild( ds64, false );
}
else
@@ -600,7 +599,7 @@ bool WAVEBehavior::parseDS64Chunk( const Chunk& ds64Chunk, WAVEBehavior::DS64& d
const XMP_Uns8* data;
XMP_Uns64 size = ds64Chunk.getData(&data);
- memset( &ds64, 0, kMinimumDS64ChunkSize );
+ memset( &ds64, 0, kMinimumDS64ChunkSize);
//
// copy fix input data into RF64 block (except chunk size table)
diff --git a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
index 3798f3d..8c3067b 100644
--- a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
+++ b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.cpp
@@ -15,6 +15,9 @@
#include "XMPFiles/source/FormatSupport/WAVE/INFOMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/BEXTMetadata.h"
#include "XMPFiles/source/FormatSupport/WAVE/CartMetadata.h"
+#include "XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h"
+
+#include "XMPFiles/source/FormatSupport/TimeConversionUtils.hpp"
// cr8r is not yet required for WAVE
//#include "Cr8rMetadata.h"
@@ -27,19 +30,69 @@ using namespace IFF_RIFF;
// ************** legacy Mappings ***************** //
+static const char * kBWF_description = "description";
+static const char * kBWF_originator = "originator";
+static const char * kBWF_originatorReference = "originatorReference";
+static const char * kBWF_originationDate = "originationDate";
+static const char * kBWF_originationTime = "originationTime";
+static const char * kBWF_timeReference = "timeReference";
+static const char * kBWF_version = "version";
+static const char * kBWF_umid = "umid";
+static const char * kBWF_codingHistory = "codingHistory";
+static const char * kBWF_timeStampSampleRate = "timeSampleRate"; // its transient should be deleted at the end.
+
static const MetadataPropertyInfo kBextProperties[] =
{
-// XMP NS XMP Property Name Native Metadata Identifier Native Datatype XMP Datatype Delete Priority ExportPolicy
- { kXMP_NS_BWF, "description", BEXTMetadata::kDescription, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:description <-> BEXT:Description
- { kXMP_NS_BWF, "originator", BEXTMetadata::kOriginator, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:originator <-> BEXT:originator
- { kXMP_NS_BWF, "originatorReference", BEXTMetadata::kOriginatorReference, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:OriginatorReference <-> BEXT:OriginatorReference
- { kXMP_NS_BWF, "originationDate", BEXTMetadata::kOriginationDate, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:originationDate <-> BEXT:originationDate
- { kXMP_NS_BWF, "originationTime", BEXTMetadata::kOriginationTime, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:originationTime <-> BEXT:originationTime
- { kXMP_NS_BWF, "timeReference", BEXTMetadata::kTimeReference, kNativeType_Uns64, kXMPType_Simple, true, false, kExport_Always }, // bext:timeReference <-> BEXT:TimeReferenceLow + BEXT:TimeReferenceHigh
+// XMP NS XMP Property Name Native Metadata Identifier Native Datatype XMP Datatype Delete Priority ExportPolicy
+ { kXMP_NS_BWF, kBWF_description, BEXTMetadata::kDescription, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:description <-> BEXT:Description
+ { kXMP_NS_BWF, kBWF_originator, BEXTMetadata::kOriginator, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:originator <-> BEXT:originator
+ { kXMP_NS_BWF, kBWF_originatorReference, BEXTMetadata::kOriginatorReference, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:OriginatorReference <-> BEXT:OriginatorReference
+ { kXMP_NS_BWF, kBWF_originationDate, BEXTMetadata::kOriginationDate, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:originationDate <-> BEXT:originationDate
+ { kXMP_NS_BWF, kBWF_originationTime, BEXTMetadata::kOriginationTime, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:originationTime <-> BEXT:originationTime
+ { kXMP_NS_BWF, kBWF_timeReference, BEXTMetadata::kTimeReference, kNativeType_Uns64, kXMPType_Simple, false, false, kExport_Always }, // bext:timeReference <-> BEXT:TimeReferenceLow + BEXT:TimeReferenceHigh
// Special case: On export BEXT:version is always written as 1
- { kXMP_NS_BWF, "version", BEXTMetadata::kVersion, kNativeType_Uns16, kXMPType_Simple, true, false, kExport_Never }, // bext:version <-> BEXT:version
+ { kXMP_NS_BWF, kBWF_version, BEXTMetadata::kVersion, kNativeType_Uns16, kXMPType_Simple, false, false, kExport_Never }, // bext:version <-> BEXT:version
// special case: bext:umid <-> BEXT:UMID
- { kXMP_NS_BWF, "codingHistory", BEXTMetadata::kCodingHistory, kNativeType_StrLocal, kXMPType_Simple, true, false, kExport_Always }, // bext:codingHistory <-> BEXT:codingHistory
+ { kXMP_NS_BWF, kBWF_codingHistory, BEXTMetadata::kCodingHistory, kNativeType_StrLocal, kXMPType_Simple, false, false, kExport_Always }, // bext:codingHistory <-> BEXT:codingHistory
+ { NULL }
+};
+
+static const char * kDM_takeNumber = "takeNumber";
+static const char * kDM_audioSampleType = "audioSampleType";
+static const char * kDM_scene = "scene";
+static const char * kDM_tapeName = "tapeName";
+static const char * kDM_logComment = "logComment";
+static const char * kDM_projectName = "projectName";
+static const char * kDM_audioSampleRate = "audioSampleRate";
+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 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_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
+ { kXMP_NS_DM, kDM_good, iXMLMetadata::kCircled, kNativeType_Bool, kXMPType_Simple, false, false, kExport_Always }, //xmpDM:good <-> iXML:CIRCLED
+ { kXMP_NS_DM, kDM_audioSampleRate, iXMLMetadata::kFileSampleRate, kNativeType_Uns64, kXMPType_Simple, false, false, kExport_Always }, // xmpDM:audioSampleRate <-> iXML:FILE_SAMPLE_RATE
+ // special case for AudioBitDepth // xmpDM:audioSampleType <-> iXML:AUDIO_BIT_DEPTH
+ { kXMP_NS_BWF, kBWF_description, iXMLMetadata::kBWFDescription, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:description <-> iXML:BWF_DESCRIPTION
+ { kXMP_NS_BWF, kBWF_originator, iXMLMetadata::kBWFOriginator, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:originator <-> iXML:BWF_ORIGINATOR
+ { kXMP_NS_BWF, kBWF_originatorReference, iXMLMetadata::kBWFOriginatorReference, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:OriginatorReference <-> iXML:BWF_ORIGINATOR_REFERENCE
+ { kXMP_NS_BWF, kBWF_originationDate, iXMLMetadata::kBWFOriginationDate, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:originationDate <-> iXML:BWF_ORIGINATION_DATE
+ { kXMP_NS_BWF, kBWF_originationTime, iXMLMetadata::kBWFOriginationTime, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:originationTime <-> iXML:BWF_ORIGINATION_TIME
+ // special case for timeReference // bext:timeReference <-> iXML:BWF_TIME_REFERENCE_LOW and iXML:BWF_TIME_REFERENCE_HIGH
+ // Special case: On export BEXT:version is always written as 1
+ { kXMP_NS_BWF, kBWF_version, iXMLMetadata::kBWFVersion, kNativeType_Uns64, kXMPType_Simple, true, false, kExport_Never }, // bext:version <-> iXML:BWF_VERSION
+ { kXMP_NS_BWF, kBWF_codingHistory, iXMLMetadata::kBWFHistory, kNativeType_StrUTF8, kXMPType_Simple, true, false, kExport_Always }, // bext:codingHistory <-> iXML:BWF_CODING_HISTORY
+ { kXMP_NS_BWF, kBWF_umid, iXMLMetadata::kBWFUMID, kNativeType_StrASCII, kXMPType_Simple, true, false, kExport_Always }, // bext:codingHistory <-> iXML:BWF_CODING_HISTORY
+ // 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
{ NULL }
};
@@ -140,6 +193,14 @@ XMP_Bool WAVEReconcile::importToXMP( SXMPMeta& outXMP, const MetadataSet& inMeta
if ( ! ignoreLocalText )
{
+ //
+ // Import iXML
+ //
+ iXMLMetadata * iXMLMeta = inMetaData.get<iXMLMetadata>();
+ if ( iXMLMeta != NULL ) {
+ changed |= IReconcile::importNativeToXMP( outXMP, *iXMLMeta, kiXMLProperties, false );
+ changed |= exportSpecialiXMLToXMP( *iXMLMeta, outXMP );
+ }
//
// Import BEXT
@@ -291,6 +352,45 @@ XMP_Bool WAVEReconcile::importToXMP( SXMPMeta& outXMP, const MetadataSet& inMeta
}
}
+ // do timecode calculations
+ if ( outXMP.DoesPropertyExist( kXMP_NS_BWF, kBWF_timeReference ) &&
+ outXMP.DoesPropertyExist( kXMP_NS_BWF, kDM_timeFormat ) &&
+ outXMP.DoesPropertyExist( kXMP_NS_BWF, kBWF_timeStampSampleRate ) )
+ {
+ std::string xmpValue;
+ XMP_Int64 sampleRate = 0;
+ XMP_Uns64 nSamples = 0;
+ std::string timeFormat;
+ bool ok = outXMP.GetProperty( kXMP_NS_BWF, kBWF_timeReference, &xmpValue, 0 );
+
+ if ( ok )
+ {
+ int count;
+ char nextCh;
+ const char * strValue = xmpValue.c_str();
+ count = sscanf ( strValue, "%llu%c", &nSamples, &nextCh );
+
+ if ( count != 1 ) ok = false;
+ }
+ if ( ok )
+ ok = outXMP.GetProperty_Int64( kXMP_NS_BWF, kBWF_timeStampSampleRate, &sampleRate, 0 );
+ if ( ok )
+ ok = outXMP.GetProperty( kXMP_NS_BWF, kDM_timeFormat, &timeFormat, 0 );
+
+ if ( ok && sampleRate != 0 && timeFormat.size() > 0 ) {
+ // compute time code from all the information we have
+ std::string timecode;
+ if ( TimeConversionUtils::ConvertSamplesToSMPTETimecode( timecode, nSamples, sampleRate, timeFormat ) ) {
+ outXMP.SetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeValue, timecode, 0 );
+ outXMP.SetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeFormat, timeFormat, 0 );
+ }
+ }
+ }
+
+ // delete transient properties
+ outXMP.DeleteProperty( kXMP_NS_BWF, kBWF_timeStampSampleRate );
+ outXMP.DeleteProperty( kXMP_NS_BWF, kDM_timeFormat );
+
return changed;
} // importToXMP
@@ -310,9 +410,55 @@ XMP_Bool WAVEReconcile::exportFromXMP( MetadataSet& outMetaData, SXMPMeta& inXMP
changed |= IReconcile::exportXMPToNative( *dispMeta, inXMP, kDISPProperties );
}
-
+ PropertyList propertiesToBeRemovedFromXMPMeta;
if ( ! ignoreLocalText )
{
+ bool removeAllPropertiesinBextNameSpace = false;
+ //
+ // Export iXML
+ //
+ iXMLMetadata *iXMLMeta = outMetaData.get<iXMLMetadata>();
+ if (iXMLMeta != NULL)
+ {
+ IReconcile::exportXMPToNative( *iXMLMeta, inXMP, kiXMLProperties, &propertiesToBeRemovedFromXMPMeta );
+ exportSpecialXMPToiXML( inXMP, *iXMLMeta, propertiesToBeRemovedFromXMPMeta );
+ changed |= iXMLMeta->hasChanged();
+ removeAllPropertiesinBextNameSpace = true;
+ // for maintaing backward compatibility we don't want to remove properties from xmp packet.
+ propertiesToBeRemovedFromXMPMeta.clear();
+
+ // update time code value
+ if ( iXMLMeta->valueExists( iXMLMetadata::kTimeStampSampleRate ) &&
+ iXMLMeta->valueExists( iXMLMetadata::kTimeStampSampleSinceMidnightHigh ) &&
+ iXMLMeta->valueExists( iXMLMetadata::kTimeStampSampleSinceMidnightLow ) &&
+ iXMLMeta->valueExists( iXMLMetadata::kTimeCodeRate ) )
+ {
+ if ( iXMLMeta->valueChanged( iXMLMetadata::kTimeStampSampleRate ) ||
+ iXMLMeta->valueChanged( iXMLMetadata::kTimeStampSampleSinceMidnightHigh ) ||
+ iXMLMeta->valueChanged( iXMLMetadata::kTimeStampSampleSinceMidnightLow ) ||
+ iXMLMeta->valueChanged( iXMLMetadata::kTimeCodeRate ) ||
+ ( iXMLMeta->valueExists( iXMLMetadata::kTimeCodeFlag ) && iXMLMeta->valueChanged( iXMLMetadata::kTimeCodeFlag ) ) )
+ {
+ // update the time code value
+ XMP_Int64 sampleRate = iXMLMeta->getValue<XMP_Uns64>( iXMLMetadata::kTimeStampSampleRate );
+ XMP_Int64 nSamples = 0;
+ std::string timeFormat;
+ bool ok = inXMP.GetProperty_Int64( kXMP_NS_BWF, kBWF_timeReference, &nSamples, 0 );
+ if ( ok )
+ ok = inXMP.GetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeFormat, &timeFormat, 0 );
+
+ if ( ok && sampleRate != 0 && timeFormat.size() > 0 ) {
+ // compute time code from all the information we have
+ std::string timecode;
+ if ( TimeConversionUtils::ConvertSamplesToSMPTETimecode( timecode, nSamples, sampleRate, timeFormat ) ) {
+ inXMP.SetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeValue, timecode, 0 );
+ }
+ }
+
+ }
+ }
+ }
+
//
// Export BEXT
//
@@ -355,12 +501,13 @@ XMP_Bool WAVEReconcile::exportFromXMP( MetadataSet& outMetaData, SXMPMeta& inXMP
bextMeta->deleteValue(BEXTMetadata::kVersion);
}
- // Remove BWF properties from the XMP
- SXMPUtils::RemoveProperties(&inXMP, kXMP_NS_BWF, NULL, kXMPUtil_DoAllProperties );
+ removeAllPropertiesinBextNameSpace = true;
changed |= bextMeta->hasChanged();
}
+ if ( removeAllPropertiesinBextNameSpace )
+ SXMPUtils::RemoveProperties(&inXMP, kXMP_NS_BWF, NULL, kXMPUtil_DoAllProperties );
//
// Export cart
@@ -486,6 +633,11 @@ XMP_Bool WAVEReconcile::exportFromXMP( MetadataSet& outMetaData, SXMPMeta& inXMP
//
inXMP.DeleteProperty( kXMP_NS_WAV, "NativeDigest" );
+ for ( PropertyList::iterator it = propertiesToBeRemovedFromXMPMeta.begin(), last = propertiesToBeRemovedFromXMPMeta.end(); it != last; it++ )
+ {
+ inXMP.DeleteProperty( it->first, it->second );
+ }
+
return changed;
} // exportFromXMP
@@ -574,3 +726,342 @@ bool WAVEReconcile::stringToFOURCC ( std::string input, XMP_Uns32 &output )
return result;
}
+
+struct iXMLAudioSampleTypeMapping
+{
+ const char * xmpStringValue;
+ XMP_Uns64 ixmlIntValue;
+};
+
+iXMLAudioSampleTypeMapping ixmlAudioSampleTypeMappings[] = {
+ { "8Int", 8 },
+ { "16Int", 16 },
+ { "24Int", 24 },
+ { "32Float", 32 },
+};
+
+struct iXMLTimeCodeRateAndFlagMapping
+{
+ const char * xmpStringValue;
+ const char * ixmlTimeCodeRateValue;
+ const char * ixmlTimeCodeFlagValue;
+};
+
+iXMLTimeCodeRateAndFlagMapping ixmlTimeCodeRateAndFlagMappings[] = {
+ { "24Timecode", "24/1", "NDF" },
+ { "25Timecode", "25/1", "NDF" },
+ { "2997DropTimecode", "30000/1001", "DF" },
+ { "2997NonDropTimecode", "30000/1001", "NDF" },
+ { "30Timecode", "30/1", "NDF" },
+ { "50Timecode", "50/1", "NDF" },
+ { "5994DropTimecode", "60000/1001", "DF" },
+ { "5994NonDropTimecode", "60000/1001", "NDF" },
+ { "60Timecode", "60/1", "NDF" },
+ { "23976Timecode", "24000/1001", "NDF" },
+};
+
+void IFF_RIFF::WAVEReconcile::exportSpecialXMPToiXML( SXMPMeta & inXMP, IMetadata & outNativeMeta, PropertyList & propertiesToBeDeleted )
+{
+ std::string sXmpValue;
+ XMP_Int64 iXMPValue;
+
+ // special case for NoGood and Circled // xmpDM:good ,-> iXML:NO_GOOD and iXML:CIRCLED
+
+ // special case for AudioBitDepth // xmpDM:audioSampleType <-> iXML:AUDIO_BIT_DEPTH
+ bool deleteNativeEntry = false;
+ try
+ {
+ if ( inXMP.GetProperty( kXMP_NS_DM, kDM_audioSampleType, &sXmpValue, 0 ) )
+ {
+ bool matchingValueFound = false;
+ XMP_Uns64 ixmlValue = 0;
+ for ( size_t i = 0, total = sizeof(ixmlAudioSampleTypeMappings )/sizeof( iXMLAudioSampleTypeMapping); i < total; i++ )
+ {
+ if ( sXmpValue.compare( ixmlAudioSampleTypeMappings[i].xmpStringValue ) == 0 )
+ {
+ ixmlValue = ixmlAudioSampleTypeMappings[i].ixmlIntValue;
+ matchingValueFound = true;
+ break;
+ }
+ }
+
+ if ( matchingValueFound )
+ {
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kAudioBitDepth, ixmlValue );
+ propertiesToBeDeleted.push_back( std::make_pair( kXMP_NS_DM, kDM_audioSampleType ) );
+ deleteNativeEntry = false;
+ }
+ else
+ {
+ deleteNativeEntry = true;
+ }
+ }
+ else
+ {
+ deleteNativeEntry = true;
+ }
+
+ if ( deleteNativeEntry )
+ {
+ if ( outNativeMeta.valueExists( iXMLMetadata::kAudioBitDepth ) )
+ {
+ XMP_Uns64 ixmlValue = outNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kAudioBitDepth );
+ bool validValue = false;
+ for ( size_t i = 0, total = sizeof(ixmlAudioSampleTypeMappings )/sizeof( iXMLAudioSampleTypeMapping); i < total; i++ )
+ {
+ if ( ixmlValue == ixmlAudioSampleTypeMappings[i].ixmlIntValue )
+ {
+ validValue = true;
+ break;
+ }
+ }
+ if ( validValue )
+ outNativeMeta.deleteValue( iXMLMetadata::kAudioBitDepth );
+ }
+ }
+ }
+ catch ( ... )
+ {
+ // do nothing
+ }
+
+ // Special case: On export BEXT:version is always written as 1
+ try
+ {
+ if ( inXMP.GetProperty( kXMP_NS_BWF, "version", NULL, 0 ) )
+ {
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kBWFVersion, 1 );
+ }
+ else
+ {
+ outNativeMeta.deleteValue( iXMLMetadata::kBWFVersion );
+ }
+ }
+ catch( ... )
+ {
+ // do nothing
+ }
+
+ // special case for xmpDM:startTimecode\xmpDM:timeFormat
+ try
+ {
+ if ( inXMP.GetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeFormat, &sXmpValue, 0 ) )
+ {
+ bool matchingValueFound = false;
+ const char * ixmlValueForTimeCodeRate = NULL;
+ const char * ixmlValueForTimeCodeFlag = NULL;
+ for ( size_t i = 0, total = sizeof(ixmlTimeCodeRateAndFlagMappings)/sizeof(iXMLTimeCodeRateAndFlagMapping); i < total; i++ )
+ {
+ if ( sXmpValue.compare( ixmlTimeCodeRateAndFlagMappings[i].xmpStringValue ) == 0 )
+ {
+ ixmlValueForTimeCodeRate = ixmlTimeCodeRateAndFlagMappings[i].ixmlTimeCodeRateValue;
+ ixmlValueForTimeCodeFlag = ixmlTimeCodeRateAndFlagMappings[i].ixmlTimeCodeFlagValue;
+ matchingValueFound = true;
+ deleteNativeEntry = false;
+ break;
+ }
+ }
+
+ if ( matchingValueFound )
+ {
+ outNativeMeta.setValue< std::string >( iXMLMetadata::kTimeCodeRate, ixmlValueForTimeCodeRate );
+ outNativeMeta.setValue< std::string >( iXMLMetadata::kTimeCodeFlag, ixmlValueForTimeCodeFlag );
+ }
+ else
+ {
+ deleteNativeEntry = true;
+ }
+ }
+ else
+ {
+ deleteNativeEntry = true;
+ }
+
+ if ( deleteNativeEntry )
+ {
+ if ( outNativeMeta.valueExists( iXMLMetadata::kTimeCodeRate ) )
+ {
+ std::string ixmlValueForTimecodeRate = outNativeMeta.getValue< std::string >( iXMLMetadata::kTimeCodeRate );
+ bool validValue = false;
+ for ( size_t i = 0, total = sizeof(ixmlTimeCodeRateAndFlagMappings)/sizeof(iXMLTimeCodeRateAndFlagMapping); i < total; i++ )
+ {
+ if ( ixmlValueForTimecodeRate.compare( ixmlTimeCodeRateAndFlagMappings[i].ixmlTimeCodeRateValue ) == 0 )
+ {
+ validValue = true;
+ break;
+ }
+ }
+ if ( validValue )
+ {
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeCodeRate );
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeCodeFlag );
+ }
+ }
+ }
+ }
+ catch( ... )
+ {
+ // do nothing
+ }
+
+ // special case for timeReference // bext:timeReference <-> iXML:BWF_TIME_REFERENCE_LOW and iXML:BWF_TIME_REFERENCE_HIGH
+ bool bextTimeReferenceDataAvailable = false;
+ XMP_Uns32 bextLowValue = 0;
+ XMP_Uns32 bextHighValue = 0;
+ bool timeCodeDataAvailable = false;
+ XMP_Uns32 tcLowValue = 0;
+ XMP_Uns32 tcHighValue = 0;
+
+ try
+ {
+ if ( inXMP.GetProperty_Int64( kXMP_NS_BWF, "timeReference", &iXMPValue, 0 ) )
+ {
+ bextTimeReferenceDataAvailable = true;
+ XMP_Uns64 uXmpValue = ( XMP_Uns64 )( iXMPValue );
+ bextLowValue = ( XMP_Uns32 ) uXmpValue;
+ bextHighValue = ( XMP_Uns32 ) ( uXmpValue >> 32 );
+ }
+ }
+ catch ( ... )
+ {
+ // do nothing
+ }
+
+#if 0 // reverse calculation from timecode to samples can result in different number of samples. So ignoring for time being
+ if ( outNativeMeta.valueExists( iXMLMetadata::kTimeStampSampleRate ) )
+ {
+ try
+ {
+ std::string timeFormat, timeValue;
+ if ( inXMP.GetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeValue, &timeValue, 0 ) &&
+ inXMP.GetStructField( kXMP_NS_DM, kDM_startTimecode, kXMP_NS_DM, kDM_timeFormat, &timeFormat, 0) )
+ {
+ XMP_Int64 nSamples;
+ if ( TimeConversionUtils::ConvertSMPTETimecodeToSamples( nSamples, timeValue,
+ outNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kTimeStampSampleRate ), timeFormat ) )
+ {
+ timeCodeDataAvailable = true;
+ XMP_Uns64 uXmpValue = ( XMP_Uns64 )( nSamples );
+ tcLowValue = ( XMP_Uns32 ) uXmpValue;
+ tcHighValue = ( XMP_Uns32 ) ( uXmpValue >> 32 );
+ }
+
+ }
+ }
+ catch ( ... )
+ {
+ // do nothing
+ }
+ }
+
+ if ( bextTimeReferenceDataAvailable && timeCodeDataAvailable )
+ {
+ // pick the one which is different, if both different pick the bext one
+ XMP_Uns64
+ }
+ else if ( bextTimeReferenceDataAvailable )
+ {
+ }
+ else if ( timeCodeDataAvailable )
+ {
+ }
+ else // none of the bextTimeReference and timeCode data is available
+ {
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeStampSampleSinceMidnightHigh );
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeStampSampleSinceMidnightLow );
+ outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceHigh );
+ outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceLow );
+ }
+#endif
+
+ if ( bextTimeReferenceDataAvailable ) {
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kBWFTimeReferenceHigh, bextHighValue );
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kBWFTimeReferenceLow, bextLowValue );
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kTimeStampSampleSinceMidnightHigh, bextHighValue );
+ outNativeMeta.setValue< XMP_Uns64 >( iXMLMetadata::kTimeStampSampleSinceMidnightLow, bextLowValue );
+ } else {
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeStampSampleSinceMidnightHigh );
+ outNativeMeta.deleteValue( iXMLMetadata::kTimeStampSampleSinceMidnightLow );
+ outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceHigh );
+ outNativeMeta.deleteValue( iXMLMetadata::kBWFTimeReferenceLow );
+ }
+}
+
+bool IFF_RIFF::WAVEReconcile::exportSpecialiXMLToXMP( IMetadata & inNativeMeta, SXMPMeta & outXMP )
+{
+ bool changed = false;
+ // special case for AudioBitDepth // xmpDM:audioSampleType <-> iXML:AUDIO_BIT_DEPTH
+ if ( inNativeMeta.valueExists( iXMLMetadata::kAudioBitDepth ) ) {
+ XMP_Uns64 ixmlValue = inNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kAudioBitDepth);
+ const char * xmpValue = NULL;
+ bool matchingValueFound = false;
+
+ for ( size_t i = 0, total = sizeof(ixmlAudioSampleTypeMappings)/sizeof(iXMLAudioSampleTypeMapping); i < total; i++ )
+ {
+ if ( ixmlAudioSampleTypeMappings[i].ixmlIntValue == ixmlValue )
+ {
+ xmpValue = ixmlAudioSampleTypeMappings[i].xmpStringValue;
+ matchingValueFound = true;
+ break;
+ }
+ }
+ if ( matchingValueFound )
+ {
+ outXMP.SetProperty( kXMP_NS_DM, kDM_audioSampleType, xmpValue );
+ changed = true;
+ }
+ }
+
+ // special case for timeReference // bext:timeReference <-> iXML:TIME_SAMPLES_SINCE_MIDNIGHT_LO and iXML:TIME_SAMPLES_SINCE_MIDNIGHT_HI
+ if ( inNativeMeta.valueExists( iXMLMetadata::kTimeStampSampleSinceMidnightHigh ) && inNativeMeta.valueExists( iXMLMetadata::kTimeStampSampleSinceMidnightLow ) ) {
+ XMP_Uns64 combinedValue = inNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kTimeStampSampleSinceMidnightHigh );
+ combinedValue = combinedValue << 32;
+ combinedValue += inNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kTimeStampSampleSinceMidnightLow );
+ std::string strValue;
+ SXMPUtils::ConvertFromInt64( combinedValue, "%llu", &strValue );
+ outXMP.SetProperty( kXMP_NS_BWF, "timeReference", strValue );
+ changed = true;
+ }
+
+ // special case for timeReference // bext:timeReference <-> iXML:BWF_TIME_REFERENCE_LOW and iXML:BWF_TIME_REFERENCE_HIGH
+ if ( inNativeMeta.valueExists( iXMLMetadata::kBWFTimeReferenceHigh ) && inNativeMeta.valueExists( iXMLMetadata::kBWFTimeReferenceLow ) ) {
+ XMP_Uns64 combinedValue = inNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kBWFTimeReferenceHigh );
+ combinedValue = combinedValue << 32;
+ combinedValue += inNativeMeta.getValue< XMP_Uns64 >( iXMLMetadata::kBWFTimeReferenceLow );
+ std::string strValue;
+ SXMPUtils::ConvertFromInt64( combinedValue, "%llu", &strValue );
+ outXMP.SetProperty( kXMP_NS_BWF, "timeReference", strValue );
+ changed = true;
+ }
+
+ // special case for xmpDM:startTimecode\xmpDM:timeFormat
+ if ( inNativeMeta.valueExists( iXMLMetadata::kTimeCodeRate ) )
+ {
+ std::string ixmlTimecodeRateValue = inNativeMeta.getValue<std::string>( iXMLMetadata::kTimeCodeRate );
+ std::string ixmlTimecodeFlagValue = "NDF";
+ const char * xmpValue = NULL;
+ bool matchingValueFound = false;
+ if ( inNativeMeta.valueExists( iXMLMetadata::kTimeCodeFlag ) )
+ {
+ ixmlTimecodeFlagValue = inNativeMeta.getValue<std::string>( iXMLMetadata::kTimeCodeFlag );
+ }
+
+ for ( size_t i = 0, total = sizeof(ixmlTimeCodeRateAndFlagMappings)/sizeof(iXMLTimeCodeRateAndFlagMapping); i < total; i++ )
+ {
+ if ( ( ixmlTimecodeRateValue.compare(ixmlTimeCodeRateAndFlagMappings[i].ixmlTimeCodeRateValue) == 0 ) &&
+ ( ixmlTimecodeFlagValue.compare(ixmlTimeCodeRateAndFlagMappings[i].ixmlTimeCodeFlagValue) == 0 ) )
+ {
+ xmpValue = ixmlTimeCodeRateAndFlagMappings[i].xmpStringValue;
+ matchingValueFound = true;
+ break;
+ }
+ }
+ if ( matchingValueFound )
+ {
+ outXMP.SetProperty( kXMP_NS_BWF, kDM_timeFormat, xmpValue );
+ changed = true;
+ }
+ }
+
+ return changed;
+}
diff --git a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h
index 44a4ef3..7f0c2b8 100644
--- a/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h
+++ b/XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h
@@ -59,6 +59,12 @@ private:
* convert a 4 character string to XPM_Uns32 (FOURCC)
*/
static bool stringToFOURCC ( std::string input, XMP_Uns32 &output );
+
+ // export all the properties requiring special conversion from inXMP into iXMLMetadata.
+ static void exportSpecialXMPToiXML( SXMPMeta & inXMP, IMetadata & outNativeMeta, PropertyList & propertiesToBeDeleted );
+
+ // export all the properties requiring special conversion from iXMLMetadata into inXMP.
+ static bool exportSpecialiXMLToXMP( IMetadata & inNativeMeta, SXMPMeta & outXMP );
};
}
diff --git a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp
new file mode 100644
index 0000000..5df7439
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.cpp
@@ -0,0 +1,815 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h"
+#include "source/Endian.h"
+
+#include "source/ExpatAdapter.hpp"
+#include "XMPFiles/source/XMPFiles_Impl.hpp"
+#include <algorithm>
+
+namespace IFF_RIFF {
+
+ static const char * tagNames[ iXMLMetadata::kLastEntry ] = {
+ "TAPE", //kTape, // std::string
+ "TAKE", //kTake, // XMP_Uns64
+ "SCENE", //kScene, // std::string
+ "NOTE", //kNote, // std::string
+ "PROJECT", //kProject, // std::string
+ "NO_GOOD", //kNoGood, // bool( true/false )
+ "FILE_SAMPLE_RATE", //kFileSampleRate, // XMP_Uns64
+ "AUDIO_BIT_DEPTH", //kAudioBitDepth, // XMP_Uns64
+ "CIRCLED", //kCircled, // bool( true/false )
+ "BWF_DESCRIPTION", //kBWFDescription, // std::string( 256 )
+ "BWF_ORIGINATOR", //kBWFOriginator, // std::string( 32 )
+ "BWF_ORIGINATOR_REFERENCE", //kBWFOriginatorReference, // std::string( 32 )
+ "BWF_ORIGINATION_DATE", //kBWFOriginationDate, // std::string( 10 )
+ "BWF_ORIGINATION_TIME", //kBWFOriginationTime, // std::string( 8 )
+ "BWF_TIME_REFERENCE_LOW", //kBWFTimeReferenceLow, // XMP_Uns32
+ "BWF_TIME_REFERENCE_HIGH", //kBWFTimeReferenceHigh, // XMP_Uns32
+ "BWF_VERSION", //kBWFVersion, // XMP_Uns16
+ "BWF_UMID", //kBWFUMID, // std::string[64]
+ "BWF_CODING_HISTORY", //kBWFHistory, // std::string
+ "TIMECODE_FLAG", //kTimeCodeFlag, // std::string[DF/NDF]
+ "TIMECODE_RATE", //kTimeCodeRate, // std::string
+ "TIMESTAMP_SAMPLE_RATE", //kTimeStampSampleRate, // XMP_Uns64
+ "TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO", //kTimeStampSampleSinceMidnightLow, // XMP_Uns32
+ "TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI", //kTimeStampSampleSinceMidnightHi, // XMP_Uns32
+ };
+
+ static const char * rootTagName = "BWFXML";
+ static const char * speedTagName = "SPEED";
+ static const char * bextTagName = "BEXT";
+
+ iXMLMetadata::iXMLMetadata()
+ : mRootNode( NULL )
+ , mExpatAdapter( NULL )
+ , mErrorCallback( NULL )
+ , mExtraSpaceSize( 1024 ) {}
+
+ iXMLMetadata::~iXMLMetadata() {
+ if ( mExpatAdapter ) {
+ mRootNode = NULL;
+ }
+ delete mExpatAdapter;
+ delete mRootNode;
+ mExpatAdapter = NULL;
+ }
+
+#define MAX_SZ ((size_t)~((size_t)0))
+
+ void iXMLMetadata::parse( const XMP_Uns8 * chunkData, XMP_Uns64 size ) {
+ if ( chunkData == NULL || size == 0 ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: iXML chunk is not well formed" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ mExpatAdapter = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
+ if ( mExpatAdapter == 0 ) XMP_Throw ( "iXMLMetadata: Can't create Expat adapter", kXMPErr_NoMemory );
+ mExpatAdapter->SetErrorCallback( mErrorCallback );
+
+ try {
+ XMP_Uns64 parsedSize = 0;
+ while ( parsedSize < size ) {
+ XMP_Uns64 currentSize = std::min<XMP_Uns64>( size - parsedSize, MAX_SZ );
+ mExpatAdapter->ParseBuffer( chunkData + parsedSize, (size_t) currentSize, false );
+ parsedSize += currentSize;
+ }
+ mExpatAdapter->ParseBuffer( 0, 0, true );
+ } catch( ... ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: iXML chunk is not well formed" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ // read the particular nodes we are interested in and store in the map
+ // Get the root node
+
+ // Get the root node of the XML tree.
+
+ XML_Node & xmlTree = mExpatAdapter->tree;
+
+ for ( size_t i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
+ if ( xmlTree.content[i]->kind == kElemNode ) {
+ mRootNode = xmlTree.content[i];
+ break;
+ }
+ }
+
+ if ( mRootNode == NULL ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: No Root Element present in iXML chunk" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ XMP_StringPtr rootLocalName = mRootNode->name.c_str() + mRootNode->nsPrefixLen;
+
+ if ( ! XMP_LitMatch ( rootLocalName, rootTagName ) ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: Unexpected Root Element present in iXML chunk" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ XMP_StringPtr ns = mRootNode->ns.c_str();
+
+ XML_NodePtr currentNode( NULL );
+
+ ParseAndSetProperties();
+ resetChanges();
+ }
+
+ XMP_Uns64 iXMLMetadata::serialize( XMP_Uns8** buffer ) {
+ *buffer = NULL;
+ if ( mRootNode == NULL ) {
+ mRootNode = new XML_Node( NULL, rootTagName, kElemNode );
+ if ( mRootNode == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "iXML Metadata reconciliation failure: Can't create Root Node" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return 0;
+ }
+ }
+
+
+ // Create SPEED and bext node if required
+ XML_Node * node = mRootNode->GetNamedElement( "", speedTagName );
+ if ( node == NULL ) {
+ node = new XML_Node( mRootNode, speedTagName, kElemNode );
+ if ( node == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "iXML Metadata reconciliation failure: Can't create Speed Node" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return 0;
+ }
+ mRootNode->content.push_back( node );
+ }
+
+ node = mRootNode->GetNamedElement( "", bextTagName );
+ if ( node == NULL ) {
+ node = new XML_Node( mRootNode, bextTagName, kElemNode );
+ if ( node == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "iXML Metadata reconciliation failure: Can't create Bext Node" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return 0;
+ }
+ mRootNode->content.push_back( node );
+ }
+
+ UpdateProperties();
+
+ // get the SPEED and bext node and remove them if empty
+ if ( node->content.size() == 0 )
+ RemoveXMLNode( mRootNode, bextTagName );
+ node = mRootNode->GetNamedElement( "", speedTagName );
+ if ( node->content.size() == 0 )
+ RemoveXMLNode( mRootNode, speedTagName );
+ node = NULL;
+
+ std::string strBuffer;
+ mRootNode->Serialize( &strBuffer );
+
+ // move the contents of the string into the new bigger buffer
+ size_t newSize = strBuffer.size() + mExtraSpaceSize;
+ XMP_Uns8 * newBuffer = new XMP_Uns8[ newSize ];
+ memset( newBuffer, 0x20, newSize );
+ memcpy( newBuffer, "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n", 39 );
+ memcpy( newBuffer + 39, strBuffer.c_str(), strBuffer.size() );
+
+ *buffer = newBuffer;
+
+ return newSize;
+ }
+
+ bool iXMLMetadata::isEmptyValue( XMP_Uns32 id, ValueObject& valueObj ) {
+ bool ret = true;
+
+ switch( id )
+ {
+ case kTape:
+ case kScene:
+ case kNote:
+ case kProject:
+ case kBWFDescription:
+ case kBWFOriginator:
+ case kBWFOriginatorReference:
+ case kBWFOriginationDate:
+ case kBWFOriginationTime:
+ case kBWFHistory:
+ case kBWFUMID:
+ case kTimeCodeFlag:
+ case kTimeCodeRate:
+ {
+ TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(&valueObj);
+
+ ret = ( strObj == NULL || ( strObj != NULL && strObj->getValue().empty() ) );
+ }
+ break;
+
+ case kTake:
+ case kFileSampleRate:
+ case kAudioBitDepth:
+ case kBWFTimeReferenceLow:
+ case kBWFTimeReferenceHigh:
+ case kBWFVersion:
+ case kTimeStampSampleRate:
+ case kTimeStampSampleSinceMidnightLow:
+ case kTimeStampSampleSinceMidnightHigh:
+ ret = false;
+ break;
+
+ case kNoGood:
+ case kCircled:
+ ret = false;
+ break;
+
+ default:
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ void iXMLMetadata::ParseAndSetStringProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ std::string nodeValue = ParseStringValue( parentNode, id );
+ if ( nodeValue.size() > 0 ) {
+ this->setValue< std::string >( id, nodeValue );
+ }
+ }
+
+ void iXMLMetadata::SetErrorCallback( GenericErrorCallback * errorCallback ) {
+ mErrorCallback = errorCallback;
+ }
+
+ void iXMLMetadata::NotifyClient( XMP_ErrorSeverity severity, XMP_Error & error ) {
+ XMPFileHandler::NotifyClient( mErrorCallback, severity, error );
+ }
+
+ static XMP_Uns64 ConvertStringToUns64( const std::string & strValue ) {
+ int count;
+ char nextCh;
+ XMP_Uns64 result;
+
+ count = sscanf ( strValue.c_str(), "%llu%c", &result, &nextCh );
+ if ( count != 1 ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam );
+
+ return result;
+ }
+
+ void iXMLMetadata::ParseAndSetIntegerProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ std::string strValue = ParseStringValue( parentNode, id );
+
+ if ( strValue.size() > 0 ) {
+ XMP_Uns64 uValue;
+ try {
+ uValue = ConvertStringToUns64( 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_Recoverable, error );
+ return;
+ }
+ this->setValue< XMP_Uns64 >( id, uValue );
+ }
+ }
+
+ void iXMLMetadata::ParseAndSetBoolProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ std::string strValue = ParseStringValue( parentNode, id );
+ if ( strValue.size() > 0 ) {
+ if ( strValue.compare( "TRUE" ) == 0 )
+ this->setValue< bool >( id, true );
+ else if ( strValue.compare( "FALSE" ) == 0 )
+ this->setValue< bool >( id, false );
+ else {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: invalid boolean value present" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ }
+ }
+ }
+
+ void iXMLMetadata::ParseAndSetProperties() {
+
+ // top level properties
+ ParseAndSetStringProperty( mRootNode, kTape );
+ ParseAndSetIntegerProperty( mRootNode, kTake );
+ ParseAndSetStringProperty( mRootNode, kScene );
+ ParseAndSetStringProperty( mRootNode, kNote );
+ ParseAndSetStringProperty( mRootNode, kProject );
+ ParseAndSetBoolProperty( mRootNode, kNoGood );
+ ParseAndSetBoolProperty( mRootNode, kCircled );
+
+ // speed node children
+ XML_Node * speedNode = mRootNode->GetNamedElement( "", speedTagName );
+ if ( speedNode ) {
+ ParseAndSetIntegerProperty( speedNode, kFileSampleRate );
+ ParseAndSetIntegerProperty( speedNode, kAudioBitDepth );
+ ParseAndSetStringProperty( speedNode, kTimeCodeFlag );
+ ParseAndSetStringProperty( speedNode, kTimeCodeRate );
+ ParseAndSetIntegerProperty( speedNode, kTimeStampSampleRate );
+ ParseAndSetIntegerProperty( speedNode, kTimeStampSampleSinceMidnightLow );
+ ParseAndSetIntegerProperty( speedNode, kTimeStampSampleSinceMidnightHigh );
+ }
+
+ // bext node children
+ XML_Node * bextNode = mRootNode->GetNamedElement( "", bextTagName );
+ if ( bextNode ) {
+ ParseAndSetStringProperty( bextNode, kBWFDescription );
+ ParseAndSetStringProperty( bextNode, kBWFOriginator );
+ ParseAndSetStringProperty( bextNode, kBWFOriginatorReference );
+ ParseAndSetStringProperty( bextNode, kBWFOriginationDate );
+ ParseAndSetStringProperty( bextNode, kBWFOriginationTime );
+ ParseAndSetIntegerProperty( bextNode, kBWFTimeReferenceLow );
+ ParseAndSetIntegerProperty( bextNode, kBWFTimeReferenceHigh );
+ ParseAndSetIntegerProperty( bextNode, kBWFVersion );
+ ParseAndSetStringProperty( bextNode, kBWFHistory );
+ ParseAndSetStringProperty( bextNode, kBWFUMID );
+ }
+ }
+
+ void iXMLMetadata::UpdateStringProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ if ( valueExists( id ) ) {
+ std::string value;
+ try {
+ value = this->getValue< std::string >( id );
+ } catch ( ... ) {
+ XMP_Error e1( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected the value to be of string type" );
+ NotifyClient( kXMPErrSev_Recoverable, e1 );
+ return;
+ }
+ UpdateXMLNode( parentNode, tagNames[ id ], value );
+ } else {
+ RemoveXMLNode( parentNode, tagNames[ id ] );
+ }
+ }
+
+ void iXMLMetadata::UpdateXMLNode( XML_Node * parentNode, const char * localName, const std::string & value ) {
+ XML_Node * node = parentNode->GetNamedElement( "", localName );
+
+ if ( node == NULL ) {
+ node = new XML_Node( parentNode, localName, kElemNode );
+ if ( node == NULL ) {
+ XMP_Error error( kXMPErr_NoMemory, "Unable to create new objects" );
+ NotifyClient( kXMPErrSev_OperationFatal, error );
+ return;
+ }
+ parentNode->content.push_back( node );
+ }
+
+ if ( node->IsLeafContentNode() == false ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: node was supposed to be a leaf node" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ node->RemoveContent();
+ }
+ node->SetLeafContentValue( value.c_str() );
+ }
+
+ void iXMLMetadata::RemoveXMLNode( XML_Node * parentNode, const char * localName ) {
+ XML_Node * node = parentNode->GetNamedElement( "", localName );
+ if ( node ) {
+ // find the position
+ XML_NodeVector::iterator it = std::find( parentNode->content.begin(), parentNode->content.end(), node );
+ XMP_Assert( it != parentNode->content.end() );
+ parentNode->content.erase( it );
+ delete node;
+ }
+ }
+
+#if XMP_WinBuild
+ #define snprintf _snprintf
+#endif
+ static std::string ConvertUns64ToString( XMP_Uns64 uValue ) {
+ char buffer[64];
+
+ snprintf( buffer, sizeof( buffer ), "%llu", uValue );
+ std::string str( buffer );
+ return str;
+ }
+
+ void iXMLMetadata::UpdateIntegerProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ if ( valueExists( id ) ) {
+ XMP_Uns64 uValue;
+ try {
+ uValue = this->getValue< XMP_Uns64 >( id );
+ } catch ( ... ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected the value to be of XMP_Uns64 type" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ std::string strValue = ConvertUns64ToString( uValue );
+ UpdateXMLNode( parentNode, tagNames[ id ], strValue );
+ } else {
+ RemoveXMLNode( parentNode, tagNames[ id ] );
+ }
+ }
+
+ void iXMLMetadata::UpdateBoolProperty( XML_Node * parentNode, XMP_Uns32 id ) {
+ if ( valueExists( id ) ) {
+ bool value;
+
+ try {
+ value = this->getValue< bool >( id );
+ } catch ( ... ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected the value to be of bool type" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ std::string strValue;
+ if ( value ) strValue = "TRUE";
+ else strValue = "FALSE";
+
+ UpdateXMLNode( parentNode, tagNames[ id ], strValue );
+ } else {
+ RemoveXMLNode( parentNode, tagNames[ id ] );
+ }
+ }
+
+ void iXMLMetadata::UpdateProperties() {
+ // top level properties
+ UpdateStringProperty( mRootNode, kTape );
+ UpdateIntegerProperty( mRootNode, kTake );
+ UpdateStringProperty( mRootNode, kScene );
+ UpdateStringProperty( mRootNode, kNote );
+ UpdateStringProperty( mRootNode, kProject );
+ UpdateBoolProperty( mRootNode, kNoGood );
+ UpdateBoolProperty( mRootNode, kCircled );
+
+ // speed node children
+ XML_Node * speedNode = mRootNode->GetNamedElement( "", speedTagName );
+ if ( speedNode ) {
+ UpdateIntegerProperty( speedNode, kFileSampleRate );
+ UpdateIntegerProperty( speedNode, kAudioBitDepth );
+ UpdateStringProperty( speedNode, kTimeCodeFlag );
+ UpdateStringProperty( speedNode, kTimeCodeRate );
+ UpdateIntegerProperty( speedNode, kTimeStampSampleRate );
+ UpdateIntegerProperty( speedNode, kTimeStampSampleSinceMidnightLow );
+ UpdateIntegerProperty( speedNode, kTimeStampSampleSinceMidnightHigh );
+ }
+
+ // bext node children
+ XML_Node * bextNode = mRootNode->GetNamedElement( "", bextTagName );
+ if ( bextNode ) {
+ UpdateStringProperty( bextNode, kBWFDescription );
+ UpdateStringProperty( bextNode, kBWFOriginator );
+ UpdateStringProperty( bextNode, kBWFOriginatorReference );
+ UpdateStringProperty( bextNode, kBWFOriginationDate );
+ UpdateStringProperty( bextNode, kBWFOriginationTime );
+ UpdateIntegerProperty( bextNode, kBWFTimeReferenceLow );
+ UpdateIntegerProperty( bextNode, kBWFTimeReferenceHigh );
+ UpdateIntegerProperty( bextNode, kBWFVersion );
+ UpdateStringProperty( bextNode, kBWFHistory );
+ UpdateStringProperty( bextNode, kBWFUMID );
+ }
+
+ }
+
+ bool iXMLMetadata::valueValid( XMP_Uns32 id, ValueObject * valueObj ) {
+ switch( id ) {
+ case kTape:
+ return validateStringSize( valueObj );
+ break;
+
+ case kTake:
+ return validateInt( valueObj );
+ break;
+
+ case kScene:
+ return validateStringSize( valueObj );
+ break;
+
+ case kNote:
+ return validateStringSize( valueObj );
+ break;
+
+ case kProject:
+ return validateStringSize( valueObj );
+ break;
+
+ case kNoGood:
+ return validateBool( valueObj );
+ break;
+
+ case kFileSampleRate:
+ return validateInt( valueObj );
+ break;
+
+ case kAudioBitDepth:
+ return validateInt( valueObj );
+ break;
+
+ case kCircled:
+ return validateBool( valueObj );
+ break;
+
+ case kBWFDescription:
+ case kBWFOriginator:
+ case kBWFOriginatorReference:
+ // string length can be anything but while setting it will be trimmed.
+ return validateStringSize( valueObj );
+ break;
+
+ case kBWFOriginationDate:
+ return validateDate( valueObj );
+ break;
+
+ case kBWFOriginationTime:
+ return validateTime( valueObj );
+ break;
+
+ case kBWFTimeReferenceLow:
+ case kBWFTimeReferenceHigh:
+ return validateInt( valueObj, 0, Max_XMP_Uns32 );
+ break;
+
+ case kBWFVersion:
+ return validateInt( valueObj, 0, Max_XMP_Uns16 );
+ break;
+
+ case kBWFUMID:
+ return validateUMID( valueObj );
+ break;
+
+ case kBWFHistory:
+ return validateStringSize( valueObj );
+ break;
+
+ case kTimeCodeFlag:
+ return validateTimeCodeFlag( valueObj );
+ break;
+
+ case kTimeCodeRate:
+ return validateRational( valueObj );
+ break;
+
+ case kTimeStampSampleRate:
+ return validateInt( valueObj );
+ break;
+
+ case kTimeStampSampleSinceMidnightHigh:
+ case kTimeStampSampleSinceMidnightLow:
+ return validateInt( valueObj, 0, Max_XMP_Uns32 );
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+
+ void iXMLMetadata::valueModify( XMP_Uns32 id, ValueObject * value ) {
+ switch( id ) {
+ case kBWFDescription:
+ shortenString( value, 256 );
+ break;
+
+ case kBWFOriginator:
+ shortenString( value, 32 );
+ break;
+
+ case kBWFOriginatorReference:
+ shortenString( value, 32 );
+ break;
+
+ case kBWFUMID:
+ shortenString( value, 128 );
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ bool iXMLMetadata::validateStringSize( ValueObject * value, size_t minSize /*= 1*/, size_t maxSize /*= std::string::npos */ ) {
+ TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(value);
+ if ( strObj ) {
+ const std::string * strPtr = &strObj->getValue();
+ size_t sizeOfString = strPtr->size();
+ if ( sizeOfString < minSize ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: length of string is less than expected" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ } else if ( sizeOfString > maxSize ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: length of string is more than expected" );
+ NotifyClient( kXMPErrSev_Recoverable, error);
+ return false;
+ } else {
+ return true;
+ }
+ } else { // object is not of string type
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected string value" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ return false;
+ }
+
+ bool iXMLMetadata::validateInt( ValueObject * value, XMP_Uns64 minValue /*= 0*/, XMP_Uns64 maxValue /*= Max_XMP_Uns64*/ ) {
+ TValueObject< XMP_Uns64 > * valuePtr = dynamic_cast< TValueObject< XMP_Uns64 > * > ( value );
+
+ if ( valuePtr ) {
+ XMP_Uns64 uValue = valuePtr->getValue();
+ if ( uValue < minValue ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: node integer value is less than allowed" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ } else if ( uValue > maxValue ) {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: node integer value is more than allowed" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected XMP_Uns64 value" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+
+ bool iXMLMetadata::validateBool( ValueObject * value ) {
+ // just check typecasts is possible or not
+ TValueObject< bool > * boolValuePtr = dynamic_cast< TValueObject< bool > * > ( value );
+ if ( boolValuePtr ) {
+ return true;
+ } else {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected bool value" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+
+ void iXMLMetadata::shortenString( ValueObject * value, size_t lengthOfString ) {
+ TValueObject< std::string > * strObj = dynamic_cast< TValueObject< std::string > * >( value );
+ if ( strObj ) {
+ const std::string * strPtr = &strObj->getValue();
+ size_t sizeOfString = strPtr->size();
+ if ( sizeOfString > lengthOfString ) {
+ std::string newString;
+ newString.append( *strPtr, 0, lengthOfString );
+ strObj->setValue( newString );
+ }
+ }
+ }
+
+ static bool charIsNumber( const char & ch ) {
+ if ( ch >= '0' && ch <= '9' )
+ return true;
+ else
+ return false;
+ }
+
+ bool iXMLMetadata::validateDate( ValueObject * value ) {
+ bool stringOK = validateStringSize( value, 10, 10 );
+ if ( stringOK ) {
+ TValueObject< std::string > * strObj = dynamic_cast< TValueObject< std::string > * >( value );
+ const std::string * strPtr = &strObj->getValue();
+ // check 0,1,2,3,5,6,8,9 elements are integer
+ for ( size_t i = 0; i < 10; i++ ) {
+ if ( i == 4 || i == 7 )
+ continue;
+ stringOK = charIsNumber( strPtr->operator[]( i ) );
+ if ( !stringOK ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected a number character" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+ return stringOK;
+ }
+ return false;
+ }
+
+ bool iXMLMetadata::validateTime( ValueObject * value ) {
+ bool stringOK = validateStringSize( value, 8, 8 );
+ if ( stringOK ) {
+ TValueObject< std::string > * strObj = dynamic_cast< TValueObject< std::string > * >( value );
+ const std::string * strPtr = &strObj->getValue();
+ // check 0,1,3,4,6,7 elements are integer
+ for ( size_t i = 0; i < 8; i++ ) {
+ if ( i == 2 || i == 5 )
+ continue;
+ stringOK = charIsNumber( strPtr->operator[]( i ) );
+ if ( !stringOK ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected a number character" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+ return stringOK;
+ }
+ return false;
+ }
+
+ static bool charIsHexDigit( const char & ch ) {
+ if ( charIsNumber( ch ) ) {
+ return true;
+ } else {
+ if ( ch >= 'A' && ch <= 'F' )
+ return true;
+ else if ( ch >= 'a' && ch <= 'f' )
+ return true;
+ else
+ return false;
+ }
+ }
+
+ bool iXMLMetadata::validateUMID( ValueObject * value ) {
+ bool stringOK = validateStringSize( value );
+ if ( stringOK ) {
+ // max size to consider is 128
+ TValueObject< std::string > * strObj = dynamic_cast< TValueObject< std::string > * >( value );
+ const std::string * strPtr = &strObj->getValue();
+ size_t effectiveLength = strPtr->size();
+ if ( effectiveLength > 128 )
+ effectiveLength = 128;
+
+ // first check length needs to even
+ if ( effectiveLength % 2 == 0 ) {
+ for ( size_t i = 0; i < effectiveLength; i++ ) {
+ stringOK = charIsHexDigit( strPtr->operator[]( i ) );
+ if ( !stringOK ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected a hex character" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+ return stringOK;
+ } else {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected the hex string length to be even" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+ return false;
+ }
+
+ std::string iXMLMetadata::ParseStringValue( XML_Node * parentNode, XMP_Uns32 id ) {
+ std::string nodeValue;
+ XML_Node * node = parentNode->GetNamedElement( "", tagNames[ id ] );
+ if ( node ) {
+ if ( node->IsLeafContentNode() && node->content.size() != 0 ) {
+ size_t lengthOfValue = node->content[0]->value.size();
+ if ( lengthOfValue > 0 ) {
+ nodeValue = node->content[0]->value;
+ }
+ } else {
+ XMP_Error error( kXMPErr_BadBlockFormat, "iXML Metadata reconciliation failure: node was supposed to be a leaf node" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ }
+ }
+ return nodeValue;
+ }
+
+ bool iXMLMetadata::validateTimeCodeFlag( ValueObject * value ) {
+ bool returnValue = validateStringSize( value, 2, 3 );
+ if ( returnValue ) {
+ TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(value);
+ if ( strObj ) {
+ const std::string * strPtr = &strObj->getValue();
+ if ( strPtr->compare( "DF" ) == 0 )
+ return true;
+ else if ( strPtr->compare( "NDF" ) == 0 )
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool iXMLMetadata::validateRational( ValueObject * value ) {
+ bool returnValue = validateStringSize( value, 3 );
+ if ( returnValue ) {
+ TValueObject<std::string>* strObj = dynamic_cast<TValueObject<std::string>*>(value);
+ if ( strObj ) {
+ const std::string * strPtr = &strObj->getValue();
+ size_t posOfSlash = strPtr->find( "/" );
+ if ( posOfSlash == std::string::npos || posOfSlash == strPtr->size() - 1 || posOfSlash == 0 ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: node value was supposed to be in a fractional format" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+
+ for ( size_t i = 0; i < strPtr->size(); i++ ) {
+ if ( i == posOfSlash )
+ continue;
+ returnValue = charIsNumber( strPtr->operator[]( i ) );
+ if ( ! returnValue ) {
+ XMP_Error error( kXMPErr_BadValue, "iXML Metadata reconciliation failure: expected a number character" );
+ NotifyClient( kXMPErrSev_Recoverable, error );
+ return false;
+ }
+ }
+ return returnValue;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h
new file mode 100644
index 0000000..815fe85
--- /dev/null
+++ b/XMPFiles/source/FormatSupport/WAVE/iXMLMetadata.h
@@ -0,0 +1,157 @@
+#ifndef __iXMLMetadata_h__
+#define __iXMLMetadata_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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/NativeMetadataSupport/IMetadata.h"
+
+class ExpatAdapter;
+class XML_Node;
+
+namespace IFF_RIFF {
+
+ /**
+ * iXML Metadata model.
+ * Implements the IMetadata interface
+ */
+ class iXMLMetadata : public IMetadata
+ {
+ public:
+ enum
+ {
+ kTape, // std::string
+ kTake, // XMP_Uns64
+ kScene, // std::string
+ kNote, // std::string
+ kProject, // std::string
+ kNoGood, // bool( true/false )
+ kFileSampleRate, // XMP_Uns64
+ kAudioBitDepth, // XMP_Uns64
+ kCircled, // bool( true/false )
+ kBWFDescription, // std::string
+ kBWFOriginator, // std::string
+ kBWFOriginatorReference, // std::string
+ kBWFOriginationDate, // std::string
+ kBWFOriginationTime, // std::string
+ kBWFTimeReferenceLow, // XMP_Uns32
+ kBWFTimeReferenceHigh, // XMP_Uns32
+ kBWFVersion, // XMP_Uns16
+ kBWFUMID, // std::string[64]
+ kBWFHistory, // std::string
+ kTimeCodeFlag, // std::string[DF/NDF]
+ kTimeCodeRate, // std::string
+ kTimeStampSampleRate, // XMP_Uns64
+ kTimeStampSampleSinceMidnightLow, // XMP_Uns32
+ kTimeStampSampleSinceMidnightHigh, // XMP_Uns32
+ kLastEntry
+ };
+
+ public:
+ /**
+ *ctor/dtor
+ */
+ iXMLMetadata();
+ ~iXMLMetadata();
+
+ /**
+ * Parses the given memory block and creates a data model representation
+ * The implementation expects that the memory block is the data area of
+ * the iXML chunk.
+ * Throws exceptions if parsing is not possible
+ *
+ * @param input The byte buffer to parse
+ * @param size Size of the given byte buffer
+ */
+ void parse( const XMP_Uns8* chunkData, XMP_Uns64 size );
+
+ /**
+ * See IMetadata::parse( const LFA_FileRef input )
+ */
+ void parse( XMP_IO* input ) { IMetadata::parse( input ); }
+
+ /**
+ * Serializes the data model to a memory block.
+ * The memory block will be the data area of a iXML chunk.
+ * Throws exceptions if serializing is not possible
+ *
+ * @param buffer Buffer that gets filled with serialized data
+ * @param size Size of passed in buffer
+ *
+ * @return Size of serialized data (might be smaller than buffer size)
+ */
+ XMP_Uns64 serialize( XMP_Uns8** buffer );
+
+ void SetErrorCallback( GenericErrorCallback * errorCallback );
+
+ void SetExtraSpaceSize( size_t size ) { mExtraSpaceSize = size; }
+
+ size_t GetExtraSpaceSize() const { return mExtraSpaceSize; }
+
+ protected:
+ /**
+ * @see IMetadata::isEmptyValue
+ */
+ virtual bool isEmptyValue( XMP_Uns32 id, ValueObject& valueObj );
+
+ /**
+ * @see iMetadata::valueValid
+ */
+ virtual bool valueValid( XMP_Uns32 id, ValueObject * valueObj );
+
+ /**
+ * @see IMetadata::valueModify
+ */
+ virtual void valueModify( XMP_Uns32 id, ValueObject * value );
+
+ void ParseAndSetProperties();
+ void UpdateProperties();
+
+ std::string ParseStringValue( XML_Node * parentNode, XMP_Uns32 id );
+ void ParseAndSetStringProperty( XML_Node * parentNode, XMP_Uns32 id );
+ void ParseAndSetIntegerProperty( XML_Node * parentNode, XMP_Uns32 id );
+ void ParseAndSetBoolProperty( XML_Node * parentNode, XMP_Uns32 id );
+
+ 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 UpdateXMLNode( XML_Node * parentNode, const char * localName, const std::string & value );
+ void RemoveXMLNode( XML_Node * parentNode, const char * localName );
+
+ void NotifyClient( XMP_ErrorSeverity severity, XMP_Error & error );
+
+ bool validateStringSize( ValueObject * value, size_t minSize = 1, size_t maxSize = std::string::npos );
+ bool validateInt( ValueObject * value, XMP_Uns64 minValue = 0, XMP_Uns64 maxValue = Max_XMP_Uns64 );
+ bool validateBool( ValueObject * value );
+ void shortenString( ValueObject * value, size_t lengthOfString );
+ bool validateDate( ValueObject * value );
+ bool validateTime( ValueObject * value );
+ bool validateUMID( ValueObject * value );
+ bool validateTimeCodeFlag( ValueObject * value );
+ bool validateRational( ValueObject * value );
+
+ private:
+ // Operators hidden on purpose
+ iXMLMetadata( const iXMLMetadata& ) {};
+ iXMLMetadata& operator=( const iXMLMetadata& ) { return *this; };
+
+ ExpatAdapter * mExpatAdapter;
+ XML_Node * mRootNode;
+ GenericErrorCallback * mErrorCallback;
+ size_t mExtraSpaceSize;
+ };
+
+}
+
+#endif // __iXMLMetadata_h__
diff --git a/XMPFiles/source/NativeMetadataSupport/IMetadata.cpp b/XMPFiles/source/NativeMetadataSupport/IMetadata.cpp
index 40a864e..2a3560c 100644
--- a/XMPFiles/source/NativeMetadataSupport/IMetadata.cpp
+++ b/XMPFiles/source/NativeMetadataSupport/IMetadata.cpp
@@ -204,3 +204,28 @@ bool IMetadata::valueChanged( XMP_Uns32 id ) const
return false;
}
+
+//-----------------------------------------------------------------------------
+//
+// IMetadata::valueValid(...)
+//
+// Purpose: Return true if the value for the passed identifier is valid
+//
+//-----------------------------------------------------------------------------
+
+bool IMetadata::valueValid( XMP_Uns32 id, ValueObject *value )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//
+// IMetadata::valueValid(...)
+//
+// Purpose: Return true if the value for the passed identifier is valid
+//
+//-----------------------------------------------------------------------------
+void IMetadata::valueModify(XMP_Uns32 id, ValueObject *value)
+{
+ return;
+} \ No newline at end of file
diff --git a/XMPFiles/source/NativeMetadataSupport/IMetadata.h b/XMPFiles/source/NativeMetadataSupport/IMetadata.h
index 1a66c86..b85239b 100644
--- a/XMPFiles/source/NativeMetadataSupport/IMetadata.h
+++ b/XMPFiles/source/NativeMetadataSupport/IMetadata.h
@@ -149,7 +149,7 @@ public:
* @param id Identifier of value
*/
virtual bool valueChanged( XMP_Uns32 id ) const;
-
+
protected:
/**
* Is the value of the passed ValueObject that belongs to the given id "empty"?
@@ -164,6 +164,20 @@ protected:
*/
virtual bool isEmptyValue( XMP_Uns32 id, ValueObject& valueObj ) = 0;
+ /**
+ * Validates the value for the passed identifier
+ * @param id Identifier of value
+ * @param value pointer to value object
+ */
+ virtual bool valueValid( XMP_Uns32 id, ValueObject * value );
+
+ /**
+ * Modify the value for the passed identifier
+ * @param id Identifier of value
+ * @param value pointer to value object
+ */
+ virtual void valueModify( XMP_Uns32 id, ValueObject * value );
+
private:
// Operators hidden on purpose
IMetadata( const IMetadata& ) {};
@@ -191,9 +205,13 @@ template<class T> void IMetadata::setValue( XMP_Uns32 id, const T& value )
//
valueObj = dynamic_cast<TValueObject<T>*>( iterator->second );
- if( valueObj != NULL )
+ if( valueObj != NULL )
{
- valueObj->setValue( value );
+ TValueObject< T > newValueObj( value );
+ if ( valueValid( id, &newValueObj ) ) {
+ valueModify( id, &newValueObj );
+ valueObj->setValue( newValueObj.getValue() );
+ }
}
else
{
@@ -206,10 +224,14 @@ template<class T> void IMetadata::setValue( XMP_Uns32 id, const T& value )
// value doesn't exists yet and is not "empty"
// so add a new value to the map
//
- valueObj = new TValueObject<T>( value );
- mValues[id] = valueObj;
-
- mDirty = true; // the new created value isn't dirty, but the container becomes dirty
+ TValueObject< T > newValueObj( value );
+ if ( this->valueValid( id, &newValueObj ) )
+ {
+ this->valueModify( id, &newValueObj );
+ valueObj = new TValueObject<T>( newValueObj.getValue() );
+ mValues[id] = valueObj;
+ mDirty = true; // the new created value isn't dirty, but the container becomes dirty
+ }
}
//
diff --git a/XMPFiles/source/NativeMetadataSupport/IReconcile.cpp b/XMPFiles/source/NativeMetadataSupport/IReconcile.cpp
index dd34725..b7d4405 100644
--- a/XMPFiles/source/NativeMetadataSupport/IReconcile.cpp
+++ b/XMPFiles/source/NativeMetadataSupport/IReconcile.cpp
@@ -141,6 +141,12 @@ bool IReconcile::importNativeToXMP( SXMPMeta& outXMP, const IMetadata& nativeMet
}
break;
+ case kNativeType_Bool:
+ {
+ SXMPUtils::ConvertFromBool( nativeMeta.getValue<bool>( propertyInfo[index].mMetadataID ), &xmpValue );
+ }
+ break;
+
default:
{
XMP_Throw( "Unknown native data type", kXMPErr_InternalFailure );
@@ -217,7 +223,7 @@ bool IReconcile::importNativeToXMP( SXMPMeta& outXMP, const IMetadata& nativeMet
//
//-----------------------------------------------------------------------------
-bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, const MetadataPropertyInfo* propertyInfo )
+bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, const MetadataPropertyInfo* propertyInfo, PropertyList * propertiesExportedSuccessfully /*= NULL*/ )
{
std::string xmpValue;
XMP_Uns32 index = 0;
@@ -275,6 +281,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
std::string ascii;
convertToASCII( xmpValue, ascii );
outNativeMeta.setValue<std::string>( propertyInfo[index].mMetadataID, ascii );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
break;
@@ -282,6 +290,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
case kNativeType_StrUTF8:
{
outNativeMeta.setValue<std::string>( propertyInfo[index].mMetadataID, xmpValue );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
break;
@@ -293,6 +303,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
{
ReconcileUtils::UTF8ToLocal( xmpValue.c_str(), xmpValue.size(), &value );
outNativeMeta.setValue<std::string>( propertyInfo[index].mMetadataID, value );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
catch( XMP_Error& e )
{
@@ -330,6 +342,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
if( ! error && value >= 0 )
{
outNativeMeta.setValue<XMP_Uns64>( propertyInfo[index].mMetadataID, static_cast<XMP_Uns64>(value) );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
}
break;
@@ -358,6 +372,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
if( ! error && value >= 0 )
{
outNativeMeta.setValue<XMP_Uns32>( propertyInfo[index].mMetadataID, static_cast<XMP_Uns32>(value) );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
}
break;
@@ -386,6 +402,8 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
if( ! error )
{
outNativeMeta.setValue<XMP_Int32>( propertyInfo[index].mMetadataID, static_cast<XMP_Int32>(value) );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
}
break;
@@ -414,6 +432,38 @@ bool IReconcile::exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, c
if( ! error && value >= 0 )
{
outNativeMeta.setValue<XMP_Uns16>( propertyInfo[index].mMetadataID, static_cast<XMP_Uns16>(value) );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
+ }
+ }
+ break;
+
+ case kNativeType_Bool:
+ {
+ bool value;
+ bool error = false;
+
+ try
+ {
+ value = SXMPUtils::ConvertToBool( xmpValue );
+ }
+ catch( XMP_Error& e )
+ {
+ if ( e.GetID() != kXMPErr_BadParam )
+ {
+ // rethrow exception if it wasn't caused by an
+ // invalid parameter for the conversion
+ throw e;
+ }
+ error = true;
+ }
+
+ // Only write the value if it could be converted to a number and has a positive value
+ if( ! error )
+ {
+ outNativeMeta.setValue<bool>( propertyInfo[index].mMetadataID, value );
+ if ( propertiesExportedSuccessfully )
+ propertiesExportedSuccessfully->push_back( std::make_pair( propertyInfo[index].mXMPSchemaNS, propertyInfo[index].mXMPPropName ) );
}
}
break;
diff --git a/XMPFiles/source/NativeMetadataSupport/IReconcile.h b/XMPFiles/source/NativeMetadataSupport/IReconcile.h
index af8646d..16a0109 100644
--- a/XMPFiles/source/NativeMetadataSupport/IReconcile.h
+++ b/XMPFiles/source/NativeMetadataSupport/IReconcile.h
@@ -42,7 +42,8 @@ enum MetadataPropertyType
kNativeType_Uns64,
kNativeType_Uns32,
kNativeType_Int32,
- kNativeType_Uns16
+ kNativeType_Uns16,
+ kNativeType_Bool
};
/** Types that describe how an XMP property is exported to native Metadata */
@@ -71,6 +72,8 @@ struct MetadataPropertyInfo
class IReconcile
{
public:
+ typedef std::vector< std::pair< XMP_StringPtr, XMP_StringPtr > > PropertyList;
+
virtual ~IReconcile() {};
/**
* Reconciles metadata from legacy formats into XMP.
@@ -128,7 +131,7 @@ protected:
@return true if any native metadata value were changed
*/
- static bool exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, const MetadataPropertyInfo* propertyInfo );
+ static bool exportXMPToNative( IMetadata& outNativeMeta, SXMPMeta& inXMP, const MetadataPropertyInfo* propertyInfo, PropertyList * propertiesExportedSuccessfully = NULL );
// Converts input string to an ascii output string
// - terminates at first 0
diff --git a/XMPFiles/source/PluginHandler/FileHandler.h b/XMPFiles/source/PluginHandler/FileHandler.h
index 8d68258..ca43ced 100644
--- a/XMPFiles/source/PluginHandler/FileHandler.h
+++ b/XMPFiles/source/PluginHandler/FileHandler.h
@@ -51,7 +51,7 @@ class FileHandler
public:
FileHandler(std::string & uid, XMP_OptionBits handlerFlags, FileHandlerType type, ModuleSharedPtr module):
- mVersion(0), mUID(uid), mHandlerFlags(handlerFlags), mOverwrite(false), mType(type), mModule(module) {}
+ mVersion(0), mUID(uid), mHandlerFlags(handlerFlags), mOverwrite(false), mType(type), mModule(module),mSerializeOption(0) {}
virtual ~FileHandler(){}
diff --git a/XMPFiles/source/PluginHandler/Module.cpp b/XMPFiles/source/PluginHandler/Module.cpp
index 595c17d..d76589c 100644
--- a/XMPFiles/source/PluginHandler/Module.cpp
+++ b/XMPFiles/source/PluginHandler/Module.cpp
@@ -246,10 +246,6 @@ bool Module::loadInternal()
errorMsg = "Plugin initialization failed.";
}
}
- else
- {
- errorMsg = "Missing plugin entry point in plugin";
- }
}
if( mLoaded != kModuleLoaded )
diff --git a/XMPFiles/source/PluginHandler/PluginManager.cpp b/XMPFiles/source/PluginHandler/PluginManager.cpp
index 3802c9b..0f47300 100644
--- a/XMPFiles/source/PluginHandler/PluginManager.cpp
+++ b/XMPFiles/source/PluginHandler/PluginManager.cpp
@@ -385,7 +385,6 @@ void PluginManager::initialize( const std::string& pluginDir, const std::string&
{
try
{
- HandlerRegistry & hdlrReg = HandlerRegistry::getInstance();
if( msPluginManager == 0 ) msPluginManager = new PluginManager( pluginDir, plugins );
msPluginManager->initializeHostAPI();
@@ -817,10 +816,7 @@ void PluginManager::initializeHostAPI()
break;
}
- if( hostAPI != NULL )
- {
- msPluginManager->mHostAPIs[ hostAPI->mVersion ] = hostAPI;
- }
+ msPluginManager->mHostAPIs[ hostAPI->mVersion ] = hostAPI;
}
}
diff --git a/XMPFiles/source/XMPFiles.cpp b/XMPFiles/source/XMPFiles.cpp
index 32ea41f..ae8f701 100644
--- a/XMPFiles/source/XMPFiles.cpp
+++ b/XMPFiles/source/XMPFiles.cpp
@@ -26,11 +26,16 @@
#endif
#include "XMPFiles/source/FormatSupport/ID3_Support.hpp"
+#include "XMPFiles/source/FormatSupport/ISOBaseMedia_Support.hpp"
#if EnablePacketScanning
#include "XMPFiles/source/FileHandlers/Scanner_Handler.hpp"
#endif
+#if EnableGenericHandling
+ #include "XMPFiles/source/FileHandlers/Generic_Handler.hpp"
+#endif
+
// =================================================================================================
/// \file XMPFiles.cpp
/// \brief High level support to access metadata in files of interest to Adobe applications.
@@ -93,6 +98,10 @@ const char * kXMPFiles_EmbeddedCopyright = kXMPFilesName " " kXMP_CopyrightStr;
(CheckFileFormatProc)0, Scanner_MetaHandlerCTor );
#endif
+#if EnableGenericHandling
+ static XMPFileHandlerInfo kGenericHandlerInfo ( kXMP_UnknownFile, kGeneric_HandlerFlags,
+ (CheckFileFormatProc)0, Generic_MetaHandlerCTor );
+#endif
// =================================================================================================
/* class-static */
@@ -291,6 +300,7 @@ XMPFiles::Terminate()
SXMPMeta::Terminate(); // Just in case the client does not.
ID3_Support::TerminateGlobals();
+ ISOMedia::TerminateGlobals();
Terminate_LibUtils();
#if UseGlobalLibraryLock & (! XMP_StaticBuild )
@@ -302,6 +312,9 @@ XMPFiles::Terminate()
xmpFilesLog = stderr;
#endif
+ // reset static variables
+ sDefaultErrorCallback.Clear();
+ sProgressDefault.Clear();
XMP_FILES_STATIC_END1 ( kXMPErrSev_ProcessFatal )
} // XMPFiles::Terminate
@@ -380,9 +393,9 @@ XMPFiles::GetFormatInfo ( XMP_FileFormat format,
XMP_OptionBits * flags /* = 0 */ )
{
XMP_FILES_STATIC_START
- return HandlerRegistry::getInstance().getFormatInfo ( format, flags );
+ return HandlerRegistry::getInstance().getFormatInfo ( format, flags );
XMP_FILES_STATIC_END1 ( kXMPErrSev_OperationFatal )
- return false;
+ return false;
} // XMPFiles::GetFormatInfo
@@ -487,11 +500,12 @@ static XMPFileHandlerInfo* CreateFileHandlerInfo (
XMPFiles* dummyParent,
XMP_FileFormat * format,
XMP_OptionBits options,
+ XMP_Bool& excluded,
const XMPFiles::ErrorCallbackInfo * _errorCallbackInfoPtr = NULL )
{
Host_IO::FileMode clientMode;
std::string fileExt; // Used to check for excluded files.
- bool excluded = FileIsExcluded ( dummyParent->GetFilePath().c_str(), &fileExt, &clientMode, &sDefaultErrorCallback ); // ! Fills in fileExt and clientMode.
+ excluded = FileIsExcluded ( dummyParent->GetFilePath().c_str(), &fileExt, &clientMode, &sDefaultErrorCallback ); // ! Fills in fileExt and clientMode.
if ( excluded ) return 0;
XMPFileHandlerInfo * handlerInfo = 0;
@@ -533,7 +547,26 @@ XMPFiles::GetFileModDate ( XMP_StringPtr clientPath,
XMPFileHandlerInfo * handlerInfo = 0;
- handlerInfo = CreateFileHandlerInfo ( &dummyParent, format, options, &sDefaultErrorCallback );
+ XMP_Bool excluded=false;
+ handlerInfo = CreateFileHandlerInfo ( &dummyParent, format, options, excluded, &sDefaultErrorCallback );
+#if EnableGenericHandling
+#if GenericHandlingAlwaysOn
+ XMP_OptionBits oldOptions = options;
+ options |= kXMPFiles_OpenUseGenericHandler;
+#endif
+ if (handlerInfo == 0 && !excluded
+ && (options & kXMPFiles_OpenUseGenericHandler) )
+ {
+ Host_IO::FileMode fileMode = Host_IO::GetFileMode( clientPath );
+ if ( fileMode == Host_IO::kFMode_DoesNotExist )
+ return false;
+
+ handlerInfo = &kGenericHandlerInfo;
+ }
+#if GenericHandlingAlwaysOn
+ options = oldOptions;
+#endif
+#endif
if ( handlerInfo == 0 ) return false;
// -------------------------------------------------------------------------
@@ -556,7 +589,7 @@ XMPFiles::GetFileModDate ( XMP_StringPtr clientPath,
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
- Host_IO::GetModifyDate ( curFilePath, &lastModDate );
+ if (!Host_IO::GetModifyDate ( curFilePath, &lastModDate ) ) continue;
if ( ! ok || ( SXMPUtils::CompareDateTime ( *modDate , lastModDate ) < 0 ) )
{
*modDate = lastModDate;
@@ -602,7 +635,26 @@ XMPFiles::GetAssociatedResources (
dummyParent.SetFilePath ( filePath );
XMPFileHandlerInfo * handlerInfo = 0;
- handlerInfo = CreateFileHandlerInfo ( &dummyParent, &format, options, &sDefaultErrorCallback );
+ XMP_Bool excluded=false;
+ handlerInfo = CreateFileHandlerInfo ( &dummyParent, &format, options, excluded, &sDefaultErrorCallback );
+#if EnableGenericHandling
+#if GenericHandlingAlwaysOn
+ XMP_OptionBits oldOptions = options;
+ options |= kXMPFiles_OpenUseGenericHandler;
+#endif
+ if (handlerInfo == 0 && !excluded
+ && (options & kXMPFiles_OpenUseGenericHandler) )
+ {
+ Host_IO::FileMode fileMode = Host_IO::GetFileMode( filePath );
+ if ( fileMode == Host_IO::kFMode_DoesNotExist )
+ return false;
+
+ handlerInfo = &kGenericHandlerInfo;
+ }
+#if GenericHandlingAlwaysOn
+ options = oldOptions;
+#endif
+#endif
if ( handlerInfo == 0 ) return false;
// -------------------------------------------------------------------------
@@ -650,7 +702,26 @@ XMPFiles::IsMetadataWritable (
dummyParent.SetFilePath ( filePath );
XMPFileHandlerInfo * handlerInfo = 0;
- handlerInfo = CreateFileHandlerInfo ( &dummyParent, &format, options, &sDefaultErrorCallback );
+ XMP_Bool excluded=false;
+ handlerInfo = CreateFileHandlerInfo ( &dummyParent, &format, options, excluded, &sDefaultErrorCallback );
+#if EnableGenericHandling
+#if GenericHandlingAlwaysOn
+ XMP_OptionBits oldOptions = options;
+ options |= kXMPFiles_OpenUseGenericHandler;
+#endif
+ if (handlerInfo == 0 && !excluded
+ && (options & kXMPFiles_OpenUseGenericHandler))
+ {
+ Host_IO::FileMode fileMode = Host_IO::GetFileMode( filePath );
+ if ( fileMode == Host_IO::kFMode_DoesNotExist )
+ return false;
+
+ handlerInfo = &kGenericHandlerInfo;
+ }
+#if GenericHandlingAlwaysOn
+ options = oldOptions;
+#endif
+#endif
if ( handlerInfo == 0 ) return false;
if ( writable == 0 ) {
@@ -670,8 +741,9 @@ XMPFiles::IsMetadataWritable (
try {
*writable = ConvertBoolToXMP_Bool( dummyParent.handler->IsMetadataWritable() );
- }
- catch ( XMP_Error& error ) {
+ } 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;
@@ -679,8 +751,10 @@ XMPFiles::IsMetadataWritable (
throw;
}
}
- delete dummyParent.handler;
- dummyParent.handler = 0;
+ if ( dummyParent.handler ) {
+ delete dummyParent.handler;
+ dummyParent.handler = 0;
+ }
XMP_FILES_STATIC_END2 ( filePath, kXMPErrSev_OperationFatal )
return true;
} // XMPFiles::IsMetadataWritable
@@ -699,6 +773,10 @@ DoOpenFile ( XMPFiles * thiz,
openFlags &= ~kXMPFiles_ForceGivenHandler; // Don't allow this flag for OpenFile.
+ if ( (openFlags & kXMPFiles_OptimizeFileLayout) && (! (openFlags & kXMPFiles_OpenForUpdate)) ) {
+ XMP_Throw ( "OptimizeFileLayout requires OpenForUpdate", kXMPErr_BadParam );
+ }
+
if ( thiz->handler != 0 ) XMP_Throw ( "File already open", kXMPErr_BadParam );
CloseLocalFile ( thiz ); // Sanity checks if prior call failed.
@@ -728,6 +806,24 @@ DoOpenFile ( XMPFiles * thiz,
if ( ! (openFlags & kXMPFiles_OpenUsePacketScanning) ) {
handlerInfo = HandlerRegistry::getInstance().selectSmartHandler( thiz, clientPath, format, openFlags );
+#if EnableGenericHandling
+#if GenericHandlingAlwaysOn
+ XMP_OptionBits oldOpenFlags = openFlags;
+ openFlags |= kXMPFiles_OpenUseGenericHandler;
+#endif
+ if (handlerInfo==0
+ && !(openFlags & kXMPFiles_OpenStrictly)
+ && (openFlags & kXMPFiles_OpenUseGenericHandler))
+ {
+ if ( clientMode == Host_IO::kFMode_DoesNotExist )
+ return false;
+
+ handlerInfo = &kGenericHandlerInfo;
+ }
+#if GenericHandlingAlwaysOn
+ openFlags = oldOpenFlags;
+#endif
+#endif
}
#if ! EnablePacketScanning
@@ -754,11 +850,21 @@ DoOpenFile ( XMPFiles * thiz,
}
if ( openFlags & kXMPFiles_OpenUseSmartHandler ) {
+ CloseLocalFile ( thiz );
XMP_Error error ( kXMPErr_NoFileHandler, "XMPFiles: No smart file handler available to handle file" );
XMP_FILES_STATIC_NOTIFY_ERROR ( &thiz->errorCallback, clientPath, kXMPErrSev_Recoverable, error );
return false;
}
+#if EnableGenericHandling
+ if ( openFlags & kXMPFiles_OpenUseGenericHandler ) {
+ CloseLocalFile ( thiz );
+ XMP_Error error ( kXMPErr_NoFileHandler, "XMPFiles: Generic handler not available to handle file" );
+ XMP_FILES_STATIC_NOTIFY_ERROR ( &thiz->errorCallback, clientPath, kXMPErrSev_Recoverable, error );
+ return false;
+ }
+#endif
+
if ( openFlags & kXMPFiles_OpenLimitedScanning ) {
bool scanningOK = false;
for ( size_t i = 0; kKnownScannedFiles[i] != 0; ++i ) {
@@ -793,6 +899,12 @@ DoOpenFile ( XMPFiles * thiz,
thiz->handler = handler;
try {
+ if ( !readOnly && handlerFlags & kXMPFiles_FolderBasedFormat ) {
+ bool isMetadataWritable = handler->IsMetadataWritable();
+ if ( !isMetadataWritable ) {
+ XMP_Throw ( "Open, file permission error", kXMPErr_FilePermission );
+ }
+ }
handler->CacheFileData();
} catch ( ... ) {
delete thiz->handler;
@@ -824,6 +936,9 @@ static bool DoOpenFile( XMPFiles* thiz,
openFlags &= ~kXMPFiles_ForceGivenHandler; // Don't allow this flag for OpenFile.
+ if ( (openFlags & kXMPFiles_OptimizeFileLayout) && (! (openFlags & kXMPFiles_OpenForUpdate)) ) {
+ XMP_Throw ( "OptimizeFileLayout requires OpenForUpdate", kXMPErr_BadParam );
+ }
if ( thiz->handler != 0 ) XMP_Throw ( "File already open", kXMPErr_BadParam );
@@ -950,6 +1065,8 @@ XMPFiles::CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
if ( this->handler == 0 ) return; // Return if there is no open file (not an error).
bool needsUpdate = this->handler->needsUpdate;
+ bool optimizeFileLayout = XMP_OptionIsSet ( this->openFlags, kXMPFiles_OptimizeFileLayout );
+
XMP_OptionBits handlerFlags = this->handler->handlerFlags;
// Decide if we're doing a safe update. If so, make sure the handler supports it. All handlers
@@ -982,6 +1099,8 @@ XMPFiles::CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
// Close the file without doing common crash-safe writing. The handler might do it.
+ needsUpdate |= optimizeFileLayout;
+
if ( needsUpdate ) {
#if GatherPerformanceData
sAPIPerf->back().extraInfo += ", direct update";
@@ -1057,7 +1176,10 @@ XMPFiles::CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
// *** Don't delete the temp or copy files, not sure which is best.
try {
- if ( this->handler != 0 ) delete this->handler;
+ if ( this->handler != 0 ) {
+ delete this->handler;
+ this->handler = 0;
+ }
} catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
if ( this->ioRef ) this->ioRef->DeleteTemp();
diff --git a/XMPFiles/source/XMPFiles.hpp b/XMPFiles/source/XMPFiles.hpp
index 70ab020..e3ecb8b 100644
--- a/XMPFiles/source/XMPFiles.hpp
+++ b/XMPFiles/source/XMPFiles.hpp
@@ -17,7 +17,7 @@
#include "public/include/XMP.hpp"
#include "public/include/XMP_IO.hpp"
-
+#include "source/SafeStringAPIs.h"
#include "source/XMP_ProgressTracker.hpp"
class XMPFileHandler;
diff --git a/XMPFiles/source/XMPFiles_Impl.cpp b/XMPFiles/source/XMPFiles_Impl.cpp
index 471c48d..68fa99f 100644
--- a/XMPFiles/source/XMPFiles_Impl.cpp
+++ b/XMPFiles/source/XMPFiles_Impl.cpp
@@ -502,3 +502,18 @@ XMP_OptionBits XMPFileHandler::GetSerializeOptions()
} // XMPFileHandler::GetSerializeOptions
// =================================================================================================
+// XMPFileHandler::NotifyClient
+// ===================================
+//
+// Generic function for all the file handlers to replace existing exception throws
+//
+void XMPFileHandler::NotifyClient(GenericErrorCallback * errCBptr, XMP_ErrorSeverity severity, XMP_Error & error)
+{
+ if (errCBptr)
+ errCBptr->NotifyClient( severity, error );
+ else {
+ if ( severity != kXMPErrSev_Recoverable )
+ throw error;
+ }
+}
+// =================================================================================================
diff --git a/XMPFiles/source/XMPFiles_Impl.hpp b/XMPFiles/source/XMPFiles_Impl.hpp
index 6e21c23..72d82e7 100644
--- a/XMPFiles/source/XMPFiles_Impl.hpp
+++ b/XMPFiles/source/XMPFiles_Impl.hpp
@@ -302,6 +302,8 @@ public:
virtual void UpdateFile ( bool doSafeUpdate ) = 0;
virtual void WriteTempFile ( XMP_IO* tempRef ) = 0;
+ static void NotifyClient(GenericErrorCallback * errCBptr, XMP_ErrorSeverity severity, XMP_Error & error);
+
// ! Leave the data members public so common code can see them.
XMPFiles * parent; // Let's the handler see the file info.