summaryrefslogtreecommitdiff
path: root/source/XMPFiles
diff options
context:
space:
mode:
Diffstat (limited to 'source/XMPFiles')
-rw-r--r--source/XMPFiles/FileHandlers/ASF_Handler.cpp352
-rw-r--r--source/XMPFiles/FileHandlers/ASF_Handler.hpp64
-rw-r--r--source/XMPFiles/FileHandlers/AVCHD_Handler.cpp2060
-rw-r--r--source/XMPFiles/FileHandlers/AVCHD_Handler.hpp79
-rw-r--r--source/XMPFiles/FileHandlers/Basic_Handler.cpp247
-rw-r--r--source/XMPFiles/FileHandlers/Basic_Handler.hpp104
-rw-r--r--source/XMPFiles/FileHandlers/FLV_Handler.cpp751
-rw-r--r--source/XMPFiles/FileHandlers/FLV_Handler.hpp73
-rw-r--r--source/XMPFiles/FileHandlers/InDesign_Handler.cpp423
-rw-r--r--source/XMPFiles/FileHandlers/InDesign_Handler.hpp60
-rw-r--r--source/XMPFiles/FileHandlers/JPEG_Handler.cpp1027
-rw-r--r--source/XMPFiles/FileHandlers/JPEG_Handler.hpp93
-rw-r--r--source/XMPFiles/FileHandlers/MP3_Handler.cpp748
-rw-r--r--source/XMPFiles/FileHandlers/MP3_Handler.hpp92
-rw-r--r--source/XMPFiles/FileHandlers/MPEG2_Handler.cpp234
-rw-r--r--source/XMPFiles/FileHandlers/MPEG2_Handler.hpp57
-rw-r--r--source/XMPFiles/FileHandlers/MPEG4_Handler.cpp2456
-rw-r--r--source/XMPFiles/FileHandlers/MPEG4_Handler.hpp94
-rw-r--r--source/XMPFiles/FileHandlers/P2_Handler.cpp1363
-rw-r--r--source/XMPFiles/FileHandlers/P2_Handler.hpp108
-rw-r--r--source/XMPFiles/FileHandlers/PNG_Handler.cpp271
-rw-r--r--source/XMPFiles/FileHandlers/PNG_Handler.hpp58
-rw-r--r--source/XMPFiles/FileHandlers/PSD_Handler.cpp428
-rw-r--r--source/XMPFiles/FileHandlers/PSD_Handler.hpp72
-rw-r--r--source/XMPFiles/FileHandlers/PostScript_Handler.cpp574
-rw-r--r--source/XMPFiles/FileHandlers/PostScript_Handler.hpp63
-rw-r--r--source/XMPFiles/FileHandlers/RIFF_Handler.cpp347
-rw-r--r--source/XMPFiles/FileHandlers/RIFF_Handler.hpp70
-rw-r--r--source/XMPFiles/FileHandlers/SWF_Handler.cpp386
-rw-r--r--source/XMPFiles/FileHandlers/SWF_Handler.hpp61
-rw-r--r--source/XMPFiles/FileHandlers/Scanner_Handler.cpp335
-rw-r--r--source/XMPFiles/FileHandlers/Scanner_Handler.hpp42
-rw-r--r--source/XMPFiles/FileHandlers/SonyHDV_Handler.cpp782
-rw-r--r--source/XMPFiles/FileHandlers/SonyHDV_Handler.hpp77
-rw-r--r--source/XMPFiles/FileHandlers/TIFF_Handler.cpp388
-rw-r--r--source/XMPFiles/FileHandlers/TIFF_Handler.hpp68
-rw-r--r--source/XMPFiles/FileHandlers/Trivial_Handler.cpp66
-rw-r--r--source/XMPFiles/FileHandlers/Trivial_Handler.hpp47
-rw-r--r--source/XMPFiles/FileHandlers/UCF_Handler.cpp850
-rw-r--r--source/XMPFiles/FileHandlers/UCF_Handler.hpp716
-rw-r--r--source/XMPFiles/FileHandlers/XDCAMEX_Handler.cpp809
-rw-r--r--source/XMPFiles/FileHandlers/XDCAMEX_Handler.hpp81
-rw-r--r--source/XMPFiles/FileHandlers/XDCAM_Handler.cpp710
-rw-r--r--source/XMPFiles/FileHandlers/XDCAM_Handler.hpp82
-rw-r--r--source/XMPFiles/FormatSupport/ASF_Support.cpp1436
-rw-r--r--source/XMPFiles/FormatSupport/ASF_Support.hpp224
-rw-r--r--source/XMPFiles/FormatSupport/ID3_Support.hpp784
-rw-r--r--source/XMPFiles/FormatSupport/IPTC_Support.cpp745
-rw-r--r--source/XMPFiles/FormatSupport/IPTC_Support.hpp304
-rw-r--r--source/XMPFiles/FormatSupport/ISOBaseMedia_Support.cpp149
-rw-r--r--source/XMPFiles/FormatSupport/ISOBaseMedia_Support.hpp100
-rw-r--r--source/XMPFiles/FormatSupport/MOOV_Support.cpp542
-rw-r--r--source/XMPFiles/FormatSupport/MOOV_Support.hpp215
-rw-r--r--source/XMPFiles/FormatSupport/MacScriptExtracts.h244
-rw-r--r--source/XMPFiles/FormatSupport/PNG_Support.cpp335
-rw-r--r--source/XMPFiles/FormatSupport/PNG_Support.hpp74
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp568
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp97
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_Support.hpp318
-rw-r--r--source/XMPFiles/FormatSupport/QuickTime_Support.cpp1148
-rw-r--r--source/XMPFiles/FormatSupport/QuickTime_Support.hpp103
-rw-r--r--source/XMPFiles/FormatSupport/RIFF.cpp879
-rw-r--r--source/XMPFiles/FormatSupport/RIFF.hpp316
-rw-r--r--source/XMPFiles/FormatSupport/RIFF_Support.cpp930
-rw-r--r--source/XMPFiles/FormatSupport/RIFF_Support.hpp42
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileIPTC.cpp855
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileLegacy.cpp185
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileLegacy.hpp272
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileTIFF.cpp2934
-rw-r--r--source/XMPFiles/FormatSupport/Reconcile_Impl.cpp406
-rw-r--r--source/XMPFiles/FormatSupport/Reconcile_Impl.hpp95
-rw-r--r--source/XMPFiles/FormatSupport/SWF_Support.cpp844
-rw-r--r--source/XMPFiles/FormatSupport/SWF_Support.hpp254
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp1901
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp592
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_Support.cpp434
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_Support.hpp915
-rw-r--r--source/XMPFiles/FormatSupport/XDCAM_Support.cpp350
-rw-r--r--source/XMPFiles/FormatSupport/XDCAM_Support.hpp43
-rw-r--r--source/XMPFiles/FormatSupport/XMPScanner.cpp1480
-rw-r--r--source/XMPFiles/FormatSupport/XMPScanner.hpp330
-rw-r--r--source/XMPFiles/WXMPFiles.cpp294
-rw-r--r--source/XMPFiles/XMPFiles.cpp1536
-rw-r--r--source/XMPFiles/XMPFiles.hpp230
-rw-r--r--source/XMPFiles/XMPFiles_Impl.cpp780
-rw-r--r--source/XMPFiles/XMPFiles_Impl.hpp446
86 files changed, 0 insertions, 42597 deletions
diff --git a/source/XMPFiles/FileHandlers/ASF_Handler.cpp b/source/XMPFiles/FileHandlers/ASF_Handler.cpp
deleted file mode 100644
index ac6aad7..0000000
--- a/source/XMPFiles/FileHandlers/ASF_Handler.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "ASF_Handler.hpp"
-
-// =================================================================================================
-/// \file ASF_Handler.hpp
-/// \brief File format handler for ASF.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// ASF_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * ASF_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new ASF_MetaHandler ( parent );
-
-} // ASF_MetaHandlerCTor
-
-// =================================================================================================
-// ASF_CheckFormat
-// ===============
-
-bool ASF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
-
- IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_WMAVFile );
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, guidLen ) ) return false;
-
- GUID guid;
- memcpy ( &guid, ioBuf.ptr, guidLen );
-
- if ( ! IsEqualGUID ( ASF_Header_Object, guid ) ) return false;
-
- return true;
-
-} // ASF_CheckFormat
-
-// =================================================================================================
-// ASF_MetaHandler::ASF_MetaHandler
-// ==================================
-
-ASF_MetaHandler::ASF_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kASF_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-}
-
-// =================================================================================================
-// ASF_MetaHandler::~ASF_MetaHandler
-// ===================================
-
-ASF_MetaHandler::~ASF_MetaHandler()
-{
- // Nothing extra to do.
-}
-
-// =================================================================================================
-// ASF_MetaHandler::CacheFileData
-// ===============================
-
-void ASF_MetaHandler::CacheFileData()
-{
-
- this->containsXMP = false;
-
- LFA_FileRef fileRef ( this->parent->fileRef );
- if ( fileRef == 0 ) return;
-
- ASF_Support support ( &this->legacyManager );
- ASF_Support::ObjectState objectState;
- long numTags = support.OpenASF ( fileRef, objectState );
- if ( numTags == 0 ) return;
-
- if ( objectState.xmpLen != 0 ) {
-
- // XMP present
-
- XMP_Int32 len = XMP_Int32 ( objectState.xmpLen );
-
- this->xmpPacket.reserve( len );
- this->xmpPacket.assign ( len, ' ' );
-
- bool found = ASF_Support::ReadBuffer ( fileRef, objectState.xmpPos, objectState.xmpLen,
- const_cast<char *>(this->xmpPacket.data()) );
- if ( found ) {
- this->packetInfo.offset = objectState.xmpPos;
- this->packetInfo.length = len;
- this->containsXMP = true;
- }
-
- }
-
-} // ASF_MetaHandler::CacheFileData
-
-// =================================================================================================
-// ASF_MetaHandler::ProcessXMP
-// ============================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-
-void ASF_MetaHandler::ProcessXMP()
-{
-
- this->processedXMP = true; // Make sure we only come through here once.
-
- // Process the XMP packet.
-
- if ( this->xmpPacket.empty() ) {
-
- // import legacy in any case, when no XMP present
- legacyManager.ImportLegacy ( &this->xmpObj );
- this->legacyManager.SetDigest ( &this->xmpObj );
-
- } else {
-
- XMP_Assert ( this->containsXMP );
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
-
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
-
- if ( ! legacyManager.CheckDigest ( this->xmpObj ) ) {
- legacyManager.ImportLegacy ( &this->xmpObj );
- }
-
- }
-
- // Assume we now have something in the XMP.
- this->containsXMP = true;
-
-} // ASF_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// ASF_MetaHandler::UpdateFile
-// ============================
-
-void ASF_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
-
- bool updated = false;
-
- if ( ! this->needsUpdate ) return;
-
- LFA_FileRef fileRef ( this->parent->fileRef );
- if ( fileRef == 0 ) return;
-
- ASF_Support support;
- ASF_Support::ObjectState objectState;
- long numTags = support.OpenASF ( fileRef, objectState );
- if ( numTags == 0 ) return;
-
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
-
- this->legacyManager.ExportLegacy ( this->xmpObj );
- if ( this->legacyManager.hasLegacyChanged() ) {
-
- this->legacyManager.SetDigest ( &this->xmpObj );
-
- // serialize with updated digest
- if ( objectState.xmpLen == 0 ) {
-
- // XMP does not exist, use standard padding
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
-
- } else {
-
- // re-use padding with static XMP size
- try {
- XMP_OptionBits compactExact = (kXMP_UseCompactFormat | kXMP_ExactPacketLength);
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, compactExact, XMP_StringLen(objectState.xmpLen) );
- } catch ( ... ) {
- // re-use padding with exact packet length failed (legacy-digest needed too much space): try again using standard padding
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- }
-
- }
-
- XMP_StringPtr packetStr = xmpPacket.c_str();
- packetLen = (XMP_StringLen)xmpPacket.size();
- if ( packetLen == 0 ) return;
-
- // value, when guessing for sufficient legacy padding (line-ending conversion etc.)
- const int paddingTolerance = 50;
-
- bool xmpGrows = ( objectState.xmpLen && (packetLen > objectState.xmpLen) && ( ! objectState.xmpIsLastObject) );
-
- bool legacyGrows = ( this->legacyManager.hasLegacyChanged() &&
- (this->legacyManager.getLegacyDiff() > (this->legacyManager.GetPadding() - paddingTolerance)) );
-
- if ( doSafeUpdate || legacyGrows || xmpGrows ) {
-
- // do a safe update in any case
- updated = SafeWriteFile();
-
- } else {
-
- // possibly we can do an in-place update
-
- if ( objectState.xmpLen < packetLen ) {
-
- updated = SafeWriteFile();
-
- } else {
-
- // current XMP chunk size is sufficient -> write (in place update)
- updated = ASF_Support::WriteBuffer(fileRef, objectState.xmpPos, packetLen, packetStr );
-
- // legacy update
- if ( updated && this->legacyManager.hasLegacyChanged() ) {
-
- ASF_Support::ObjectIterator curPos = objectState.objects.begin();
- ASF_Support::ObjectIterator endPos = objectState.objects.end();
-
- for ( ; curPos != endPos; ++curPos ) {
-
- ASF_Support::ObjectData object = *curPos;
-
- // find header-object
- if ( IsEqualGUID ( ASF_Header_Object, object.guid ) ) {
- // update header object
- updated = support.UpdateHeaderObject ( fileRef, object, legacyManager );
- }
-
- }
-
- }
-
- }
-
- }
-
- if ( ! updated ) return; // If there's an error writing the chunk, bail.
-
- this->needsUpdate = false;
-
-} // ASF_MetaHandler::UpdateFile
-
-// =================================================================================================
-// ASF_MetaHandler::WriteFile
-// ===========================
-
-void ASF_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- LFA_FileRef destRef = this->parent->fileRef;
-
- ASF_Support support;
- ASF_Support::ObjectState objectState;
- long numTags = support.OpenASF ( sourceRef, objectState );
- if ( numTags == 0 ) return;
-
- LFA_Truncate ( destRef, 0 );
-
- ASF_Support::ObjectIterator curPos = objectState.objects.begin();
- ASF_Support::ObjectIterator endPos = objectState.objects.end();
-
- for ( ; curPos != endPos; ++curPos ) {
-
- ASF_Support::ObjectData object = *curPos;
-
- // discard existing XMP object
- if ( object.xmp ) continue;
-
- // update header-object, when legacy needs update
- if ( IsEqualGUID ( ASF_Header_Object, object.guid) && this->legacyManager.hasLegacyChanged( ) ) {
- // rewrite header object
- support.WriteHeaderObject ( sourceRef, destRef, object, this->legacyManager, false );
- } else {
- // copy any other object
- ASF_Support::CopyObject ( sourceRef, destRef, object );
- }
-
- // write XMP object immediately after the (one and only) top-level DataObject
- if ( IsEqualGUID ( ASF_Data_Object, object.guid ) ) {
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
- ASF_Support::WriteXMPObject ( destRef, packetLen, packetStr );
- }
-
- }
-
- support.UpdateFileSize ( destRef );
-
-} // ASF_MetaHandler::WriteFile
-
-// =================================================================================================
-// ASF_MetaHandler::SafeWriteFile
-// ===========================
-
-bool ASF_MetaHandler::SafeWriteFile ()
-{
- bool ret = false;
-
- std::string origPath = this->parent->filePath;
- LFA_FileRef origRef = this->parent->fileRef;
-
- std::string updatePath;
- LFA_FileRef updateRef = 0;
-
- CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
-
- this->parent->filePath = updatePath;
- this->parent->fileRef = updateRef;
-
- try {
- this->WriteFile ( origRef, origPath );
- ret = true;
- } catch ( ... ) {
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = origRef;
- throw;
- }
-
- LFA_Close ( origRef );
- LFA_Delete ( origPath.c_str() );
-
- LFA_Close ( updateRef );
- LFA_Rename ( updatePath.c_str(), origPath.c_str() );
- this->parent->filePath = origPath;
-
- this->parent->fileRef = 0;
-
- return ret;
-
-} // ASF_MetaHandler::SafeWriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/ASF_Handler.hpp b/source/XMPFiles/FileHandlers/ASF_Handler.hpp
deleted file mode 100644
index e5fec1c..0000000
--- a/source/XMPFiles/FileHandlers/ASF_Handler.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __ASF_Handler_hpp__
-#define __ASF_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "XMPFiles_Impl.hpp"
-#include "ASF_Support.hpp"
-
-// =================================================================================================
-/// \file ASF_Handler.hpp
-/// \brief File format handler for ASF.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler* ASF_MetaHandlerCTor ( XMPFiles* parent );
-
-extern bool ASF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kASF_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_NeedsReadOnlyPacket );
-
-class ASF_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string& sourcePath );
-
- bool SafeWriteFile ();
-
- ASF_MetaHandler ( XMPFiles* parent );
- virtual ~ASF_MetaHandler();
-
-private:
-
- ASF_LegacyManager legacyManager;
-
-}; // ASF_MetaHandler
-
-// =================================================================================================
-
-#endif /* __ASF_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/AVCHD_Handler.cpp b/source/XMPFiles/FileHandlers/AVCHD_Handler.cpp
deleted file mode 100644
index f842a73..0000000
--- a/source/XMPFiles/FileHandlers/AVCHD_Handler.cpp
+++ /dev/null
@@ -1,2060 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "AVCHD_Handler.hpp"
-
-#include "MD5.h"
-#include "UnicodeConversions.hpp"
-
-using namespace std;
-
-// AVCHD maker ID values. Panasonic has confirmed their Maker ID with us, the others come from examining
-// sample data files.
-#define kMakerIDPanasonic 0x103
-#define kMakerIDSony 0x108
-#define kMakerIDCanon 0x1011
-
-// =================================================================================================
-/// \file AVCHD_Handler.cpp
-/// \brief Folder format handler for AVCHD.
-///
-/// This handler is for the AVCHD video format.
-///
-/// A typical AVCHD layout looks like:
-///
-/// BDMV/
-/// index.bdmv
-/// MovieObject.bdmv
-/// PLAYLIST/
-/// 00000.mpls
-/// 00001.mpls
-/// STREAM/
-/// 00000.m2ts
-/// 00001.m2ts
-/// CLIPINF/
-/// 00000.clpi
-/// 00001.clpi
-/// BACKUP/
-///
-// =================================================================================================
-
-// =================================================================================================
-
-// AVCHD Format. Book 1: Playback System Basic Specifications V 1.01. p. 76
-
-struct AVCHD_blkProgramInfo
-{
- XMP_Uns32 mLength;
- XMP_Uns8 mReserved1[2];
- XMP_Uns32 mSPNProgramSequenceStart;
- XMP_Uns16 mProgramMapPID;
- XMP_Uns8 mNumberOfStreamsInPS;
- XMP_Uns8 mReserved2;
-
- // Video stream.
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mVideoFormat;
- XMP_Uns8 mFrameRate;
- XMP_Uns8 mAspectRatio;
- XMP_Uns8 mCCFlag;
- } mVideoStream;
-
- // Audio stream.
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mAudioPresentationType;
- XMP_Uns8 mSamplingFrequency;
- XMP_Uns8 mAudioLanguageCode[4];
- } mAudioStream;
-
- // Pverlay bitmap stream.
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mOBLanguageCode[4];
- } mOverlayBitmapStream;
-
- // Menu bitmap stream.
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mBMLanguageCode[4];
- } mMenuBitmapStream;
-
-};
-
-// AVCHD Format, Panasonic proprietary PRO_PlayListMark block
-
-struct AVCCAM_blkProPlayListMark
-{
- XMP_Uns8 mPresent;
- XMP_Uns8 mProTagID;
- XMP_Uns8 mFillItem1;
- XMP_Uns16 mLength;
- XMP_Uns8 mMarkType;
-
- // Entry mark
- struct
- {
- XMP_Uns8 mGlobalClipID[32];
- XMP_Uns8 mStartTimeCode[4];
- XMP_Uns8 mStreamTimecodeInfo;
- XMP_Uns8 mStartBinaryGroup[4];
- XMP_Uns8 mLastUpdateTimeZone;
- XMP_Uns8 mLastUpdateDate[7];
- XMP_Uns16 mFillItem;
- } mEntryMark;
-
- // Shot Mark
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mShotMark;
- XMP_Uns8 mFillItem[3];
- } mShotMark;
-
- // Access
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mCreatorCharacterSet;
- XMP_Uns8 mCreatorLength;
- XMP_Uns8 mCreator[32];
- XMP_Uns8 mLastUpdatePersonCharacterSet;
- XMP_Uns8 mLastUpdatePersonLength;
- XMP_Uns8 mLastUpdatePerson[32];
- } mAccess;
-
- // Device
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns16 mMakerID;
- XMP_Uns16 mMakerModelCode;
- XMP_Uns8 mSerialNoCharacterCode;
- XMP_Uns8 mSerialNoLength;
- XMP_Uns8 mSerialNo[24];
- XMP_Uns16 mFillItem;
- } mDevice;
-
- // Shoot
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mShooterCharacterSet;
- XMP_Uns8 mShooterLength;
- XMP_Uns8 mShooter[32];
- XMP_Uns8 mStartDateTimeZone;
- XMP_Uns8 mStartDate[7];
- XMP_Uns8 mEndDateTimeZone;
- XMP_Uns8 mEndDate[7];
- XMP_Uns16 mFillItem;
- } mShoot;
-
- // Location
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mSource;
- XMP_Uns32 mGPSLatitudeRef;
- XMP_Uns32 mGPSLatitude1;
- XMP_Uns32 mGPSLatitude2;
- XMP_Uns32 mGPSLatitude3;
- XMP_Uns32 mGPSLongitudeRef;
- XMP_Uns32 mGPSLongitude1;
- XMP_Uns32 mGPSLongitude2;
- XMP_Uns32 mGPSLongitude3;
- XMP_Uns32 mGPSAltitudeRef;
- XMP_Uns32 mGPSAltitude;
- XMP_Uns8 mPlaceNameCharacterSet;
- XMP_Uns8 mPlaceNameLength;
- XMP_Uns8 mPlaceName[64];
- XMP_Uns8 mFillItem;
- } mLocation;
-};
-
-// AVCHD Format, Panasonic proprietary extension data (AVCCAM)
-
-struct AVCCAM_Pro_PlayListInfo
-{
- XMP_Uns8 mPresent;
- XMP_Uns8 mTagID;
- XMP_Uns8 mTagVersion;
- XMP_Uns16 mFillItem1;
- XMP_Uns32 mLength;
- XMP_Uns16 mNumberOfPlayListMarks;
- XMP_Uns16 mFillItem2;
-
- // Although a playlist may contain multiple marks, we only store the one that corresponds to
- // the clip/shot of interest.
- AVCCAM_blkProPlayListMark mPlayListMark;
-};
-
-// AVCHD Format, Panasonic proprietary extension data (AVCCAM)
-
-struct AVCHD_blkPanasonicPrivateData
-{
- XMP_Uns8 mPresent;
- XMP_Uns16 mNumberOfData;
- XMP_Uns16 mReserved;
-
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mTagID;
- XMP_Uns8 mTagVersion;
- XMP_Uns16 mTagLength;
- XMP_Uns8 mProfessionalMetaID[16];
- } mProMetaIDBlock;
-
- struct
- {
- XMP_Uns8 mPresent;
- XMP_Uns8 mTagID;
- XMP_Uns8 mTagVersion;
- XMP_Uns16 mTagLength;
- XMP_Uns8 mGlobalClipID[32];
- XMP_Uns8 mStartTimecode[4];
- XMP_Uns32 mStartBinaryGroup;
- } mProClipIDBlock;
-
- AVCCAM_Pro_PlayListInfo mProPlaylistInfoBlock;
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.2.4.2. plus Panasonic extensions
-
-struct AVCHD_blkMakersPrivateData
-{
- XMP_Uns8 mPresent;
- XMP_Uns32 mLength;
- XMP_Uns32 mDataBlockStartAddress;
- XMP_Uns8 mReserved[3];
- XMP_Uns8 mNumberOfMakerEntries;
- XMP_Uns16 mMakerID;
- XMP_Uns16 mMakerModelCode;
- AVCHD_blkPanasonicPrivateData mPanasonicPrivateData;
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.4.2.1
-
-struct AVCHD_blkClipInfoExt
-{
- XMP_Uns32 mLength;
- XMP_Uns16 mMakerID;
- XMP_Uns16 mMakerModelCode;
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.4.1.2
-
-struct AVCHD_blkClipExtensionData
-{
- XMP_Uns8 mPresent;
- XMP_Uns8 mTypeIndicator[4];
- XMP_Uns8 mReserved1[4];
- XMP_Uns32 mProgramInfoExtStartAddress;
- XMP_Uns32 mMakersPrivateDataStartAddress;
-
- AVCHD_blkClipInfoExt mClipInfoExt;
- AVCHD_blkMakersPrivateData mMakersPrivateData;
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.3.3.1 -- although each playlist
-// may contain a list of these, we only record the one that matches our target shot/clip.
-
-struct AVCHD_blkPlayListMarkExt
-{
- XMP_Uns32 mLength;
- XMP_Uns16 mNumberOfPlaylistMarks;
- bool mPresent;
- XMP_Uns16 mMakerID;
- XMP_Uns16 mMakerModelCode;
- XMP_Uns8 mReserved1[3];
- XMP_Uns8 mFlags; // bit 0: MarkWriteProtectFlag, bits 1-2: pulldown
- XMP_Uns16 mRefToMarkThumbnailIndex;
- XMP_Uns8 mBlkTimezone;
- XMP_Uns8 mRecordDataAndTime[7];
- XMP_Uns8 mMarkCharacterSet;
- XMP_Uns8 mMarkNameLength;
- XMP_Uns8 mMarkName[24];
- XMP_Uns8 mMakersInformation[16];
- XMP_Uns8 mBlkTimecode[4];
- XMP_Uns16 mReserved2;
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.3.2.1
-
-struct AVCHD_blkPlaylistMeta
-{
- XMP_Uns32 mLength;
- XMP_Uns16 mMakerID;
- XMP_Uns16 mMakerModelCode;
- XMP_Uns32 mReserved1;
- XMP_Uns16 mRefToMenuThumbnailIndex;
- XMP_Uns8 mBlkTimezone;
- XMP_Uns8 mRecordDataAndTime[7];
- XMP_Uns8 mReserved2;
- XMP_Uns8 mPlaylistCharacterSet;
- XMP_Uns8 mPlaylistNameLength;
- XMP_Uns8 mPlaylistName[255];
-};
-
-// AVCHD Format. Book 2: Recording Extension Specifications, section 4.3.1.2
-
-struct AVCHD_blkPlayListExtensionData
-{
- XMP_Uns8 mPresent;
- char mTypeIndicator[4];
- XMP_Uns8 mReserved[4];
- XMP_Uns32 mPlayListMarkExtStartAddress;
- XMP_Uns32 mMakersPrivateDataStartAddress;
-
- AVCHD_blkPlaylistMeta mPlaylistMeta;
- AVCHD_blkPlayListMarkExt mPlaylistMarkExt;
- AVCHD_blkMakersPrivateData mMakersPrivateData;
-};
-
-// AVCHD Format. Book 1: Playback System Basic Specifications V 1.01. p. 38
-struct AVCHD_blkExtensionData
-{
- XMP_Uns32 mLength;
- XMP_Uns32 mDataBlockStartAddress;
- XMP_Uns8 mReserved[3];
- XMP_Uns8 mNumberOfDataEntries;
-
- struct AVCHD_blkExtDataEntry
- {
- XMP_Uns16 mExtDataType;
- XMP_Uns16 mExtDataVersion;
- XMP_Uns32 mExtDataStartAddress;
- XMP_Uns32 mExtDataLength;
- } mExtDataEntry;
-};
-
-// Simple container for the various AVCHD legacy metadata structures we care about for an AVCHD clip
-
-struct AVCHD_LegacyMetadata
-{
- AVCHD_blkProgramInfo mProgramInfo;
- AVCHD_blkClipExtensionData mClipExtensionData;
- AVCHD_blkPlayListExtensionData mPlaylistExtensionData;
-};
-
-// =================================================================================================
-// MakeLeafPath
-// ============
-
-static bool MakeLeafPath ( std::string * path, XMP_StringPtr root, XMP_StringPtr group,
- XMP_StringPtr clip, XMP_StringPtr suffix, bool checkFile = false )
-{
- size_t partialLen;
-
- *path = root;
- *path += kDirChar;
- *path += "BDMV";
- *path += kDirChar;
- *path += group;
- *path += kDirChar;
- *path += clip;
- partialLen = path->size();
- *path += suffix;
-
- if ( ! checkFile ) return true;
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- // Convert the suffix to uppercase and try again. Even on Mac/Win, in case a remote file system is sensitive.
- for ( char* chPtr = ((char*)path->c_str() + partialLen); *chPtr != 0; ++chPtr ) {
- if ( (0x61 <= *chPtr) && (*chPtr <= 0x7A) ) *chPtr -= 0x20;
- }
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- if ( XMP_LitMatch ( suffix, ".clpi" ) ) { // Special case of ".cpi" for the clip file.
-
- path->erase ( partialLen );
- *path += ".cpi";
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- path->erase ( partialLen );
- *path += ".CPI";
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- } else if ( XMP_LitMatch ( suffix, ".mpls" ) ) { // Special case of ".mpl" for the playlist file.
-
- path->erase ( partialLen );
- *path += ".mpl";
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- path->erase ( partialLen );
- *path += ".MPL";
- if ( GetFileMode ( path->c_str() ) == kFMode_IsFile ) return true;
-
- }
-
- // Still not found, revert to the original suffix.
- path->erase ( partialLen );
- *path += suffix;
- return false;
-
-} // MakeLeafPath
-
-// =================================================================================================
-// AVCHD_CheckFormat
-// =================
-//
-// This version checks for the presence of a top level BPAV directory, and the required files and
-// directories immediately within it. The CLIPINF, PLAYLIST, and STREAM subfolders are required, as
-// are the index.bdmv and MovieObject.bdmv files.
-//
-// The state of the string parameters depends on the form of the path passed by the client. If the
-// client passed a logical clip path, like ".../MyMovie/00001", the parameters are:
-// rootPath - ".../MyMovie"
-// gpName - empty
-// parentName - empty
-// leafName - "00001"
-// If the client passed a full file path, like ".../MyMovie/BDMV/CLIPINF/00001.clpi", they are:
-// rootPath - ".../MyMovie"
-// gpName - "BDMV"
-// parentName - "CLIPINF" or "PALYLIST" or "STREAM"
-// leafName - "00001"
-
-// ! The common code has shifted the gpName, parentName, and leafName strings to upper case. It has
-// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
-// ! file exists for a full file path.
-
-// ! Using explicit '/' as a separator when creating paths, it works on Windows.
-
-// ! Sample files show that the ".bdmv" extension can sometimes be ".bdm". Allow either.
-
-bool AVCHD_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent )
-{
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- if ( ! gpName.empty() ) {
- if ( gpName != "BDMV" ) return false;
- if ( (parentName != "CLIPINF") && (parentName != "PLAYLIST") && (parentName != "STREAM") ) return false;
- }
-
- // Check the rest of the required general structure. Look for both ".bdmv" and ".bmd" extensions.
-
- std::string bdmvPath ( rootPath );
- bdmvPath += kDirChar;
- bdmvPath += "BDMV";
-
- if ( GetChildMode ( bdmvPath, "CLIPINF" ) != kFMode_IsFolder ) return false;
- if ( GetChildMode ( bdmvPath, "PLAYLIST" ) != kFMode_IsFolder ) return false;
- if ( GetChildMode ( bdmvPath, "STREAM" ) != kFMode_IsFolder ) return false;
-
- if ( (GetChildMode ( bdmvPath, "index.bdmv" ) != kFMode_IsFile) &&
- (GetChildMode ( bdmvPath, "index.bdm" ) != kFMode_IsFile) &&
- (GetChildMode ( bdmvPath, "INDEX.BDMV" ) != kFMode_IsFile) && // Some usage is all caps.
- (GetChildMode ( bdmvPath, "INDEX.BDM" ) != kFMode_IsFile) ) return false;
-
- if ( (GetChildMode ( bdmvPath, "MovieObject.bdmv" ) != kFMode_IsFile) &&
- (GetChildMode ( bdmvPath, "MovieObj.bdm" ) != kFMode_IsFile) &&
- (GetChildMode ( bdmvPath, "MOVIEOBJECT.BDMV" ) != kFMode_IsFile) && // Some usage is all caps.
- (GetChildMode ( bdmvPath, "MOVIEOBJ.BDM" ) != kFMode_IsFile) ) return false;
-
-
- // Make sure the .clpi file exists.
- std::string tempPath;
- bool foundClpi = MakeLeafPath ( &tempPath, rootPath.c_str(), "CLIPINF", leafName.c_str(), ".clpi", true /* checkFile */ );
- if ( ! foundClpi ) return false;
-
- // And now save the pseudo path for the handler object.
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += leafName;
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for AVCHD clip info", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen );
-
- return true;
-
-} // AVCHD_CheckFormat
-
-// =================================================================================================
-// ReadAVCHDProgramInfo
-// ============
-
-static bool ReadAVCHDProgramInfo ( LFA_FileRef& cpiFileRef, AVCHD_blkProgramInfo& avchdProgramInfo )
-{
- avchdProgramInfo.mLength = LFA_ReadUns32_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, avchdProgramInfo.mReserved1, 2 );
- avchdProgramInfo.mSPNProgramSequenceStart = LFA_ReadUns32_BE ( cpiFileRef );
- avchdProgramInfo.mProgramMapPID = LFA_ReadUns16_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, &avchdProgramInfo.mNumberOfStreamsInPS, 1 );
- LFA_Read ( cpiFileRef, &avchdProgramInfo.mReserved2, 1 );
-
- XMP_Uns16 streamPID = 0;
- for ( int i=0; i<avchdProgramInfo.mNumberOfStreamsInPS; ++i ) {
-
- XMP_Uns8 length = 0;
- XMP_Uns8 streamCodingType = 0;
-
- streamPID = LFA_ReadUns16_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, &length, 1 );
-
- XMP_Int64 pos = LFA_Tell ( cpiFileRef );
-
- LFA_Read ( cpiFileRef, &streamCodingType, 1 );
-
- switch ( streamCodingType ) {
-
- case 0x1B : // Video stream case.
- {
- XMP_Uns8 videoFormatAndFrameRate;
- LFA_Read ( cpiFileRef, &videoFormatAndFrameRate, 1 );
- avchdProgramInfo.mVideoStream.mVideoFormat = videoFormatAndFrameRate >> 4; // hi 4 bits
- avchdProgramInfo.mVideoStream.mFrameRate = videoFormatAndFrameRate & 0x0f; // lo 4 bits
-
- XMP_Uns8 aspectRatioAndReserved = 0;
- LFA_Read ( cpiFileRef, &aspectRatioAndReserved, 1 );
- avchdProgramInfo.mVideoStream.mAspectRatio = aspectRatioAndReserved >> 4; // hi 4 bits
-
- XMP_Uns8 ccFlag = 0;
- LFA_Read ( cpiFileRef, &ccFlag, 1 );
- avchdProgramInfo.mVideoStream.mCCFlag = ccFlag;
-
- avchdProgramInfo.mVideoStream.mPresent = 1;
- }
- break;
-
- case 0x80 : // Fall through.
- case 0x81 : // Audio stream case.
- {
- XMP_Uns8 audioPresentationTypeAndFrequency = 0;
- LFA_Read ( cpiFileRef, &audioPresentationTypeAndFrequency, 1 );
-
- avchdProgramInfo.mAudioStream.mAudioPresentationType = audioPresentationTypeAndFrequency >> 4; // hi 4 bits
- avchdProgramInfo.mAudioStream.mSamplingFrequency = audioPresentationTypeAndFrequency & 0x0f; // lo 4 bits
-
- LFA_Read ( cpiFileRef, avchdProgramInfo.mAudioStream.mAudioLanguageCode, 3 );
- avchdProgramInfo.mAudioStream.mAudioLanguageCode[3] = 0;
-
- avchdProgramInfo.mAudioStream.mPresent = 1;
- }
- break;
-
- case 0x90 : // Overlay bitmap stream case.
- LFA_Read ( cpiFileRef, &avchdProgramInfo.mOverlayBitmapStream.mOBLanguageCode, 3 );
- avchdProgramInfo.mOverlayBitmapStream.mOBLanguageCode[3] = 0;
- avchdProgramInfo.mOverlayBitmapStream.mPresent = 1;
- break;
-
- case 0x91 : // Menu bitmap stream.
- LFA_Read ( cpiFileRef, &avchdProgramInfo.mMenuBitmapStream.mBMLanguageCode, 3 );
- avchdProgramInfo.mMenuBitmapStream.mBMLanguageCode[3] = 0;
- avchdProgramInfo.mMenuBitmapStream.mPresent = 1;
- break;
-
- default :
- break;
-
- }
-
- LFA_Seek ( cpiFileRef, pos + length, SEEK_SET );
-
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDExtensionData
-// ============
-
-static bool ReadAVCHDExtensionData ( LFA_FileRef& cpiFileRef, AVCHD_blkExtensionData& extensionDataHeader )
-{
- extensionDataHeader.mLength = LFA_ReadUns32_BE ( cpiFileRef );
-
- if ( extensionDataHeader.mLength == 0 ) {
- // Nothing to read
- return true;
- }
-
- extensionDataHeader.mDataBlockStartAddress = LFA_ReadUns32_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, extensionDataHeader.mReserved, 3 );
- LFA_Read ( cpiFileRef, &extensionDataHeader.mNumberOfDataEntries, 1 );
-
- if ( extensionDataHeader.mNumberOfDataEntries != 1 ) {
- // According to AVCHD Format. Book1. v. 1.01. p 38, "This field shall be set to 1 in this format."
- return false;
- }
-
- extensionDataHeader.mExtDataEntry.mExtDataType = LFA_ReadUns16_BE ( cpiFileRef );
- extensionDataHeader.mExtDataEntry.mExtDataVersion = LFA_ReadUns16_BE ( cpiFileRef );
- extensionDataHeader.mExtDataEntry.mExtDataStartAddress = LFA_ReadUns32_BE ( cpiFileRef );
- extensionDataHeader.mExtDataEntry.mExtDataLength = LFA_ReadUns32_BE ( cpiFileRef );
-
- if ( extensionDataHeader.mExtDataEntry.mExtDataType != 0x1000 ) {
- // According to AVCHD Format. Book1. v. 1.01. p 38, "If the metadata is for an AVCHD application,
- // this value shall be set to 'Ox1OOO'."
- return false;
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAMProMetaID-- read Panasonic's proprietary PRO_MetaID block
-// ============
-
-static bool ReadAVCCAMProMetaID ( LFA_FileRef& cpiFileRef, XMP_Uns8 tagID, AVCHD_blkPanasonicPrivateData& extensionDataHeader )
-{
- extensionDataHeader.mPresent = 1;
- extensionDataHeader.mProMetaIDBlock.mPresent = 1;
- extensionDataHeader.mProMetaIDBlock.mTagID = tagID;
- LFA_Read ( cpiFileRef, &extensionDataHeader.mProMetaIDBlock.mTagVersion, 1);
- extensionDataHeader.mProMetaIDBlock.mTagLength = LFA_ReadUns16_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, &extensionDataHeader.mProMetaIDBlock.mProfessionalMetaID, 16);
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAMProClipInfo-- read Panasonic's proprietary PRO_ClipInfo block
-// ============
-
-static bool ReadAVCCAMProClipInfo ( LFA_FileRef& cpiFileRef, XMP_Uns8 tagID, AVCHD_blkPanasonicPrivateData& extensionDataHeader )
-{
- extensionDataHeader.mPresent = 1;
- extensionDataHeader.mProClipIDBlock.mPresent = 1;
- extensionDataHeader.mProClipIDBlock.mTagID = tagID;
- LFA_Read ( cpiFileRef, &extensionDataHeader.mProClipIDBlock.mTagVersion, 1);
- extensionDataHeader.mProClipIDBlock.mTagLength = LFA_ReadUns16_BE ( cpiFileRef );
- LFA_Read ( cpiFileRef, &extensionDataHeader.mProClipIDBlock.mGlobalClipID, 32);
- LFA_Read ( cpiFileRef, &extensionDataHeader.mProClipIDBlock.mStartTimecode, 4 );
- extensionDataHeader.mProClipIDBlock.mStartBinaryGroup = LFA_ReadUns32_BE ( cpiFileRef );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAM_blkPRO_ShotMark -- read Panasonic's proprietary PRO_ShotMark block
-// ============
-
-static bool ReadAVCCAM_blkPRO_ShotMark ( LFA_FileRef& mplFileRef, AVCCAM_blkProPlayListMark& proMark )
-{
- proMark.mShotMark.mPresent = 1;
- LFA_Read ( mplFileRef, &proMark.mShotMark.mShotMark, 1);
- LFA_Read ( mplFileRef, &proMark.mShotMark.mFillItem, 3);
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAM_blkPRO_Access -- read Panasonic's proprietary PRO_Access block
-// ============
-
-static bool ReadAVCCAM_blkPRO_Access ( LFA_FileRef& mplFileRef, AVCCAM_blkProPlayListMark& proMark )
-{
- proMark.mAccess.mPresent = 1;
- LFA_Read ( mplFileRef, &proMark.mAccess.mCreatorCharacterSet, 1 );
- LFA_Read ( mplFileRef, &proMark.mAccess.mCreatorLength, 1 );
- LFA_Read ( mplFileRef, &proMark.mAccess.mCreator, 32 );
- LFA_Read ( mplFileRef, &proMark.mAccess.mLastUpdatePersonCharacterSet, 1 );
- LFA_Read ( mplFileRef, &proMark.mAccess.mLastUpdatePersonLength, 1 );
- LFA_Read ( mplFileRef, &proMark.mAccess.mLastUpdatePerson, 32 );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAM_blkPRO_Device -- read Panasonic's proprietary PRO_Device block
-// ============
-
-static bool ReadAVCCAM_blkPRO_Device ( LFA_FileRef& mplFileRef, AVCCAM_blkProPlayListMark& proMark )
-{
- proMark.mDevice.mPresent = 1;
- proMark.mDevice.mMakerID = LFA_ReadUns16_BE ( mplFileRef );
- proMark.mDevice.mMakerModelCode = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &proMark.mDevice.mSerialNoCharacterCode, 1 );
- LFA_Read ( mplFileRef, &proMark.mDevice.mSerialNoLength, 1 );
- LFA_Read ( mplFileRef, &proMark.mDevice.mSerialNo, 24 );
- LFA_Read ( mplFileRef, &proMark.mDevice.mFillItem, 2 );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAM_blkPRO_Shoot -- read Panasonic's proprietary PRO_Shoot block
-// ============
-
-static bool ReadAVCCAM_blkPRO_Shoot ( LFA_FileRef& mplFileRef, AVCCAM_blkProPlayListMark& proMark )
-{
- proMark.mShoot.mPresent = 1;
- LFA_Read ( mplFileRef, &proMark.mShoot.mShooterCharacterSet, 1 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mShooterLength, 1 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mShooter, 32 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mStartDateTimeZone, 1 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mStartDate, 7 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mEndDateTimeZone, 1 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mEndDate, 7 );
- LFA_Read ( mplFileRef, &proMark.mShoot.mFillItem, 2 );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAM_blkPRO_Location -- read Panasonic's proprietary PRO_Location block
-// ============
-
-static bool ReadAVCCAM_blkPRO_Location ( LFA_FileRef& mplFileRef, AVCCAM_blkProPlayListMark& proMark )
-{
- proMark.mLocation.mPresent = 1;
- LFA_Read ( mplFileRef, &proMark.mLocation.mSource, 1 );
- proMark.mLocation.mGPSLatitudeRef = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLatitude1 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLatitude2 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLatitude3 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLongitudeRef = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLongitude1 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLongitude2 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSLongitude3 = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSAltitudeRef = LFA_ReadUns32_BE ( mplFileRef );
- proMark.mLocation.mGPSAltitude = LFA_ReadUns32_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &proMark.mLocation.mPlaceNameCharacterSet, 1 );
- LFA_Read ( mplFileRef, &proMark.mLocation.mPlaceNameLength, 1 );
- LFA_Read ( mplFileRef, &proMark.mLocation.mPlaceName, 64 );
- LFA_Read ( mplFileRef, &proMark.mLocation.mFillItem, 1 );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAMProPlaylistInfo -- read Panasonic's proprietary PRO_PlayListInfo block
-// ============
-
-static bool ReadAVCCAMProPlaylistInfo ( LFA_FileRef& mplFileRef,
- XMP_Uns8 tagID,
- XMP_Uns16 playlistMarkID,
- AVCHD_blkPanasonicPrivateData& extensionDataHeader )
-{
- AVCCAM_Pro_PlayListInfo& playlistBlock = extensionDataHeader.mProPlaylistInfoBlock;
-
- playlistBlock.mTagID = tagID;
- LFA_Read ( mplFileRef, &playlistBlock.mTagVersion, 1);
- LFA_Read ( mplFileRef, &playlistBlock.mFillItem1, 2);
- playlistBlock.mLength = LFA_ReadUns32_BE ( mplFileRef );
- playlistBlock.mNumberOfPlayListMarks = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &playlistBlock.mFillItem2, 2);
-
- if ( playlistBlock.mNumberOfPlayListMarks == 0 ) return true;
-
- extensionDataHeader.mPresent = 1;
-
- XMP_Uns64 blockStart = 0;
-
- for ( int i = 0; i < playlistBlock.mNumberOfPlayListMarks; ++i ) {
- AVCCAM_blkProPlayListMark& currMark = playlistBlock.mPlayListMark;
-
- LFA_Read ( mplFileRef, &currMark.mProTagID, 1);
- LFA_Read ( mplFileRef, &currMark.mFillItem1, 1);
- currMark.mLength = LFA_ReadUns16_BE ( mplFileRef );
- blockStart = LFA_Tell ( mplFileRef );
- LFA_Read ( mplFileRef, &currMark.mMarkType, 1 );
-
- if ( ( currMark.mProTagID == 0x40 ) && ( currMark.mMarkType == 0x01 ) ) {
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mGlobalClipID, 32);
-
- // skip marks for different clips
- if ( i == playlistMarkID ) {
- playlistBlock.mPresent = 1;
- currMark.mPresent = 1;
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mStartTimeCode, 4);
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mStreamTimecodeInfo, 1);
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mStartBinaryGroup, 4);
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mLastUpdateTimeZone, 1);
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mLastUpdateDate, 7);
- LFA_Read ( mplFileRef, &currMark.mEntryMark.mFillItem, 2);
-
- XMP_Uns64 currPos = LFA_Tell ( mplFileRef );
- XMP_Uns8 blockTag = 0;
- XMP_Uns8 blockFill;
- XMP_Uns16 blockLength = 0;
-
- while ( currPos < ( blockStart + currMark.mLength ) ) {
- LFA_Read ( mplFileRef, &blockTag, 1);
- LFA_Read ( mplFileRef, &blockFill, 1);
- blockLength = LFA_ReadUns16_BE ( mplFileRef );
- currPos += 4;
-
- switch ( blockTag ) {
- case 0x20:
- if ( ! ReadAVCCAM_blkPRO_ShotMark ( mplFileRef, currMark ) ) return false;
- break;
-
-
- case 0x21:
- if ( ! ReadAVCCAM_blkPRO_Access ( mplFileRef, currMark ) ) return false;
- break;
-
- case 0x22:
- if ( ! ReadAVCCAM_blkPRO_Device ( mplFileRef, currMark ) ) return false;
- break;
-
- case 0x23:
- if ( ! ReadAVCCAM_blkPRO_Shoot ( mplFileRef, currMark ) ) return false;
- break;
-
- case 0x24:
- if (! ReadAVCCAM_blkPRO_Location ( mplFileRef, currMark ) ) return false;
- break;
-
- default : break;
- }
-
- currPos += blockLength;
- LFA_Seek ( mplFileRef, currPos, SEEK_SET );
- }
- }
- }
-
- LFA_Seek ( mplFileRef, blockStart + currMark.mLength, SEEK_SET );
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCCAMMakersPrivateData -- read Panasonic's implementation of an AVCCAM "Maker's Private Data"
-// block. Panasonic calls their extensions "AVCCAM."
-// ============
-
-static bool ReadAVCCAMMakersPrivateData ( LFA_FileRef& fileRef,
- XMP_Uns16 playlistMarkID,
- AVCHD_blkPanasonicPrivateData& avccamPrivateData )
-{
- const XMP_Uns64 blockStart = LFA_Tell(fileRef);
-
- avccamPrivateData.mNumberOfData = LFA_ReadUns16_BE ( fileRef );
- LFA_Read ( fileRef, &avccamPrivateData.mReserved, 2 );
-
- for (int i = 0; i < avccamPrivateData.mNumberOfData; ++i) {
- const XMP_Uns8 tagID = LFA_ReadUns8 ( fileRef );
-
- switch ( tagID ) {
- case 0xe0: ReadAVCCAMProMetaID ( fileRef, tagID, avccamPrivateData );
- break;
- case 0xe2: ReadAVCCAMProClipInfo( fileRef, tagID, avccamPrivateData );
- break;
- case 0xf0: ReadAVCCAMProPlaylistInfo( fileRef, tagID, playlistMarkID, avccamPrivateData );
- break;
-
- default:
- // Ignore any blocks we don't now or care about
- break;
- }
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDMakersPrivateData (AVCHD Format. Book 2: Recording Extension Specifications, section 4.2.4.2)
-// ============
-
-static bool ReadAVCHDMakersPrivateData ( LFA_FileRef& mplFileRef,
- XMP_Uns16 playlistMarkID,
- AVCHD_blkMakersPrivateData& avchdLegacyData )
-{
- const XMP_Uns64 blockStart = LFA_Tell ( mplFileRef );
-
- avchdLegacyData.mLength = LFA_ReadUns32_BE ( mplFileRef );
-
- if ( avchdLegacyData.mLength == 0 ) return false;
-
- avchdLegacyData.mPresent = 1;
- avchdLegacyData.mDataBlockStartAddress = LFA_ReadUns32_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &avchdLegacyData.mReserved, 3 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mNumberOfMakerEntries, 1 );
-
- if ( avchdLegacyData.mNumberOfMakerEntries == 0 ) return true;
-
- XMP_Uns16 makerID;
- XMP_Uns16 makerModelCode;
- XMP_Uns32 mpdStartAddress;
- XMP_Uns32 mpdLength;
-
- for ( int i = 0; i < avchdLegacyData.mNumberOfMakerEntries; ++i ) {
- makerID = LFA_ReadUns16_BE ( mplFileRef );
- makerModelCode = LFA_ReadUns16_BE ( mplFileRef );
- mpdStartAddress = LFA_ReadUns32_BE ( mplFileRef );
- mpdLength = LFA_ReadUns32_BE ( mplFileRef );
-
- // We only have documentation for Panasonic's Maker's Private Data blocks, so we'll ignore everyone else's
- if ( makerID == kMakerIDPanasonic ) {
- avchdLegacyData.mMakerID = makerID;
- avchdLegacyData.mMakerModelCode = makerModelCode;
- LFA_Seek ( mplFileRef, blockStart + mpdStartAddress, SEEK_SET );
-
- if (! ReadAVCCAMMakersPrivateData ( mplFileRef, playlistMarkID, avchdLegacyData.mPanasonicPrivateData ) ) return false;
- }
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDClipExtensionData
-// ============
-
-static bool ReadAVCHDClipExtensionData ( LFA_FileRef& cpiFileRef, AVCHD_blkClipExtensionData& avchdExtensionData )
-{
- const XMP_Int64 extensionBlockStart = LFA_Tell ( cpiFileRef );
- AVCHD_blkExtensionData extensionDataHeader;
-
- if ( ! ReadAVCHDExtensionData ( cpiFileRef, extensionDataHeader ) ) {
- return false;
- }
-
- if ( extensionDataHeader.mLength == 0 ) {
- return true;
- }
-
- const XMP_Int64 dataBlockStart = extensionBlockStart + extensionDataHeader.mDataBlockStartAddress;
-
- LFA_Seek ( cpiFileRef, dataBlockStart, SEEK_SET );
- LFA_Read ( cpiFileRef, avchdExtensionData.mTypeIndicator, 4 );
-
- if ( strncmp ( reinterpret_cast<const char*>( avchdExtensionData.mTypeIndicator ), "CLEX", 4 ) != 0 ) return false;
-
- avchdExtensionData.mPresent = 1;
- LFA_Read ( cpiFileRef, avchdExtensionData.mReserved1, 4 );
- avchdExtensionData.mProgramInfoExtStartAddress = LFA_ReadUns32_BE ( cpiFileRef );
- avchdExtensionData.mMakersPrivateDataStartAddress = LFA_ReadUns32_BE ( cpiFileRef );
-
- // read Clip info extension
- LFA_Seek ( cpiFileRef, dataBlockStart + 40, SEEK_SET );
- avchdExtensionData.mClipInfoExt.mLength = LFA_ReadUns32_BE ( cpiFileRef );
- avchdExtensionData.mClipInfoExt.mMakerID = LFA_ReadUns16_BE ( cpiFileRef );
- avchdExtensionData.mClipInfoExt.mMakerModelCode = LFA_ReadUns16_BE ( cpiFileRef );
-
- if ( avchdExtensionData.mMakersPrivateDataStartAddress == 0 ) return true;
-
- if ( avchdExtensionData.mClipInfoExt.mMakerID == kMakerIDPanasonic ) {
- // Read Maker's Private Data block -- we only have Panasonic's definition for their AVCCAM models
- // at this point, so we'll ignore the block if its from a different manufacturer.
- LFA_Seek ( cpiFileRef, dataBlockStart + avchdExtensionData.mMakersPrivateDataStartAddress, SEEK_SET );
-
- if ( ! ReadAVCHDMakersPrivateData ( cpiFileRef, 0, avchdExtensionData.mMakersPrivateData ) ) {
- return false;
- }
- }
-
- return true;
-}
-
-// =================================================================================================
-// AVCHD_PlaylistContainsClip -- returns true of the specified AVCHD playlist block references the
-// specified clip, or false if not.
-// ====================
-
-static bool AVCHD_PlaylistContainsClip ( LFA_FileRef& mplFileRef, XMP_Uns16& playItemID, const std::string& strClipName )
-{
- // Read clip header. ( AVCHD Format. Book1. v. 1.01. p 45 )
- struct AVCHD_blkPlayList
- {
- XMP_Uns32 mLength;
- XMP_Uns16 mReserved;
- XMP_Uns16 mNumberOfPlayItems;
- XMP_Uns16 mNumberOfSubPaths;
- };
-
- AVCHD_blkPlayList blkPlayList;
- blkPlayList.mLength = LFA_ReadUns32_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &blkPlayList.mReserved, 2 );
- blkPlayList.mNumberOfPlayItems = LFA_ReadUns16_BE ( mplFileRef );
- blkPlayList.mNumberOfSubPaths = LFA_ReadUns16_BE ( mplFileRef );
-
- // Search the play items. ( AVCHD Format. Book1. v. 1.01. p 47 )
- struct AVCHD_blkPlayItem
- {
- XMP_Uns16 mLength;
- char mClipInformationFileName[5];
- // Note: remaining fields omitted because we don't care about them
- };
-
- AVCHD_blkPlayItem currPlayItem;
- XMP_Uns64 blockStart = 0;
- for ( playItemID = 0; playItemID < blkPlayList.mNumberOfPlayItems; ++playItemID ) {
- currPlayItem.mLength = LFA_ReadUns16_BE ( mplFileRef );
-
- // mLength is measured from the end of mLength, not the start of the block ( AVCHD Format. Book1. v. 1.01. p 47 )
- blockStart = LFA_Tell ( mplFileRef );
- LFA_Read ( mplFileRef, currPlayItem.mClipInformationFileName, 5 );
-
- if ( strncmp ( strClipName.c_str(), currPlayItem.mClipInformationFileName, 5 ) == 0 ) return true;
-
- LFA_Seek ( mplFileRef, blockStart + currPlayItem.mLength, SEEK_SET );
- }
-
- return false;
-}
-
-// =================================================================================================
-// ReadAVCHDPlaylistMetadataBlock
-// ============
-
-static bool ReadAVCHDPlaylistMetadataBlock ( LFA_FileRef& mplFileRef,
- AVCHD_blkPlaylistMeta& avchdLegacyData )
-{
- avchdLegacyData.mLength = LFA_ReadUns32_BE ( mplFileRef );
-
- if ( avchdLegacyData.mLength < sizeof ( AVCHD_blkPlaylistMeta ) ) return false;
-
- avchdLegacyData.mMakerID = LFA_ReadUns16_BE ( mplFileRef );
- avchdLegacyData.mMakerModelCode = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &avchdLegacyData.mReserved1, 4 );
- avchdLegacyData.mRefToMenuThumbnailIndex = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &avchdLegacyData.mBlkTimezone, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mRecordDataAndTime, 7 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mReserved2, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mPlaylistCharacterSet, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mPlaylistNameLength, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mPlaylistName, avchdLegacyData.mPlaylistNameLength );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDPlaylistMarkExtension
-// ============
-
-static bool ReadAVCHDPlaylistMarkExtension ( LFA_FileRef& mplFileRef,
- XMP_Uns16 playlistMarkID,
- AVCHD_blkPlayListMarkExt& avchdLegacyData )
-{
- avchdLegacyData.mLength = LFA_ReadUns32_BE ( mplFileRef );
-
- if ( avchdLegacyData.mLength == 0 ) return false;
-
- avchdLegacyData.mNumberOfPlaylistMarks = LFA_ReadUns16_BE ( mplFileRef );
-
- if ( avchdLegacyData.mNumberOfPlaylistMarks <= playlistMarkID ) return true;
-
- // Number of bytes in blkMarkExtension, AVCHD Book 2, section 4.3.3.1
- const XMP_Uns64 markExtensionSize = 66;
-
- // Entries in the mark extension block correspond one-to-one with entries in
- // blkPlaylistMark, so we'll only read the one that corresponds to the
- // chosen clip.
- const XMP_Uns64 markOffset = markExtensionSize * playlistMarkID;
-
- avchdLegacyData.mPresent = 1;
- LFA_Seek ( mplFileRef, markOffset, SEEK_CUR );
- avchdLegacyData.mMakerID = LFA_ReadUns16_BE ( mplFileRef );
- avchdLegacyData.mMakerModelCode = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &avchdLegacyData.mReserved1, 3 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mFlags, 1 );
- avchdLegacyData.mRefToMarkThumbnailIndex = LFA_ReadUns16_BE ( mplFileRef );
- LFA_Read ( mplFileRef, &avchdLegacyData.mBlkTimezone, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mRecordDataAndTime, 7 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mMarkCharacterSet, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mMarkNameLength, 1 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mMarkName, 24 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mMakersInformation, 16 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mBlkTimecode, 4 );
- LFA_Read ( mplFileRef, &avchdLegacyData.mReserved2, 2 );
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDPlaylistMarkID -- read the playlist mark block to find the ID of the playlist mark that
-// matches the specified playlist item.
-// ============
-
-static bool ReadAVCHDPlaylistMarkID ( LFA_FileRef& mplFileRef,
- XMP_Uns16 playItemID,
- XMP_Uns16& markID )
-{
- XMP_Uns32 length = LFA_ReadUns32_BE ( mplFileRef );
- XMP_Uns16 numberOfPlayListMarks = LFA_ReadUns16_BE ( mplFileRef );
-
- if ( length == 0 ) return false;
-
- XMP_Uns8 reserved;
- XMP_Uns8 markType;
- XMP_Uns16 refToPlayItemID;
-
- for ( int i = 0; i < numberOfPlayListMarks; ++i ) {
- LFA_Read ( mplFileRef, &reserved, 1 );
- LFA_Read ( mplFileRef, &markType, 1 );
- refToPlayItemID = LFA_ReadUns16_BE ( mplFileRef );
-
- if ( ( markType == 0x01 ) && ( refToPlayItemID == playItemID ) ) {
- markID = i;
- return true;
- }
-
- LFA_Seek ( mplFileRef, 10, SEEK_CUR );
- }
-
- return false;
-}
-
-// =================================================================================================
-// ReadAVCHDPlaylistExtensionData
-// ============
-
-static bool ReadAVCHDPlaylistExtensionData ( LFA_FileRef& mplFileRef,
- AVCHD_LegacyMetadata& avchdLegacyData,
- XMP_Uns16 playlistMarkID )
-{
- const XMP_Int64 extensionBlockStart = LFA_Tell ( mplFileRef );
- AVCHD_blkExtensionData extensionDataHeader;
-
- if ( ! ReadAVCHDExtensionData ( mplFileRef, extensionDataHeader ) ) {
- return false;
- }
-
- if ( extensionDataHeader.mLength == 0 ) {
- return true;
- }
-
- const XMP_Int64 dataBlockStart = extensionBlockStart + extensionDataHeader.mDataBlockStartAddress;
- AVCHD_blkPlayListExtensionData& extensionData = avchdLegacyData.mPlaylistExtensionData;
- const int reserved2Len = 24;
-
- LFA_Seek ( mplFileRef, dataBlockStart, SEEK_SET );
- LFA_Read ( mplFileRef, extensionData.mTypeIndicator, 4 );
-
- if ( strncmp ( extensionData.mTypeIndicator, "PLEX", 4 ) != 0 ) return false;
-
- extensionData.mPresent = true;
- LFA_Read ( mplFileRef, extensionData.mReserved, 4 );
- extensionData.mPlayListMarkExtStartAddress = LFA_ReadUns32_BE ( mplFileRef );
- extensionData.mMakersPrivateDataStartAddress = LFA_ReadUns32_BE ( mplFileRef );
- LFA_Seek ( mplFileRef, reserved2Len, SEEK_CUR );
-
- if ( ! ReadAVCHDPlaylistMetadataBlock ( mplFileRef, extensionData.mPlaylistMeta ) ) return false;
-
- LFA_Seek ( mplFileRef, dataBlockStart + extensionData.mPlayListMarkExtStartAddress, SEEK_SET );
-
- if ( ! ReadAVCHDPlaylistMarkExtension ( mplFileRef, playlistMarkID, extensionData.mPlaylistMarkExt ) ) return false;
-
- if ( extensionData.mMakersPrivateDataStartAddress > 0 ) {
-
- if ( ! avchdLegacyData.mClipExtensionData.mMakersPrivateData.mPanasonicPrivateData.mPresent ) return false;
-
- LFA_Seek ( mplFileRef, dataBlockStart + extensionData.mMakersPrivateDataStartAddress, SEEK_SET );
-
- if ( ! ReadAVCHDMakersPrivateData ( mplFileRef, playlistMarkID, extensionData.mMakersPrivateData ) ) return false;
-
- }
-
- return true;
-}
-
-// =================================================================================================
-// ReadAVCHDLegacyClipFile -- read the legacy metadata stored in an AVCHD .CPI file
-// ====================
-
-static bool ReadAVCHDLegacyClipFile ( const std::string& strPath, AVCHD_LegacyMetadata& avchdLegacyData )
-{
- bool success = false;
-
- try {
-
- AutoFile cpiFile;
- cpiFile.fileRef = LFA_Open ( strPath.c_str(), 'r' );
- if ( cpiFile.fileRef == 0 ) return false; // The open failed.
-
- memset ( &avchdLegacyData, 0, sizeof(AVCHD_LegacyMetadata) );
-
- // Read clip header. ( AVCHD Format. Book1. v. 1.01. p 64 )
- struct AVCHD_ClipInfoHeader
- {
- char mTypeIndicator[4];
- char mTypeIndicator2[4];
- XMP_Uns32 mSequenceInfoStartAddress;
- XMP_Uns32 mProgramInfoStartAddress;
- XMP_Uns32 mCPIStartAddress;
- XMP_Uns32 mClipMarkStartAddress;
- XMP_Uns32 mExtensionDataStartAddress;
- XMP_Uns8 mReserved[12];
- };
-
- // Read the AVCHD header.
- AVCHD_ClipInfoHeader avchdHeader;
- LFA_Read ( cpiFile.fileRef, avchdHeader.mTypeIndicator, 4 );
- LFA_Read ( cpiFile.fileRef, avchdHeader.mTypeIndicator2, 4 );
-
- if ( strncmp ( avchdHeader.mTypeIndicator, "HDMV", 4 ) != 0 ) return false;
- if ( strncmp ( avchdHeader.mTypeIndicator2, "0100", 4 ) != 0 ) return false;
-
- avchdHeader.mSequenceInfoStartAddress = LFA_ReadUns32_BE ( cpiFile.fileRef );
- avchdHeader.mProgramInfoStartAddress = LFA_ReadUns32_BE ( cpiFile.fileRef );
- avchdHeader.mCPIStartAddress = LFA_ReadUns32_BE ( cpiFile.fileRef );
- avchdHeader.mClipMarkStartAddress = LFA_ReadUns32_BE ( cpiFile.fileRef );
- avchdHeader.mExtensionDataStartAddress = LFA_ReadUns32_BE ( cpiFile.fileRef );
- LFA_Read ( cpiFile.fileRef, avchdHeader.mReserved, 12 );
-
- // Seek to the program header. (AVCHD Format. Book1. v. 1.01. p 77 )
- LFA_Seek ( cpiFile.fileRef, avchdHeader.mProgramInfoStartAddress, SEEK_SET );
-
- // Read the program info block
- success = ReadAVCHDProgramInfo ( cpiFile.fileRef, avchdLegacyData.mProgramInfo );
-
- if ( success && ( avchdHeader.mExtensionDataStartAddress != 0 ) ) {
- // Seek to the program header. (AVCHD Format. Book1. v. 1.01. p 77 )
- LFA_Seek ( cpiFile.fileRef, avchdHeader.mExtensionDataStartAddress, SEEK_SET );
- success = ReadAVCHDClipExtensionData ( cpiFile.fileRef, avchdLegacyData.mClipExtensionData );
- }
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return success;
-}
-
-// =================================================================================================
-// ReadAVCHDLegacyPlaylistFile -- read the legacy metadata stored in an AVCHD .MPL file
-// ====================
-
-static bool ReadAVCHDLegacyPlaylistFile ( const std::string& strRootPath,
- const std::string& strClipName,
- AVCHD_LegacyMetadata& avchdLegacyData )
-{
- bool success = false;
- std::string mplPath;
- char playlistName [10];
- const int rootPlaylistNum = atoi(strClipName.c_str());
-
- // Find the corresponding .MPL file -- because of clip spanning the .MPL name may not match the .CPI name for
- // a given clip -- we need to open .MPL files and look for one that contains a reference to the clip name. To speed
- // up the search we'll start with the playlist with the same number/name as the clip and search backwards. Assuming
- // this directory was generated by a camera, the clip numbers will increase sequentially across the playlist files,
- // though one playlist file may reference more than one clip.
- for ( int i = rootPlaylistNum; i >= 0; --i ) {
-
- sprintf ( playlistName, "%05d", i );
-
- if ( MakeLeafPath ( &mplPath, strRootPath.c_str(), "PLAYLIST", playlistName, ".mpl", true /* checkFile */ ) ) {
-
- try {
-
- AutoFile mplFile;
- mplFile.fileRef = LFA_Open ( mplPath.c_str(), 'r' );
- if ( mplFile.fileRef == 0 ) return false; // The open failed.
-
- // Read playlist header. ( AVCHD Format. Book1. v. 1.01. p 43 )
- struct AVCHD_PlaylistFileHeader
- {
- char mTypeIndicator[4];
- char mTypeIndicator2[4];
- XMP_Uns32 mPlaylistStartAddress;
- XMP_Uns32 mPlaylistMarkStartAddress;
- XMP_Uns32 mExtensionDataStartAddress;
- };
-
- // Read the AVCHD playlist file header.
- AVCHD_PlaylistFileHeader avchdHeader;
- LFA_Read ( mplFile.fileRef, avchdHeader.mTypeIndicator, 4 );
- LFA_Read ( mplFile.fileRef, avchdHeader.mTypeIndicator2, 4 );
-
- if ( strncmp ( avchdHeader.mTypeIndicator, "MPLS", 4 ) != 0 ) return false;
- if ( strncmp ( avchdHeader.mTypeIndicator2, "0100", 4 ) != 0 ) return false;
-
- avchdHeader.mPlaylistStartAddress = LFA_ReadUns32_BE ( mplFile.fileRef );
- avchdHeader.mPlaylistMarkStartAddress = LFA_ReadUns32_BE ( mplFile.fileRef );
- avchdHeader.mExtensionDataStartAddress = LFA_ReadUns32_BE ( mplFile.fileRef );
-
- if ( avchdHeader.mExtensionDataStartAddress == 0 ) return false;
-
- // Seek to the start of the Playlist block. (AVCHD Format. Book1. v. 1.01. p 45 )
- LFA_Seek ( mplFile.fileRef, avchdHeader.mPlaylistStartAddress, SEEK_SET );
-
- XMP_Uns16 playItemID = 0xFFFF;
- XMP_Uns16 playlistMarkID = 0xFFFF;
-
- if ( AVCHD_PlaylistContainsClip ( mplFile.fileRef, playItemID, strClipName ) ) {
- LFA_Seek ( mplFile.fileRef, avchdHeader.mPlaylistMarkStartAddress, SEEK_SET );
-
- if ( ! ReadAVCHDPlaylistMarkID ( mplFile.fileRef, playItemID, playlistMarkID ) ) return false;
-
- LFA_Seek ( mplFile.fileRef, avchdHeader.mExtensionDataStartAddress, SEEK_SET );
- success = ReadAVCHDPlaylistExtensionData ( mplFile.fileRef, avchdLegacyData, playlistMarkID );
- }
- } catch ( ... ) {
-
- return false;
-
- }
- }
-
- }
-
- return success;
-}
-
-// =================================================================================================
-// ReadAVCHDLegacyMetadata -- read the legacy metadata stored in an AVCHD .CPI file
-// ====================
-
-static bool ReadAVCHDLegacyMetadata ( const std::string& strPath,
- const std::string& strRootPath,
- const std::string& strClipName,
- AVCHD_LegacyMetadata& avchdLegacyData )
-{
- bool success = ReadAVCHDLegacyClipFile ( strPath, avchdLegacyData );
-
- if ( success && avchdLegacyData.mClipExtensionData.mPresent ) {
- success = ReadAVCHDLegacyPlaylistFile ( strRootPath, strClipName, avchdLegacyData );
- }
-
- return success;
-
-} // ReadAVCHDLegacyMetadata
-
-// =================================================================================================
-// AVCCAM_SetXMPStartTimecode
-// =============================
-
-static void AVCCAM_SetXMPStartTimecode ( SXMPMeta& xmpObj, const XMP_Uns8* avccamTimecode, XMP_Uns8 avchdFrameRate )
-{
- // Timecode in SMPTE 12M format, according to Panasonic's documentation
- if ( *reinterpret_cast<const XMP_Uns32*>( avccamTimecode ) == 0xFFFFFFFF ) {
- // 0xFFFFFFFF means timecode not specified
- return;
- }
-
- const XMP_Uns8 isColor = ( avccamTimecode[0] >> 7 ) & 0x01;
- const XMP_Uns8 isDropFrame = ( avccamTimecode[0] >> 6 ) & 0x01;
- const XMP_Uns8 frameTens = ( avccamTimecode[0] >> 4 ) & 0x03;
- const XMP_Uns8 frameUnits = avccamTimecode[0] & 0x0f;
- const XMP_Uns8 secondTens = ( avccamTimecode[1] >> 4 ) & 0x07;
- const XMP_Uns8 secondUnits = avccamTimecode[1] & 0x0f;
- const XMP_Uns8 minuteTens = ( avccamTimecode[2] >> 4 ) & 0x07;
- const XMP_Uns8 minuteUnits = avccamTimecode[2] & 0x0f;
- const XMP_Uns8 hourTens = ( avccamTimecode[3] >> 4 ) & 0x03;
- const XMP_Uns8 hourUnits = avccamTimecode[3] & 0x0f;
- char tcSeparator = ':';
- const char* dmTimeFormat = NULL;
- const char* dmTimeScale = NULL;
- const char* dmTimeSampleSize = NULL;
-
- switch ( avchdFrameRate ) {
- case 1 :
- // 23.976i
- dmTimeFormat = "23976Timecode";
- dmTimeScale = "24000";
- dmTimeSampleSize = "1001";
- break;
-
- case 2 :
- // 24p
- dmTimeFormat = "24Timecode";
- dmTimeScale = "24";
- dmTimeSampleSize = "1";
- break;
-
- case 3 :
- case 6 :
- // 50i or 25p
- dmTimeFormat = "25Timecode";
- dmTimeScale = "25";
- dmTimeSampleSize = "1";
- break;
-
- case 4 :
- case 7 :
- // 29.97p or 59.94i
- if ( isDropFrame ) {
- dmTimeFormat = "2997DropTimecode";
- tcSeparator = ';';
- } else {
- dmTimeFormat = "2997NonDropTimecode";
- }
-
- dmTimeScale = "30000";
- dmTimeSampleSize = "1001";
-
- break;
- }
-
- if ( dmTimeFormat != NULL ) {
- char timecodeBuff [12];
-
- sprintf ( timecodeBuff, "%d%d%c%d%d%c%d%d%c%d%d", hourTens, hourUnits, tcSeparator,
- minuteTens, minuteUnits, tcSeparator, secondTens, secondUnits, tcSeparator, frameTens, frameUnits);
-
- xmpObj.SetProperty( kXMP_NS_DM, "startTimeScale", dmTimeScale, kXMP_DeleteExisting );
- xmpObj.SetProperty( kXMP_NS_DM, "startTimeSampleSize", dmTimeSampleSize, kXMP_DeleteExisting );
- xmpObj.SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", timecodeBuff, 0 );
- xmpObj.SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", dmTimeFormat, 0 );
- }
-}
-
-// =================================================================================================
-// AVCHD_SetXMPMakeAndModel
-// =============================
-
-static bool AVCHD_SetXMPMakeAndModel ( SXMPMeta& xmpObj, const AVCHD_blkClipExtensionData& clipExtData )
-{
- if ( ! clipExtData.mPresent ) return false;
-
- XMP_StringPtr xmpValue = 0;
-
- // Set the Make. Use a hex string for unknown makes.
- {
- char hexMakeNumber [7];
-
- switch ( clipExtData.mClipInfoExt.mMakerID ) {
- case kMakerIDCanon : xmpValue = "Canon"; break;
- case kMakerIDPanasonic : xmpValue = "Panasonic"; break;
- case kMakerIDSony : xmpValue = "Sony"; break;
- default :
- std::sprintf ( hexMakeNumber, "0x%04x", clipExtData.mClipInfoExt.mMakerID );
- xmpValue = hexMakeNumber;
-
- break;
- }
-
- xmpObj.SetProperty ( kXMP_NS_TIFF, "Make", xmpValue, kXMP_DeleteExisting );
- }
-
- // Set the Model number. Use a hex string for unknown model numbers so they can still be distinguished.
- {
- char hexModelNumber [7];
-
- xmpValue = 0;
-
- switch ( clipExtData.mClipInfoExt.mMakerID ) {
- case kMakerIDCanon :
- switch ( clipExtData.mClipInfoExt.mMakerModelCode ) {
- case 0x1000 : xmpValue = "HR10"; break;
- case 0x2000 : xmpValue = "HG10"; break;
- case 0x2001 : xmpValue = "HG21"; break;
- case 0x3000 : xmpValue = "HF100"; break;
- case 0x3003 : xmpValue = "HF S10"; break;
- default : break;
- }
- break;
-
- case kMakerIDPanasonic :
- switch ( clipExtData.mClipInfoExt.mMakerModelCode ) {
- case 0x0202 : xmpValue = "HD-writer"; break;
- case 0x0400 : xmpValue = "AG-HSC1U"; break;
- case 0x0401 : xmpValue = "AG-HMC70"; break;
- case 0x0410 : xmpValue = "AG-HMC150"; break;
- case 0x0411 : xmpValue = "AG-HMC40"; break;
- case 0x0412 : xmpValue = "AG-HMC80"; break;
- case 0x0413 : xmpValue = "AG-3DA1"; break;
- case 0x0414 : xmpValue = "AG-AF100"; break;
- case 0x0450 : xmpValue = "AG-HMR10"; break;
- case 0x0451 : xmpValue = "AJ-YCX250"; break;
- case 0x0452 : xmpValue = "AG-MDR15"; break;
- case 0x0490 : xmpValue = "AVCCAM Restorer"; break;
- case 0x0491 : xmpValue = "AVCCAM Viewer"; break;
- case 0x0492 : xmpValue = "AVCCAM Viewer for Mac"; break;
- default : break;
- }
-
- break;
-
- default : break;
- }
-
- if ( ( xmpValue == 0 ) && ( clipExtData.mClipInfoExt.mMakerID != kMakerIDSony ) ) {
- // Panasonic has said that if we don't have a string for the model number, they'd like to see the code
- // anyway. We'll do the same for every manufacturer except Sony, who have said that they use
- // the same model number for multiple cameras.
- std::sprintf ( hexModelNumber, "0x%04x", clipExtData.mClipInfoExt.mMakerModelCode );
- xmpValue = hexModelNumber;
- }
-
- if ( xmpValue != 0 ) xmpObj.SetProperty ( kXMP_NS_TIFF, "Model", xmpValue, kXMP_DeleteExisting );
- }
-
- return true;
-}
-
-// =================================================================================================
-// AVCHD_StringFieldToXMP
-// =============================
-
-static std::string AVCHD_StringFieldToXMP ( XMP_Uns8 avchdLength,
- XMP_Uns8 avchdCharacterSet,
- const XMP_Uns8* avchdField,
- XMP_Uns8 avchdFieldSize )
-{
- std::string xmpString;
-
- if ( avchdCharacterSet == 0x02 ) {
- // UTF-16, Big Endian
- UTF8Unit utf8Name [512];
- const XMP_Uns8 avchdMaxChars = ( avchdFieldSize / 2);
- size_t utf16Read;
- size_t utf8Written;
-
- // The spec doesn't say whether AVCHD length fields count bytes or characters, so we'll
- // clamp to the max number of UTF-16 characters just in case.
- const int stringLength = ( avchdLength > avchdMaxChars ) ? avchdMaxChars : avchdLength;
-
- UTF16BE_to_UTF8 ( reinterpret_cast<const UTF16Unit*> ( avchdField ), stringLength,
- utf8Name, 512, &utf16Read, &utf8Written );
- xmpString.assign ( reinterpret_cast<const char*> ( utf8Name ), utf8Written );
- } else {
- // AVCHD supports many character encodings, but UTF-8 (0x01) and ASCII (0x90) are the only ones I've
- // seen in the wild at this point. We'll treat the other character sets as UTF-8 on the assumption that
- // at least a few characters will come across, and something is better than nothing.
- const int stringLength = ( avchdLength > avchdFieldSize ) ? avchdFieldSize : avchdLength;
-
- xmpString.assign ( reinterpret_cast<const char*> ( avchdField ), stringLength );
- }
-
- return xmpString;
-}
-
-// =================================================================================================
-// AVCHD_SetXMPShotName
-// =============================
-
-static void AVCHD_SetXMPShotName ( SXMPMeta& xmpObj, const AVCHD_blkPlayListMarkExt& markExt, const std::string& strClipName )
-{
- if ( markExt.mPresent ) {
- const std::string shotName = AVCHD_StringFieldToXMP ( markExt.mMarkNameLength, markExt.mMarkCharacterSet, markExt.mMarkName, 24 );
-
- if ( ! shotName.empty() ) xmpObj.SetProperty ( kXMP_NS_DC, "shotName", shotName.c_str(), kXMP_DeleteExisting );
- }
-}
-
-// =================================================================================================
-// BytesToHex
-// =============================
-
-#define kHexDigits "0123456789ABCDEF"
-
-static std::string BytesToHex ( const XMP_Uns8* inClipIDBytes, int inNumBytes )
-{
- const int numChars = ( inNumBytes * 2 );
- std::string hexStr;
-
- hexStr.reserve(numChars);
-
- for ( int i = 0; i < inNumBytes; ++i ) {
- const XMP_Uns8 byte = inClipIDBytes[i];
- hexStr.push_back ( kHexDigits [byte >> 4] );
- hexStr.push_back ( kHexDigits [byte & 0xF] );
- }
-
- return hexStr;
-}
-
-// =================================================================================================
-// AVCHD_DateFieldToXMP (AVCHD Format Book 2, section 4.2.2.2)
-// =============================
-
-static std::string AVCHD_DateFieldToXMP ( XMP_Uns8 avchdTimeZone, const XMP_Uns8* avchdDateTime )
-{
- const XMP_Uns8 daylightSavingsTime = ( avchdTimeZone >> 6 ) & 0x01;
- const XMP_Uns8 timezoneSign = ( avchdTimeZone >> 5 ) & 0x01;
- const XMP_Uns8 timezoneValue = ( avchdTimeZone >> 1 ) & 0x0F;
- const XMP_Uns8 halfHourFlag = avchdTimeZone & 0x01;
- int utcOffsetHours = 0;
- unsigned int utcOffsetMinutes = 0;
-
- // It's not entirely clear how to interpret the daylightSavingsTime flag from the documentation -- my best
- // guess is that it should only be used if trying to display local time, not the UTC-relative time that
- // XMP specifies.
- if ( timezoneValue != 0xF ) {
- utcOffsetHours = timezoneSign ? -timezoneValue : timezoneValue;
- utcOffsetMinutes = 30 * halfHourFlag;
- }
-
- char dateBuff [26];
-
- sprintf ( dateBuff,
- "%01d%01d%01d%01d-%01d%01d-%01d%01dT%01d%01d:%01d%01d:%01d%01d%+02d:%02d",
- (avchdDateTime[0] >> 4), (avchdDateTime[0] & 0x0F),
- (avchdDateTime[1] >> 4), (avchdDateTime[1] & 0x0F),
- (avchdDateTime[2] >> 4), (avchdDateTime[2] & 0x0F),
- (avchdDateTime[3] >> 4), (avchdDateTime[3] & 0x0F),
- (avchdDateTime[4] >> 4), (avchdDateTime[4] & 0x0F),
- (avchdDateTime[5] >> 4), (avchdDateTime[5] & 0x0F),
- (avchdDateTime[6] >> 4), (avchdDateTime[6] & 0x0F),
- utcOffsetHours, utcOffsetMinutes );
-
- return std::string(dateBuff);
-}
-
-// =================================================================================================
-// AVCHD_MetaHandlerCTor
-// =====================
-
-XMPFileHandler * AVCHD_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new AVCHD_MetaHandler ( parent );
-
-} // AVCHD_MetaHandlerCTor
-
-// =================================================================================================
-// AVCHD_MetaHandler::AVCHD_MetaHandler
-// ====================================
-
-AVCHD_MetaHandler::AVCHD_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kAVCHD_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- // Extract the root path and clip name.
-
- XMP_Assert ( this->parent->tempPtr != 0 );
-
- this->rootPath.assign ( (char*) this->parent->tempPtr );
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- SplitLeafName ( &this->rootPath, &this->clipName );
-
-} // AVCHD_MetaHandler::AVCHD_MetaHandler
-
-// =================================================================================================
-// AVCHD_MetaHandler::~AVCHD_MetaHandler
-// =====================================
-
-AVCHD_MetaHandler::~AVCHD_MetaHandler()
-{
-
- if ( this->parent->tempPtr != 0 ) {
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
- }
-
-} // AVCHD_MetaHandler::~AVCHD_MetaHandler
-
-// =================================================================================================
-// AVCHD_MetaHandler::MakeClipInfoPath
-// ===================================
-
-bool AVCHD_MetaHandler::MakeClipInfoPath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ ) const
-{
- return MakeLeafPath ( path, this->rootPath.c_str(), "CLIPINF", this->clipName.c_str(), suffix, checkFile );
-} // AVCHD_MetaHandler::MakeClipInfoPath
-
-// =================================================================================================
-// AVCHD_MetaHandler::MakeClipStreamPath
-// =====================================
-
-bool AVCHD_MetaHandler::MakeClipStreamPath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ ) const
-{
- return MakeLeafPath ( path, this->rootPath.c_str(), "STREAM", this->clipName.c_str(), suffix, checkFile );
-} // AVCHD_MetaHandler::MakeClipStreamPath
-
-// =================================================================================================
-// AVCHD_MetaHandler::MakePlaylistPath
-// =====================================
-
-bool AVCHD_MetaHandler::MakePlaylistPath ( std::string * path, XMP_StringPtr suffix, bool checkFile /* = false */ ) const
-{
- return MakeLeafPath ( path, this->rootPath.c_str(), "PLAYLIST", this->clipName.c_str(), suffix, checkFile );
-} // AVCHD_MetaHandler::MakePlaylistPath
-
-// =================================================================================================
-// AVCHD_MetaHandler::MakeLegacyDigest
-// ===================================
-
-void AVCHD_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
-{
- std::string strClipPath;
- std::string strPlaylistPath;
- std::vector<XMP_Uns8> legacyBuff;
-
- bool ok = this->MakeClipInfoPath ( &strClipPath, ".clpi", true /* checkFile */ );
- if ( ! ok ) return;
-
- ok = this->MakePlaylistPath ( &strPlaylistPath, ".mpls", true /* checkFile */ );
- if ( ! ok ) return;
-
- try {
- {
- AutoFile cpiFile;
- cpiFile.fileRef = LFA_Open ( strClipPath.c_str(), 'r' );
- if ( cpiFile.fileRef == 0 ) return; // The open failed.
-
- // Read at most the first 2k of data from the cpi file to use in the digest
- // (every CPI file I've seen is less than 1k).
- const XMP_Int64 cpiLen = LFA_Measure ( cpiFile.fileRef );
- const XMP_Int64 buffLen = (cpiLen <= 2048) ? cpiLen : 2048;
-
- legacyBuff.resize ( (unsigned int) buffLen );
- LFA_Read ( cpiFile.fileRef, &(legacyBuff[0]), static_cast<XMP_Int32> ( buffLen ) );
- }
-
- {
- AutoFile mplFile;
- mplFile.fileRef = LFA_Open ( strPlaylistPath.c_str(), 'r' );
- if ( mplFile.fileRef == 0 ) return; // The open failed.
-
- // Read at most the first 2k of data from the cpi file to use in the digest
- // (every playlist file I've seen is less than 1k).
- const XMP_Int64 mplLen = LFA_Measure ( mplFile.fileRef );
- const XMP_Int64 buffLen = (mplLen <= 2048) ? mplLen : 2048;
- const XMP_Int64 clipBuffLen = legacyBuff.size();
-
- legacyBuff.resize ( (unsigned int) (clipBuffLen + buffLen) );
- LFA_Read ( mplFile.fileRef, &( legacyBuff [(unsigned int)clipBuffLen] ), (XMP_Int32)buffLen );
- }
- } catch (...) {
- return;
- }
-
- MD5_CTX context;
- unsigned char digestBin [16];
-
- MD5Init ( &context );
- MD5Update ( &context, (XMP_Uns8*)&(legacyBuff[0]), (unsigned int) legacyBuff.size() );
- MD5Final ( digestBin, &context );
-
- *digestStr = BytesToHex ( digestBin, 16 );
-} // AVCHD_MetaHandler::MakeLegacyDigest
-
-// =================================================================================================
-// AVCHD_MetaHandler::CacheFileData
-// ================================
-
-void AVCHD_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- // See if the clip's .XMP file exists.
-
- std::string xmpPath;
- bool found = this->MakeClipStreamPath ( &xmpPath, ".xmp", true /* checkFile */ );
- if ( ! found ) return;
-
- // Read the entire .XMP file.
-
- char openMode = 'r';
- if ( this->parent->openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- LFA_FileRef xmpFile = LFA_Open ( xmpPath.c_str(), openMode );
- if ( xmpFile == 0 ) return; // The open failed.
-
- XMP_Int64 xmpLen = LFA_Measure ( xmpFile );
- if ( xmpLen > 100*1024*1024 ) {
- XMP_Throw ( "AVCHD XMP is outrageously large", kXMPErr_InternalFailure ); // Sanity check.
- }
-
- this->xmpPacket.erase();
- this->xmpPacket.reserve ( (size_t ) xmpLen );
- this->xmpPacket.append ( (size_t ) xmpLen, ' ' );
-
- XMP_Int32 ioCount = LFA_Read ( xmpFile, (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen, kLFA_RequireAll );
- XMP_Assert ( ioCount == xmpLen );
-
- this->packetInfo.offset = 0;
- this->packetInfo.length = (XMP_Int32)xmpLen;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- XMP_Assert ( this->parent->fileRef == 0 );
- if ( openMode == 'r' ) {
- LFA_Close ( xmpFile );
- } else {
- this->parent->fileRef = xmpFile;
- }
-
- this->containsXMP = true;
-
-} // AVCHD_MetaHandler::CacheFileData
-
-// =================================================================================================
-// AVCHD_MetaHandler::ProcessXMP
-// =============================
-
-void AVCHD_MetaHandler::ProcessXMP()
-{
- 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() );
- }
-
- // read clip info
- AVCHD_LegacyMetadata avchdLegacyData;
- std::string strPath;
-
- bool ok = this->MakeClipInfoPath ( &strPath, ".clpi", true /* checkFile */ );
- if ( ok ) ReadAVCHDLegacyMetadata ( strPath, this->rootPath, this->clipName, avchdLegacyData );
- if ( ! ok ) return;
-
- const AVCHD_blkPlayListMarkExt& markExt = avchdLegacyData.mPlaylistExtensionData.mPlaylistMarkExt;
- XMP_Uns8 pulldownFlag = 0;
-
- if ( markExt.mPresent ) {
- const std::string dateString = AVCHD_DateFieldToXMP ( markExt.mBlkTimezone, markExt.mRecordDataAndTime );
-
- if ( ! dateString.empty() ) this->xmpObj.SetProperty ( kXMP_NS_DM, "shotDate", dateString.c_str(), kXMP_DeleteExisting );
- AVCHD_SetXMPShotName ( this->xmpObj, markExt, this->clipName );
- AVCCAM_SetXMPStartTimecode ( this->xmpObj, markExt.mBlkTimecode, avchdLegacyData.mProgramInfo.mVideoStream.mFrameRate );
- pulldownFlag = (markExt.mFlags >> 1) & 0x03; // bits 1 and 2
- }
-
- // Video Stream. AVCHD Format v. 1.01 p. 78
-
- const bool has2_2pulldown = (pulldownFlag == 0x01);
- const bool has3_2pulldown = (pulldownFlag == 0x10);
- XMP_StringPtr xmpValue = 0;
-
- if ( avchdLegacyData.mProgramInfo.mVideoStream.mPresent ) {
-
- // XMP videoFrameSize.
- xmpValue = 0;
- int frameIndex = -1;
- bool isProgressiveHD = false;
- const char* frameWidth[4] = { "720", "720", "1280", "1920" };
- const char* frameHeight[4] = { "480", "576", "720", "1080" };
-
- switch ( avchdLegacyData.mProgramInfo.mVideoStream.mVideoFormat ) {
- case 1 : frameIndex = 0; break; // 480i
- case 2 : frameIndex = 1; break; // 576i
- case 3 : frameIndex = 0; break; // 480p
- case 4 : frameIndex = 3; break; // 1080i
- case 5 : frameIndex = 2; isProgressiveHD = true; break; // 720p
- case 6 : frameIndex = 3; isProgressiveHD = true; break; // 1080p
- default: break;
- }
-
- if ( frameIndex != -1 ) {
- xmpValue = frameWidth[frameIndex];
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "w", xmpValue, 0 );
- xmpValue = frameHeight[frameIndex];
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "h", xmpValue, 0 );
- xmpValue = "pixels";
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "unit", xmpValue, 0 );
- }
-
- // XMP videoFrameRate. The logic below seems pretty tortured, but matches "Table 4-4 pulldown" on page 31 of Book 2 of the AVCHD
- // spec, if you interepret "frame_mbs_only_flag" as "isProgressiveHD", "frame-rate [Hz]" as the frame rate encoded in
- // mVideoStream.mFrameRate, and "Video Scan Type" as the desired xmp output value. The algorithm produces correct results for
- // all the AVCHD media I've tested.
- xmpValue = 0;
- if ( isProgressiveHD ) {
-
- switch ( avchdLegacyData.mProgramInfo.mVideoStream.mFrameRate ) {
- case 1 : xmpValue = "23.98p"; break; // "23.976"
- case 2 : xmpValue = "24p"; break; // "24"
- case 3 : xmpValue = "25p"; break; // "25"
- case 4 : xmpValue = has2_2pulldown ? "29.97p" : "59.94p"; break; // "29.97"
- case 6 : xmpValue = has2_2pulldown ? "25p" : "50p"; break; // "50"
- case 7 : // "59.94"
- if ( has2_2pulldown )
- xmpValue = "29.97p";
- else
- xmpValue = has3_2pulldown ? "23.98p" : "59.94p";
-
- break;
- default: break;
- }
-
- } else {
-
- switch ( avchdLegacyData.mProgramInfo.mVideoStream.mFrameRate ) {
- case 3 : xmpValue = has2_2pulldown ? "25p" : "50i"; break; // "25" (but 1080p25 is reported as 1080i25 with 2:2 pulldown...)
- case 4 : // "29.97"
- if ( has2_2pulldown )
- xmpValue = "29.97p";
- else
- xmpValue = has3_2pulldown ? "23.98p" : "59.94i";
-
- break;
- default: break;
- }
-
- }
-
- if ( xmpValue != 0 ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "videoFrameRate", xmpValue, kXMP_DeleteExisting );
- }
-
- this->containsXMP = true;
-
- }
-
- // Audio Stream.
- if ( avchdLegacyData.mProgramInfo.mAudioStream.mPresent ) {
-
- xmpValue = 0;
- switch ( avchdLegacyData.mProgramInfo.mAudioStream.mAudioPresentationType ) {
- case 1 : xmpValue = "Mono"; break;
- case 3 : xmpValue = "Stereo"; break;
- default : break;
- }
- if ( xmpValue != 0 ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "audioChannelType", xmpValue, kXMP_DeleteExisting );
- }
-
- xmpValue = 0;
- switch ( avchdLegacyData.mProgramInfo.mAudioStream.mSamplingFrequency ) {
- case 1 : xmpValue = "48000"; break;
- case 4 : xmpValue = "96000"; break;
- case 5 : xmpValue = "192000"; break;
- default : break;
- }
- if ( xmpValue != 0 ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "audioSampleRate", xmpValue, kXMP_DeleteExisting );
- }
-
- this->containsXMP = true;
- }
-
- // Proprietary vendor extensions
- if ( AVCHD_SetXMPMakeAndModel ( this->xmpObj, avchdLegacyData.mClipExtensionData ) ) this->containsXMP = true;
-
- this->xmpObj.SetProperty ( kXMP_NS_DM, "title", this->clipName.c_str(), kXMP_DeleteExisting );
- this->containsXMP = true;
-
- if ( avchdLegacyData.mClipExtensionData.mMakersPrivateData.mPresent &&
- ( avchdLegacyData.mClipExtensionData.mClipInfoExt.mMakerID == kMakerIDPanasonic ) ) {
-
- const AVCHD_blkPanasonicPrivateData& panasonicClipData = avchdLegacyData.mClipExtensionData.mMakersPrivateData.mPanasonicPrivateData;
-
- if ( panasonicClipData.mProClipIDBlock.mPresent ) {
- const std::string globalClipIDString = BytesToHex ( panasonicClipData.mProClipIDBlock.mGlobalClipID, 32 );
-
- this->xmpObj.SetProperty ( kXMP_NS_DC, "identifier", globalClipIDString.c_str(), kXMP_DeleteExisting );
- }
-
- const AVCHD_blkPanasonicPrivateData& panasonicPlaylistData =
- avchdLegacyData.mPlaylistExtensionData.mMakersPrivateData.mPanasonicPrivateData;
-
- if ( panasonicPlaylistData.mProPlaylistInfoBlock.mPlayListMark.mPresent ) {
- const AVCCAM_blkProPlayListMark& playlistMark = panasonicPlaylistData.mProPlaylistInfoBlock.mPlayListMark;
-
- if ( playlistMark.mShotMark.mPresent ) {
- // Unlike P2, where "shotmark" is a boolean, Panasonic treats their AVCCAM shotmark as a bit field with
- // 8 user-definable bits. For now we're going to treat any bit being set as xmpDM::good == true, and all
- // bits being clear as xmpDM::good == false.
- const bool isGood = ( playlistMark.mShotMark.mShotMark != 0 );
-
- xmpObj.SetProperty_Bool ( kXMP_NS_DM, "good", isGood, kXMP_DeleteExisting );
- }
-
- if ( playlistMark.mAccess.mPresent && ( playlistMark.mAccess.mCreatorLength > 0 ) ) {
- const std::string creatorString = AVCHD_StringFieldToXMP (
- playlistMark.mAccess.mCreatorLength, playlistMark.mAccess.mCreatorCharacterSet, playlistMark.mAccess.mCreator, 32 ) ;
-
- if ( ! creatorString.empty() ) {
- xmpObj.DeleteProperty ( kXMP_NS_DC, "creator" );
- xmpObj.AppendArrayItem ( kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, creatorString.c_str() );
- }
- }
-
- if ( playlistMark.mDevice.mPresent && ( playlistMark.mDevice.mSerialNoLength > 0 ) ) {
- const std::string serialNoString = AVCHD_StringFieldToXMP (
- playlistMark.mDevice.mSerialNoLength, playlistMark.mDevice.mSerialNoCharacterCode, playlistMark.mDevice.mSerialNo, 24 ) ;
-
- if ( ! serialNoString.empty() ) xmpObj.SetProperty ( kXMP_NS_EXIF_Aux, "SerialNumber", serialNoString.c_str(), kXMP_DeleteExisting );
- }
-
- if ( playlistMark.mLocation.mPresent && ( playlistMark.mLocation.mPlaceNameLength > 0 ) ) {
- const std::string placeNameString = AVCHD_StringFieldToXMP (
- playlistMark.mLocation.mPlaceNameLength, playlistMark.mLocation.mPlaceNameCharacterSet, playlistMark.mLocation.mPlaceName, 64 ) ;
-
- if ( ! placeNameString.empty() ) xmpObj.SetProperty ( kXMP_NS_DM, "shotLocation", placeNameString.c_str(), kXMP_DeleteExisting );
- }
- }
- }
-
-} // AVCHD_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// AVCHD_MetaHandler::UpdateFile
-// =============================
-//
-// Note that UpdateFile is only called from XMPFiles::CloseFile, so it is OK to close the file here.
-
-void AVCHD_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- this->needsUpdate = false; // Make sure only called once.
-
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "AVCHD", newDigest.c_str(), kXMP_DeleteExisting );
-
- LFA_FileRef oldFile = this->parent->fileRef;
-
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() );
-
- if ( oldFile == 0 ) {
-
- // The XMP does not exist yet.
-
- std::string xmpPath;
- this->MakeClipStreamPath ( &xmpPath, ".xmp" );
-
- LFA_FileRef xmpFile = LFA_Create ( xmpPath.c_str() );
- if ( xmpFile == 0 ) XMP_Throw ( "Failure creating AVCHD XMP file", kXMPErr_ExternalFailure );
- LFA_Write ( xmpFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( xmpFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XMP file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- std::string xmpPath, tempPath;
-
- bool found = this->MakeClipStreamPath ( &xmpPath, ".xmp", true /* checkFile */ );
- if ( ! found ) XMP_Throw ( "AVCHD_MetaHandler::UpdateFile - XMP is supposed to exist", kXMPErr_InternalFailure );
-
- CreateTempFile ( xmpPath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( xmpPath.c_str() );
- LFA_Rename ( tempPath.c_str(), xmpPath.c_str() );
-
- }
-
- this->parent->fileRef = 0;
-
-} // AVCHD_MetaHandler::UpdateFile
-
-// =================================================================================================
-// AVCHD_MetaHandler::WriteFile
-// ============================
-
-void AVCHD_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- // ! WriteFile is not supposed to be called for handlers that own the file.
- XMP_Throw ( "AVCHD_MetaHandler::WriteFile should not be called", kXMPErr_InternalFailure );
-
-} // AVCHD_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/AVCHD_Handler.hpp b/source/XMPFiles/FileHandlers/AVCHD_Handler.hpp
deleted file mode 100644
index 4123089..0000000
--- a/source/XMPFiles/FileHandlers/AVCHD_Handler.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef __AVCHD_Handler_hpp__
-#define __AVCHD_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#include "ExpatAdapter.hpp"
-
-// =================================================================================================
-/// \file AVCHD_Handler.hpp
-/// \brief Folder format handler for AVCHD.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * AVCHD_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool AVCHD_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kAVCHD_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_FolderBasedFormat);
-
-class AVCHD_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions() // *** These should be standard for standalone XMP files.
- { return (kXMP_UseCompactFormat | kXMP_OmitPacketWrapper); };
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- AVCHD_MetaHandler ( XMPFiles * _parent );
- virtual ~AVCHD_MetaHandler();
-
-private:
-
- AVCHD_MetaHandler() {}; // Hidden on purpose.
-
- bool MakeClipInfoPath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false ) const;
- bool MakeClipStreamPath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false ) const;
- bool MakePlaylistPath ( std::string * path, XMP_StringPtr suffix, bool checkFile = false ) const;
-
- void MakeLegacyDigest ( std::string * digestStr );
-
- std::string rootPath, clipName;
-
-}; // AVCHD_MetaHandler
-
-// =================================================================================================
-
-#endif /* __AVCHD_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Basic_Handler.cpp b/source/XMPFiles/FileHandlers/Basic_Handler.cpp
deleted file mode 100644
index 3efd739..0000000
--- a/source/XMPFiles/FileHandlers/Basic_Handler.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "Basic_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file Basic_Handler.cpp
-/// \brief Base class for basic handlers that only process in-place XMP.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// Basic_MetaHandler::~Basic_MetaHandler
-// =====================================
-
-Basic_MetaHandler::~Basic_MetaHandler()
-{
- // ! Inherit the base cleanup.
-
-} // Basic_MetaHandler::~Basic_MetaHandler
-
-// =================================================================================================
-// Basic_MetaHandler::UpdateFile
-// =============================
-
-// ! This must be called from the destructor for all derived classes. It can't be called from the
-// ! Basic_MetaHandler destructor, by then calls to the virtual functions would not go to the
-// ! actual implementations for the derived class.
-
-void Basic_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- IgnoreParam ( doSafeUpdate );
- XMP_Assert ( ! doSafeUpdate ); // Not supported at this level.
- if ( ! this->needsUpdate ) return;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
- std::string & xmpPacket = this->xmpPacket;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- this->CaptureFileEnding(); // ! Do this first, before any location info changes.
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
- }
-
- this->NoteXMPRemoval();
- this->ShuffleTrailingContent();
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
- }
-
- XMP_Int64 tempLength = this->xmpFileOffset - this->xmpPrefixSize + this->trailingContentSize;
- LFA_Truncate ( fileRef, tempLength );
- LFA_Flush ( fileRef );
-
- packetInfo.offset = tempLength + this->xmpPrefixSize;
- this->NoteXMPInsertion();
-
- LFA_Seek ( fileRef, 0, SEEK_END );
- this->WriteXMPPrefix();
- LFA_Write ( fileRef, xmpPacket.c_str(), (XMP_StringLen)xmpPacket.size() );
- this->WriteXMPSuffix();
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
- }
-
- this->RestoreFileEnding();
- LFA_Flush ( fileRef );
-
- this->xmpFileOffset = packetInfo.offset;
- this->xmpFileSize = packetInfo.length;
- this->needsUpdate = false;
-
-} // Basic_MetaHandler::UpdateFile
-
-// =================================================================================================
-// Basic_MetaHandler::WriteFile
-// ============================
-
-// *** What about computing the new file length and pre-allocating the file?
-
-void Basic_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- IgnoreParam ( sourcePath );
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_FileRef destRef = this->parent->fileRef;
-
- // Capture the "back" of the source file.
-
- this->parent->fileRef = sourceRef;
- this->CaptureFileEnding();
- this->parent->fileRef = destRef;
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
- }
-
- // Seek to the beginning of the source and destination files, truncate the destination.
-
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Seek ( destRef, 0, SEEK_SET );
- LFA_Truncate ( destRef, 0 );
-
- // Copy the front of the source file to the destination. Note the XMP (pseudo) removal and
- // insertion. This mainly updates info about the new XMP length.
-
- XMP_Int64 xmpSectionOffset = this->xmpFileOffset - this->xmpPrefixSize;
- XMP_Int32 oldSectionLength = this->xmpPrefixSize + this->xmpFileSize + this->xmpSuffixSize;
-
- LFA_Copy ( sourceRef, destRef, xmpSectionOffset, abortProc, abortArg );
- this->NoteXMPRemoval();
- packetInfo.offset = this->xmpFileOffset; // ! The packet offset does not change.
- this->NoteXMPInsertion();
- LFA_Seek ( destRef, 0, SEEK_END );
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
- }
-
- // Write the new XMP section to the destination.
-
- this->WriteXMPPrefix();
- LFA_Write ( destRef, this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->WriteXMPSuffix();
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
- }
-
- // Copy the trailing file content from the source and write the "back" of the file.
-
- XMP_Int64 remainderOffset = xmpSectionOffset + oldSectionLength;
-
- LFA_Seek ( sourceRef, remainderOffset, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, this->trailingContentSize, abortProc, abortArg );
- this->RestoreFileEnding();
-
- // Done.
-
- LFA_Flush ( destRef );
-
- this->xmpFileOffset = packetInfo.offset;
- this->xmpFileSize = packetInfo.length;
- this->needsUpdate = false;
-
-} // Basic_MetaHandler::WriteFile
-
-// =================================================================================================
-// ShuffleTrailingContent
-// ======================
-//
-// Shuffle the trailing content portion of a file forward. This does not include the final "back"
-// portion of the file, just the arbitrary length content between the XMP section and the back.
-// Don't use LFA_Copy, that assumes separate files and hence separate I/O positions.
-
-// ! The XMP packet location and prefix/suffix sizes must still reflect the XMP section that is in
-// ! the process of being removed.
-
-void Basic_MetaHandler::ShuffleTrailingContent()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
-
- XMP_Int64 readOffset = this->packetInfo.offset + xmpSuffixSize;
- XMP_Int64 writeOffset = this->packetInfo.offset - xmpPrefixSize;
-
- XMP_Int64 remainingLength = this->trailingContentSize;
-
- enum { kBufferSize = 64*1024 };
- char buffer [kBufferSize];
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- while ( remainingLength > 0 ) {
-
- XMP_Int32 ioCount = kBufferSize;
- if ( remainingLength < kBufferSize ) ioCount = (XMP_Int32)remainingLength;
-
- LFA_Seek ( fileRef, readOffset, SEEK_SET );
- LFA_Read ( fileRef, buffer, ioCount, kLFA_RequireAll );
- LFA_Seek ( fileRef, writeOffset, SEEK_SET );
- LFA_Write ( fileRef, buffer, ioCount );
-
- readOffset += ioCount;
- writeOffset += ioCount;
- remainingLength -= ioCount;
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Basic_MetaHandler::ShuffleTrailingContent - User abort", kXMPErr_UserAbort );
- }
-
- }
-
- LFA_Flush ( fileRef );
-
-} // ShuffleTrailingContent
-
-// =================================================================================================
-// Dummies needed for VS.Net
-// =========================
-
-void Basic_MetaHandler::WriteXMPPrefix()
-{
- XMP_Throw ( "Basic_MetaHandler::WriteXMPPrefix - Needs specific override", kXMPErr_InternalFailure );
-}
-
-void Basic_MetaHandler::WriteXMPSuffix()
-{
- XMP_Throw ( "Basic_MetaHandler::WriteXMPSuffix - Needs specific override", kXMPErr_InternalFailure );
-}
-
-void Basic_MetaHandler::NoteXMPRemoval()
-{
- XMP_Throw ( "Basic_MetaHandler::NoteXMPRemoval - Needs specific override", kXMPErr_InternalFailure );
-}
-
-void Basic_MetaHandler::NoteXMPInsertion()
-{
- XMP_Throw ( "Basic_MetaHandler::NoteXMPInsertion - Needs specific override", kXMPErr_InternalFailure );
-}
-
-void Basic_MetaHandler::CaptureFileEnding()
-{
- XMP_Throw ( "Basic_MetaHandler::CaptureFileEnding - Needs specific override", kXMPErr_InternalFailure );
-}
-
-void Basic_MetaHandler::RestoreFileEnding()
-{
- XMP_Throw ( "Basic_MetaHandler::RestoreFileEnding - Needs specific override", kXMPErr_InternalFailure );
-}
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Basic_Handler.hpp b/source/XMPFiles/FileHandlers/Basic_Handler.hpp
deleted file mode 100644
index 17b9775..0000000
--- a/source/XMPFiles/FileHandlers/Basic_Handler.hpp
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef __Basic_Handler_hpp__
-#define __Basic_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "XMPFiles_Impl.hpp"
-
-// =================================================================================================
-/// \file Basic_Handler.hpp
-///
-/// \brief Base class for handlers that support a simple file model allowing insertion and expansion
-/// of XMP, but probably not reconciliation with other forms of metadata. Reconciliation would have
-/// to be done within the I/O model presented here.
-///
-/// \note Any specific derived handler might not be able to do insertion, but all must support
-/// expansion. If a handler can't do either it should be derived from Trivial_Handler. Common code
-/// must check the actual canInject flag where appropriate.
-///
-/// The model for a basic handler divides the file into 6 portions:
-///
-/// \li The front of the file. This portion can be arbitrarily large. Files over 4GB are supported.
-/// Adding or expanding the XMP must not require expanding this portion of the file. The XMP offset
-/// or length might be written into reserved space in this section though.
-///
-/// \li A prefix for the XMP section. The prefix and suffix for the XMP "section" are the format
-/// specific portions that surround the raw XMP packet. They must be generated on the fly, even when
-/// updating existing XMP with or without expansion. Their length must not depend on the XMP packet.
-///
-/// \li The XMP packet, as created by SXMPMeta::SerializeToBuffer. The size must be less than 2GB.
-///
-/// \li A suffix for the XMP section.
-///
-/// \li Trailing file content. This portion can be arbitarily large. It must be possible to remove
-/// the XMP, move this portion of the file forward, then reinsert the XMP after this portion. This
-/// is actually how the XMP is expanded. There must not be any embedded file offsets in this part,
-/// this content must not change if the XMP changes size.
-///
-/// \li The back of the file. This portion must have modest size, and/or be generated on the fly.
-/// When inserting XMP, part of this may be buffered in RAM (hence the modest size requirement), the
-/// XMP section is written, then this portion is rewritten. There must not be any embedded file
-/// offsets in this part, this content must not change if the XMP changes size.
-///
-/// \note There is no general promise here about crash-safe I/O. An update to an existing file might
-/// have invalid partial state, for example while moving the trailing content portion forward if the
-/// XMP increases in size or even rewriting existing XMP in-place. Crash-safe updates are managed at
-/// a higher level of XMPFiles, using a temporary file and final swap of file content.
-///
-// =================================================================================================
-
-static const XMP_OptionBits kBasic_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate);
-
-class Basic_MetaHandler : public XMPFileHandler
-{
-public:
-
- Basic_MetaHandler() :
- xmpFileOffset(0), xmpFileSize(0), xmpPrefixSize(0), xmpSuffixSize(0), trailingContentSize(0) {};
- ~Basic_MetaHandler();
-
- virtual void CacheFileData() = 0; // Sets offset for insertion if no XMP yet.
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
-protected:
-
- virtual void WriteXMPPrefix() = 0; // ! Must have override in actual handlers!
- virtual void WriteXMPSuffix() = 0; // ! Must have override in actual handlers!
-
- virtual void NoteXMPRemoval() = 0; // ! Must have override in actual handlers!
- virtual void NoteXMPInsertion() = 0; // ! Must have override in actual handlers!
-
- virtual void CaptureFileEnding() = 0; // ! Must have override in actual handlers!
- virtual void RestoreFileEnding() = 0; // ! Must have override in actual handlers!
-
- void ShuffleTrailingContent(); // Move the trailing content portion forward. Excludes "back" of the file.
-
- XMP_Uns64 xmpFileOffset; // The offset of the XMP in the file.
- XMP_Uns32 xmpFileSize; // The size of the XMP in the file.
- // ! The packetInfo offset and length are updated by PutXMP, before the file is updated!
-
- XMP_Uns32 xmpPrefixSize; // The size of the existing header for the XMP section.
- XMP_Uns32 xmpSuffixSize; // The size of the existing trailer for the XMP section.
-
- XMP_Uns64 trailingContentSize; // The size of the existing trailing content. Excludes "back" of the file.
-
-}; // Basic_MetaHandler
-
-// =================================================================================================
-
-#endif /* __Basic_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/FLV_Handler.cpp b/source/XMPFiles/FileHandlers/FLV_Handler.cpp
deleted file mode 100644
index f9624ed..0000000
--- a/source/XMPFiles/FileHandlers/FLV_Handler.cpp
+++ /dev/null
@@ -1,751 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "FLV_Handler.hpp"
-
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file FLV_Handler.cpp
-/// \brief File format handler for FLV.
-///
-/// FLV is a fairly simple format, with a strong orientation to streaming use. It consists of a
-/// small file header then a sequence of tags that can contain audio data, video data, or
-/// ActionScript data. All integers in FLV are big endian.
-///
-/// For FLV version 1, the file header contains:
-///
-/// UI24 signature - the characters "FLV"
-/// UI8 version - 1
-/// UI8 flags - 0x01 = has video tags, 0x04 = has audio tags
-/// UI32 length in bytes of file header
-///
-/// For FLV version 1, each tag begins with an 11 byte header:
-///
-/// UI8 tag type - 8 = audio tag, 9 = video tag, 18 = script data tag
-/// UI24 content length in bytes
-/// UI24 time - low order 3 bytes
-/// UI8 time - high order byte
-/// UI24 stream ID
-///
-/// This is followed by the tag's content, then a UI32 "back pointer" which is the header size plus
-/// the content size. A UI32 zero is placed between the file header and the first tag as a
-/// terminator for backward scans. The time in a tag header is the start of playback for that tag.
-/// The tags must be in ascending time order. For a given time it is preferred that script data tags
-/// precede audio and video tags.
-///
-/// For metadata purposes only the script data tags are of interest. Script data information becomes
-/// accessible to ActionScript at the playback moment of the script data tag through a call to a
-/// registered data handler. The content of a script data tag contains a string and an ActionScript
-/// data value. The string is the name of the handler to be invoked, the data value is passed as an
-/// ActionScript Object parameter to the handler.
-///
-/// The XMP is placed in a script data tag with the name "onXMPData". A variety of legacy metadata
-/// is contained in a script data tag with the name "onMetaData". This contains only "internal"
-/// information (like duration or width/height), nothing that is user or author editiable (like
-/// title or description). Some of these legacy items are imported into the XMP, none are updated
-/// from the XMP.
-///
-/// A script data tag's content is:
-///
-/// UI8 0x02
-/// UI16 name length - includes nul terminator if present
-/// UI8n object name - UTF-8, possibly with nul terminator
-/// ... object value - serialized ActionScript value (SCRIPTDATAVALUE in FLV spec)
-///
-/// The onXMPData and onMetaData values are both ECMA arrays. These have more in common with XMP
-/// structs than arrays, the items have arbitrary string names. The serialized form is:
-///
-/// UI8 0x08
-/// UI32 array length - need not be exact, an optimization hint
-/// array items
-/// UI16 name length - includes nul terminator if present
-/// UI8n item name - UTF-8, possibly with nul terminator
-/// ... object value - serialized ActionScript value (SCRIPTDATAVALUE in FLV spec)
-/// UI24 0x000009 - array terminator
-///
-/// The object names and array item names in sample files do not have a nul terminator. The policy
-/// here is to treat them as optional when reading, and to omit them when writing.
-///
-/// The onXMPData array typically has one item named "liveXML". The value of this is a short or long
-/// string as necessary:
-///
-/// UI8 type - 2 for a short string, 12 for a long string
-/// UIx value length - UI16 for a short string, UI32 for a long string, includes nul terminator
-/// UI8n value - UTF-8 with nul terminator
-///
-// =================================================================================================
-
-static inline XMP_Uns32 GetUns24BE ( const void * addr )
-{
- return (GetUns32BE(addr) >> 8);
-}
-
-static inline void PutUns24BE ( XMP_Uns32 value, void * addr )
-{
- XMP_Uns8 * bytes = (XMP_Uns8*)addr;
- bytes[0] = (XMP_Uns8)(value >> 16);
- bytes[1] = (XMP_Uns8)(value >> 8);
- bytes[2] = (XMP_Uns8)(value);
-}
-
-// =================================================================================================
-// FLV_CheckFormat
-// ===============
-//
-// Check for "FLV" and 1 in the first 4 bytes, that the header length is at least 9, that the file
-// size is at least as big as the header, and that the leading 0 back pointer is present if the file
-// is bigger than the header.
-
-#define kFLV1 0x464C5601UL
-
-bool FLV_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- XMP_Uns8 buffer [9];
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- XMP_Uns32 ioCount = LFA_Read ( fileRef, buffer, 9 );
- if ( ioCount != 9 ) return false;
-
- XMP_Uns32 fileSignature = GetUns32BE ( &buffer[0] );
- if ( fileSignature != kFLV1 ) return false;
-
- XMP_Uns32 headerSize = GetUns32BE ( &buffer[5] );
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
- if ( (fileSize < (headerSize + 4)) && (fileSize != headerSize) ) return false;
-
- if ( fileSize >= (headerSize + 4) ) {
- XMP_Uns32 bpZero;
- LFA_Seek ( fileRef, headerSize, SEEK_SET );
- ioCount = LFA_Read ( fileRef, &bpZero, 4 );
- if ( (ioCount != 4) || (bpZero != 0) ) return false;
- }
-
- return true;
-
-} // FLV_CheckFormat
-
-// =================================================================================================
-// FLV_MetaHandlerCTor
-// ===================
-
-XMPFileHandler * FLV_MetaHandlerCTor ( XMPFiles * parent )
-{
-
- return new FLV_MetaHandler ( parent );
-
-} // FLV_MetaHandlerCTor
-
-// =================================================================================================
-// FLV_MetaHandler::FLV_MetaHandler
-// ================================
-
-FLV_MetaHandler::FLV_MetaHandler ( XMPFiles * _parent )
- : flvHeaderLen(0), longXMP(false), xmpTagPos(0), omdTagPos(0), xmpTagLen(0), omdTagLen(0)
-{
-
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kFLV_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // FLV_MetaHandler::FLV_MetaHandler
-
-// =================================================================================================
-// FLV_MetaHandler::~FLV_MetaHandler
-// =================================
-
-FLV_MetaHandler::~FLV_MetaHandler()
-{
-
- // Nothing to do yet.
-
-} // FLV_MetaHandler::~FLV_MetaHandler
-
-// =================================================================================================
-// GetTagInfo
-// ==========
-//
-// Seek to the start of a tag and extract the type, data size, and timestamp. Leave the file
-// positioned at the first byte of data.
-
-struct TagInfo {
- XMP_Uns8 type;
- XMP_Uns32 time;
- XMP_Uns32 dataSize;
-};
-
-static void GetTagInfo ( LFA_FileRef fileRef, XMP_Uns64 tagPos, TagInfo * info )
-{
- XMP_Uns8 buffer [11];
-
- LFA_Seek ( fileRef, tagPos, SEEK_SET );
- LFA_Read ( fileRef, buffer, 11, kLFA_RequireAll );
-
- info->type = buffer[0];
- info->time = GetUns24BE ( &buffer[4] ) || (buffer[7] << 24);
- info->dataSize = GetUns24BE ( &buffer[1] );
-
-} // GetTagInfo
-
-// =================================================================================================
-// GetASValueLen
-// =============
-//
-// Return the full length of a serialized ActionScript value, including the type byte, zero if unknown.
-
-static XMP_Uns32 GetASValueLen ( const XMP_Uns8 * asValue, const XMP_Uns8 * asLimit )
-{
- XMP_Uns32 valueLen = 0;
- const XMP_Uns8 * itemPtr;
- XMP_Uns32 arrayCount;
-
- switch ( asValue[0] ) {
-
- case 0 : // IEEE double
- valueLen = 1 + 8;
- break;
-
- case 1 : // UI8 Boolean
- valueLen = 1 + 1;
- break;
-
- case 2 : // Short string
- valueLen = 1 + 2 + GetUns16BE ( &asValue[1] );
- break;
-
- case 3 : // ActionScript object, a name and value.
- itemPtr = &asValue[1];
- itemPtr += 2 + GetUns16BE ( itemPtr ); // Move past the name portion.
- itemPtr += GetASValueLen ( itemPtr, asLimit ); // And past the data portion.
- valueLen = (XMP_Uns32) (itemPtr - asValue);
- break;
-
- case 4 : // Short string (movie clip path)
- valueLen = 1 + 2 + GetUns16BE ( &asValue[1] );
- break;
-
- case 5 : // Null
- valueLen = 1;
- break;
-
- case 6 : // Undefined
- valueLen = 1;
- break;
-
- case 7 : // UI16 reference ID
- valueLen = 1 + 2;
- break;
-
- case 8 : // ECMA array, ignore the count, look for the 0x000009 terminator.
- itemPtr = &asValue[5];
- while ( itemPtr < asLimit ) {
- XMP_Uns16 nameLen = GetUns16BE ( itemPtr );
- itemPtr += 2 + nameLen; // Move past the name portion.
- if ( (nameLen == 0) && (*itemPtr == 9) ) {
- itemPtr += 1;
- break; // Done, found the 0x000009 terminator.
- }
- itemPtr += GetASValueLen ( itemPtr, asLimit ); // And past the data portion.
- }
- valueLen = (XMP_Uns32) (itemPtr - asValue);
- break;
-
- case 10 : // Strict array, has an exact count.
- arrayCount = GetUns32BE ( &asValue[1] );
- itemPtr = &asValue[5];
- for ( ; (arrayCount > 0) && (itemPtr < asLimit); --arrayCount ) {
- itemPtr += 2 + GetUns16BE ( itemPtr ); // Move past the name portion.
- itemPtr += GetASValueLen ( itemPtr, asLimit ); // And past the data portion.
- }
- valueLen = (XMP_Uns32) (itemPtr - asValue);
- break;
-
- case 11 : // Date
- valueLen = 1 + 8 + 2;
- break;
-
- case 12: // Long string
- valueLen = 1 + 4 + GetUns32BE ( &asValue[1] );
- break;
-
- }
-
- return valueLen;
-
-} // GetASValueLen
-
-// =================================================================================================
-// CheckName
-// =========
-//
-// Check for the name portion of a script data tag or array item, with optional nul terminator. The
-// wantedLen must not count the terminator.
-
-static inline bool CheckName ( XMP_StringPtr inputName, XMP_Uns16 inputLen,
- XMP_StringPtr wantedName, XMP_Uns16 wantedLen )
-{
-
- if ( inputLen == wantedLen+1 ) {
- if ( inputName[wantedLen] != 0 ) return false; // Extra byte must be terminating nul.
- --inputLen;
- }
-
- if ( (inputLen == wantedLen) && XMP_LitNMatch ( inputName, wantedName, wantedLen ) ) return true;
- return false;
-
-} // CheckName
-
-// =================================================================================================
-// FLV_MetaHandler::CacheFileData
-// ==============================
-//
-// Look for the onXMPData and onMetaData script data tags at time 0. Cache all of onMetaData, it
-// shouldn't be that big and this removes a need to know what is reconciled. It can't be more than
-// 16MB anyway, the size field is only 24 bits.
-
-void FLV_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
-
- XMP_Uns8 buffer [16]; // Enough for 1+2+"onMetaData"+nul.
- XMP_Uns32 ioCount;
- TagInfo info;
-
- LFA_Seek ( fileRef, 5, SEEK_SET );
- LFA_Read ( fileRef, buffer, 4, kLFA_RequireAll );
-
- this->flvHeaderLen = GetUns32BE ( &buffer[0] );
- XMP_Uns32 firstTagPos = this->flvHeaderLen + 4; // Include the initial zero back pointer.
-
- if ( firstTagPos >= fileSize ) return; // Quit now if the file is just a header.
-
- for ( XMP_Uns64 tagPos = firstTagPos; tagPos < fileSize; tagPos += (11 + info.dataSize + 4) ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "FLV_MetaHandler::LookForMetadata - User abort", kXMPErr_UserAbort );
- }
-
- GetTagInfo ( fileRef, tagPos, &info ); // ! GetTagInfo seeks to the tag offset.
- if ( info.time != 0 ) break;
- if ( info.type != 18 ) continue;
-
- XMP_Assert ( sizeof(buffer) >= (1+2+10+1) ); // 02 000B onMetaData 00
- ioCount = LFA_Read ( fileRef, buffer, sizeof(buffer) );
- if ( (ioCount < 4) || (buffer[0] != 0x02) ) continue;
-
- XMP_Uns16 nameLen = GetUns16BE ( &buffer[1] );
- XMP_StringPtr namePtr = (XMP_StringPtr)(&buffer[3]);
-
- if ( this->onXMP.empty() && CheckName ( namePtr, nameLen, "onXMPData", 9 ) ) {
-
- // ! Put the raw data in onXMPData, analyze the value in ProcessXMP.
-
- this->xmpTagPos = tagPos;
- this->xmpTagLen = 11 + info.dataSize + 4; // ! Includes the trailing back pointer.
-
- this->packetInfo.offset = tagPos + 11 + 1+2+nameLen; // ! Not the real offset yet, the offset of the onXMPData value.
-
- ioCount = info.dataSize - (1+2+nameLen); // Just the onXMPData value portion.
- this->onXMP.reserve ( ioCount );
- this->onXMP.assign ( ioCount, ' ' );
- LFA_Seek ( fileRef, this->packetInfo.offset, SEEK_SET );
- LFA_Read ( fileRef, (void*)this->onXMP.data(), ioCount, kLFA_RequireAll );
-
- if ( ! this->onMetaData.empty() ) break; // Done if we've found both.
-
- } else if ( this->onMetaData.empty() && CheckName ( namePtr, nameLen, "onMetaData", 10 ) ) {
-
- this->omdTagPos = tagPos;
- this->omdTagLen = 11 + info.dataSize + 4; // ! Includes the trailing back pointer.
-
- ioCount = info.dataSize - (1+2+nameLen); // Just the onMetaData value portion.
- this->onMetaData.reserve ( ioCount );
- this->onMetaData.assign ( ioCount, ' ' );
- LFA_Seek ( fileRef, (tagPos + 11 + 1+2+nameLen), SEEK_SET );
- LFA_Read ( fileRef, (void*)this->onMetaData.data(), ioCount, kLFA_RequireAll );
-
- if ( ! this->onXMP.empty() ) break; // Done if we've found both.
-
- }
-
- }
-
-} // FLV_MetaHandler::CacheFileData
-
-// =================================================================================================
-// FLV_MetaHandler::MakeLegacyDigest
-// =================================
-
-#define kHexDigits "0123456789ABCDEF"
-
-void FLV_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
-{
- MD5_CTX context;
- unsigned char digestBin [16];
-
- MD5Init ( &context );
- MD5Update ( &context, (XMP_Uns8*)this->onMetaData.data(), (unsigned int)this->onMetaData.size() );
- MD5Final ( digestBin, &context );
-
- 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->erase();
- digestStr->append ( buffer, 32 );
-
-} // FLV_MetaHandler::MakeLegacyDigest
-
-// =================================================================================================
-// FLV_MetaHandler::ExtractLiveXML
-// ===============================
-//
-// Extract the XMP packet from the cached onXMPData ECMA array's "liveXMP" item.
-
-void FLV_MetaHandler::ExtractLiveXML()
-{
- if ( this->onXMP[0] != 0x08 ) return; // Make sure onXMPData is an ECMA array.
- const XMP_Uns8 * ecmaArray = (const XMP_Uns8 *) this->onXMP.c_str();
- const XMP_Uns8 * ecmaLimit = ecmaArray + this->onXMP.size();
-
- if ( this->onXMP.size() >= 3 ) { // Omit the 0x000009 terminator, simplifies the loop.
- if ( GetUns24BE ( ecmaLimit-3 ) == 9 ) ecmaLimit -= 3;
- }
-
- for ( const XMP_Uns8 * itemPtr = ecmaArray + 5; itemPtr < ecmaLimit; /* internal increment */ ) {
-
- // Find the "liveXML" array item, make sure it is a short or long string.
-
- XMP_Uns16 nameLen = GetUns16BE ( itemPtr );
- const XMP_Uns8 * namePtr = itemPtr + 2;
-
- itemPtr += (2 + nameLen); // Move to the value portion.
- XMP_Uns32 valueLen = GetASValueLen ( itemPtr, ecmaLimit );
- if ( valueLen == 0 ) return; // ! Unknown value type, can't look further.
-
- if ( CheckName ( (char*)namePtr, nameLen, "liveXML", 7 ) ) {
-
- XMP_Uns32 lenLen = 2; // Assume a short string.
- if ( *itemPtr == 12 ) {
- lenLen = 4;
- this->longXMP = true;
- } else if ( *itemPtr != 2 ) {
- return; // Not a short or long string.
- }
-
- valueLen -= (1 + lenLen);
- itemPtr += (1 + lenLen);
-
- this->packetInfo.offset += (itemPtr - ecmaArray);
- this->packetInfo.length += valueLen;
-
- this->xmpPacket.reserve ( valueLen );
- this->xmpPacket.assign ( (char*)itemPtr, valueLen );
-
- return;
-
- }
-
- itemPtr += valueLen; // Move past the value portion.
-
- }
-
-} // FLV_MetaHandler::ExtractLiveXML
-
-// =================================================================================================
-// FLV_MetaHandler::ProcessXMP
-// ===========================
-
-void FLV_MetaHandler::ProcessXMP()
-{
- if ( this->processedXMP ) return;
- this->processedXMP = true; // Make sure only called once.
-
- if ( ! this->onXMP.empty() ) { // Look for the XMP packet.
-
- this->ExtractLiveXML();
- if ( ! this->xmpPacket.empty() ) {
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->containsXMP = true;
- }
-
- }
-
- // Now process the legacy, if necessary.
-
- if ( this->onMetaData.empty() ) return; // No legacy, we're done.
-
- std::string oldDigest;
- bool oldDigestFound = this->xmpObj.GetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "FLV", &oldDigest, 0 );
-
- if ( oldDigestFound ) {
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- if ( oldDigest == newDigest ) return; // No legacy changes.
- }
-
- // *** No spec yet for what legacy to reconcile.
-
-} // FLV_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// FLV_MetaHandler::UpdateFile
-// ===========================
-
-void FLV_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
-
- // Make sure the XMP has a legacy digest if appropriate.
-
- if ( ! this->onMetaData.empty() ) {
-
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests",
- kXMP_NS_XMP, "FLV", newDigest.c_str(), kXMP_DeleteExisting );
-
- try {
- XMP_StringLen xmpLen = (XMP_StringLen)this->xmpPacket.size();
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, (kXMP_UseCompactFormat | kXMP_ExactPacketLength), xmpLen );
- } catch ( ... ) {
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- }
-
- // Rewrite the packet in-place if it fits. Otherwise rewrite the whole file.
-
- if ( this->xmpPacket.size() == (size_t)this->packetInfo.length ) {
-
- LFA_Seek ( fileRef, this->packetInfo.offset, SEEK_SET );
- LFA_Write ( fileRef, this->xmpPacket.data(), (XMP_Int32)this->xmpPacket.size() );
-
- } else {
-
- std::string origPath = this->parent->filePath;
- LFA_FileRef origRef = this->parent->fileRef;
-
- std::string updatePath;
- LFA_FileRef updateRef = 0;
-
- CreateTempFile ( origPath, &updatePath );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
-
- this->parent->filePath = updatePath;
- this->parent->fileRef = updateRef;
-
- try {
- this->WriteFile ( origRef, origPath );
- } catch ( ... ) {
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = origRef;
- throw;
- }
-
- LFA_Close ( origRef );
- LFA_Delete ( origPath.c_str() );
-
- LFA_Close ( updateRef );
- LFA_Rename ( updatePath.c_str(), origPath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = 0;
-
- }
-
- this->needsUpdate = false;
-
-} // FLV_MetaHandler::UpdateFile
-
-// =================================================================================================
-// WriteOnXMP
-// ==========
-//
-// Write the XMP packet wrapped up in an ECMA array script data tag:
-//
-// 0 UI8 tag type : 18
-// 1 UI24 content length : 1+2+9+1+4+2+7+1 + <2 or 4> + XMP packet size + 1 + 3
-// 4 UI24 time low : 0
-// 7 UI8 time high : 0
-// 8 UI24 stream ID : 0
-//
-// 11 UI8 0x02
-// 12 UI16 name length : 9
-// 14 str9 tag name : "onXMPData", no nul terminator
-// 23 UI8 value type : 8
-// 24 UI32 array count : 1
-// 28 UI16 name length : 7
-// 30 str7 item name : "liveXML", no nul terminator
-//
-// 37 UI8 value type : 2 for a short string, 12 for a long string
-// 38 UIn XMP packet size + 1, UI16 or UI32 as needed
-// -- str XMP packet, with nul terminator
-//
-// -- UI24 array terminator : 0x000009
-// -- UI32 back pointer : content length + 11
-
-static void WriteOnXMP ( LFA_FileRef fileRef, const std::string & xmpPacket )
-{
- char buffer [64];
- bool longXMP = false;
- XMP_Uns32 tagLen = 1+2+9+1+4+2+7+1 + 2 + (XMP_Uns32)xmpPacket.size() + 1 + 3;
-
- if ( xmpPacket.size() > 0xFFFE ) {
- longXMP = true;
- tagLen += 2;
- }
-
- if ( tagLen > 16*1024*1024 ) XMP_Throw ( "FLV tags can't be larger than 16MB", kXMPErr_TBD );
-
- // Fill in the script data tag header.
-
- buffer[0] = 18;
- PutUns24BE ( tagLen, &buffer[1] );
- PutUns24BE ( 0, &buffer[4] );
- buffer[7] = 0;
- PutUns24BE ( 0, &buffer[8] );
-
- // Fill in the "onXMPData" name, ECMA array start, and "liveXML" name.
-
- buffer[11] = 2;
- PutUns16BE ( 9, &buffer[12] );
- memcpy ( &buffer[14], "onXMPData", 9 ); // AUDIT: Safe, buffer has 64 chars.
- buffer[23] = 8;
- PutUns32BE ( 1, &buffer[24] );
- PutUns16BE ( 7, &buffer[28] );
- memcpy ( &buffer[30], "liveXML", 7 ); // AUDIT: Safe, buffer has 64 chars.
-
- // Fill in the XMP packet string type and length, write what we have so far.
-
- LFA_Seek ( fileRef, 0, SEEK_END );
- if ( ! longXMP ) {
- buffer[37] = 2;
- PutUns16BE ( (XMP_Uns16)xmpPacket.size()+1, &buffer[38] );
- LFA_Write ( fileRef, buffer, 40 );
- } else {
- buffer[37] = 12;
- PutUns32BE ( (XMP_Uns32)xmpPacket.size()+1, &buffer[38] );
- LFA_Write ( fileRef, buffer, 42 );
- }
-
- // Write the XMP packet, nul terminator, array terminator, and back pointer.
-
- LFA_Write ( fileRef, xmpPacket.c_str(), (XMP_Int32)xmpPacket.size()+1 );
- PutUns24BE ( 9, &buffer[0] );
- PutUns32BE ( tagLen+11, &buffer[3] );
- LFA_Write ( fileRef, buffer, 7 );
-
-} // WriteOnXMP
-
-// =================================================================================================
-// FLV_MetaHandler::WriteFile
-// ==========================
-//
-// Use a source (old) file and the current XMP to build a destination (new) file. All of the source
-// file is copied except for previous XMP. The current XMP is inserted after onMetaData, or at least
-// before the first time 0 audio or video tag.
-
-// ! We do not currently update anything in onMetaData.
-
-void FLV_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- if ( ! this->needsUpdate ) return;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_FileRef destRef = this->parent->fileRef;
-
- XMP_Uns64 sourceLen = LFA_Measure ( sourceRef );
- XMP_Uns64 sourcePos = 0;
-
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Seek ( destRef, 0, SEEK_SET );
- LFA_Truncate ( destRef, 0 );
-
- // First do whatever is needed to put the new XMP after any existing onMetaData tag, or as the
- // first time 0 tag.
-
- if ( this->omdTagPos == 0 ) {
-
- // There is no onMetaData tag. Copy the file header, then write the new XMP as the first tag.
- // Allow the degenerate case of a file with just a header, no initial back pointer or tags.
-
- LFA_Copy ( sourceRef, destRef, this->flvHeaderLen, abortProc, abortArg );
-
- XMP_Uns32 zero = 0; // Don't require the initial 0 back pointer to be in the source file.
- LFA_Write ( destRef, &zero, 4 );
-
- sourcePos = this->flvHeaderLen + 4;
-
- WriteOnXMP ( destRef, this->xmpPacket );
-
- } else {
-
- // There is an onMetaData tag. Copy the front of the file through the onMetaData tag,
- // skipping any XMP that happens to be in the way. The XMP should not be before onMetaData,
- // but let's be robust. Write the new XMP immediately after onMetaData, at the same time.
-
- XMP_Uns64 omdEnd = this->omdTagPos + this->omdTagLen;
-
- if ( (this->xmpTagPos != 0) && (this->xmpTagPos < this->omdTagPos) ) {
- LFA_Copy ( sourceRef, destRef, this->xmpTagPos, abortProc, abortArg );
- sourcePos = this->xmpTagPos + this->xmpTagLen;
- LFA_Seek ( sourceRef, sourcePos, SEEK_SET );
- }
-
- LFA_Copy ( sourceRef, destRef, (omdEnd - sourcePos), abortProc, abortArg );
- sourcePos = omdEnd;
-
- WriteOnXMP ( destRef, this->xmpPacket );
-
- }
-
- // Copy the rest of the file, skipping any XMP that is in the way.
-
- if ( (this->xmpTagPos != 0) && (this->xmpTagPos >= sourcePos) ) {
- LFA_Copy ( sourceRef, destRef, (this->xmpTagPos - sourcePos), abortProc, abortArg );
- sourcePos = this->xmpTagPos + this->xmpTagLen;
- LFA_Seek ( sourceRef, sourcePos, SEEK_SET );
- }
-
- LFA_Copy ( sourceRef, destRef, (sourceLen - sourcePos), abortProc, abortArg );
-
- this->needsUpdate = false;
-
-} // FLV_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/FLV_Handler.hpp b/source/XMPFiles/FileHandlers/FLV_Handler.hpp
deleted file mode 100644
index 80ed1a0..0000000
--- a/source/XMPFiles/FileHandlers/FLV_Handler.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef __FLV_Handler_hpp__
-#define __FLV_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMPFiles_Impl.hpp"
-
-// ================================================================================================
-/// \file FLV_Handler.hpp
-/// \brief File format handler for FLV.
-///
-/// This header ...
-///
-// ================================================================================================
-
-extern XMPFileHandler * FLV_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool FLV_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kFLV_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate
- );
-
-class FLV_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- FLV_MetaHandler ( XMPFiles * _parent );
- virtual ~FLV_MetaHandler();
-
-private:
-
- FLV_MetaHandler() : flvHeaderLen(0), longXMP(false),
- xmpTagPos(0), omdTagPos(0), xmpTagLen(0), omdTagLen(0) {}; // Hidden on purpose.
-
- void ExtractLiveXML();
- void MakeLegacyDigest ( std::string * digestStr );
-
- XMP_Uns32 flvHeaderLen;
- bool longXMP; // True if the stored XMP is a long string (4 byte length).
-
- XMP_Uns64 xmpTagPos, omdTagPos; // The file offset and length of onXMP and onMetaData tags.
- XMP_Uns32 xmpTagLen, omdTagLen; // Zero if the tag is not present.
-
- std::string onXMP, onMetaData; // ! Actually contains structured binary data.
-
-}; // FLV_MetaHandler
-
-// =================================================================================================
-
-#endif // __FLV_Handler_hpp__
diff --git a/source/XMPFiles/FileHandlers/InDesign_Handler.cpp b/source/XMPFiles/FileHandlers/InDesign_Handler.cpp
deleted file mode 100644
index 2f9845e..0000000
--- a/source/XMPFiles/FileHandlers/InDesign_Handler.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "InDesign_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file InDesign_Handler.cpp
-/// \brief File format handler for InDesign files.
-///
-/// This header ...
-///
-/// The layout of an InDesign file in terms of the Basic_MetaHandler model is:
-///
-/// \li The front of the file. This is everything up to the XMP contiguous object section. The file
-/// starts with a pair of master pages, followed by the data pages, followed by contiguous object
-/// sections, finished with padding to a page boundary.
-///
-/// \li A prefix for the XMP section. This is the contiguous object header. The offset is
-/// (this->packetInfo.offset - this->xmpPrefixSize).
-///
-/// \li The XMP packet. The offset is this->packetInfo.offset.
-///
-/// \li A suffix for the XMP section. This is the contiguous object header. The offset is
-/// (this->packetInfo.offset + this->packetInfo.length).
-///
-/// \li Trailing file content. This is the contiguous objects that follow the XMP. The offset is
-/// (this->packetInfo.offset + this->packetInfo.length + this->xmpSuffixSize).
-///
-/// \li The back of the file. This is the final padding to a page boundary. The offset is
-/// (this->packetInfo.offset + this->packetInfo.length + this->xmpSuffixSize + this->trailingContentSize).
-///
-// =================================================================================================
-
-// *** Add PutXMP overrides that throw if the file does not contain XMP.
-
-#ifndef TraceInDesignHandler
- #define TraceInDesignHandler 0
-#endif
-
-enum { kInDesignGUIDSize = 16 };
-
-struct InDesignMasterPage {
- XMP_Uns8 fGUID [kInDesignGUIDSize];
- XMP_Uns8 fMagicBytes [8];
- XMP_Uns8 fObjectStreamEndian;
- XMP_Uns8 fIrrelevant1 [239];
- XMP_Uns64 fSequenceNumber;
- XMP_Uns8 fIrrelevant2 [8];
- XMP_Uns32 fFilePages;
- XMP_Uns8 fIrrelevant3 [3812];
-};
-
-enum {
- kINDD_PageSize = 4096,
- kINDD_PageMask = (kINDD_PageSize - 1),
- kINDD_LittleEndian = 1,
- kINDD_BigEndian = 2 };
-
-struct InDesignContigObjMarker {
- XMP_Uns8 fGUID [kInDesignGUIDSize];
- XMP_Uns32 fObjectUID;
- XMP_Uns32 fObjectClassID;
- XMP_Uns32 fStreamLength;
- XMP_Uns32 fChecksum;
-};
-
-static const XMP_Uns8 * kINDD_MasterPageGUID =
- (const XMP_Uns8 *) "\x06\x06\xED\xF5\xD8\x1D\x46\xE5\xBD\x31\xEF\xE7\xFE\x74\xB7\x1D";
-
-static const XMP_Uns8 * kINDDContigObjHeaderGUID =
- (const XMP_Uns8 *) "\xDE\x39\x39\x79\x51\x88\x4B\x6C\x8E\x63\xEE\xF8\xAE\xE0\xDD\x38";
-
-static const XMP_Uns8 * kINDDContigObjTrailerGUID =
- (const XMP_Uns8 *) "\xFD\xCE\xDB\x70\xF7\x86\x4B\x4F\xA4\xD3\xC7\x28\xB3\x41\x71\x06";
-
-// =================================================================================================
-// InDesign_MetaHandlerCTor
-// ========================
-
-XMPFileHandler * InDesign_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new InDesign_MetaHandler ( parent );
-
-} // InDesign_MetaHandlerCTor
-
-// =================================================================================================
-// InDesign_CheckFormat
-// ====================
-//
-// For InDesign we check that the pair of master pages begin with the 16 byte GUID.
-
-bool InDesign_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_InDesignFile );
- XMP_Assert ( strlen ( (const char *) kINDD_MasterPageGUID ) == kInDesignGUIDSize );
-
- enum { kBufferSize = 2*kINDD_PageSize };
- XMP_Uns8 buffer [kBufferSize];
-
- XMP_Int64 filePos = 0;
- XMP_Uns8 * bufPtr = buffer;
- XMP_Uns8 * bufLimit = bufPtr + kBufferSize;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- size_t bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
- if ( bufLen != kBufferSize ) return false;
-
- if ( ! CheckBytes ( bufPtr, kINDD_MasterPageGUID, kInDesignGUIDSize ) ) return false;
- if ( ! CheckBytes ( bufPtr+kINDD_PageSize, kINDD_MasterPageGUID, kInDesignGUIDSize ) ) return false;
-
- return true;
-
-} // InDesign_CheckFormat
-
-// =================================================================================================
-// InDesign_MetaHandler::InDesign_MetaHandler
-// ==========================================
-
-InDesign_MetaHandler::InDesign_MetaHandler ( XMPFiles * _parent ) : streamBigEndian(0), xmpObjID(0), xmpClassID(0)
-{
- this->parent = _parent;
- this->handlerFlags = kInDesign_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // InDesign_MetaHandler::InDesign_MetaHandler
-
-// =================================================================================================
-// InDesign_MetaHandler::~InDesign_MetaHandler
-// ===========================================
-
-InDesign_MetaHandler::~InDesign_MetaHandler()
-{
- // Nothing to do here.
-
-} // InDesign_MetaHandler::~InDesign_MetaHandler
-
-// =================================================================================================
-// InDesign_MetaHandler::CacheFileData
-// ===================================
-//
-// Look for the XMP in an InDesign database file. This is a paged database using 4K byte pages,
-// followed by redundant "contiguous object streams". Each contiguous object stream is a copy of a
-// database object stored as a contiguous byte stream. The XMP that we want is one of these.
-//
-// The first 2 pages of the database are alternating master pages. A generation number is used to
-// select the active master page. The master page contains an offset to the start of the contiguous
-// object streams. Each of the contiguous object streams contains a header and trailer, allowing
-// fast motion from one stream to the next.
-//
-// There is no unique "what am I" tagging to the contiguous object streams, so we simply pick the
-// first one that looks right. At present this is a 4 byte little endian packet size followed by the
-// packet.
-
-// ! Note that insertion of XMP is not allowed for InDesign, the XMP must be a contiguous copy of an
-// ! internal database object. So we don't set the packet offset to an insertion point if not found.
-
-void InDesign_MetaHandler::CacheFileData()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- IOBuffer ioBuf;
- size_t dbPages;
- XMP_Uns8 cobjEndian;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- XMP_Assert ( kINDD_PageSize == sizeof(InDesignMasterPage) );
- XMP_Assert ( kIOBufferSize >= (2 * kINDD_PageSize) );
-
- this->containsXMP = false;
-
- // ---------------------------------------------------------------------------------
- // Figure out which master page is active and seek to the contiguous object portion.
-
- {
- ioBuf.filePos = 0;
- ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
- LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
- RefillBuffer ( fileRef, &ioBuf );
- if ( ioBuf.len < (2 * kINDD_PageSize) ) XMP_Throw ( "GetMainPacket/ScanInDesignFile: Read failure", kXMPErr_ExternalFailure );
-
- InDesignMasterPage * masters = (InDesignMasterPage *) ioBuf.ptr;
- XMP_Uns64 seq0 = GetUns64LE ( (XMP_Uns8 *) &masters[0].fSequenceNumber );
- XMP_Uns64 seq1 = GetUns64LE ( (XMP_Uns8 *) &masters[1].fSequenceNumber );
-
- dbPages = GetUns32LE ( (XMP_Uns8 *) &masters[0].fFilePages );
- cobjEndian = masters[0].fObjectStreamEndian;
- if ( seq1 > seq0 ) {
- dbPages = GetUns32LE ( (XMP_Uns8 *) &masters[1].fFilePages );
- cobjEndian = masters[1].fObjectStreamEndian;
- }
- }
-
- XMP_Assert ( ! this->streamBigEndian );
- if ( cobjEndian == kINDD_BigEndian ) this->streamBigEndian = true;
-
- // ---------------------------------------------------------------------------------------------
- // Look for the XMP contiguous object stream. Most of the time there will be just one stream and
- // it will be the XMP. So we might as well fill the whole buffer and not worry about reading too
- // much and seeking back to the start of the following stream.
-
- XMP_Int64 cobjPos = (XMP_Int64)dbPages * kINDD_PageSize; // ! Use a 64 bit multiply!
- cobjPos -= (2 * sizeof(InDesignContigObjMarker)); // ! For the first pass in the loop.
- XMP_Uns32 streamLength = 0; // ! For the first pass in the loop.
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "InDesign_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
- }
-
- // Fetch the start of the next stream and check the contiguous object header.
- // ! The writeable bit of fObjectClassID is ignored, we use the packet trailer flag.
-
- cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
- ioBuf.filePos = cobjPos;
- ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
- LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
- RefillBuffer ( fileRef, &ioBuf );
- if ( ioBuf.len < (2 * sizeof(InDesignContigObjMarker)) ) break; // Too small, must be end of file.
-
- const InDesignContigObjMarker * cobjHeader = (const InDesignContigObjMarker *) ioBuf.ptr;
- if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break; // Not a contiguous object header.
- this->xmpObjID = cobjHeader->fObjectUID; // Save these now while the buffer is good.
- this->xmpClassID = cobjHeader->fObjectClassID;
- streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );
- ioBuf.ptr += sizeof ( InDesignContigObjMarker );
-
- // See if this is the XMP stream. Only check for UTF-8, others get caught in fallback scanning.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) continue; // Too small, can't possibly be XMP.
-
- XMP_Uns32 innerLength = GetUns32LE ( ioBuf.ptr );
- if ( this->streamBigEndian ) innerLength = GetUns32BE ( ioBuf.ptr );
- if ( innerLength != (streamLength - 4) ) continue; // Not legit XMP.
- ioBuf.ptr += 4;
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, kUTF8_PacketHeaderLen ) ) continue; // Too small, can't possibly be XMP.
-
- if ( ! CheckBytes ( ioBuf.ptr, kUTF8_PacketStart, strlen((char*)kUTF8_PacketStart) ) ) continue;
- ioBuf.ptr += strlen((char*)kUTF8_PacketStart);
-
- XMP_Uns8 quote = *ioBuf.ptr;
- if ( (quote != '\'') && (quote != '"') ) continue;
- ioBuf.ptr += 1;
- if ( *ioBuf.ptr != quote ) {
- if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr("\xEF\xBB\xBF"), 3 ) ) continue;
- ioBuf.ptr += 3;
- }
- if ( *ioBuf.ptr != quote ) continue;
- ioBuf.ptr += 1;
-
- if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(" id="), 4 ) ) continue;
- ioBuf.ptr += 4;
- quote = *ioBuf.ptr;
- if ( (quote != '\'') && (quote != '"') ) continue;
- ioBuf.ptr += 1;
- if ( ! CheckBytes ( ioBuf.ptr, kUTF8_PacketID, strlen((char*)kUTF8_PacketID) ) ) continue;
- ioBuf.ptr += strlen((char*)kUTF8_PacketID);
- if ( *ioBuf.ptr != quote ) continue;
- ioBuf.ptr += 1;
-
- // We've seen enough, it is the XMP. To fit the Basic_Handler model we need to compute the
- // total size of remaining contiguous objects, the trailingContentSize.
-
- this->xmpPrefixSize = sizeof(InDesignContigObjMarker) + 4;
- this->xmpSuffixSize = sizeof(InDesignContigObjMarker);
- packetInfo.offset = cobjPos + this->xmpPrefixSize;
- packetInfo.length = innerLength;
-
-
- XMP_Int64 tcStart = cobjPos + streamLength + (2 * sizeof(InDesignContigObjMarker));
- while ( true ) {
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "InDesign_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
- }
- cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
- ioBuf.filePos = cobjPos;
- ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
- LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
- RefillBuffer ( fileRef, &ioBuf );
- if ( ioBuf.len < sizeof(InDesignContigObjMarker) ) break; // Too small, must be end of file.
- cobjHeader = (const InDesignContigObjMarker *) ioBuf.ptr;
- if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break; // Not a contiguous object header.
- streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );
- }
- this->trailingContentSize = cobjPos - tcStart;
-
- #if TraceInDesignHandler
- XMP_Uns32 pktOffset = (XMP_Uns32)this->packetInfo.offset;
- printf ( "Found XMP in InDesign file, offsets:\n" );
- printf ( " CObj head %X, XMP %X, CObj tail %X, file tail %X, padding %X\n",
- (pktOffset - this->xmpPrefixSize), pktOffset, (pktOffset + this->packetInfo.length),
- (pktOffset + this->packetInfo.length + this->xmpSuffixSize),
- (pktOffset + this->packetInfo.length + this->xmpSuffixSize + (XMP_Uns32)this->trailingContentSize) );
- #endif
-
- this->containsXMP = true;
- break;
-
- }
-
- if ( this->containsXMP ) {
- this->xmpFileOffset = packetInfo.offset;
- this->xmpFileSize = packetInfo.length;
- ReadXMPPacket ( this );
- }
-
-} // InDesign_MetaHandler::CacheFileData
-
-// =================================================================================================
-// InDesign_MetaHandler::WriteXMPPrefix
-// ====================================
-
-void InDesign_MetaHandler::WriteXMPPrefix()
-{
- // Write the contiguous object header and the 4 byte length of the XMP packet.
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns32 packetSize = (XMP_Uns32)this->xmpPacket.size();
-
- InDesignContigObjMarker header;
- memcpy ( header.fGUID, kINDDContigObjHeaderGUID, sizeof(header.fGUID) ); // AUDIT: Use of dest sizeof for length is safe.
- header.fObjectUID = this->xmpObjID;
- header.fObjectClassID = this->xmpClassID;
- header.fStreamLength = MakeUns32LE ( 4 + packetSize );
- header.fChecksum = (XMP_Uns32)(-1);
- LFA_Write ( fileRef, &header, sizeof(header) );
-
- XMP_Uns32 pktLength = MakeUns32LE ( packetSize );
- if ( this->streamBigEndian ) pktLength = MakeUns32BE ( packetSize );
- LFA_Write ( fileRef, &pktLength, sizeof(pktLength) );
-
-} // InDesign_MetaHandler::WriteXMPPrefix
-
-// =================================================================================================
-// InDesign_MetaHandler::WriteXMPSuffix
-// ====================================
-
-void InDesign_MetaHandler::WriteXMPSuffix()
-{
- // Write the contiguous object trailer.
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns32 packetSize = (XMP_Uns32)this->xmpPacket.size();
-
- InDesignContigObjMarker trailer;
-
- memcpy ( trailer.fGUID, kINDDContigObjTrailerGUID, sizeof(trailer.fGUID) ); // AUDIT: Use of dest sizeof for length is safe.
- trailer.fObjectUID = this->xmpObjID;
- trailer.fObjectClassID = this->xmpClassID;
- trailer.fStreamLength = MakeUns32LE ( 4 + packetSize );
- trailer.fChecksum = (XMP_Uns32)(-1);
-
- LFA_Write ( fileRef, &trailer, sizeof(trailer) );
-
-} // InDesign_MetaHandler::WriteXMPSuffix
-
-// =================================================================================================
-// InDesign_MetaHandler::NoteXMPRemoval
-// ====================================
-
-void InDesign_MetaHandler::NoteXMPRemoval()
-{
- // Nothing to do.
-
-} // InDesign_MetaHandler::NoteXMPRemoval
-
-// =================================================================================================
-// InDesign_MetaHandler::NoteXMPInsertion
-// ======================================
-
-void InDesign_MetaHandler::NoteXMPInsertion()
-{
- // Nothing to do.
-
-} // InDesign_MetaHandler::NoteXMPInsertion
-
-// =================================================================================================
-// InDesign_MetaHandler::CaptureFileEnding
-// =======================================
-
-void InDesign_MetaHandler::CaptureFileEnding()
-{
- // Nothing to do. The back of an InDesign file is the final zero padding.
-
-} // InDesign_MetaHandler::CaptureFileEnding
-
-// =================================================================================================
-// InDesign_MetaHandler::RestoreFileEnding
-// =======================================
-
-void InDesign_MetaHandler::RestoreFileEnding()
-{
- // Pad the file with zeros to a page boundary.
-
- LFA_FileRef fileRef = this->parent->fileRef;
-
- XMP_Int64 dataLength = LFA_Measure ( fileRef );
- XMP_Int32 padLength = (kINDD_PageSize - ((XMP_Int32)dataLength & kINDD_PageMask)) & kINDD_PageMask;
-
- XMP_Uns8 buffer [kINDD_PageSize];
- memset ( buffer, 0, kINDD_PageSize );
- LFA_Write ( fileRef, buffer, padLength );
-
-} // InDesign_MetaHandler::RestoreFileEnding
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/InDesign_Handler.hpp b/source/XMPFiles/FileHandlers/InDesign_Handler.hpp
deleted file mode 100644
index aded52e..0000000
--- a/source/XMPFiles/FileHandlers/InDesign_Handler.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __InDesign_Handler_hpp__
-#define __InDesign_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "Basic_Handler.hpp"
-
-// =================================================================================================
-/// \file InDesign_Handler.hpp
-/// \brief File format handler for InDesign files.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * InDesign_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool InDesign_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kInDesign_HandlerFlags = kBasic_HandlerFlags & (~kXMPFiles_CanInjectXMP); // ! InDesign can't inject.
-
-class InDesign_MetaHandler : public Basic_MetaHandler
-{
-public:
-
- InDesign_MetaHandler ( XMPFiles * parent );
- ~InDesign_MetaHandler();
-
- void CacheFileData();
-
-protected:
-
- void WriteXMPPrefix();
- void WriteXMPSuffix();
-
- void NoteXMPRemoval();
- void NoteXMPInsertion();
-
- void CaptureFileEnding();
- void RestoreFileEnding();
-
- bool streamBigEndian; // Set from master page's fObjectStreamEndian.
- XMP_Uns32 xmpObjID; // Set from contiguous object's fObjectID, still as little endian.
- XMP_Uns32 xmpClassID; // Set from contiguous object's fObjectClassID, still as little endian.
-
-}; // InDesign_MetaHandler
-
-// =================================================================================================
-
-#endif /* __InDesign_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/JPEG_Handler.cpp b/source/XMPFiles/FileHandlers/JPEG_Handler.cpp
deleted file mode 100644
index a3842f8..0000000
--- a/source/XMPFiles/FileHandlers/JPEG_Handler.cpp
+++ /dev/null
@@ -1,1027 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "JPEG_Handler.hpp"
-
-#include "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-#include "ReconcileLegacy.hpp"
-#include "Reconcile_Impl.hpp"
-
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file JPEG_Handler.cpp
-/// \brief File format handler for JPEG.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-static const char * kExifSignatureString = "Exif\0\x00";
-static const char * kExifSignatureAltStr = "Exif\0\xFF";
-static const size_t kExifSignatureLength = 6;
-static const size_t kExifMaxDataLength = 0xFFFF - 2 - kExifSignatureLength;
-
-static const char * kPSIRSignatureString = "Photoshop 3.0\0";
-static const size_t kPSIRSignatureLength = 14;
-static const size_t kPSIRMaxDataLength = 0xFFFF - 2 - kPSIRSignatureLength;
-
-static const char * kMainXMPSignatureString = "http://ns.adobe.com/xap/1.0/\0";
-static const size_t kMainXMPSignatureLength = 29;
-
-static const char * kExtXMPSignatureString = "http://ns.adobe.com/xmp/extension/\0";
-static const size_t kExtXMPSignatureLength = 35;
-static const size_t kExtXMPPrefixLength = kExtXMPSignatureLength + 32 + 4 + 4;
-
-typedef std::map < XMP_Uns32 /* offset */, std::string /* portion */ > ExtXMPPortions;
-
-struct ExtXMPContent {
- XMP_Uns32 length;
- ExtXMPPortions portions;
- ExtXMPContent() : length(0) {};
- ExtXMPContent ( XMP_Uns32 _length ) : length(_length) {};
-};
-
-typedef std::map < JPEG_MetaHandler::GUID_32 /* guid */, ExtXMPContent /* content */ > ExtendedXMPInfo;
-
-#ifndef Trace_UnlimitedJPEG
- #define Trace_UnlimitedJPEG 0
-#endif
-
-// =================================================================================================
-// JPEG_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * JPEG_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new JPEG_MetaHandler ( parent );
-
-} // JPEG_MetaHandlerCTor
-
-// =================================================================================================
-// JPEG_CheckFormat
-// ================
-
-// For JPEG we just check for the initial SOI standalone marker followed by any of the other markers
-// that might, well, follow it. A more aggressive check might be to read 4KB then check for legit
-// marker segments within that portion. Probably won't buy much, and thrashes the dCache more. We
-// tolerate only a small amount of 0xFF padding between the SOI and following marker. This formally
-// violates the rules of JPEG, but in practice there won't be any padding anyway.
-//
-// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
-
-bool JPEG_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_JPEGFile );
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false; // We need at least 4, the buffer is filled anyway.
-
- // First look for the SOI standalone marker. Then skip all 0xFF bytes, padding plus the high
- // order byte of the next marker. Finally see if the next marker is legit.
-
- if ( ! CheckBytes ( ioBuf.ptr, "\xFF\xD8", 2 ) ) return false;
- ioBuf.ptr += 2; // Move past the SOI.
- while ( (ioBuf.ptr < ioBuf.limit) && (*ioBuf.ptr == 0xFF) ) ++ioBuf.ptr;
- if ( ioBuf.ptr == ioBuf.limit ) return false;
-
- XMP_Uns8 id = *ioBuf.ptr;
- if ( id >= 0xDD ) return true; // The most probable cases.
- if ( (id < 0xC0) || ((id & 0xF8) == 0xD0) || (id == 0xD8) || (id == 0xDA) || (id == 0xDC) ) return false;
- return true;
-
-} // JPEG_CheckFormat
-
-// =================================================================================================
-// JPEG_MetaHandler::JPEG_MetaHandler
-// ==================================
-
-JPEG_MetaHandler::JPEG_MetaHandler ( XMPFiles * _parent )
- : exifMgr(0), psirMgr(0), iptcMgr(0), skipReconcile(false)
-{
- this->parent = _parent;
- this->handlerFlags = kJPEG_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // JPEG_MetaHandler::JPEG_MetaHandler
-
-// =================================================================================================
-// JPEG_MetaHandler::~JPEG_MetaHandler
-// ===================================
-
-JPEG_MetaHandler::~JPEG_MetaHandler()
-{
-
- if ( exifMgr != 0 ) delete ( exifMgr );
- if ( psirMgr != 0 ) delete ( psirMgr );
- if ( iptcMgr != 0 ) delete ( iptcMgr );
-
-} // JPEG_MetaHandler::~JPEG_MetaHandler
-
-// =================================================================================================
-// JPEG_MetaHandler::CacheFileData
-// ===============================
-//
-// Look for the Exif metadata, Photoshop image resources, and XMP in a JPEG (JFIF) file. The native
-// thumbnail is inside the Exif. The general layout of a JPEG file is:
-// SOI marker, 2 bytes, 0xFFD8
-// Marker segments for tables and metadata
-// SOFn marker segment
-// Image data
-// EOI marker, 2 bytes, 0xFFD9
-//
-// Each marker segment begins with a 2 byte big endian marker and a 2 byte big endian length. The
-// length includes the 2 bytes of the length field but not the marker. The high order byte of a
-// marker is 0xFF, the low order byte tells what kind of marker. A marker can be preceeded by any
-// number of 0xFF fill bytes, however there are no alignment constraints.
-//
-// There are virtually no constraints on the order of the marker segments before the SOFn. A reader
-// must be prepared to handle any order.
-//
-// The Exif metadata is in an APP1 marker segment with a 6 byte signature string of "Exif\0\0" at
-// the start of the data. The rest of the data is a TIFF stream.
-//
-// The Photoshop image resources are in an APP13 marker segment with a 14 byte signature string of
-// "Photoshop 3.0\0". The rest of the data is a sequence of image resources.
-//
-// The main XMP is in an APP1 marker segment with a 29 byte signature string of
-// "http://ns.adobe.com/xap/1.0/\0". The rest of the data is the serialized XMP packet. This is the
-// only XMP if everything fits within the 64KB limit for marker segment data. If not, there will be
-// a series of XMP extension segments.
-//
-// Each XMP extension segment is an APP1 marker segment whose data contains:
-// - A 35 byte signature string of "http://ns.adobe.com/xmp/extension/\0".
-// - A 128 bit GUID stored as 32 ASCII hex digits, capital A-F, no nul termination.
-// - A 32 bit unsigned integer length for the full extended XMP serialization.
-// - A 32 bit unsigned integer offset for this portion of the extended XMP serialization.
-// - A portion of the extended XMP serialization, up to about 65400 bytes (at most 65458).
-//
-// A reader must be prepared to encounter the extended XMP portions out of order. Also to encounter
-// defective files that have differing extended XMP according to the GUID. The main XMP contains the
-// GUID for the associated extended XMP.
-
-// *** This implementation simply returns when invalid JPEG is encountered. Should we throw instead?
-
-void JPEG_MetaHandler::CacheFileData()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- size_t segLen;
- bool ok;
- IOBuffer ioBuf;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- ExtendedXMPInfo extXMP;
-
- XMP_Assert ( ! this->containsXMP );
- // Set containsXMP to true here only if the standard XMP packet is found.
-
- XMP_Assert ( kPSIRSignatureLength == (strlen(kPSIRSignatureString) + 1) );
- XMP_Assert ( kMainXMPSignatureLength == (strlen(kMainXMPSignatureString) + 1) );
- XMP_Assert ( kExtXMPSignatureLength == (strlen(kExtXMPSignatureString) + 1) );
-
- // -------------------------------------------------------------------------------------------
- // Look for any of the Exif, PSIR, main XMP, or extended XMP marker segments. Quit when we hit
- // an SOFn, EOI, or invalid/unexpected marker.
-
- LFA_Seek ( fileRef, 2, SEEK_SET ); // Skip the SOI. The JPEG header has already been verified.
- ioBuf.filePos = 2;
- RefillBuffer ( fileRef, &ioBuf );
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "JPEG_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
- }
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
-
- if ( *ioBuf.ptr != 0xFF ) return; // All valid markers have a high byte of 0xFF.
- while ( *ioBuf.ptr == 0xFF ) { // Skip padding 0xFF bytes and the marker's high byte.
- ++ioBuf.ptr;
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return;
- }
-
- XMP_Uns16 marker = 0xFF00 + *ioBuf.ptr;
-
- if ( (marker == 0xFFDA) || (marker == 0xFFD9) ) break; // Quit reading at the first SOS marker or at EOI.
-
- if ( (marker == 0xFF01) || // Ill-formed file if we encounter a TEM or RSTn marker.
- ((0xFFD0 <= marker) && (marker <= 0xFFD7)) ) return;
-
- if ( marker == 0xFFED ) {
-
- // This is an APP13 marker, is it the Photoshop image resources?
-
- ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
-
- segLen = GetUns16BE ( ioBuf.ptr );
- if ( segLen < 2 ) return; // Invalid JPEG.
-
- ioBuf.ptr += 2; // Move ioBuf.ptr to the marker segment content.
- segLen -= 2; // Adjust segLen to count just the content portion.
-
- ok = CheckFileSpace ( fileRef, &ioBuf, kPSIRSignatureLength );
- if ( ok && (segLen >= kPSIRSignatureLength) &&
- CheckBytes ( ioBuf.ptr, kPSIRSignatureString, kPSIRSignatureLength ) ) {
-
- // This is the Photoshop image resources, cache the contents.
-
- ioBuf.ptr += kPSIRSignatureLength; // Move ioBuf.ptr to the image resources.
- segLen -= kPSIRSignatureLength; // Adjust segLen to count just the image resources.
- ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
- if ( ! ok ) return; // Must be a truncated file.
-
- this->psirContents.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
- ioBuf.ptr += segLen;
-
- } else {
-
- // This is the not Photoshop image resources, skip the marker segment's content.
-
- if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
- ioBuf.ptr += segLen; // The next marker is in this buffer.
- } else {
- // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
- size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
- ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
- ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
- }
-
- }
-
- continue; // Move on to the next marker.
-
- } else if ( marker == 0xFFE1 ) {
-
- // This is an APP1 marker, is it the Exif, main XMP, or extended XMP?
- // ! Check in that order, which happens to be increasing signature string length.
-
- ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
-
- segLen = GetUns16BE ( ioBuf.ptr );
- if ( segLen < 2 ) return; // Invalid JPEG.
-
- ioBuf.ptr += 2; // Move ioBuf.ptr to the marker segment content.
- segLen -= 2; // Adjust segLen to count just the content portion.
-
- // Check for the Exif APP1 marker segment.
-
- ok = CheckFileSpace ( fileRef, &ioBuf, kExifSignatureLength );
- if ( ok && (segLen >= kExifSignatureLength) &&
- (CheckBytes ( ioBuf.ptr, kExifSignatureString, kExifSignatureLength ) ||
- CheckBytes ( ioBuf.ptr, kExifSignatureAltStr, kExifSignatureLength )) ) {
-
- // This is the Exif metadata, cache the contents.
-
- ioBuf.ptr += kExifSignatureLength; // Move ioBuf.ptr to the TIFF stream.
- segLen -= kExifSignatureLength; // Adjust segLen to count just the TIFF stream.
- ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
- if ( ! ok ) return; // Must be a truncated file.
-
- this->exifContents.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
- ioBuf.ptr += segLen;
-
- continue; // Move on to the next marker.
-
- }
-
- // Check for the main XMP APP1 marker segment.
-
- ok = CheckFileSpace ( fileRef, &ioBuf, kMainXMPSignatureLength );
- if ( ok && (segLen >= kMainXMPSignatureLength) &&
- CheckBytes ( ioBuf.ptr, kMainXMPSignatureString, kMainXMPSignatureLength ) ) {
-
- // This is the main XMP, cache the contents.
-
- ioBuf.ptr += kMainXMPSignatureLength; // Move ioBuf.ptr to the XMP Packet.
- segLen -= kMainXMPSignatureLength; // Adjust segLen to count just the XMP Packet.
- ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
- if ( ! ok ) return; // Must be a truncated file.
-
- this->packetInfo.offset = ioBuf.filePos + (ioBuf.ptr - &ioBuf.data[0]);
- this->packetInfo.length = (XMP_Int32)segLen;
- this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
- this->packetInfo.charForm = kXMP_CharUnknown;
- this->packetInfo.writeable = true;
-
- this->xmpPacket.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
- ioBuf.ptr += segLen; // ! Set this->packetInfo.offset first!
-
- this->containsXMP = true; // Found the standard XMP packet.
- continue; // Move on to the next marker.
-
- }
-
- // Check for an extension XMP APP1 marker segment.
-
- ok = CheckFileSpace ( fileRef, &ioBuf, kExtXMPPrefixLength ); // ! The signature, GUID, length, and offset.
- if ( ok && (segLen >= kExtXMPPrefixLength) &&
- CheckBytes ( ioBuf.ptr, kExtXMPSignatureString, kExtXMPSignatureLength ) ) {
-
- // This is a portion of the extended XMP, cache the contents. This is complicated by
- // the need to tolerate files where the extension portions are not in order. The
- // local ExtendedXMPInfo map uses the GUID as the key and maps that to a struct that
- // has the full length and a map of the known portions. This known portion map uses
- // the offset of the portion as the key and maps that to a string. Only fully seen
- // extended XMP streams are kept, the right one gets picked in ProcessXMP.
-
- segLen -= kExtXMPPrefixLength; // Adjust segLen to count just the XMP stream portion.
-
- ioBuf.ptr += kExtXMPSignatureLength; // Move ioBuf.ptr to the GUID.
- GUID_32 guid;
- XMP_Assert ( sizeof(guid.data) == 32 );
- memcpy ( &guid.data[0], ioBuf.ptr, sizeof(guid.data) ); // AUDIT: Use of sizeof(guid.data) is safe.
-
- ioBuf.ptr += 32; // Move ioBuf.ptr to the length and offset.
- XMP_Uns32 fullLen = GetUns32BE ( ioBuf.ptr );
- XMP_Uns32 offset = GetUns32BE ( ioBuf.ptr+4 );
-
- ioBuf.ptr += 8; // Move ioBuf.ptr to the XMP stream portion.
-
- #if Trace_UnlimitedJPEG
- printf ( "New extended XMP portion: fullLen %d, offset %d, GUID %.32s\n", fullLen, offset, guid.data );
- #endif
-
- // Find the ExtXMPContent for this GUID, and the string for this portion's offset.
-
- ExtendedXMPInfo::iterator guidPos = extXMP.find ( guid );
- if ( guidPos == extXMP.end() ) {
- ExtXMPContent newExtContent ( fullLen );
- guidPos = extXMP.insert ( extXMP.begin(), ExtendedXMPInfo::value_type ( guid, newExtContent ) );
- }
-
- ExtXMPPortions::iterator offsetPos;
- ExtXMPContent & extContent = guidPos->second;
-
- if ( extContent.portions.empty() ) {
- // When new create a full size offset 0 string, to which all in-order portions will get appended.
- offsetPos = extContent.portions.insert ( extContent.portions.begin(),
- ExtXMPPortions::value_type ( 0, std::string() ) );
- offsetPos->second.reserve ( extContent.length );
- }
-
- // Try to append this portion to a logically contiguous preceeding one.
-
- if ( offset == 0 ) {
- offsetPos = extContent.portions.begin();
- XMP_Assert ( (offsetPos->first == 0) && (offsetPos->second.size() == 0) );
- } else {
- offsetPos = extContent.portions.lower_bound ( offset );
- --offsetPos; // Back up to the portion whose offset is less than the new offset.
- if ( (offsetPos->first + offsetPos->second.size()) != offset ) {
- // Can't append, create a new portion.
- offsetPos = extContent.portions.insert ( extContent.portions.begin(),
- ExtXMPPortions::value_type ( offset, std::string() ) );
- }
- }
-
- // Cache this portion of the extended XMP.
-
- std::string & extPortion = offsetPos->second;
- ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
- if ( ! ok ) return; // Must be a truncated file.
- extPortion.append ( (XMP_StringPtr)ioBuf.ptr, segLen );
- ioBuf.ptr += segLen;
-
- continue; // Move on to the next marker.
-
- }
-
- // If we get here this is some other uninteresting APP1 marker segment, skip it.
-
- if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
- ioBuf.ptr += segLen; // The next marker is in this buffer.
- } else {
- // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
- size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
- ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
- ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
- }
-
- } else {
-
- // This is a non-terminating but uninteresting marker segment. Skip it.
-
- ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
-
- segLen = GetUns16BE ( ioBuf.ptr ); // Remember that the length includes itself.
- if ( segLen < 2 ) return; // Invalid JPEG.
-
- if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
- ioBuf.ptr += segLen; // The next marker is in this buffer.
- } else {
- // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
- size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
- ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
- ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
- }
-
- continue; // Move on to the next marker.
-
- }
-
- }
-
- if ( ! extXMP.empty() ) {
-
- // We have extended XMP. Find out which ones are complete, collapse them into a single
- // string, and save them for ProcessXMP.
-
- ExtendedXMPInfo::iterator guidPos = extXMP.begin();
- ExtendedXMPInfo::iterator guidEnd = extXMP.end();
-
- for ( ; guidPos != guidEnd; ++guidPos ) {
-
- ExtXMPContent & thisContent = guidPos->second;
- ExtXMPPortions::iterator partZero = thisContent.portions.begin();
- ExtXMPPortions::iterator partEnd = thisContent.portions.end();
- ExtXMPPortions::iterator partPos = partZero;
-
- #if Trace_UnlimitedJPEG
- printf ( "Extended XMP portions for GUID %.32s, full length %d\n",
- guidPos->first.data, guidPos->second.length );
- printf ( " Offset %d, length %d, next offset %d\n",
- partZero->first, partZero->second.size(), (partZero->first + partZero->second.size()) );
- #endif
-
- for ( ++partPos; partPos != partEnd; ++partPos ) {
- #if Trace_UnlimitedJPEG
- printf ( " Offset %d, length %d, next offset %d\n",
- partPos->first, partPos->second.size(), (partPos->first + partPos->second.size()) );
- #endif
- if ( partPos->first != partZero->second.size() ) break; // Quit if not contiguous.
- partZero->second.append ( partPos->second );
- }
-
- if ( (partPos == partEnd) && (partZero->first == 0) && (partZero->second.size() == thisContent.length) ) {
- // This is a complete extended XMP stream.
- this->extendedXMP.insert ( ExtendedXMPMap::value_type ( guidPos->first, partZero->second ) );
- #if Trace_UnlimitedJPEG
- printf ( "Full extended XMP for GUID %.32s, full length %d\n",
- guidPos->first.data, partZero->second.size() );
- #endif
- }
-
- }
-
- }
-
-} // JPEG_MetaHandler::CacheFileData
-
-// =================================================================================================
-// TrimFullExifAPP1
-// ================
-//
-// Try to trim trailing padding from full Exif APP1 segment written by some Nikon cameras. Do a
-// temporary read-only parse of the Exif APP1 contents, determine the highest used offset, trim the
-// padding if all zero bytes.
-
-static const char * IFDNames[] = { "Primary", "TNail", "Exif", "GPS", "Interop", };
-
-static void TrimFullExifAPP1 ( std::string * exifContents )
-{
- TIFF_MemoryReader tempMgr;
- TIFF_MemoryReader::TagInfo tagInfo;
- bool tagFound, isNikon;
-
- // ! Make a copy of the data to parse! The RO memory TIFF manager will flip bytes in-place!
- tempMgr.ParseMemoryStream ( exifContents->data(), (XMP_Uns32)exifContents->size(), true /* copy data */ );
-
- // Only trim the Exif APP1 from Nikon cameras.
- tagFound = tempMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_Make, &tagInfo );
- isNikon = tagFound && (tagInfo.type == kTIFF_ASCIIType) && (tagInfo.count >= 5) &&
- (memcmp ( tagInfo.dataPtr, "NIKON", 5) == 0);
- if ( ! isNikon ) return;
-
- // Determine the highest used offset (actually 1 beyond that). Look at the IFD structure, and
- // the thumbnail info. Ignore the MakerNote tag, Nikon says they are self-contained.
-
- XMP_Uns32 maxOffset = 0;
-
- for ( XMP_Uns8 ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- TIFF_MemoryReader::TagInfoMap tagMap;
- bool ifdFound = tempMgr.GetIFD ( ifd, &tagMap );
- if ( ! ifdFound ) continue;
-
- TIFF_MemoryReader::TagInfoMap::const_iterator mapPos = tagMap.begin();
- TIFF_MemoryReader::TagInfoMap::const_iterator mapEnd = tagMap.end();
-
- for ( ; mapPos != mapEnd; ++mapPos ) {
- const TIFF_MemoryReader::TagInfo & tagInfo = mapPos->second;
- XMP_Uns32 tagEnd = tempMgr.GetValueOffset ( ifd, tagInfo.id ) + tagInfo.dataLen;
- if ( tagEnd > maxOffset ) maxOffset = tagEnd;
- }
-
- }
-
- tagFound = tempMgr.GetTag ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat, &tagInfo );
- if ( tagFound ) {
- XMP_Uns32 tnailOffset = tempMgr.GetUns32 ( tagInfo.dataPtr );
- tagFound = tempMgr.GetTag ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormatLength, &tagInfo );
- if ( ! tagFound ) return; // Don't trim if there is a TNail offset but no length.
- tnailOffset += tempMgr.GetUns32 ( tagInfo.dataPtr );
- if ( tnailOffset > maxOffset ) maxOffset = tnailOffset;
- }
-
- if ( maxOffset >= exifContents->size() ) return; // Sanity check for in bounds maximum offset.
-
- for ( size_t i = maxOffset, limit = exifContents->size(); i < limit; ++i ) {
- if ( (*exifContents)[i] != 0 ) return; // Don't trim if unless the trailer is all zero.
- }
-
- exifContents->erase ( maxOffset );
-
-} // TrimFullExifAPP1
-
-// =================================================================================================
-// JPEG_MetaHandler::ProcessXMP
-// ============================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-
-void JPEG_MetaHandler::ProcessXMP()
-{
-
- XMP_Assert ( ! this->processedXMP );
- this->processedXMP = true; // Make sure we only come through here once.
-
- // Create the PSIR and IPTC handlers, even if there is no legacy. They might be needed for updates.
-
- XMP_Assert ( (this->psirMgr == 0) && (this->iptcMgr == 0) ); // ProcessTNail might create the exifMgr.
-
- bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
-
- if ( readOnly ) {
- if ( this->exifMgr == 0 ) this->exifMgr = new TIFF_MemoryReader();
- this->psirMgr = new PSIR_MemoryReader();
- this->iptcMgr = new IPTC_Reader(); // ! Parse it later.
- } else {
- if ( this->exifContents.size() == (65534 - 2 - 6) ) TrimFullExifAPP1 ( &this->exifContents );
- if ( this->exifMgr == 0 ) this->exifMgr = new TIFF_FileWriter();
- this->psirMgr = new PSIR_FileWriter();
- this->iptcMgr = new IPTC_Writer(); // ! Parse it later.
- }
-
- // 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.
-
- TIFF_Manager & exif = *this->exifMgr; // Give the compiler help in recognizing non-aliases.
- PSIR_Manager & psir = *this->psirMgr;
- IPTC_Manager & iptc = *this->iptcMgr;
-
- bool haveExif = (! this->exifContents.empty());
- if ( haveExif ) {
- exif.ParseMemoryStream ( this->exifContents.c_str(), (XMP_Uns32)this->exifContents.size() );
- }
-
- bool havePSIR = (! this->psirContents.empty());
- if ( havePSIR ) {
- psir.ParseMemoryResources ( this->psirContents.c_str(), (XMP_Uns32)this->psirContents.size() );
- }
-
- PSIR_Manager::ImgRsrcInfo iptcInfo;
- bool haveIPTC = false;
- if ( havePSIR ) haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );;
- int iptcDigestState = kDigestMatches;
-
- if ( haveIPTC ) {
-
- bool haveDigest = false;
- PSIR_Manager::ImgRsrcInfo digestInfo;
- if ( havePSIR ) haveDigest = psir.GetImgRsrc ( kPSIR_IPTCDigest, &digestInfo );
- if ( digestInfo.dataLen != 16 ) haveDigest = false;
-
- if ( ! haveDigest ) {
- iptcDigestState = kDigestMissing;
- } else {
- iptcDigestState = PhotoDataUtils::CheckIPTCDigest ( iptcInfo.dataPtr, iptcInfo.dataLen, digestInfo.dataPtr );
- }
-
- }
-
- XMP_OptionBits options = 0;
- if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
- if ( haveExif ) options |= k2XMP_FileHadExif;
- if ( haveIPTC ) options |= k2XMP_FileHadIPTC;
-
- // Process the main XMP packet. If it fails to parse, do a forced legacy import but still throw
- // an exception. This tells the caller that an error happened, but gives them recovered legacy
- // should they want to proceed with that.
-
- bool haveXMP = false;
-
- if ( ! this->xmpPacket.empty() ) {
- XMP_Assert ( this->containsXMP );
- // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
- try {
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
- haveXMP = true;
- } catch ( ... ) {
- XMP_ClearOption ( options, k2XMP_FileHadXMP );
- if ( haveIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- if ( iptcDigestState == kDigestMatches ) iptcDigestState = kDigestMissing;
- ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
- throw; // ! Rethrow the exception, don't absorb it.
- }
- }
-
- // Process the extended XMP if it has a matching GUID.
-
- if ( ! this->extendedXMP.empty() ) {
-
- bool found;
- GUID_32 g32;
- std::string extGUID, extPacket;
- ExtendedXMPMap::iterator guidPos = this->extendedXMP.end();
-
- found = this->xmpObj.GetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", &extGUID, 0 );
- if ( found && (extGUID.size() == sizeof(g32.data)) ) {
- XMP_Assert ( sizeof(g32.data) == 32 );
- memcpy ( g32.data, extGUID.c_str(), sizeof(g32.data) ); // AUDIT: Use of sizeof(g32.data) is safe.
- guidPos = this->extendedXMP.find ( g32 );
- this->xmpObj.DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" ); // ! Must only be in the file.
- #if Trace_UnlimitedJPEG
- printf ( "%s extended XMP for GUID %s\n",
- ((guidPos != this->extendedXMP.end()) ? "Found" : "Missing"), extGUID.c_str() );
- #endif
- }
-
- if ( guidPos != this->extendedXMP.end() ) {
- try {
- XMP_StringPtr extStr = guidPos->second.c_str();
- XMP_StringLen extLen = (XMP_StringLen)guidPos->second.size();
- SXMPMeta extXMP ( extStr, extLen );
- SXMPUtils::MergeFromJPEG ( &this->xmpObj, extXMP );
- } catch ( ... ) {
- // Ignore failures, let the rest of the XMP and legacy be kept.
- }
- }
-
- }
-
- // Process the legacy metadata.
-
- if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
-
- this->containsXMP = true; // Assume we had something for the XMP.
-
-} // JPEG_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// JPEG_MetaHandler::UpdateFile
-// ============================
-
-void JPEG_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
-
- XMP_Int64 oldPacketOffset = this->packetInfo.offset;
- XMP_Int32 oldPacketLength = this->packetInfo.length;
-
- if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
- if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
-
- bool fileHadXMP = ((oldPacketOffset != 0) && (oldPacketLength != 0));
-
- // Update the IPTC-IIM and native TIFF/Exif metadata. ExportPhotoData also trips the tiff: and
- // exif: copies from the XMP, so reserialize the now final XMP packet.
-
- ExportPhotoData ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->iptcMgr, this->psirMgr );
-
- try {
- XMP_OptionBits options = kXMP_UseCompactFormat;
- if ( fileHadXMP ) options |= kXMP_ExactPacketLength;
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, options, oldPacketLength );
- } catch ( ... ) {
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- // Decide whether to do an in-place update. This can only happen if all of the following are true:
- // - There is a standard packet in the file.
- // - There is no extended XMP in the file.
- // - The are no changes to the legacy Exif or PSIR portions. (The IPTC is in the PSIR.)
- // - The new XMP can fit in the old space, without extensions.
-
- bool doInPlace = (fileHadXMP && (this->xmpPacket.size() <= (size_t)oldPacketLength));
-
- if ( ! this->extendedXMP.empty() ) doInPlace = false;
-
- if ( (this->exifMgr != 0) && (this->exifMgr->IsLegacyChanged()) ) doInPlace = false;
- if ( (this->psirMgr != 0) && (this->psirMgr->IsLegacyChanged()) ) doInPlace = false;
-
- if ( doInPlace ) {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", JPEG in-place update";
- #endif
-
- if ( this->xmpPacket.size() < (size_t)this->packetInfo.length ) {
- // They ought to match, cheap to be sure.
- size_t extraSpace = (size_t)this->packetInfo.length - this->xmpPacket.size();
- this->xmpPacket.append ( extraSpace, ' ' );
- }
-
- LFA_FileRef liveFile = this->parent->fileRef;
- std::string & newPacket = this->xmpPacket;
-
- XMP_Assert ( newPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
-
- LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
- LFA_Write ( liveFile, newPacket.c_str(), (XMP_Int32)newPacket.size() );
-
- } else {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", JPEG copy update";
- #endif
-
- std::string origPath = this->parent->filePath;
- LFA_FileRef origRef = this->parent->fileRef;
-
- std::string updatePath;
- LFA_FileRef updateRef = 0;
-
- CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
-
- this->parent->filePath = updatePath;
- this->parent->fileRef = updateRef;
-
- try {
- XMP_Assert ( ! this->skipReconcile );
- this->skipReconcile = true;
- this->WriteFile ( origRef, origPath );
- this->skipReconcile = false;
- } catch ( ... ) {
- this->skipReconcile = false;
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = origRef;
- throw;
- }
-
- LFA_Close ( origRef );
- LFA_Delete ( origPath.c_str() );
-
- LFA_Close ( updateRef );
- LFA_Rename ( updatePath.c_str(), origPath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = 0;
-
- }
-
- this->needsUpdate = false;
-
-} // JPEG_MetaHandler::UpdateFile
-
-// =================================================================================================
-// JPEG_MetaHandler::WriteFile
-// ===========================
-//
-// The metadata parts of a JPEG file are APP1 marker segments for Exif and XMP, and an APP13 marker
-// segment for Photoshop image resources which contain the IPTC. Corresponding marker segments in
-// the source file are ignored, other parts of the source file are copied. Any initial APP0 marker
-// segments are copied first. Then the new Exif, XMP, and PSIR marker segments are written. Then the
-// rest of the file is copied, skipping the old Exif, XMP, and PSIR. The checking for old metadata
-// stops at the first SOFn marker.
-
-// *** What about Mac resources?
-
-void JPEG_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- LFA_FileRef destRef = this->parent->fileRef;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- XMP_Uns16 marker;
- size_t segLen; // ! Must be a size to hold at least 64k+2.
- IOBuffer ioBuf;
- XMP_Uns32 first4;
-
- XMP_Assert ( kIOBufferSize >= (2 + 64*1024) ); // Enough for a marker plus maximum contents.
-
- if ( LFA_Measure ( sourceRef ) == 0 ) return; // Tolerate empty files.
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Truncate (destRef, 0 );
-
- if ( ! skipReconcile ) {
- // Update the IPTC-IIM and native TIFF/Exif metadata, and reserialize the now final XMP packet.
- ExportPhotoData ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->iptcMgr, this->psirMgr );
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- RefillBuffer ( sourceRef, &ioBuf );
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) {
- XMP_Throw ( "JPEG must have at least SOI and EOI markers", kXMPErr_BadJPEG );
- }
-
- marker = GetUns16BE ( ioBuf.ptr );
- if ( marker != 0xFFD8 ) XMP_Throw ( "Missing SOI marker", kXMPErr_BadJPEG );
- LFA_Write ( destRef, ioBuf.ptr, 2 );
- ioBuf.ptr += 2;
-
- // Copy the leading APP0 marker segments.
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
- }
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
- marker = GetUns16BE ( ioBuf.ptr );
- if ( marker == 0xFFFF ) {
- LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte.
- ++ioBuf.ptr;
- continue;
- }
-
- if ( marker != 0xFFE0 ) break;
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
- segLen = GetUns16BE ( ioBuf.ptr+2 );
- segLen += 2; // ! Don't do above in case machine does 16 bit "+".
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
- LFA_Write ( destRef, ioBuf.ptr, (XMP_Int32)segLen );
- ioBuf.ptr += segLen;
-
- }
-
- // Write the new Exif APP1 marker segment.
-
- if ( this->exifMgr != 0 ) {
-
- 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 );
-
- if ( exifLen > 0 ) {
- first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + exifLen );
- LFA_Write ( destRef, &first4, 4 );
- LFA_Write ( destRef, kExifSignatureString, kExifSignatureLength );
- LFA_Write ( destRef, exifPtr, exifLen );
- }
-
- }
-
- // Write the new XMP APP1 marker segment, with possible extension marker segments.
-
- std::string mainXMP, extXMP, extDigest;
- SXMPUtils::PackageForJPEG ( this->xmpObj, &mainXMP, &extXMP, &extDigest );
- XMP_Assert ( (extXMP.size() == 0) || (extDigest.size() == 32) );
-
- first4 = MakeUns32BE ( 0xFFE10000 + 2 + kMainXMPSignatureLength + (XMP_Uns32)mainXMP.size() );
- LFA_Write ( destRef, &first4, 4 );
- LFA_Write ( destRef, kMainXMPSignatureString, kMainXMPSignatureLength );
- LFA_Write ( destRef, mainXMP.c_str(), (XMP_Int32)mainXMP.size() );
-
- size_t extPos = 0;
- size_t extLen = extXMP.size();
-
- while ( extLen > 0 ) {
-
- size_t partLen = extLen;
- if ( partLen > 65000 ) partLen = 65000;
-
- first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExtXMPPrefixLength + (XMP_Uns32)partLen );
- LFA_Write ( destRef, &first4, 4 );
-
- LFA_Write ( destRef, kExtXMPSignatureString, kExtXMPSignatureLength );
- LFA_Write ( destRef, extDigest.c_str(), (XMP_Int32)extDigest.size() );
-
- first4 = MakeUns32BE ( (XMP_Int32)extXMP.size() );
- LFA_Write ( destRef, &first4, 4 );
- first4 = MakeUns32BE ( (XMP_Int32)extPos );
- LFA_Write ( destRef, &first4, 4 );
-
- LFA_Write ( destRef, &extXMP[extPos], (XMP_Int32)partLen );
-
- extPos += partLen;
- extLen -= partLen;
-
- }
-
- // Write the new PSIR APP13 marker segment.
-
- 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 );
- LFA_Write ( destRef, &first4, 4 );
- LFA_Write ( destRef, kPSIRSignatureString, kPSIRSignatureLength );
- LFA_Write ( destRef, psirPtr, psirLen );
- }
-
- }
-
- // Copy remaining marker segments, skipping old metadata, to the first SOS marker or to EOI.
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
- }
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
- marker = GetUns16BE ( ioBuf.ptr );
- if ( marker == 0xFFFF ) {
- LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte.
- ++ioBuf.ptr;
- continue;
- }
-
- if ( (marker == 0xFFDA) || (marker == 0xFFD9) ) break; // Quit at the first SOS marker or at EOI.
-
- if ( (marker == 0xFF01) || // Ill-formed file if we encounter a TEM or RSTn marker.
- ((0xFFD0 <= marker) && (marker <= 0xFFD7)) ) {
- XMP_Throw ( "Unexpected TEM or RSTn marker", kXMPErr_BadJPEG );
- }
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
- segLen = GetUns16BE ( ioBuf.ptr+2 );
-
- if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2+segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
-
- bool copySegment = true;
- XMP_Uns8* signaturePtr = ioBuf.ptr + 4;
-
- if ( marker == 0xFFED ) {
- if ( (segLen >= kPSIRSignatureLength) &&
- CheckBytes ( signaturePtr, kPSIRSignatureString, kPSIRSignatureLength ) ) {
- copySegment = false;
- }
- } else if ( marker == 0xFFE1 ) {
- if ( (segLen >= kExifSignatureLength) &&
- (CheckBytes ( signaturePtr, kExifSignatureString, kExifSignatureLength ) ||
- CheckBytes ( signaturePtr, kExifSignatureAltStr, kExifSignatureLength )) ) {
- copySegment = false;
- } else if ( (segLen >= kMainXMPSignatureLength) &&
- CheckBytes ( signaturePtr, kMainXMPSignatureString, kMainXMPSignatureLength ) ) {
- copySegment = false;
- } else if ( (segLen >= kExtXMPPrefixLength) &&
- CheckBytes ( signaturePtr, kExtXMPSignatureString, kExtXMPSignatureLength ) ) {
- copySegment = false;
- }
- }
-
- if ( copySegment ) LFA_Write ( destRef, ioBuf.ptr, (XMP_Int32)(2+segLen) );
-
- ioBuf.ptr += 2+segLen;
-
- }
-
- // Copy the remainder of the source file.
-
- size_t bufTail = ioBuf.len - (ioBuf.ptr - &ioBuf.data[0]);
- LFA_Write ( destRef, ioBuf.ptr, (XMP_Int32)bufTail );
- ioBuf.ptr += bufTail;
-
- while ( true ) {
- RefillBuffer ( sourceRef, &ioBuf );
- if ( ioBuf.len == 0 ) break;
- LFA_Write ( destRef, ioBuf.ptr, (XMP_Int32)ioBuf.len );
- ioBuf.ptr += ioBuf.len;
- }
-
- this->needsUpdate = false;
-
-} // JPEG_MetaHandler::WriteFile
diff --git a/source/XMPFiles/FileHandlers/JPEG_Handler.hpp b/source/XMPFiles/FileHandlers/JPEG_Handler.hpp
deleted file mode 100644
index 650a5b5..0000000
--- a/source/XMPFiles/FileHandlers/JPEG_Handler.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef __JPEG_Handler_hpp__
-#define __JPEG_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-
-// =================================================================================================
-/// \file JPEG_Handler.hpp
-/// \brief File format handler for JPEG.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler * JPEG_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool JPEG_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kJPEG_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate);
-
-class JPEG_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- struct GUID_32 { // A hack to get an assignment operator for an array.
- char data [32];
- void operator= ( const GUID_32 & in )
- {
- memcpy ( this->data, in.data, sizeof(this->data) ); // AUDIT: Use of sizeof(this->data) is safe.
- };
- bool operator< ( const GUID_32 & right ) const
- {
- return (memcmp ( this->data, right.data, sizeof(this->data) ) < 0);
- };
- bool operator== ( const GUID_32 & right ) const
- {
- return (memcmp ( this->data, right.data, sizeof(this->data) ) == 0);
- };
- };
-
- JPEG_MetaHandler ( XMPFiles * parent );
- virtual ~JPEG_MetaHandler();
-
-private:
-
- JPEG_MetaHandler() : exifMgr(0), psirMgr(0), iptcMgr(0), skipReconcile(false) {}; // Hidden on purpose.
-
- std::string exifContents;
- std::string psirContents;
-
- TIFF_Manager * exifMgr; // The Exif manager will be created by ProcessTNail or ProcessXMP.
- PSIR_Manager * psirMgr; // Need to use pointers so we can properly select between read-only and
- IPTC_Manager * iptcMgr; // read-write modes of usage.
-
- bool skipReconcile; // ! Used between UpdateFile and WriteFile.
-
- typedef std::map < GUID_32, std::string > ExtendedXMPMap;
-
- ExtendedXMPMap extendedXMP; // ! Only contains those with complete data.
-
-}; // JPEG_MetaHandler
-
-// =================================================================================================
-
-#endif /* __JPEG_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MP3_Handler.cpp b/source/XMPFiles/FileHandlers/MP3_Handler.cpp
deleted file mode 100644
index 2c8f547..0000000
--- a/source/XMPFiles/FileHandlers/MP3_Handler.cpp
+++ /dev/null
@@ -1,748 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include "MP3_Handler.hpp"
-
-// =================================================================================================
-/// \file MP3_Handler.cpp
-/// \brief MP3 handler class.
-// =================================================================================================
-
-// =================================================================================================
-// Helper structs and private routines
-// ====================
-struct ReconProps {
- const char* frameID;
- const char* ns;
- const char* prop;
-};
-
-const static XMP_Uns32 XMP_FRAME_ID = 0x50524956;
-
-const static ReconProps reconProps[] = {
- { "TPE1", kXMP_NS_DM, "artist" },
- { "TALB", kXMP_NS_DM, "album" },
- { "TRCK", kXMP_NS_DM, "trackNumber" },
- // exceptions that need attention:
- { "TCON", kXMP_NS_DM, "genre" }, // genres might be numeric
- { "TIT2", kXMP_NS_DC, "title" }, // ["x-default"] language alternatives
- { "COMM", kXMP_NS_DM, "logComment" }, // two distinct strings, language alternative
-
- { "TYER", kXMP_NS_XMP, "CreateDate" }, // Year (YYYY) Deprecated since 2.4
- { "TDAT", kXMP_NS_XMP, "CreateDate" }, // Date (DDMM) Deprecated since 2.4
- { "TIME", kXMP_NS_XMP, "CreateDate" }, // Time (HHMM) Deprecated since 2.4
- { "TDRC", kXMP_NS_XMP, "CreateDate" }, // assemble date/time v2.4
-
- // new reconciliations introduced in Version 5
- { "TCMP", kXMP_NS_DM, "partOfCompilation" }, // presence/absence of TCMP frame dedides
- { "USLT", kXMP_NS_DM, "lyrics" },
- { "TCOM", kXMP_NS_DM, "composer" },
- { "TPOS", kXMP_NS_DM, "discNumber" }, // * a text field! might contain "/<total>"
- { "TCOP", kXMP_NS_DC, "rights" }, // ["x-default"] language alternatives
- { "TPE4", kXMP_NS_DM, "engineer" },
- { "WCOP", kXMP_NS_XMP_Rights , "WebStatement" },
-
- { 0, 0, 0 } // must be last as a sentinel
-};
-
-// =================================================================================================
-// MP3_MetaHandlerCTor
-// ====================
-XMPFileHandler * MP3_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new MP3_MetaHandler ( parent );
-}
-
-// =================================================================================================
-// MP3_CheckFormat
-// ===============
-// For MP3 we check parts .... See the MP3 spec for offset info.
-bool MP3_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef file,
- XMPFiles * parent )
-{
- IgnoreParam(filePath); IgnoreParam(parent); //supress warnings
- XMP_Assert ( format == kXMP_MP3File ); //standard assert
- LFA_Rewind( file );
-
- XMP_Uns8 header[3];
- LFA_Read( file, header, 3, true );
- if ( !CheckBytes( &header[0], "ID3", 3 ))
- return (parent->format == kXMP_MP3File); // No ID3 signature -> depend on first call hint.
-
- XMP_Uns8 major = LFA_ReadUns8( file );
- XMP_Uns8 minor = LFA_ReadUns8( file );
-
- if ( (major<3 || major>4) || (minor == 0xFF) )
- return false; // only support IDv2.3 and ID3v2.4, minor must not be 0xFF
-
- XMP_Uns8 flags = LFA_ReadUns8( file );
-
- //TODO
- if ( flags & 0x10 )
- XMP_Throw("no support for MP3 with footer",kXMPErr_Unimplemented); //no support for MP3 with footer
- if ( flags & 0x80 )
- return false; //no support for unsynchronized MP3 (as before, also see [1219125])
- if ( flags & 0x0F )
- XMP_Throw("illegal header lower bits",kXMPErr_Unimplemented);
-
- XMP_Uns32 size = LFA_ReadUns32_BE( file );
- if ( size & 0x80808080 ) return false; //if any bit survives -> not a valid synchsafe 32 bit integer
-
- return true;
-} // MP3_CheckFormat
-
-
-// =================================================================================================
-// MP3_MetaHandler::MP3_MetaHandler
-// ================================
-
-MP3_MetaHandler::MP3_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kMP3_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-}
-
-// =================================================================================================
-// MP3_MetaHandler::~MP3_MetaHandler
-// =================================
-
-MP3_MetaHandler::~MP3_MetaHandler()
-{
- // free frames
- ID3v2Frame* curFrame;
- while( !this->framesVector.empty() )
- {
- curFrame = this->framesVector.back();
- delete curFrame;
- framesVector.pop_back();
- }
-}
-
-// =================================================================================================
-// MP3_MetaHandler::CacheFileData
-// ==============================
-void MP3_MetaHandler::CacheFileData()
-{
- //*** abort procedures
- this->containsXMP = false; //assume no XMP for now
-
- LFA_FileRef file = this->parent->fileRef;
- XMP_PacketInfo &packetInfo = this->packetInfo;
-
- LFA_Rewind(file);
-
- hasID3Tag = id3Header.read( file );
- majorVersion = id3Header.fields[ID3Header::o_version_major];
- minorVersion = id3Header.fields[ID3Header::o_version_minor];
- hasExtHeader = (0 != ( 0x40 & id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag
- hasFooter = ( 0 != ( 0x10 & id3Header.fields[ID3Header::o_flags])); //'naturally' false if no ID3Tag
-
- // stored size is w/o initial header (thus adding 10)
- // + but extended header (if existing)
- // + padding + frames after unsynchronisation (?)
- // (if no ID3 tag existing, constructed default correctly sets size to 10.)
- oldTagSize = 10 + synchToInt32(GetUns32BE( &id3Header.fields[ID3Header::o_size] ));
-
- if (hasExtHeader)
- {
- extHeaderSize = synchToInt32( LFA_ReadInt32_BE( file));
- XMP_Uns8 extHeaderNumFlagBytes = LFA_ReadUns8( file );
-
- // v2.3 doesn't include the size, while v2.4 does
- if ( majorVersion < 4 ) extHeaderSize += 4;
- XMP_Validate( extHeaderSize >= 6, "extHeader size too small", kXMPErr_BadFileFormat );
-
- bool ok;
- LFA_Seek(file, extHeaderSize - 6, SEEK_CUR , &ok);
- XMP_Assert(ok);
- }
- else
- {
- extHeaderSize = 0; // := there is no such header.
- }
-
- this->framesVector.clear(); //mac precaution
- ID3v2Frame* curFrame = 0; // reusable
-
- ////////////////////////////////////////////////////
- // read frames
- while ( LFA_Tell(file) < oldTagSize )
- {
- curFrame = new ID3v2Frame();
-
- try {
- XMP_Int64 frameSize = curFrame->read( file, majorVersion );
- if (frameSize == 0) // no more frames coming => proceed to padding
- {
- delete curFrame; // ..since not becoming part of vector for latter delete.
- break; // not a throw. There's nothing wrong with padding.
- }
- this->containsXMP = true;
- } catch( XMP_Error e)
- {
- delete curFrame;
- XMP_Throw( e.GetErrMsg(), e.GetID()); // rethrow
- }
-
- // these are both pointer assignments, no (copy) construction
- // (MemLeak Note: for all things pushed, memory cleanup is taken care of in destructor.)
- this->framesVector.push_back( curFrame );
-
- //remember XMP-Frame, if it occurs:
- if ( CheckBytes( &curFrame->fields[ID3v2Frame::o_id], "PRIV", 4 ))
- if( curFrame->contentSize > 8 ) // to avoid adress violation on very small non-XMP PRIV frames
- if( CheckBytes( &curFrame->content[0], "XMP\0", 4 ))
- {
- // be sure that this is the first packet (all else would be illegal format)
- XMP_Validate( framesMap[ XMP_FRAME_ID] == 0, "two XMP packets in one file", kXMPErr_BadFileFormat );
- //add this to map, needed on reconciliation
- framesMap[ XMP_FRAME_ID ] = curFrame;
-
- this->packetInfo.length = curFrame->contentSize - 4; // content minus "XMP\0"
- this->packetInfo.offset = ( LFA_Tell(file) - this->packetInfo.length );
-
- this->xmpPacket.erase(); //safety
- this->xmpPacket.assign( &curFrame->content[4], curFrame->contentSize - 4 );
- this->containsXMP = true; // do this last, after all possible failure
- }
-
- // No space for another frame? => assume into ID3v2.4 padding.
- if ( LFA_Tell(file) + 10 >= oldTagSize )
- break;
- }
-
- ////////////////////////////////////////////////////
- // padding
- oldPadding = oldTagSize - LFA_Tell( file );
- oldFramesSize = oldTagSize - 10 - oldPadding;
-
- XMP_Validate( oldPadding >= 0, "illegal oldTagSize or padding value", kXMPErr_BadFileFormat );
-
- for ( XMP_Int64 i = oldPadding; i > 0;)
- {
- if ( i >= 8 ) // worthwhile optimization
- {
- if ( LFA_ReadInt64_BE(file) != 0 )
- XMP_Throw ( "padding not nulled out.", kXMPErr_BadFileFormat );
- i -= 8;
- continue;
- }
- if ( LFA_ReadUns8(file) != 0)
- XMP_Throw ( "padding(2) not nulled out.", kXMPErr_BadFileFormat );
- i--;
- }
-
- //// read ID3v1 tag
- if ( ! this->containsXMP ) // all else has priority
- {
- this->containsXMP = id3v1Tag.read( file, &this->xmpObj );
- }
-
-} // MP3_MetaHandler::CacheFileData
-
-
-// =================================================================================================
-// MP3_MetaHandler::ProcessXMP
-// ===========================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-void MP3_MetaHandler::ProcessXMP()
-{
- // Process the XMP packet.
- if ( ! this->xmpPacket.empty() ) {
- XMP_Assert ( this->containsXMP );
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen) this->xmpPacket.size();
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
- this->processedXMP = true;
- }
-
- ///////////////////////////////////////////////////////////////////
- // assumptions on presence-absence "flag tags"
- // ( unless no xmp whatsoever present )
- if ( ! this->xmpPacket.empty() ) {
- this->xmpObj.SetProperty( kXMP_NS_DM, "partOfCompilation", "false" );
- }
-
- ////////////////////////////////////////////////////////////////////
- // import of legacy properties
- ID3v2Frame* curFrame;
- XMP_Bool hasTDRC = false;
- XMP_DateTime newDateTime;
-
- if (this->hasID3Tag) // otherwise pretty pointless...
- for (int r=0; reconProps[r].frameID != 0; r++)
- {
- //get the frame ID to look for
- XMP_Uns32 frameID = GetUns32BE( reconProps[r].frameID );
-
- // deal with each such frame in the frameVector
- // (since there might be several, some of them not applicable, i.e. COMM)
- for ( vector<ID3_Support::ID3v2Frame*>::iterator it = framesVector.begin(); it!=framesVector.end(); ++it)
- {
- curFrame = *it;
- if (frameID != curFrame->id) // nothing applicable. Next!
- continue;
-
- // go deal with it!
- // get the property
- std::string utf8string;
- bool result = curFrame->getFrameValue(majorVersion, frameID, &utf8string);
-
- if (! result)
- continue; //ignore but preserve this frame (i.e. not applicable COMM frame)
-
- //////////////////////////////////////////////////////////////////////////////////
- // if we come as far as here, it's proven that there's a relevant XMP property
- this->containsXMP = true;
-
- ID3_Support::ID3v2Frame* t = framesMap[ frameID ];
- if ( t != 0 ) // an (earlier, relevant) frame?
- t->active = false;
-
- // add this to map (needed on reconciliation)
- // note: above code reaches, that COMM/USLT frames
- // only then reach this map, if they are 'eng'(lish)
- // multiple occurences indeed leads to last one survives
- // ( in this map, all survive in the file )
- framesMap[ frameID ] = curFrame;
-
- // now write away as needed;
- // merely based on existence, relevant even if empty:
- if ( frameID == 0x54434D50) // TCMP if exists: part of compilation
- {
- this->xmpObj.SetProperty( kXMP_NS_DM, "partOfCompilation", "true" );
- } else if ( ! utf8string.empty() )
- switch( frameID )
- {
- case 0x54495432: // TIT2 -> title["x-default"]
- case 0x54434F50: // TCOP -> rights["x-default"]
- this->xmpObj.SetLocalizedText( reconProps[r].ns , reconProps[r].prop,"" , "x-default" , utf8string );
- break;
- case 0x54434F4E: // TCON -> genre ( might be numeric string. prior to 2.3 a one-byte numeric value? )
- {
- XMP_Int32 pos = 0; // going through input string
- if ( utf8string[pos] == '(' ) { // number in brackets?
- pos++;
- XMP_Uns8 iGenre = (XMP_Uns8) atoi( &utf8string.c_str()[1] );
- if ( (iGenre > 0) && (iGenre < 127) ) {
- utf8string.assign( Genres[iGenre] );
- } else {
- utf8string.assign( Genres[12] ); // "Other"
- }
- } else {
- // Text, let's "try" to find it anyway (for best upper/lower casing)
- int i;
- const char* genreCString = utf8string.c_str();
- for ( i=0; i < 127; ++i ) {
- if (
- (strlen( genreCString ) == strlen(Genres[i])) && //fixing buggy stricmp behaviour on PPC
- (stricmp( genreCString, Genres[i] ) == 0 )) {
- utf8string.assign( Genres[i] ); // found, let's use the one in the list
- break;
- }
- }
- // otherwise (if for-loop runs through): leave as is
- }
- // write out property (derived or direct, but certainly non-numeric)
- this->xmpObj.SetProperty( reconProps[r].ns, reconProps[r].prop, utf8string );
- }
- break;
- case 0x54594552: // TYER -> xmp:CreateDate.year
- {
- try { // Don't let wrong dates in id3 stop import.
- if ( !hasTDRC )
- {
- newDateTime.year = SXMPUtils::ConvertToInt( utf8string );
- newDateTime.hasDate = true;
- }
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- }
- break;
- }
- case 0x54444154: //TDAT -> xmp:CreateDate.month and day
- {
- try { // Don't let wrong dates in id3 stop import.
- // only if no TDRC has been found before
- //&& must have the format DDMM
- if ( !hasTDRC && utf8string.length() == 4 )
- {
- newDateTime.day = SXMPUtils::ConvertToInt(utf8string.substr(0,2));
- newDateTime.month = SXMPUtils::ConvertToInt( utf8string.substr(2,2));
- newDateTime.hasDate = true;
- }
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- }
- break;
- }
- case 0x54494D45: //TIME -> xmp:CreateDate.hours and minutes
- {
- try { // Don't let wrong dates in id3 stop import.
- // only if no TDRC has been found before
- // && must have the format HHMM
- if ( !hasTDRC && utf8string.length() == 4 )
- {
- newDateTime.hour = SXMPUtils::ConvertToInt(utf8string.substr(0,2));
- newDateTime.minute = SXMPUtils::ConvertToInt( utf8string.substr(2,2));
- newDateTime.hasTime = true;
- }
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- }
- break;
- }
- case 0x54445243: // TDRC -> xmp:CreateDate //id3 v2.4
- {
- try { // Don't let wrong dates in id3 stop import.
- hasTDRC = true;
- // This always wins over TYER, TDAT and TIME
- SXMPUtils::ConvertToDate( utf8string, &newDateTime );
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- }
- break;
- }
- default:
- // NB: COMM/USLT need no special fork regarding language alternatives/multiple occurence.
- // relevant code forks are in ID3_Support::getFrameValue()
- this->xmpObj.SetProperty( reconProps[r].ns, reconProps[r].prop, utf8string );
- break;
- }//switch
- } //for iterator
- }//for reconProps
-
- // import DateTime
- XMP_DateTime oldDateTime;
- xmpObj.GetProperty_Date( kXMP_NS_XMP, "CreateDate", &oldDateTime, 0 );
-
-
-
- // 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 {
- // invalid year will be catched and blocks import
- XMP_Validate( (newDateTime.year > 0 && newDateTime.year < 9999), "", kXMPErr_BadParam );
-
- // 2. if year has changed --> everything (date/time) has changed --> overwrite old DateTime with new DateTime
- if ( ( newDateTime.year != oldDateTime.year ) || // year has changed?
- // or has same year but new day/month (checking existance month indicates both (day and month) in our case)
- (( newDateTime.month != 0 ) && ( newDateTime.day != oldDateTime.day || newDateTime.month != oldDateTime.month )) ||
- // or has same year and same date but different time
- ( newDateTime.hasTime && ( newDateTime.hour != oldDateTime.minute || newDateTime.hour != oldDateTime.minute )) )
- {
- this->xmpObj.SetProperty_Date( kXMP_NS_XMP, "CreateDate", newDateTime );
- } // ..else: keep old dateTime to don't loose data
-
- } catch ( ... ) {
- // Dont import invalid dates from ID3
- }
-
-
- // very important to avoid multiple runs! (in which case I'd need to clean certain
- // fields (i.e. regarding ->active setting)
- this->processedXMP = true;
-
-} // MP3_MetaHandler::ProcessXMP
-
-
-// =================================================================================================
-// MP3_MetaHandler::UpdateFile
-// ===========================
-void MP3_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( doSafeUpdate )
- XMP_Throw ( "UCF_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
-
- LFA_FileRef file ( this->parent->fileRef );
-
- // leave 2.3 resp. 2.4 header, since we want to let alone
- // and don't know enough about the encoding of unrelated frames...
- XMP_Assert( this->containsXMP );
-
- tagIsDirty = false;
- mustShift = false;
-
- // write out native properties:
- // * update existing ones
- // * create new frames as needed
- // * delete frames if property is gone!
- // see what there is to do for us:
-
- // RECON LOOP START
- for (int r=0; reconProps[r].frameID != 0; r++)
- {
- std::string value;
- bool needDescriptor = false;
- bool need16LE = true;
- bool needEncodingByte = true;
-
- XMP_Uns32 frameID = GetUns32BE( reconProps[r].frameID ); // the would-be frame
- ID3v2Frame* frame = framesMap[ frameID ]; // the actual frame (if already existing)
-
- // get XMP property
- // * honour specific exceptions
- // * leave value empty() if it doesn't exist ==> frame must be delete/not created
- switch( frameID )
- {
- case 0x54434D50: // TCMP if exists: part of compilation
- need16LE = false;
- if ( xmpObj.GetProperty( kXMP_NS_DM, "partOfCompilation", &value, 0 )
- && ( 0 == stricmp( value.c_str(), "true" ) ))
- value = "1"; // set a TCMP frame of value 1
- else
- value.erase(); // delete/prevent creation of frame
- break;
-
- case 0x54495432: // TIT2 -> title["x-default"]
- case 0x54434F50: // TCOP -> rights["x-default"]
- if (! xmpObj.GetLocalizedText( reconProps[r].ns, reconProps[r].prop, "", "x-default", 0, &value, 0 )) //jaja, side effect.
- value.erase(); // if not, erase string.
- break;
- case 0x54434F4E: // TCON -> genre
- {
- if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
- { // nothing found? -> Erase string. (Leads to Unset below)
- value.erase();
- break;
- }
- // genre: we need to get the number back, if possible
- XMP_Int16 iFound = -1; // flag as "not found"
- for ( int i=0; i < 127; ++i ) {
- if ( (value.size() == strlen(Genres[i]))
- && (stricmp( value.c_str(), Genres[i] ) == 0) ) //fixing stricmp buggy on PPC
- {
- iFound = i; // Found
- break;
- }
- }
- if ( iFound == -1 ) // not found known numeric genre?
- break; // stick with the literal value (also for v2.3, since this is common practice!)
-
- need16LE = false; // no unicode need for (##)
- char strGenre[64];
- snprintf ( strGenre, sizeof(strGenre), "(%d)", iFound ); // AUDIT: Using sizeof(strGenre) is safe.
- value.assign(strGenre);
- }
- break;
- case 0x434F4D4D: // COMM
- case 0x55534C54: // USLT, both need descriptor.
- needDescriptor = true;
- if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
- value.erase();
- break;
- case 0x54594552: //TYER
- case 0x54444154: //TDAT
- case 0x54494D45: //TIME
- {
- if ( majorVersion <= 3 ) // TYER, TIME and TDAT depricated since v. 2.4 -> else use TDRC
- {
- XMP_DateTime dateTime;
- if (! xmpObj.GetProperty_Date( reconProps[r].ns, reconProps[r].prop, &dateTime, 0 ))
- { // nothing found? -> Erase string. (Leads to Unset below)
- value.erase();
- break;
- }
-
- // TYER
- if ( frameID == 0x54594552 )
- {
- XMP_Validate( dateTime.year <= 9999 && dateTime.year > 0 , "Year is out of range", kXMPErr_BadParam);
- // get only Year!
- SXMPUtils::ConvertFromInt( dateTime.year, "", &value );
- break;
- }
- // TDAT
- else if ( frameID == 0x54444154 && dateTime.hasDate ) // date validation made by "GetProperty_Date"
- {
- std::string day, month;
- SXMPUtils::ConvertFromInt( dateTime.day, "", &day );
- SXMPUtils::ConvertFromInt( dateTime.month, "", &month );
- if ( dateTime.day < 10 )
- value = "0";
- value += day;
- if ( dateTime.month < 10 )
- value += "0";
- value += month;
- break;
- }
- // TIME
- else if ( frameID == 0x54494D45 && dateTime.hasTime ) // time validation made by "GetProperty_Date" )
- {
- std::string hour, minute;
- SXMPUtils::ConvertFromInt( dateTime.hour, "", &hour );
- SXMPUtils::ConvertFromInt( dateTime.minute, "", &minute );
- if ( dateTime.hour < 10 )
- value = "0";
- value += hour;
- if ( dateTime.minute < 10 )
- value += "0";
- value += minute;
- break;
- }
- else
- {
- value.erase();
- break;
- }
- }
- else // v.2.4 --> delete TYER,TIME or TDAT & write into TDRC
- {
- value.erase();
- break;
- }
- }
- case 0x54445243: //TDRC (only v2.4)
- {
- // only export for id3 > v2.4
- if ( majorVersion > 3 ) // (only v2.4)
- {
- if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
- value.erase();
- }
- break;
- }
- break;
- case 0x57434F50: //WCOP
- needEncodingByte = false;
- need16LE = false;
- if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
- value.erase(); // if not, erase string
- break;
- case 0x5452434B: // TRCK
- case 0x54504F53: // TPOS
- need16LE = false;
- // no break, go on:
- default:
- if (! xmpObj.GetProperty( reconProps[r].ns, reconProps[r].prop, &value, 0 ))
- value.erase(); // if not, erase string
- break;
- }
-
- // [XMP exist] x [frame exist] => four cases:
- // 1/4) nothing before, nothing now
- if ( value.empty() && (frame==0))
- continue; // nothing to do
-
- // all else means there will be rewrite work to do:
- tagIsDirty = true;
-
- // 2/4) value before, now gone:
- if ( value.empty() && (frame!=0))
- {
- frame->active = false; //mark for non-use
- continue;
- }
- // 3/4) no old value, create new value
- if ( frame==0)
- {
- ID3v2Frame* newFrame=new ID3v2Frame( frameID );
- newFrame->setFrameValue( value, needDescriptor, need16LE, false, needEncodingByte ); //always write as utf16-le incl. BOM
- framesVector.push_back( newFrame );
- framesMap[ frameID ] = newFrame;
- continue;
- }
- // 4/4) change existing value
- else // resp. change frame
- {
- frame->setFrameValue( value, needDescriptor, need16LE, false, needEncodingByte );
- }
- } // RECON LOOP END
-
- /////////////////////////////////////////////////////////////////////////////////
- // (Re)Build XMP frame:
- ID3v2Frame* frame = framesMap[ XMP_FRAME_ID ];
- if ( frame == 0)
- {
- ID3v2Frame* newFrame=new ID3v2Frame( XMP_FRAME_ID );
- newFrame->setFrameValue( this->xmpPacket, false, false, true );
- framesVector.push_back( newFrame );
- framesMap[ XMP_FRAME_ID ] = newFrame;
- } else
- frame->setFrameValue( this->xmpPacket, false, false, true );
-
- ////////////////////////////////////////////////////////////////////////////////
- // Decision making
- newFramesSize = 0;
- for ( XMP_Uns32 i=0; i < framesVector.size(); i++)
- {
- if (framesVector[i]->active)
- newFramesSize += (10 + framesVector[i]->contentSize );
- }
-
- mustShift = ( newFramesSize > (oldTagSize - 10)) ||
- //optimization: If more than 8K can be saved by rewriting the MP3, go do it:
- ((newFramesSize + 8*1024) < oldTagSize );
-
- if (!mustShift) // fill what we got
- newTagSize = oldTagSize;
- else // if need to shift anyway, get some nice 2K padding
- newTagSize = newFramesSize + 2048 + 10;
- newPadding = newTagSize -10 - newFramesSize;
-
- // shifting needed? -> shift
- if ( mustShift )
- {
- XMP_Int64 filesize = LFA_Measure( file );
- if ( this->hasID3Tag )
- LFA_Move( file, oldTagSize, file, newTagSize , filesize - oldTagSize ); //fix [2338569]
- else
- LFA_Move( file, 0, file, newTagSize, filesize ); // move entire file up.
- }
-
- // correct size stuff, write out header
- LFA_Rewind( file );
- id3Header.write( file, newTagSize);
-
- // write out tags
- for ( XMP_Uns32 i=0; i < framesVector.size(); i++)
- {
- if ( framesVector[i]->active)
- framesVector[i]->write(file, majorVersion);
- }
-
- // write out padding:
- for ( XMP_Int64 i = newPadding; i > 0;)
- {
- const XMP_Uns64 zero = 0;
- if ( i >= 8 ) // worthwhile optimization
- {
- LFA_Write( file, &zero, 8 );
- i -= 8;
- continue;
- }
- LFA_Write( file, &zero, 1 );
- i--;
- }
-
- // check end of file for ID3v1 tag
- XMP_Int64 possibleTruncationPoint = LFA_Seek( file, -128, SEEK_END);
- bool alreadyHasID3v1 = (LFA_ReadInt32_BE( file ) & 0xFFFFFF00) == 0x54414700; // "TAG"
- if ( ! alreadyHasID3v1 ) // extend file
- LFA_Extend( file, LFA_Measure( file ) + 128 );
- id3v1Tag.write( file, &this->xmpObj );
-
- this->needsUpdate = false; //do last for safety reasons
-} // MP3_MetaHandler::UpdateFile
-
-// =================================================================================================
-// MP3_MetaHandler::WriteFile
-// ==========================
-
-void MP3_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
- const std::string & sourcePath )
-{
- IgnoreParam(sourceRef); IgnoreParam(sourcePath);
- XMP_Throw ( "MP3_MetaHandler::WriteFile: Not supported", kXMPErr_Unimplemented );
-} // MP3_MetaHandler::WriteFile
diff --git a/source/XMPFiles/FileHandlers/MP3_Handler.hpp b/source/XMPFiles/FileHandlers/MP3_Handler.hpp
deleted file mode 100644
index d6be9cf..0000000
--- a/source/XMPFiles/FileHandlers/MP3_Handler.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef __MP3_Handler_hpp__
-#define __MP3_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include "XMPFiles_Impl.hpp"
-#include "ID3_Support.hpp"
-
-using namespace std;
-using namespace ID3_Support;
-
-extern XMPFileHandler * MP3_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool MP3_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kMP3_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket|
- kXMPFiles_CanReconcile);
-
-class MP3_MetaHandler : public XMPFileHandler
-{
-public:
- MP3_MetaHandler ( XMPFiles * parent );
- ~MP3_MetaHandler();
-
- void CacheFileData();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
- void ProcessXMP();
-
-private:
- ////////////////////////////////////////////////////////////////////////////////////
- // instance vars
- XMP_Int64 oldTagSize; // the entire tag, including padding, including 10B header
- XMP_Int64 oldPadding; // number of padding bytes
- XMP_Int64 oldFramesSize; // actual space needed by frames := oldTagSize - 10 - oldPadding
-
- XMP_Int64 newTagSize;
- XMP_Int64 newPadding;
- XMP_Int64 newFramesSize;
-
- // decision making:
- bool tagIsDirty; // true, if any legacy properties changed.
- bool mustShift; // entire tag to rewrite? (or possibly just XMP?)
-
-
- XMP_Uns8 majorVersion, minorVersion; // Version Number post ID3v2, i.e. 3 0 ==> ID3v2.3.0
- bool hasID3Tag; //incoming file has an ID3 tag?
- bool hasFooter;
- bool legacyChanged; // tag rewrite certainly needed?
-
- ID3Header id3Header;
-
- XMP_Int64 extHeaderSize;
- bool hasExtHeader;
-
- // the frames
- // * all to be kept till write-out
- // * parsed/understood only if needed
- // * vector used to free memory in handler destructor
- std::vector<ID3_Support::ID3v2Frame*> framesVector;
-
- // ID3v1 - treated as a single object
- ID3v1Tag id3v1Tag;
-
- // * also kept in a map for better import<->export access
- // * only keeps legacy 'relevant frames' (i.e. no abused COMM frames)
- // * only keeps last relevant frame
- // * earlier 'relevant frames' will be deleted. This map also helps in this
- // * key shall be the FrameID, always interpreted as BE
- std::map<XMP_Uns32,ID3_Support::ID3v2Frame*> framesMap;
-
-}; // MP3_MetaHandler
-
-// =================================================================================================
-
-#endif /* __MP3_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MPEG2_Handler.cpp b/source/XMPFiles/FileHandlers/MPEG2_Handler.cpp
deleted file mode 100644
index 438e705..0000000
--- a/source/XMPFiles/FileHandlers/MPEG2_Handler.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2005 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.
-// =================================================================================================
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-#include "MPEG2_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file MPEG2_Handler.cpp
-/// \brief File format handler for MPEG2.
-///
-/// BLECH! YUCK! GAG! MPEG-2 is done using a sidecar and recognition only by file extension! BARF!!!!!
-///
-// =================================================================================================
-
-// =================================================================================================
-// FindFileExtension
-// =================
-
-static inline XMP_StringPtr FindFileExtension ( XMP_StringPtr filePath )
-{
-
- XMP_StringPtr pathEnd = filePath + strlen(filePath);
- XMP_StringPtr extPtr;
-
- for ( extPtr = pathEnd-1; extPtr > filePath; --extPtr ) {
- if ( (*extPtr == '.') || (*extPtr == '/') ) break;
- #if XMP_WinBuild
- if ( (*extPtr == '\\') || (*extPtr == ':') ) break;
- #endif
- }
-
- if ( (extPtr < filePath) || (*extPtr != '.') ) return pathEnd;
- return extPtr;
-
-} // FindFileExtension
-
-// =================================================================================================
-// MPEG2_MetaHandlerCTor
-// =====================
-
-XMPFileHandler * MPEG2_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new MPEG2_MetaHandler ( parent );
-
-} // MPEG2_MetaHandlerCTor
-
-// =================================================================================================
-// MPEG2_CheckFormat
-// =================
-
-// The MPEG-2 handler uses just the file extension, not the file content. Worse yet, it also uses a
-// sidecar file for the XMP. This works better if the handler owns the file, we open the sidecar
-// instead of the actual MPEG-2 file.
-
-bool MPEG2_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(fileRef);
-
- XMP_Assert ( (format == kXMP_MPEGFile) || (format == kXMP_MPEG2File) );
- XMP_Assert ( fileRef == 0 );
-
- return ( (parent->format == kXMP_MPEGFile) || (parent->format == kXMP_MPEGFile) ); // ! Just use the first call's format hint.
-
-} // MPEG2_CheckFormat
-
-// =================================================================================================
-// MPEG2_MetaHandler::MPEG2_MetaHandler
-// ====================================
-
-MPEG2_MetaHandler::MPEG2_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kMPEG2_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // MPEG2_MetaHandler::MPEG2_MetaHandler
-
-// =================================================================================================
-// MPEG2_MetaHandler::~MPEG2_MetaHandler
-// =====================================
-
-MPEG2_MetaHandler::~MPEG2_MetaHandler()
-{
- // Nothing to do.
-
-} // MPEG2_MetaHandler::~MPEG2_MetaHandler
-
-// =================================================================================================
-// MPEG2_MetaHandler::CacheFileData
-// ================================
-
-void MPEG2_MetaHandler::CacheFileData()
-{
- bool readOnly = (! (this->parent->openFlags & kXMPFiles_OpenForUpdate));
-
- this->containsXMP = false;
- this->processedXMP = true; // Whatever we do here is all that we do for XMPFiles::OpenFile.
-
- // Try to open the sidecar XMP file. Tolerate an open failure, there might not be any XMP.
- // Note that MPEG2_CheckFormat can't save the sidecar path because the handler doesn't exist then.
-
- XMP_StringPtr filePath = this->parent->filePath.c_str();
- XMP_StringPtr extPtr = FindFileExtension ( filePath );
- this->sidecarPath.assign ( filePath, (extPtr - filePath) );
- this->sidecarPath += ".xmp";
-
- if ( readOnly ) {
-
- try { // *** At this time LFA_Open throws for a failure.
- this->parent->fileRef = LFA_Open ( this->sidecarPath.c_str(), 'r' );
- if ( this->parent->fileRef == 0 ) return; // *** Could someday check for a permission failure.
- } catch ( ... ) {
- return; // *** Could someday check for a permission failure.
- }
-
- } else {
-
- try { // *** At this time LFA_Open throws for a failure.
- this->parent->fileRef = LFA_Open ( this->sidecarPath.c_str(), 'w' );
- } catch ( ... ) {
- this->parent->fileRef = 0; // *** Could someday check for a permission failure.
- }
-
- if ( this->parent->fileRef == 0 ) {
- // Try to create a file if it does not yet exist.
- // *** Could someday check for a permission failure versus no .xmp file.
- this->parent->fileRef = LFA_Create ( this->sidecarPath.c_str() );
- if ( this->parent->fileRef == 0 ) XMP_Throw ( "Can't create MPEG-2 sidecar", kXMPErr_ExternalFailure );
- }
-
- }
-
- // Extract the sidecar's contents and parse.
-
- this->packetInfo.offset = 0; // We take the whole sidecar file.
- this->packetInfo.length = (XMP_Int32) LFA_Measure ( this->parent->fileRef );
-
- if ( this->packetInfo.length > 0 ) {
-
- this->xmpPacket.assign ( this->packetInfo.length, ' ' );
- LFA_Read ( this->parent->fileRef, (void*)this->xmpPacket.c_str(), this->packetInfo.length, kLFA_RequireAll );
- if ( readOnly ) {
- LFA_Close ( this->parent->fileRef );
- this->parent->fileRef = 0;
- }
-
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->containsXMP = true;
-
- }
-
-} // MPEG2_MetaHandler::CacheFileData
-
-// =================================================================================================
-// MPEG2_MetaHandler::UpdateFile
-// =============================
-
-void MPEG2_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Assert ( fileRef != 0 );
-
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
-
- if ( ! doSafeUpdate ) {
-
- // Not doing a crash-safe update, simply rewrite the existing sidecar file.
- LFA_Seek ( fileRef, 0, SEEK_SET );
- LFA_Truncate ( fileRef, 0 );
- LFA_Write ( fileRef, packetStr, packetLen );
-
- } else {
-
- // Do the usual crash-safe update dance.
-
- LFA_FileRef tempFileRef = 0;
- std::string tempFilePath;
-
- try {
-
- CreateTempFile ( this->sidecarPath, &tempFilePath, kCopyMacRsrc );
- tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
- LFA_Write ( tempFileRef, packetStr, packetLen );
-
- LFA_Close ( fileRef );
- this->parent->fileRef = 0;
- LFA_Close ( tempFileRef );
- tempFileRef = 0;
-
- LFA_Delete ( this->sidecarPath.c_str() );
- LFA_Rename ( tempFilePath.c_str(), this->sidecarPath.c_str() );
-
- } catch ( ... ) {
-
- if ( tempFileRef != 0 ) LFA_Close ( tempFileRef );
- if ( ! tempFilePath.empty() ) LFA_Delete ( tempFilePath.c_str() );
-
- }
-
- }
-
- this->needsUpdate = false;
-
-} // MPEG2_MetaHandler::UpdateFile
-
-// =================================================================================================
-// MPEG2_MetaHandler::WriteFile
-// ============================
-
-void MPEG2_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
- const std::string & sourcePath )
-{
- IgnoreParam(sourceRef); IgnoreParam(sourcePath);
-
- XMP_Throw ( "MPEG2_MetaHandler::WriteFile: Should never be called", kXMPErr_Unavailable );
-
-} // MPEG2_MetaHandler::WriteFile
diff --git a/source/XMPFiles/FileHandlers/MPEG2_Handler.hpp b/source/XMPFiles/FileHandlers/MPEG2_Handler.hpp
deleted file mode 100644
index 96ef407..0000000
--- a/source/XMPFiles/FileHandlers/MPEG2_Handler.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __MPEG2_Handler_hpp__
-#define __MPEG2_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2005 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 "XMPFiles_Impl.hpp"
-
-// =================================================================================================
-/// \file MPEG2_Handler.hpp
-/// \brief File format handler for MPEG2.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * MPEG2_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool MPEG2_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent);
-
-static const XMP_OptionBits kMPEG2_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_UsesSidecarXMP );
-
-class MPEG2_MetaHandler : public XMPFileHandler
-{
-public:
-
- std::string sidecarPath;
-
- MPEG2_MetaHandler ( XMPFiles * parent );
- ~MPEG2_MetaHandler();
-
- void CacheFileData();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
-}; // MPEG2_MetaHandler
-
-// =================================================================================================
-
-#endif /* __MPEG2_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MPEG4_Handler.cpp b/source/XMPFiles/FileHandlers/MPEG4_Handler.cpp
deleted file mode 100644
index 06400d1..0000000
--- a/source/XMPFiles/FileHandlers/MPEG4_Handler.cpp
+++ /dev/null
@@ -1,2456 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "MPEG4_Handler.hpp"
-#include "ISOBaseMedia_Support.hpp"
-#include "MOOV_Support.hpp"
-
-#include "UnicodeConversions.hpp"
-#include "MD5.h"
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-using namespace std;
-
-// =================================================================================================
-/// \file MPEG4_Handler.cpp
-/// \brief File format handler for MPEG-4, a flavor of the ISO Base Media File Format.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// The basic content of a timecode sample description table entry. Does not include trailing boxes.
-
-#pragma pack ( push, 1 )
-
-struct stsdBasicEntry {
- XMP_Uns32 entrySize;
- XMP_Uns32 format;
- XMP_Uns8 reserved_1 [6];
- XMP_Uns16 dataRefIndex;
- XMP_Uns32 reserved_2;
- XMP_Uns32 flags;
- XMP_Uns32 timeScale;
- XMP_Uns32 frameDuration;
- XMP_Uns8 frameCount;
- XMP_Uns8 reserved_3;
-};
-
-#pragma pack ( pop )
-
-// =================================================================================================
-
-// ! The buffer and constants are both already big endian.
-#define Get4CharCode(buffPtr) (*((XMP_Uns32*)(buffPtr)))
-
-// =================================================================================================
-
-static inline bool IsClassicQuickTimeBox ( XMP_Uns32 boxType )
-{
- if ( (boxType == ISOMedia::k_moov) || (boxType == ISOMedia::k_mdat) || (boxType == ISOMedia::k_pnot) ||
- (boxType == ISOMedia::k_free) || (boxType == ISOMedia::k_skip) || (boxType == ISOMedia::k_wide) ) return true;
- return false;
-} // IsClassicQuickTimeBox
-
-// =================================================================================================
-
-// Pairs of 3 letter ISO 639-2 codes mapped to 2 letter ISO 639-1 codes from:
-// http://www.loc.gov/standards/iso639-2/php/code_list.php
-// Would have to write an "==" operator to use std::map, must compare values not pointers.
-// ! Not fully sorted, do not use a binary search.
-
-static XMP_StringPtr kKnownLangs[] =
- { "aar", "aa", "abk", "ab", "afr", "af", "aka", "ak", "alb", "sq", "sqi", "sq", "amh", "am",
- "ara", "ar", "arg", "an", "arm", "hy", "hye", "hy", "asm", "as", "ava", "av", "ave", "ae",
- "aym", "ay", "aze", "az", "bak", "ba", "bam", "bm", "baq", "eu", "eus", "eu", "bel", "be",
- "ben", "bn", "bih", "bh", "bis", "bi", "bod", "bo", "tib", "bo", "bos", "bs", "bre", "br",
- "bul", "bg", "bur", "my", "mya", "my", "cat", "ca", "ces", "cs", "cze", "cs", "cha", "ch",
- "che", "ce", "chi", "zh", "zho", "zh", "chu", "cu", "chv", "cv", "cor", "kw", "cos", "co",
- "cre", "cr", "cym", "cy", "wel", "cy", "cze", "cs", "ces", "cs", "dan", "da", "deu", "de",
- "ger", "de", "div", "dv", "dut", "nl", "nld", "nl", "dzo", "dz", "ell", "el", "gre", "el",
- "eng", "en", "epo", "eo", "est", "et", "eus", "eu", "baq", "eu", "ewe", "ee", "fao", "fo",
- "fas", "fa", "per", "fa", "fij", "fj", "fin", "fi", "fra", "fr", "fre", "fr", "fre", "fr",
- "fra", "fr", "fry", "fy", "ful", "ff", "geo", "ka", "kat", "ka", "ger", "de", "deu", "de",
- "gla", "gd", "gle", "ga", "glg", "gl", "glv", "gv", "gre", "el", "ell", "el", "grn", "gn",
- "guj", "gu", "hat", "ht", "hau", "ha", "heb", "he", "her", "hz", "hin", "hi", "hmo", "ho",
- "hrv", "hr", "scr", "hr", "hun", "hu", "hye", "hy", "arm", "hy", "ibo", "ig", "ice", "is",
- "isl", "is", "ido", "io", "iii", "ii", "iku", "iu", "ile", "ie", "ina", "ia", "ind", "id",
- "ipk", "ik", "isl", "is", "ice", "is", "ita", "it", "jav", "jv", "jpn", "ja", "kal", "kl",
- "kan", "kn", "kas", "ks", "kat", "ka", "geo", "ka", "kau", "kr", "kaz", "kk", "khm", "km",
- "kik", "ki", "kin", "rw", "kir", "ky", "kom", "kv", "kon", "kg", "kor", "ko", "kua", "kj",
- "kur", "ku", "lao", "lo", "lat", "la", "lav", "lv", "lim", "li", "lin", "ln", "lit", "lt",
- "ltz", "lb", "lub", "lu", "lug", "lg", "mac", "mk", "mkd", "mk", "mah", "mh", "mal", "ml",
- "mao", "mi", "mri", "mi", "mar", "mr", "may", "ms", "msa", "ms", "mkd", "mk", "mac", "mk",
- "mlg", "mg", "mlt", "mt", "mol", "mo", "mon", "mn", "mri", "mi", "mao", "mi", "msa", "ms",
- "may", "ms", "mya", "my", "bur", "my", "nau", "na", "nav", "nv", "nbl", "nr", "nde", "nd",
- "ndo", "ng", "nep", "ne", "nld", "nl", "dut", "nl", "nno", "nn", "nob", "nb", "nor", "no",
- "nya", "ny", "oci", "oc", "oji", "oj", "ori", "or", "orm", "om", "oss", "os", "pan", "pa",
- "per", "fa", "fas", "fa", "pli", "pi", "pol", "pl", "por", "pt", "pus", "ps", "que", "qu",
- "roh", "rm", "ron", "ro", "rum", "ro", "rum", "ro", "ron", "ro", "run", "rn", "rus", "ru",
- "sag", "sg", "san", "sa", "scc", "sr", "srp", "sr", "scr", "hr", "hrv", "hr", "sin", "si",
- "slk", "sk", "slo", "sk", "slo", "sk", "slk", "sk", "slv", "sl", "sme", "se", "smo", "sm",
- "sna", "sn", "snd", "sd", "som", "so", "sot", "st", "spa", "es", "sqi", "sq", "alb", "sq",
- "srd", "sc", "srp", "sr", "scc", "sr", "ssw", "ss", "sun", "su", "swa", "sw", "swe", "sv",
- "tah", "ty", "tam", "ta", "tat", "tt", "tel", "te", "tgk", "tg", "tgl", "tl", "tha", "th",
- "tib", "bo", "bod", "bo", "tir", "ti", "ton", "to", "tsn", "tn", "tso", "ts", "tuk", "tk",
- "tur", "tr", "twi", "tw", "uig", "ug", "ukr", "uk", "urd", "ur", "uzb", "uz", "ven", "ve",
- "vie", "vi", "vol", "vo", "wel", "cy", "cym", "cy", "wln", "wa", "wol", "wo", "xho", "xh",
- "yid", "yi", "yor", "yo", "zha", "za", "zho", "zh", "chi", "zh", "zul", "zu",
- 0, 0 };
-
-static inline XMP_StringPtr Lookup2LetterLang ( XMP_StringPtr lang3 )
-{
- for ( size_t i = 0; kKnownLangs[i] != 0; i += 2 ) {
- if ( XMP_LitMatch ( lang3, kKnownLangs[i] ) ) return kKnownLangs[i+1];
- }
- return "";
-}
-
-static inline XMP_StringPtr Lookup3LetterLang ( XMP_StringPtr lang2 )
-{
- for ( size_t i = 0; kKnownLangs[i] != 0; i += 2 ) {
- if ( XMP_LitMatch ( lang2, kKnownLangs[i+1] ) ) return kKnownLangs[i];
- }
- return "";
-}
-
-// =================================================================================================
-// MPEG4_CheckFormat
-// =================
-//
-// There are 3 variations of recognized file:
-// - Normal MPEG-4 - has an 'ftyp' box containing a known compatible brand but not 'qt '.
-// - Modern QuickTime - has an 'ftyp' box containing 'qt ' as a compatible brand.
-// - Classic QuickTime - has no 'ftyp' box, should have recognized top level boxes.
-//
-// An MPEG-4 or modern QuickTime file is an instance of an ISO Base Media file, ISO 14496-12 and -14.
-// A classic QuickTime file has the same physical box structure, but somewhat different box types.
-// The ISO files must begin with an 'ftyp' box containing 'mp41', 'mp42', 'f4v ', or 'qt ' in the
-// compatible brands.
-//
-// The general box structure is:
-//
-// 0 4 uns32 box size, 0 means "to EoF", 1 means 64-bit size follows
-// 4 4 uns32 box type
-// 8 8 uns64 box size, present only if uns32 size is 1
-// - * box content
-//
-// The 'ftyp' box content is:
-//
-// - 4 uns32 major brand
-// - 4 uns32 minor version
-// - * uns32 sequence of compatible brands, to the end of the box
-
-// ! With the addition of QuickTime support there is some change in behavior in OpenFile when the
-// ! kXMPFiles_OpenStrictly option is used wth a specific file format. The kXMP_MPEG4File and
-// ! kXMP_MOVFile formats are treated uniformly, you can't force "real MOV" or "real MPEG-4". You
-// ! can check afterwards using GetFileInfo to see what the file happens to be.
-
-bool MPEG4_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles* parent )
-{
- XMP_Uns8 buffer [4*1024];
- XMP_Uns32 ioCount, brandCount, brandOffset;
- 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);
-
- bool openStrictly = XMP_OptionIsSet ( parent->openFlags, kXMPFiles_OpenStrictly);
-
- // Get the first box's info, see if it is 'ftyp' or not.
-
- XMP_Assert ( (parent->tempPtr == 0) && (parent->tempUI32 == 0) );
-
- fileSize = LFA_Measure ( fileRef );
- nextOffset = ISOMedia::GetBoxInfo ( fileRef, 0, fileSize, &currBox );
- if ( currBox.headerSize < 8 ) return false; // Can't be an ISO or QuickTime file.
-
- if ( currBox.boxType == ISOMedia::k_ftyp ) {
-
- // Have an 'ftyp' box, look through the compatible brands. If 'qt ' is present then this is
- // a modern QuickTime file, regardless of what else is found. Otherwise this is plain ISO if
- // any of the other recognized brands are found.
-
- if ( currBox.contentSize < 12 ) return false; // No compatible brands at all.
- if ( currBox.contentSize > 1024*1024 ) return false; // Sanity check and make sure count fits in 32 bits.
- brandCount = ((XMP_Uns32)currBox.contentSize - 8) >> 2;
-
- LFA_Seek ( fileRef, 8, SEEK_CUR ); // Skip the major and minor brands.
- ioCount = brandOffset = 0;
-
- bool haveCompatibleBrand = false;
-
- for ( ; brandCount > 0; --brandCount, brandOffset += 4 ) {
-
- if ( brandOffset >= ioCount ) {
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "MPEG4_CheckFormat - User abort", kXMPErr_UserAbort );
- }
- ioCount = 4 * brandCount;
- if ( ioCount > sizeof(buffer) ) ioCount = sizeof(buffer);
- ioCount = LFA_Read ( fileRef, buffer, ioCount, kLFA_RequireAll );
- brandOffset = 0;
- }
-
- XMP_Uns32 brand = GetUns32BE ( &buffer[brandOffset] );
- if ( brand == ISOMedia::k_qt ) { // Don't need to look further.
- if ( openStrictly && (format != kXMP_MOVFile) ) return false;
- parent->format = kXMP_MOVFile;
- parent->tempUI32 = MOOV_Manager::kFileIsModernQT;
- return true;
- } else if ( (brand == ISOMedia::k_mp41) || (brand == ISOMedia::k_mp42) || (brand == ISOMedia::k_f4v) ) {
- haveCompatibleBrand = true; // Need to keep looking in case 'qt ' follows.
- }
-
- }
-
- if ( ! haveCompatibleBrand ) return false;
- if ( openStrictly && (format != kXMP_MPEG4File) ) return false;
- parent->format = kXMP_MPEG4File;
- parent->tempUI32 = MOOV_Manager::kFileIsNormalISO;
- return true;
-
- } else {
-
- // No 'ftyp', look for classic QuickTime: 'moov', 'mdat', 'pnot', 'free', 'skip', and 'wide'.
- // As an expedient, quit when a 'moov' box is found. Tolerate other boxes, they are in the
- // wild for ill-formed files, e.g. seen when 'moov'/'udta' children get left at top level.
-
- 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 ( nextOffset >= fileSize ) return false;
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "MPEG4_CheckFormat - User abort", kXMPErr_UserAbort );
- }
- nextOffset = ISOMedia::GetBoxInfo ( fileRef, nextOffset, fileSize, &currBox );
-
- }
-
- if ( openStrictly && (format != kXMP_MOVFile) ) return false;
- parent->format = kXMP_MOVFile;
- parent->tempUI32 = MOOV_Manager::kFileIsTraditionalQT;
- return true;
-
- }
-
- return false;
-
-} // MPEG4_CheckFormat
-
-// =================================================================================================
-// MPEG4_MetaHandlerCTor
-// =====================
-
-XMPFileHandler * MPEG4_MetaHandlerCTor ( XMPFiles * parent )
-{
-
- return new MPEG4_MetaHandler ( parent );
-
-} // MPEG4_MetaHandlerCTor
-
-// =================================================================================================
-// MPEG4_MetaHandler::MPEG4_MetaHandler
-// ====================================
-
-MPEG4_MetaHandler::MPEG4_MetaHandler ( XMPFiles * _parent )
- : fileMode(0), havePreferredXMP(false), xmpBoxPos(0), moovBoxPos(0), xmpBoxSize(0), moovBoxSize(0)
-{
-
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kMPEG4_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
- this->fileMode = (XMP_Uns8)_parent->tempUI32;
- _parent->tempUI32 = 0;
-
-} // MPEG4_MetaHandler::MPEG4_MetaHandler
-
-// =================================================================================================
-// MPEG4_MetaHandler::~MPEG4_MetaHandler
-// =====================================
-
-MPEG4_MetaHandler::~MPEG4_MetaHandler()
-{
-
- // Nothing to do.
-
-} // MPEG4_MetaHandler::~MPEG4_MetaHandler
-
-// =================================================================================================
-// SecondsToXMPDate
-// ================
-
-// *** ASF has similar code with different origin, should make a shared utility.
-
-static void SecondsToXMPDate ( XMP_Uns64 isoSeconds, XMP_DateTime * xmpDate )
-{
- memset ( xmpDate, 0, sizeof(XMP_DateTime) ); // AUDIT: Using sizeof(XMP_DateTime) is safe.
-
- XMP_Int32 days = (XMP_Int32) (isoSeconds / 86400);
- isoSeconds -= ((XMP_Uns64)days * 86400);
-
- XMP_Int32 hour = (XMP_Int32) (isoSeconds / 3600);
- isoSeconds -= ((XMP_Uns64)hour * 3600);
-
- XMP_Int32 minute = (XMP_Int32) (isoSeconds / 60);
- isoSeconds -= ((XMP_Uns64)minute * 60);
-
- XMP_Int32 second = (XMP_Int32)isoSeconds;
-
- xmpDate->year = 1904; // Start with the ISO origin.
- xmpDate->month = 1;
- xmpDate->day = 1;
-
- xmpDate->day += days; // Add in the delta.
- xmpDate->hour = hour;
- xmpDate->minute = minute;
- xmpDate->second = second;
-
- xmpDate->hasTimeZone = true; // ! Needed for ConvertToUTCTime to do anything.
- SXMPUtils::ConvertToUTCTime ( xmpDate ); // Normalize the date/time.
-
-} // SecondsToXMPDate
-
-// =================================================================================================
-// XMPDateToSeconds
-// ================
-
-// *** ASF has similar code with different origin, should make a shared utility.
-
-static bool IsLeapYear ( XMP_Int32 year )
-{
- if ( year < 0 ) year = -year + 1; // Fold the negative years, assuming there is a year 0.
- if ( (year % 4) != 0 ) return false; // Not a multiple of 4.
- if ( (year % 100) != 0 ) return true; // A multiple of 4 but not a multiple of 100.
- if ( (year % 400) == 0 ) return true; // A multiple of 400.
- return false; // A multiple of 100 but not a multiple of 400.
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static XMP_Int32 DaysInMonth ( XMP_Int32 year, XMP_Int32 month )
-{
- static XMP_Int32 daysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
- XMP_Int32 days = daysInMonth[month];
- if ( (month == 2) && IsLeapYear(year) ) days += 1;
- return days;
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static void XMPDateToSeconds ( const XMP_DateTime & _xmpDate, XMP_Uns64 * isoSeconds )
-{
- XMP_DateTime xmpDate = _xmpDate;
- SXMPUtils::ConvertToUTCTime ( &xmpDate );
-
- XMP_Uns64 tempSeconds = (XMP_Uns64)xmpDate.second;
- tempSeconds += (XMP_Uns64)xmpDate.minute * 60;
- tempSeconds += (XMP_Uns64)xmpDate.hour * 3600;
-
- XMP_Int32 days = (xmpDate.day - 1);
-
- --xmpDate.month;
- while ( xmpDate.month >= 1 ) {
- days += DaysInMonth ( xmpDate.year, xmpDate.month );
- --xmpDate.month;
- }
-
- --xmpDate.year;
- while ( xmpDate.year >= 1904 ) {
- days += (IsLeapYear ( xmpDate.year) ? 366 : 365 );
- --xmpDate.year;
- }
-
- tempSeconds += (XMP_Uns64)days * 86400;
- *isoSeconds = tempSeconds;
-
-} // XMPDateToSeconds
-
-// =================================================================================================
-// ImportMVHDItems
-// ===============
-
-static bool ImportMVHDItems ( MOOV_Manager::BoxInfo mvhdInfo, SXMPMeta * xmp )
-{
- XMP_Assert ( mvhdInfo.boxType == ISOMedia::k_mvhd );
- if ( mvhdInfo.contentSize < 4 ) return false; // Just enough to check the version/flags at first.
-
- XMP_Uns8 mvhdVersion = *mvhdInfo.content;
- if ( mvhdVersion > 1 ) return false;
-
- XMP_Uns64 creationTime, modificationTime, duration;
- XMP_Uns32 timescale;
-
- if ( mvhdVersion == 0 ) {
-
- if ( mvhdInfo.contentSize < sizeof ( MOOV_Manager::Content_mvhd_0 ) ) return false;
- MOOV_Manager::Content_mvhd_0 * mvhdRaw_0 = (MOOV_Manager::Content_mvhd_0*) mvhdInfo.content;
-
- creationTime = (XMP_Uns64) GetUns32BE ( &mvhdRaw_0->creationTime );
- modificationTime = (XMP_Uns64) GetUns32BE ( &mvhdRaw_0->modificationTime );
- timescale = GetUns32BE ( &mvhdRaw_0->timescale );
- duration = (XMP_Uns64) GetUns32BE ( &mvhdRaw_0->duration );
-
- } else {
-
- XMP_Assert ( mvhdVersion == 1 );
- if ( mvhdInfo.contentSize < sizeof ( MOOV_Manager::Content_mvhd_1 ) ) return false;
- MOOV_Manager::Content_mvhd_1 * mvhdRaw_1 = (MOOV_Manager::Content_mvhd_1*) mvhdInfo.content;
-
- creationTime = GetUns64BE ( &mvhdRaw_1->creationTime );
- modificationTime = GetUns64BE ( &mvhdRaw_1->modificationTime );
- timescale = GetUns32BE ( &mvhdRaw_1->timescale );
- duration = GetUns64BE ( &mvhdRaw_1->duration );
-
- }
-
- bool haveImports = false;
- XMP_DateTime xmpDate;
-
- if ( (creationTime >> 32) < 0xFF ) { // Sanity check for bogus date info.
- SecondsToXMPDate ( creationTime, &xmpDate );
- xmp->SetProperty_Date ( kXMP_NS_XMP, "CreateDate", xmpDate );
- haveImports = true;
- }
-
- if ( (modificationTime >> 32) < 0xFF ) { // Sanity check for bogus date info.
- SecondsToXMPDate ( modificationTime, &xmpDate );
- xmp->SetProperty_Date ( kXMP_NS_XMP, "ModifyDate", xmpDate );
- haveImports = true;
- }
-
- if ( timescale != 0 ) { // Avoid 1/0 for the scale field.
- char buffer [32]; // A 64-bit number is at most 20 digits.
- xmp->DeleteProperty ( kXMP_NS_DM, "duration" ); // Delete the whole struct.
- snprintf ( buffer, sizeof(buffer), "%llu", duration ); // AUDIT: The buffer is big enough.
- xmp->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "value", &buffer[0] );
- snprintf ( buffer, sizeof(buffer), "1/%u", timescale ); // AUDIT: The buffer is big enough.
- xmp->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "scale", &buffer[0] );
- haveImports = true;
- }
-
- return haveImports;
-
-} // ImportMVHDItems
-
-// =================================================================================================
-// ExportMVHDItems
-// ===============
-
-static void ExportMVHDItems ( const SXMPMeta & xmp, MOOV_Manager * moovMgr )
-{
- XMP_DateTime xmpDate;
- bool createFound, modifyFound;
- XMP_Uns64 createSeconds = 0, modifySeconds = 0;
-
- MOOV_Manager::BoxInfo mvhdInfo;
- MOOV_Manager::BoxRef mvhdRef = moovMgr->GetBox ( "moov/mvhd", &mvhdInfo );
- if ( (mvhdRef == 0) || (mvhdInfo.contentSize < 4) ) return;
-
- XMP_Uns8 version = *mvhdInfo.content;
- if ( version > 1 ) return;
-
- createFound = xmp.GetProperty_Date ( kXMP_NS_XMP, "CreateDate", &xmpDate, 0 );
- if ( createFound ) XMPDateToSeconds ( xmpDate, &createSeconds );
-
- modifyFound = xmp.GetProperty_Date ( kXMP_NS_XMP, "ModifyDate", &xmpDate, 0 );
- if ( modifyFound ) XMPDateToSeconds ( xmpDate, &modifySeconds );
-
- if ( version == 1 ) {
-
- // Modify the v1 box in-place.
-
- if ( mvhdInfo.contentSize < sizeof ( MOOV_Manager::Content_mvhd_1 ) ) return;
-
- XMP_Uns64 oldCreate = GetUns64BE ( mvhdInfo.content + 4 );
- XMP_Uns64 oldModify = GetUns64BE ( mvhdInfo.content + 12 );
-
- if ( createFound ) {
- if ( createSeconds != oldCreate ) PutUns64BE ( createSeconds, ((XMP_Uns8*)mvhdInfo.content + 4) );
- moovMgr->NoteChange();
- }
- if ( modifyFound ) {
- if ( modifySeconds != oldModify ) PutUns64BE ( modifySeconds, ((XMP_Uns8*)mvhdInfo.content + 12) );
- moovMgr->NoteChange();
- }
-
- } else if ( ((createSeconds >> 32) == 0) && ((modifySeconds >> 32) == 0) ) {
-
- // Modify the v0 box in-place.
-
- if ( mvhdInfo.contentSize < sizeof ( MOOV_Manager::Content_mvhd_0 ) ) return;
-
- XMP_Uns32 oldCreate = GetUns32BE ( mvhdInfo.content + 4 );
- XMP_Uns32 oldModify = GetUns32BE ( mvhdInfo.content + 8 );
-
- if ( createFound ) {
- if ( (XMP_Uns32)createSeconds != oldCreate ) PutUns32BE ( (XMP_Uns32)createSeconds, ((XMP_Uns8*)mvhdInfo.content + 4) );
- moovMgr->NoteChange();
- }
- if ( modifyFound ) {
- if ( (XMP_Uns32)modifySeconds != oldModify ) PutUns32BE ( (XMP_Uns32)modifySeconds, ((XMP_Uns8*)mvhdInfo.content + 8) );
- moovMgr->NoteChange();
- }
-
- } else {
-
- // Replace the v0 box with a v1 box.
-
- XMP_Assert ( createFound | modifyFound ); // One of them has high bits set.
- if ( mvhdInfo.contentSize != sizeof ( MOOV_Manager::Content_mvhd_0 ) ) return;
-
- MOOV_Manager::Content_mvhd_0 * mvhdV0 = (MOOV_Manager::Content_mvhd_0*) mvhdInfo.content;
- MOOV_Manager::Content_mvhd_1 mvhdV1;
-
- // Copy the unchanged fields directly.
-
- mvhdV1.timescale = mvhdV0->timescale;
- mvhdV1.rate = mvhdV0->rate;
- mvhdV1.volume = mvhdV0->volume;
- mvhdV1.pad_1 = mvhdV0->pad_1;
- mvhdV1.pad_2 = mvhdV0->pad_2;
- mvhdV1.pad_3 = mvhdV0->pad_3;
- for ( int i = 0; i < 9; ++i ) mvhdV1.matrix[i] = mvhdV0->matrix[i];
- for ( int i = 0; i < 6; ++i ) mvhdV1.preDef[i] = mvhdV0->preDef[i];
- mvhdV1.nextTrackID = mvhdV0->nextTrackID;
-
- // Set the fields that have changes.
-
- mvhdV1.vFlags = (1 << 24) | (mvhdV0->vFlags & 0xFFFFFF);
- mvhdV1.duration = MakeUns64BE ( (XMP_Uns64) GetUns32BE ( &mvhdV0->duration ) );
-
- XMP_Uns64 temp64;
-
- temp64 = (XMP_Uns64) GetUns32BE ( &mvhdV0->creationTime );
- if ( createFound ) temp64 = createSeconds;
- mvhdV1.creationTime = MakeUns64BE ( temp64 );
-
- temp64 = (XMP_Uns64) GetUns32BE ( &mvhdV0->modificationTime );
- if ( modifyFound ) temp64 = modifySeconds;
- mvhdV1.modificationTime = MakeUns64BE ( temp64 );
-
- moovMgr->SetBox ( mvhdRef, &mvhdV1, sizeof ( MOOV_Manager::Content_mvhd_1 ) );
-
- }
-
-} // ExportMVHDItems
-
-// =================================================================================================
-// ImportISOCopyrights
-// ===================
-//
-// The cached 'moov'/'udta'/'cprt' boxes are full boxes. The "real" content is a UInt16 packed 3
-// character language code and a UTF-8 or UTF-16 string.
-
-static bool ImportISOCopyrights ( const std::vector<MOOV_Manager::BoxInfo> & cprtBoxes, SXMPMeta * xmp )
-{
- bool haveImports = false;
-
- std::string tempStr;
- char lang3 [4]; // The unpacked ISO-639-2/T language code with final null.
- lang3[3] = 0;
-
- for ( size_t i = 0, limit = cprtBoxes.size(); i < limit; ++i ) {
-
- const MOOV_Manager::BoxInfo & currBox = cprtBoxes[i];
- if ( currBox.contentSize < 4+2+1 ) continue; // Want enough for a non-empty value.
- if ( *currBox.content != 0 ) continue; // Only proceed for version 0, ignore the flags.
-
- XMP_Uns16 packedLang = GetUns16BE ( currBox.content + 4 );
- lang3[0] = (packedLang >> 10) + 0x60;
- lang3[1] = ((packedLang >> 5) & 0x1F) + 0x60;
- lang3[2] = (packedLang & 0x1F) + 0x60;
- XMP_StringPtr xmpLang = Lookup2LetterLang ( lang3 );
- if ( *xmpLang == 0 ) continue;
-
- XMP_StringPtr textPtr = (XMP_StringPtr) (currBox.content + 6);
- XMP_StringLen textLen = currBox.contentSize - 6;
-
- if ( (textLen >= 2) && (GetUns16BE(textPtr) == 0xFEFF) ) {
- FromUTF16 ( (UTF16Unit*)textPtr, textLen/2, &tempStr, true /* big endian */ );
- textPtr = tempStr.c_str();
- }
-
- xmp->SetLocalizedText ( kXMP_NS_DC, "rights", xmpLang, xmpLang, textPtr );
- haveImports = true;
-
- }
-
- return haveImports;
-
-} // ImportISOCopyrights
-
-// =================================================================================================
-// ExportISOCopyrights
-// ===================
-
-static void ExportISOCopyrights ( const SXMPMeta & xmp, MOOV_Manager * moovMgr )
-{
- bool haveMappings = false; // True if any ISO-XMP language mappings are found.
-
- // Go through the ISO 'cprt' items and look for a corresponding XMP item. Ignore the ISO item if
- // there is no language mapping to XMP. Update the ISO item if the mappable XMP exists, delete
- // the ISO item if the mappable XMP does not exist. Since the import side would have made sure
- // the mappable XMP items existed, if they don't now they must have been deleted.
-
- MOOV_Manager::BoxInfo udtaInfo;
- MOOV_Manager::BoxRef udtaRef = moovMgr->GetBox ( "moov/udta", &udtaInfo );
- if ( udtaRef == 0 ) return;
-
- std::string xmpPath, xmpValue, xmpLang, tempStr;
- char lang3 [4]; // An unpacked ISO-639-2/T language code.
- lang3[3] = 0;
-
- for ( XMP_Uns32 ordinal = udtaInfo.childCount; ordinal > 0; --ordinal ) { // ! Go backwards because of deletions.
-
- MOOV_Manager::BoxInfo cprtInfo;
- MOOV_Manager::BoxRef cprtRef = moovMgr->GetNthChild ( udtaRef, ordinal-1, &cprtInfo );
- if ( (cprtRef == 0) ) break; // Sanity check, should not happen.
- if ( (cprtInfo.boxType != ISOMedia::k_cprt) || (cprtInfo.contentSize < 6) ) continue;
- if ( *cprtInfo.content != 0 ) continue; // Only accept version 0, ignore the flags.
-
- XMP_Uns16 packedLang = GetUns16BE ( cprtInfo.content + 4 );
- lang3[0] = (packedLang >> 10) + 0x60;
- lang3[1] = ((packedLang >> 5) & 0x1F) + 0x60;
- lang3[2] = (packedLang & 0x1F) + 0x60;
-
- XMP_StringPtr lang2 = Lookup2LetterLang ( lang3 );
- if ( *lang2 == 0 ) continue; // No language mapping to XMP.
- haveMappings = true;
-
- bool xmpFound = xmp.GetLocalizedText ( kXMP_NS_DC, "rights", lang2, lang2, &xmpLang, &xmpValue, 0 );
- if ( xmpFound ) {
- if ( (xmpLang.size() < 2) ||
- ( (xmpLang.size() == 2) && (xmpLang != lang2) ) ||
- ( (xmpLang.size() > 2) && ( (xmpLang[2] != '-') || (! XMP_LitNMatch ( xmpLang.c_str(), lang2, 2)) ) ) ) {
- xmpFound = false; // The language does not match, the corresponding XMP does not exist.
- }
- }
-
- if ( ! xmpFound ) {
-
- // No XMP, delete the ISO item.
- moovMgr->DeleteNthChild ( udtaRef, ordinal-1 );
-
- } else {
-
- // Update the ISO item if necessary.
- XMP_StringPtr isoStr = (XMP_StringPtr)cprtInfo.content + 6;
- size_t rawLen = cprtInfo.contentSize - 6;
- if ( (rawLen >= 8) && (GetUns16BE(isoStr) == 0xFEFF) ) {
- FromUTF16 ( (UTF16Unit*)(isoStr+2), (rawLen-2)/2, &tempStr, true /* big endian */ );
- isoStr = tempStr.c_str();
- }
- if ( xmpValue != isoStr ) {
- std::string newContent = "vfffll";
- newContent += xmpValue;
- memcpy ( (char*)newContent.c_str(), cprtInfo.content, 6 ); // Keep old version, flags, and language.
- moovMgr->SetBox ( cprtRef, newContent.c_str(), (XMP_Uns32)(newContent.size() + 1) );
- }
-
- }
-
- }
-
- // Go through the XMP items and look for a corresponding ISO item. Skip if found (did it above),
- // otherwise add a new ISO item.
-
- bool haveXDefault = false;
- XMP_Index xmpCount = xmp.CountArrayItems ( kXMP_NS_DC, "rights" );
-
- for ( XMP_Index xmpIndex = 1; xmpIndex <= xmpCount; ++xmpIndex ) { // ! The first XMP array index is 1.
-
- SXMPUtils::ComposeArrayItemPath ( kXMP_NS_DC, "rights", xmpIndex, &xmpPath );
- xmp.GetArrayItem ( kXMP_NS_DC, "rights", xmpIndex, &xmpValue, 0 );
- bool hasLang = xmp.GetQualifier ( kXMP_NS_DC, xmpPath.c_str(), kXMP_NS_XML, "lang", &xmpLang, 0 );
- if ( ! hasLang ) continue; // Sanity check.
- if ( xmpLang == "x-default" ) {
- haveXDefault = true; // See later special case.
- continue;
- }
-
- XMP_StringPtr isoLang = "";
- size_t rootLen = xmpLang.find ( '-' );
- if ( rootLen == std::string::npos ) rootLen = xmpLang.size();
- if ( rootLen == 2 ) {
- xmpLang[2] = 0;
- isoLang = Lookup3LetterLang ( xmpLang.c_str() );
- if ( *isoLang == 0 ) continue;
- } else if ( rootLen == 3 ) {
- xmpLang[3] = 0;
- isoLang = xmpLang.c_str();
- } else {
- continue;
- }
- haveMappings = true;
-
- bool isoFound = false;
- XMP_Uns16 packedLang = ((isoLang[0] - 0x60) << 10) | ((isoLang[1] - 0x60) << 5) | (isoLang[2] - 0x60);
-
- for ( XMP_Uns32 isoIndex = 0; (isoIndex < udtaInfo.childCount) && (! isoFound); ++isoIndex ) {
-
- MOOV_Manager::BoxInfo cprtInfo;
- MOOV_Manager::BoxRef cprtRef = moovMgr->GetNthChild ( udtaRef, isoIndex, &cprtInfo );
- if ( (cprtRef == 0) ) break; // Sanity check, should not happen.
- if ( (cprtInfo.boxType != ISOMedia::k_cprt) || (cprtInfo.contentSize < 6) ) continue;
- if ( *cprtInfo.content != 0 ) continue; // Only accept version 0, ignore the flags.
- if ( packedLang != GetUns16BE ( cprtInfo.content + 4 ) ) continue; // Look for matching language.
-
- isoFound = true; // Found the language entry, whether or not we update it.
-
- }
-
- if ( ! isoFound ) {
-
- std::string newContent = "vfffll";
- newContent += xmpValue;
- *((XMP_Uns32*)newContent.c_str()) = 0; // Set the version and flags to zero.
- PutUns16BE ( packedLang, (char*)newContent.c_str() + 4 );
- moovMgr->AddChildBox ( udtaRef, ISOMedia::k_cprt, newContent.c_str(), (XMP_Uns32)(newContent.size() + 1) );
-
- }
-
- }
-
- // If there were no mappings in the loops, export the XMP "x-default" value to the first ISO item.
-
- if ( ! haveMappings ) {
-
- MOOV_Manager::BoxInfo cprtInfo;
- MOOV_Manager::BoxRef cprtRef = moovMgr->GetTypeChild ( udtaRef, ISOMedia::k_cprt, &cprtInfo );
-
- if ( (cprtRef != 0) && (cprtInfo.contentSize >= 6) && (*cprtInfo.content == 0) ) {
-
- bool xmpFound = xmp.GetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", &xmpLang, &xmpValue, 0 );
-
- if ( xmpFound && (xmpLang == "x-default") ) {
-
- // Update the ISO item if necessary.
- XMP_StringPtr isoStr = (XMP_StringPtr)cprtInfo.content + 6;
- size_t rawLen = cprtInfo.contentSize - 6;
- if ( (rawLen >= 8) && (GetUns16BE(isoStr) == 0xFEFF) ) {
- FromUTF16 ( (UTF16Unit*)(isoStr+2), (rawLen-2)/2, &tempStr, true /* big endian */ );
- isoStr = tempStr.c_str();
- }
- if ( xmpValue != isoStr ) {
- std::string newContent = "vfffll";
- newContent += xmpValue;
- memcpy ( (char*)newContent.c_str(), cprtInfo.content, 6 ); // Keep old version, flags, and language.
- moovMgr->SetBox ( cprtRef, newContent.c_str(), (XMP_Uns32)(newContent.size() + 1) );
- }
-
- }
-
- }
-
- }
-
-} // ExportISOCopyrights
-
-// =================================================================================================
-// ExportQuickTimeItems
-// ====================
-
-static void ExportQuickTimeItems ( const SXMPMeta & xmp, TradQT_Manager * qtMgr, MOOV_Manager * moovMgr )
-{
-
- // The QuickTime 'udta' timecode items are done here for simplicity.
-
- #define createWithZeroLang true
-
- qtMgr->ExportSimpleXMP ( kQTilst_Reel, xmp, kXMP_NS_DM, "tapeName" );
- qtMgr->ExportSimpleXMP ( kQTilst_Timecode, xmp, kXMP_NS_DM, "startTimecode/xmpDM:timeValue", createWithZeroLang );
- qtMgr->ExportSimpleXMP ( kQTilst_TimeScale, xmp, kXMP_NS_DM, "startTimeScale", createWithZeroLang );
- qtMgr->ExportSimpleXMP ( kQTilst_TimeSize, xmp, kXMP_NS_DM, "startTimeSampleSize", createWithZeroLang );
-
- qtMgr->UpdateChangedBoxes ( moovMgr );
-
-} // ExportQuickTimeItems
-
-// =================================================================================================
-// SelectTimeFormat
-// ================
-
-static const char * SelectTimeFormat ( const MPEG4_MetaHandler::TimecodeTrackInfo & tmcdInfo )
-{
- const char * timeFormat = 0;
-
- float fltFPS = (float)tmcdInfo.timeScale / (float)tmcdInfo.frameDuration;
- int intFPS = (int) (fltFPS + 0.5);
-
- switch ( intFPS ) {
-
- case 30:
- if ( fltFPS >= 29.985 ) {
- timeFormat = "30Timecode";
- } else if ( tmcdInfo.isDropFrame ) {
- timeFormat = "2997DropTimecode";
- } else {
- timeFormat = "2997NonDropTimecode";
- }
- break;
-
- case 24:
- if ( fltFPS >= 23.988 ) {
- timeFormat = "24Timecode";
- } else {
- timeFormat = "23976Timecode";
- }
- break;
-
- case 25:
- timeFormat = "25Timecode";
- break;
-
- case 50:
- timeFormat = "50Timecode";
- break;
-
- case 60:
- if ( fltFPS >= 59.97 ) {
- timeFormat = "60Timecode";
- } else if ( tmcdInfo.isDropFrame ) {
- timeFormat = "5994DropTimecode";
- } else {
- timeFormat = "5994NonDropTimecode";
- }
- break;
-
- }
-
- return timeFormat;
-
-} // SelectTimeFormat
-
-// =================================================================================================
-// SelectTimeFormat
-// ================
-
-static const char * SelectTimeFormat ( const SXMPMeta & xmp )
-{
- bool ok;
- MPEG4_MetaHandler::TimecodeTrackInfo tmcdInfo;
-
- XMP_Int64 timeScale;
- ok = xmp.GetProperty_Int64 ( kXMP_NS_DM, "startTimeScale", &timeScale, 0 );
- if ( ! ok ) return 0;
- tmcdInfo.timeScale = (XMP_Uns32)timeScale;
-
- XMP_Int64 frameDuration;
- ok = xmp.GetProperty_Int64 ( kXMP_NS_DM, "startTimeSampleSize", &frameDuration, 0 );
- if ( ! ok ) return 0;
- tmcdInfo.frameDuration = (XMP_Uns32)frameDuration;
-
- std::string timecode;
- ok = xmp.GetProperty ( kXMP_NS_DM, "startTimecode/xmpDM:timeValue", &timecode, 0 );
- if ( ! ok ) return 0;
- if ( (timecode.size() == 11) && (timecode[8] == ';') ) tmcdInfo.isDropFrame = true;
-
- return SelectTimeFormat ( tmcdInfo );
-
-} // SelectTimeFormat
-
-// =================================================================================================
-// ComposeTimecode
-// ===============
-
-static const char * kDecDigits = "0123456789";
-#define TwoDigits(val,str) (str)[0] = kDecDigits[(val)/10]; (str)[1] = kDecDigits[(val)%10]
-
-static bool ComposeTimecode ( const MPEG4_MetaHandler::TimecodeTrackInfo & tmcdInfo, std::string * strValue )
-{
- float fltFPS = (float)tmcdInfo.timeScale / (float)tmcdInfo.frameDuration;
- int intFPS = (int) (fltFPS + 0.5);
- if ( (intFPS != 30) && (intFPS != 24) && (intFPS != 25) && (intFPS != 50) && (intFPS != 60) ) return false;
-
- XMP_Uns32 framesPerDay = intFPS * 24*60*60;
- XMP_Uns32 dropLimit = 2; // Used in the drop-frame correction.
-
- if ( tmcdInfo.isDropFrame ) {
- if ( intFPS == 30 ) {
- framesPerDay = 2589408; // = 29.97 * 24*60*60
- } else if ( intFPS == 60 ) {
- framesPerDay = 5178816; // = 59.94 * 24*60*60
- dropLimit = 4;
- } else {
- strValue->erase();
- return false; // Dropframe can only apply to 29.97 and 59.94.
- }
- }
-
- XMP_Uns32 framesPerHour = framesPerDay / 24;
- XMP_Uns32 framesPerTenMinutes = framesPerHour / 6;
- XMP_Uns32 framesPerMinute = framesPerTenMinutes / 10;
-
- XMP_Uns32 frameCount = tmcdInfo.timecodeSample;
- while (frameCount >= framesPerDay ) frameCount -= framesPerDay; // Normalize to be within 24 hours.
-
- XMP_Uns32 hours, minHigh, minLow, seconds;
-
- hours = frameCount / framesPerHour;
- frameCount -= (hours * framesPerHour);
-
- minHigh = frameCount / framesPerTenMinutes;
- frameCount -= (minHigh * framesPerTenMinutes);
-
- minLow = frameCount / framesPerMinute;
- frameCount -= (minLow * framesPerMinute);
-
- // Do some drop-frame corrections at this point: If this is drop-frame and the units of minutes
- // is non-zero, and the seconds are zero, and the frames are zero or one, the time is illegal.
- // Perform correction by subtracting 1 from the units of minutes and adding 1798 to the frames.Ê
- // For example, 1:00:00 becomes 59:28, and 1:00:01 becomes 59:29. A special case can occur for
- // when the frameCount just before the minHigh calculation is less than framesPerTenMinutes but
- // more than 10*framesPerMinute. This happens because of roundoff, and will result in a minHigh
- // of 0 and a minLow of 10.ÊThe drop frame correction mustÊalso be performed for this case.
-
- if ( tmcdInfo.isDropFrame ) {
- if ( (minLow == 10) || ((minLow != 0) && (frameCount < dropLimit)) ) {
- minLow -= 1;
- frameCount += framesPerMinute;
- }
- }
-
- seconds = frameCount / intFPS;
- frameCount -= (seconds * intFPS);
-
- if ( tmcdInfo.isDropFrame ) {
- *strValue = "hh;mm;ss;ff";
- } else {
- *strValue = "hh:mm:ss:ff";
- }
-
- char * str = (char*)strValue->c_str();
- TwoDigits ( hours, str );
- str[3] = kDecDigits[minHigh]; str[4] = kDecDigits[minLow];
- TwoDigits ( seconds, str+6 );
- TwoDigits ( frameCount, str+9 );
-
- return true;
-
-} // ComposeTimecode
-
-// =================================================================================================
-// DecomposeTimecode
-// =================
-
-static bool DecomposeTimecode ( const char * strValue, MPEG4_MetaHandler::TimecodeTrackInfo * tmcdInfo )
-{
- float fltFPS = (float)tmcdInfo->timeScale / (float)tmcdInfo->frameDuration;
- int intFPS = (int) (fltFPS + 0.5);
- if ( (intFPS != 30) && (intFPS != 24) && (intFPS != 25) && (intFPS != 50) && (intFPS != 60) ) return false;
-
- XMP_Uns32 framesPerDay = intFPS * 24*60*60;
-
- int items, hours, minutes, seconds, frames;
-
- if ( ! tmcdInfo->isDropFrame ) {
- items = sscanf ( strValue, "%d:%d:%d:%d", &hours, &minutes, &seconds, &frames );
- } else {
- items = sscanf ( strValue, "%d;%d;%d;%d", &hours, &minutes, &seconds, &frames );
- if ( intFPS == 30 ) {
- framesPerDay = 2589408; // = 29.97 * 24*60*60
- } else if ( intFPS == 60 ) {
- framesPerDay = 5178816; // = 59.94 * 24*60*60
- } else {
- return false; // Dropframe can only apply to 29.97 and 59.94.
- }
- }
-
- if ( items != 4 ) return false;
- int minHigh = minutes / 10;
- int minLow = minutes % 10;
-
- XMP_Uns32 framesPerHour = framesPerDay / 24;
- XMP_Uns32 framesPerTenMinutes = framesPerHour / 6;
- XMP_Uns32 framesPerMinute = framesPerTenMinutes / 10;
-
- tmcdInfo->timecodeSample = (hours * framesPerHour) + (minHigh * framesPerTenMinutes) +
- (minLow * framesPerMinute) + (seconds * intFPS) + frames;
-
- return true;
-
-} // DecomposeTimecode
-
-// =================================================================================================
-// FindTimecodeTrack
-// =================
-//
-// Look for a well-formed timecode track, return the .../mdia/minf/stbl box ref.
-
-static MOOV_Manager::BoxRef FindTimecodeTrack ( const MOOV_Manager & moovMgr )
-{
-
- // Find a 'trak' box with a handler type of 'tmcd'.
-
- MOOV_Manager::BoxInfo moovInfo;
- MOOV_Manager::BoxRef moovRef = moovMgr.GetBox ( "moov", &moovInfo );
- XMP_Assert ( moovRef != 0 );
-
- MOOV_Manager::BoxInfo trakInfo;
- MOOV_Manager::BoxRef trakRef;
-
- size_t i = 0;
- for ( ; i < moovInfo.childCount; ++i ) {
-
- trakRef = moovMgr.GetNthChild ( moovRef, i, &trakInfo );
- if ( trakRef == 0 ) return 0; // Sanity check, should not happen.
- if ( trakInfo.boxType != ISOMedia::k_trak ) continue;
-
- MOOV_Manager::BoxRef innerRef;
- MOOV_Manager::BoxInfo innerInfo;
-
- innerRef = moovMgr.GetTypeChild ( trakRef, ISOMedia::k_mdia, &innerInfo );
- if ( innerRef == 0 ) continue;
-
- innerRef = moovMgr.GetTypeChild ( innerRef, ISOMedia::k_hdlr, &innerInfo );
- if ( (innerRef == 0) || (innerInfo.contentSize < sizeof ( MOOV_Manager::Content_hdlr )) ) continue;
-
- const MOOV_Manager::Content_hdlr * hdlr = (MOOV_Manager::Content_hdlr*) innerInfo.content;
- if ( hdlr->versionFlags != 0 ) continue;
- if ( GetUns32BE ( &hdlr->handlerType ) == ISOMedia::k_tmcd ) break;
-
- }
- if ( i == moovInfo.childCount ) return 0;
-
- // Find the .../mdia/minf/stbl box.
-
- MOOV_Manager::BoxInfo tempInfo;
- MOOV_Manager::BoxRef tempRef, stblRef;
-
- tempRef = moovMgr.GetTypeChild ( trakRef, ISOMedia::k_mdia, &tempInfo );
- if ( tempRef == 0 ) return 0;
-
- tempRef = moovMgr.GetTypeChild ( tempRef, ISOMedia::k_minf, &tempInfo );
- if ( tempRef == 0 ) return 0;
-
- stblRef = moovMgr.GetTypeChild ( tempRef, ISOMedia::k_stbl, &tempInfo );
- return stblRef;
-
-} // FindTimecodeTrack
-
-// =================================================================================================
-// ImportTimecodeItems
-// ===================
-
-static bool ImportTimecodeItems ( const MPEG4_MetaHandler::TimecodeTrackInfo & tmcdInfo,
- const TradQT_Manager & qtInfo, SXMPMeta * xmp )
-{
- std::string xmpValue;
- bool haveItem;
- bool haveImports = false;
-
- // The QT user data item '©REL' goes into xmpDM:tapeName, and the 'name' box at the end of the
- // timecode sample description goes into xmpDM:altTapeName.
- haveImports |= qtInfo.ImportSimpleXMP ( kQTilst_Reel, xmp, kXMP_NS_DM, "tapeName" );
- if ( ! tmcdInfo.macName.empty() ) {
- haveItem = ConvertFromMacLang ( tmcdInfo.macName, tmcdInfo.macLang, &xmpValue );
- if ( haveItem ) {
- xmp->SetProperty ( kXMP_NS_DM, "altTapeName", xmpValue.c_str() );
- haveImports = true;
- }
- }
-
- // The QT user data item '©TSC' goes into xmpDM:startTimeScale. If that isn't present, then
- // the timecode sample description's timeScale is used.
- haveItem = qtInfo.ImportSimpleXMP ( kQTilst_TimeScale, xmp, kXMP_NS_DM, "startTimeScale" );
- if ( tmcdInfo.stsdBoxFound & (! haveItem) ) {
- xmp->SetProperty_Int64 ( kXMP_NS_DM, "startTimeScale", tmcdInfo.timeScale );
- haveItem = true;
- }
- haveImports |= haveItem;
-
- // The QT user data item '©TSZ' goes into xmpDM:startTimeSampleSize. If that isn't present, then
- // the timecode sample description's frameDuration is used.
- haveItem = qtInfo.ImportSimpleXMP ( kQTilst_TimeSize, xmp, kXMP_NS_DM, "startTimeSampleSize" );
- if ( tmcdInfo.stsdBoxFound & (! haveItem) ) {
- xmp->SetProperty_Int64 ( kXMP_NS_DM, "startTimeSampleSize", tmcdInfo.frameDuration );
- haveItem = true;
- }
- haveImports |= haveItem;
-
- const char * timeFormat;
-
- // The Timecode struct type is used for xmpDM:startTimecode and xmpDM:altTimecode. For both, only
- // the xmpDM:timeValue and xmpDM:timeFormat fields are set.
-
- // The QT user data item '©TIM' goes into xmpDM:startTimecode/xmpDM:timeValue. This is an already
- // formatted timecode string. The XMP values of xmpDM:startTimeScale, xmpDM:startTimeSampleSize,
- // and xmpDM:startTimecode/xmpDM:timeValue are used to select the timeFormat value.
- haveImports |= qtInfo.ImportSimpleXMP ( kQTilst_Timecode, xmp, kXMP_NS_DM, "startTimecode/xmpDM:timeValue" );
- timeFormat = SelectTimeFormat ( *xmp );
- if ( timeFormat != 0 ) {
- xmp->SetProperty ( kXMP_NS_DM, "startTimecode/xmpDM:timeFormat", timeFormat );
- haveImports = true;
- }
-
- if ( tmcdInfo.stsdBoxFound ) {
-
- haveItem = ComposeTimecode ( tmcdInfo, &xmpValue );
- if ( haveItem ) {
- xmp->SetProperty ( kXMP_NS_DM, "altTimecode/xmpDM:timeValue", xmpValue.c_str() );
- haveImports = true;
- }
-
- timeFormat = SelectTimeFormat ( tmcdInfo );
- if ( timeFormat != 0 ) {
- xmp->SetProperty ( kXMP_NS_DM, "altTimecode/xmpDM:timeFormat", timeFormat );
- haveImports = true;
- }
-
- }
-
- return haveImports;
-
-} // ImportTimecodeItems
-
-// =================================================================================================
-// ExportTimecodeItems
-// ===================
-
-static void ExportTimecodeItems ( const SXMPMeta & xmp, MPEG4_MetaHandler::TimecodeTrackInfo * tmcdInfo,
- TradQT_Manager * qtMgr, MOOV_Manager * moovMgr )
-{
- // Export the items that go into the timecode track:
- // - the timescale and frame duration in the first 'stsd' table entry
- // - the 'name' box appended to the first 'stsd' table entry
- // - the first timecode sample
- // ! The QuickTime 'udta' timecode items are handled in ExportQuickTimeItems.
-
- if ( ! tmcdInfo->stsdBoxFound ) return; // Don't make changes unless there is a well-formed timecode track.
-
- MOOV_Manager::BoxRef stblRef = FindTimecodeTrack ( *moovMgr );
- if ( stblRef == 0 ) return;
-
- MOOV_Manager::BoxInfo stsdInfo;
- MOOV_Manager::BoxRef stsdRef;
-
- stsdRef = moovMgr->GetTypeChild ( stblRef, ISOMedia::k_stsd, &stsdInfo );
- if ( stsdRef == 0 ) return;
- if ( stsdInfo.contentSize < (8 + sizeof ( MOOV_Manager::Content_stsd_entry )) ) return;
- if ( GetUns32BE ( stsdInfo.content + 4 ) == 0 ) return; // Make sure the entry count is non-zero.
-
- const MOOV_Manager::Content_stsd_entry * stsdRawEntry = (MOOV_Manager::Content_stsd_entry*) (stsdInfo.content + 8);
-
- XMP_Uns32 stsdEntrySize = GetUns32BE ( &stsdRawEntry->entrySize );
- if ( stsdEntrySize > (stsdInfo.contentSize - 4) ) stsdEntrySize = stsdInfo.contentSize - 4;
- if ( stsdEntrySize < sizeof ( MOOV_Manager::Content_stsd_entry ) ) return;
-
- bool ok;
- std::string xmpValue;
- XMP_Int64 int64; // Used to allow UInt32 values, GetProperty_Int is SInt32.
-
- // The tmcdInfo timeScale field is set from xmpDM:startTimeScale.
- ok = xmp.GetProperty_Int64 ( kXMP_NS_DM, "startTimeScale", &int64, 0 );
- if ( ok && (int64 <= 0xFFFFFFFF) && ((XMP_Uns32)int64 != tmcdInfo->timeScale) ) {
- tmcdInfo->timeScale = (XMP_Uns32)int64;
- PutUns32BE ( tmcdInfo->timeScale, (void*)&stsdRawEntry->timeScale );
- moovMgr->NoteChange();
- }
-
- // The tmcdInfo frameDuration field is set from xmpDM:startTimeSampleSize.
- ok = xmp.GetProperty_Int64 ( kXMP_NS_DM, "startTimeSampleSize", &int64, 0 );
- if ( ok && (int64 <= 0xFFFFFFFF) && ((XMP_Uns32)int64 != tmcdInfo->frameDuration) ) {
- tmcdInfo->frameDuration = (XMP_Uns32)int64;
- PutUns32BE ( tmcdInfo->frameDuration, (void*)&stsdRawEntry->frameDuration );
- moovMgr->NoteChange();
- }
-
- // The tmcdInfo isDropFrame flag is set from xmpDM:altTimecode/xmpDM:timeValue. The timeScale
- // and frameDuration must be updated first, they are used by DecomposeTimecode. Compute the new
- // UInt32 timecode sample, but it gets written to the file later by UpdateFile.
-
- ok = xmp.GetProperty ( kXMP_NS_DM, "altTimecode/xmpDM:timeValue", &xmpValue, 0 );
- if ( ok && (xmpValue.size() == 11) ) {
-
- bool oldDropFrame = tmcdInfo->isDropFrame;
- tmcdInfo->isDropFrame = false;
- if ( xmpValue[8] == ';' ) tmcdInfo->isDropFrame = true;
- if ( oldDropFrame != tmcdInfo->isDropFrame ) {
- XMP_Uns32 flags = GetUns32BE ( &stsdRawEntry->flags );
- flags = (flags & 0xFFFFFFFE) | (XMP_Uns32)tmcdInfo->isDropFrame;
- PutUns32BE ( flags, (void*)&stsdRawEntry->flags );
- moovMgr->NoteChange();
- }
-
- XMP_Uns32 oldSample = tmcdInfo->timecodeSample;
- ok = DecomposeTimecode ( xmpValue.c_str(), tmcdInfo );
- if ( ok && (oldSample != tmcdInfo->timecodeSample) ) moovMgr->NoteChange();
-
- }
-
- // The 'name' box attached to the first 'stsd' table entry is set from xmpDM:altTapeName.
-
- bool replaceNameBox = false;
-
- ok = xmp.GetProperty ( kXMP_NS_DM, "altTapeName", &xmpValue, 0 );
- if ( (! ok) || xmpValue.empty() ) {
- if ( tmcdInfo->nameOffset != 0 ) replaceNameBox = true; // No XMP, get rid of existing name.
- } else {
- std::string macValue;
- ok = ConvertToMacLang ( xmpValue, tmcdInfo->macLang, &macValue );
- if ( ok && (macValue != tmcdInfo->macName) ) {
- tmcdInfo->macName = macValue;
- replaceNameBox = true; // Write changed name.
- }
- }
-
- if ( replaceNameBox ) {
-
- // To replace the 'name' box we have to create an entire new 'stsd' box, and attach the
- // new name to the first 'stsd' table entry. The 'name' box content is a UInt16 text length,
- // UInt16 language code, and Mac encoded text with no nul termination.
-
- if ( tmcdInfo->macName.size() > 0xFFFF ) tmcdInfo->macName.erase ( 0xFFFF );
-
- ISOMedia::BoxInfo oldNameInfo;
- XMP_Assert ( (oldNameInfo.headerSize == 0) && (oldNameInfo.contentSize == 0) );
- if ( tmcdInfo->nameOffset != 0 ) {
- const XMP_Uns8 * oldNamePtr = stsdInfo.content + tmcdInfo->nameOffset;
- const XMP_Uns8 * oldNameLimit = stsdInfo.content + stsdInfo.contentSize;
- (void) ISOMedia::GetBoxInfo ( oldNamePtr, oldNameLimit, &oldNameInfo );
- }
-
- XMP_Uns32 oldNameBoxSize = (XMP_Uns32)oldNameInfo.headerSize + (XMP_Uns32)oldNameInfo.contentSize;
- XMP_Uns32 newNameBoxSize = 0;
- if ( ! tmcdInfo->macName.empty() ) newNameBoxSize = 4+4 + 2+2 + (XMP_Uns32)tmcdInfo->macName.size();
-
- XMP_Uns32 stsdNewContentSize = stsdInfo.contentSize - oldNameBoxSize + newNameBoxSize;
- RawDataBlock stsdNewContent;
- stsdNewContent.assign ( stsdNewContentSize, 0 ); // Get the space allocated, direct fill below.
-
- XMP_Uns32 stsdPrefixSize = tmcdInfo->nameOffset;
- if ( tmcdInfo->nameOffset == 0 ) stsdPrefixSize = 4+4 + sizeof ( MOOV_Manager::Content_stsd_entry );
-
- XMP_Uns32 oldSuffixOffset = stsdPrefixSize + oldNameBoxSize;
- XMP_Uns32 newSuffixOffset = stsdPrefixSize + newNameBoxSize;
- XMP_Uns32 stsdSuffixSize = stsdInfo.contentSize - oldSuffixOffset;
-
- memcpy ( &stsdNewContent[0], stsdInfo.content, stsdPrefixSize );
- if ( stsdSuffixSize != 0 ) memcpy ( &stsdNewContent[newSuffixOffset], (stsdInfo.content + oldSuffixOffset), stsdSuffixSize );
-
- XMP_Uns32 newEntrySize = stsdEntrySize - oldNameBoxSize + newNameBoxSize;
- MOOV_Manager::Content_stsd_entry * stsdNewEntry = (MOOV_Manager::Content_stsd_entry*) (&stsdNewContent[0] + 8);
- PutUns32BE ( newEntrySize, &stsdNewEntry->entrySize );
-
- if ( newNameBoxSize != 0 ) {
- PutUns32BE ( newNameBoxSize, &stsdNewContent[stsdPrefixSize] );
- PutUns32BE ( ISOMedia::k_name, &stsdNewContent[stsdPrefixSize+4] );
- PutUns16BE ( (XMP_Uns16)tmcdInfo->macName.size(), &stsdNewContent[stsdPrefixSize+8] );
- PutUns16BE ( tmcdInfo->macLang, &stsdNewContent[stsdPrefixSize+10] );
- memcpy ( &stsdNewContent[stsdPrefixSize+12], tmcdInfo->macName.c_str(), tmcdInfo->macName.size() );
- }
-
- moovMgr->SetBox ( stsdRef, &stsdNewContent[0], stsdNewContentSize );
-
- }
-
-} // ExportTimecodeItems
-
-// =================================================================================================
-// ImportCr8rItems
-// ===============
-
-#pragma pack ( push, 1 )
-
-struct PrmLBoxContent {
- XMP_Uns32 magic;
- XMP_Uns32 size;
- XMP_Uns16 verAPI;
- XMP_Uns16 verCode;
- XMP_Uns32 exportType;
- XMP_Uns16 MacVRefNum;
- XMP_Uns32 MacParID;
- char filePath[260];
-};
-
-enum { kExportTypeMovie = 0, kExportTypeStill = 1, kExportTypeAudio = 2, kExportTypeCustom = 3 };
-
-struct Cr8rBoxContent {
- XMP_Uns32 magic;
- XMP_Uns32 size;
- XMP_Uns16 majorVer;
- XMP_Uns16 minorVer;
- XMP_Uns32 creatorCode;
- XMP_Uns32 appleEvent;
- char fileExt[16];
- char appOptions[16];
- char appName[32];
-};
-
-#pragma pack ( pop )
-
-// -------------------------------------------------------------------------------------------------
-
-static bool ImportCr8rItems ( const MOOV_Manager & moovMgr, SXMPMeta * xmp )
-{
- bool haveXMP = false;
-
- MOOV_Manager::BoxInfo infoPrmL, infoCr8r;
- MOOV_Manager::BoxRef refPrmL = moovMgr.GetBox ( "moov/udta/PrmL", &infoPrmL );
- MOOV_Manager::BoxRef refCr8r = moovMgr.GetBox ( "moov/udta/Cr8r", &infoCr8r );
-
- bool havePrmL = ( (refPrmL != 0) && (infoPrmL.contentSize == sizeof ( PrmLBoxContent )) );
- bool haveCr8r = ( (refCr8r != 0) && (infoCr8r.contentSize == sizeof ( Cr8rBoxContent )) );
-
- if ( havePrmL ) {
-
- PrmLBoxContent rawPrmL;
- XMP_Assert ( sizeof ( rawPrmL ) == 282 );
- XMP_Assert ( sizeof ( rawPrmL.filePath ) == 260 );
- memcpy ( &rawPrmL, infoPrmL.content, sizeof ( rawPrmL ) );
- if ( rawPrmL.magic != 0xBEEFCAFE ) {
- Flip4 ( &rawPrmL.exportType ); // The only numeric field that we care about.
- }
-
- rawPrmL.filePath[259] = 0; // Ensure a terminating nul.
- if ( rawPrmL.filePath[0] != 0 ) {
- if ( rawPrmL.filePath[0] == '/' ) {
- haveXMP = true;
- xmp->SetStructField ( kXMP_NS_CreatorAtom, "macAtom",
- kXMP_NS_CreatorAtom, "posixProjectPath", rawPrmL.filePath );
- } else if ( XMP_LitNMatch ( rawPrmL.filePath, "\\\\?\\", 4 ) ) {
- haveXMP = true;
- xmp->SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom",
- kXMP_NS_CreatorAtom, "uncProjectPath", rawPrmL.filePath );
- }
- }
-
- const char * exportStr = 0;
- switch ( rawPrmL.exportType ) {
- case kExportTypeMovie : exportStr = "movie"; break;
- case kExportTypeStill : exportStr = "still"; break;
- case kExportTypeAudio : exportStr = "audio"; break;
- case kExportTypeCustom : exportStr = "custom"; break;
- }
- if ( exportStr != 0 ) {
- haveXMP = true;
- xmp->SetStructField ( kXMP_NS_DM, "projectRef", kXMP_NS_DM, "type", exportStr );
- }
-
- }
-
- if ( haveCr8r ) {
-
- Cr8rBoxContent rawCr8r;
- XMP_Assert ( sizeof ( rawCr8r ) == 84 );
- XMP_Assert ( sizeof ( rawCr8r.fileExt ) == 16 );
- XMP_Assert ( sizeof ( rawCr8r.appOptions ) == 16 );
- XMP_Assert ( sizeof ( rawCr8r.appName ) == 32 );
- memcpy ( &rawCr8r, infoCr8r.content, sizeof ( rawCr8r ) );
- if ( rawCr8r.magic != 0xBEEFCAFE ) {
- Flip4 ( &rawCr8r.creatorCode ); // The only numeric fields that we care about.
- Flip4 ( &rawCr8r.appleEvent );
- }
-
- std::string fieldPath;
-
- SXMPUtils::ComposeStructFieldPath ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &fieldPath );
- if ( rawCr8r.creatorCode != 0 ) {
- haveXMP = true;
- xmp->SetProperty_Int64 ( kXMP_NS_CreatorAtom, fieldPath.c_str(), (XMP_Int64)rawCr8r.creatorCode ); // ! Unsigned trickery.
- }
-
- SXMPUtils::ComposeStructFieldPath ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &fieldPath );
- if ( rawCr8r.appleEvent != 0 ) {
- haveXMP = true;
- xmp->SetProperty_Int64 ( kXMP_NS_CreatorAtom, fieldPath.c_str(), (XMP_Int64)rawCr8r.appleEvent ); // ! Unsigned trickery.
- }
-
- rawCr8r.fileExt[15] = 0; // Ensure a terminating nul.
- if ( rawCr8r.fileExt[0] != 0 ) {
- haveXMP = true;
- xmp->SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", rawCr8r.fileExt );
- }
-
- rawCr8r.appOptions[15] = 0; // Ensure a terminating nul.
- if ( rawCr8r.appOptions[0] != 0 ) {
- haveXMP = true;
- xmp->SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", rawCr8r.appOptions );
- }
-
- rawCr8r.appName[31] = 0; // Ensure a terminating nul.
- if ( rawCr8r.appName[0] != 0 ) {
- haveXMP = true;
- xmp->SetProperty ( kXMP_NS_XMP, "CreatorTool", rawCr8r.appName );
- }
-
- }
-
- return haveXMP;
-
-} // ImportCr8rItems
-
-// =================================================================================================
-// ExportCr8rItems
-// ===============
-
-static inline void SetBufferedString ( char * dest, const std::string source, size_t limit )
-{
- memset ( dest, 0, limit );
- size_t count = source.size();
- if ( count >= limit ) count = limit - 1; // Ensure a terminating nul.
- memcpy ( dest, source.c_str(), count );
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static void ExportCr8rItems ( const SXMPMeta & xmp, MOOV_Manager * moovMgr )
-{
- bool haveNewCr8r = false;
- std::string creatorCode, appleEvent, fileExt, appOptions, appName;
-
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &creatorCode, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &appleEvent, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", &fileExt, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", &appOptions, 0 );
- haveNewCr8r |= xmp.GetProperty ( kXMP_NS_XMP, "CreatorTool", &appName, 0 );
-
- MOOV_Manager::BoxInfo infoCr8r;
- MOOV_Manager::BoxRef refCr8r = moovMgr->GetBox ( "moov/udta/Cr8r", &infoCr8r );
- bool haveOldCr8r = ( (refCr8r != 0) && (infoCr8r.contentSize == sizeof ( Cr8rBoxContent )) );
-
- if ( ! haveNewCr8r ) {
- if ( haveOldCr8r ) {
- MOOV_Manager::BoxRef udtaRef = moovMgr->GetBox ( "moov/udta", 0 );
- moovMgr->DeleteTypeChild ( udtaRef, 0x43723872 /* 'Cr8r' */ );
- }
- return;
- }
-
- Cr8rBoxContent newCr8r;
- const Cr8rBoxContent * oldCr8r = (Cr8rBoxContent*) infoCr8r.content;
-
- if ( ! haveOldCr8r ) {
-
- memset ( &newCr8r, 0, sizeof(newCr8r) );
- newCr8r.magic = MakeUns32BE ( 0xBEEFCAFE );
- newCr8r.size = MakeUns32BE ( sizeof ( newCr8r ) );
- newCr8r.majorVer = MakeUns16BE ( 1 );
-
- } else {
-
- memcpy ( &newCr8r, oldCr8r, sizeof(newCr8r) );
- if ( GetUns32BE ( &newCr8r.magic ) != 0xBEEFCAFE ) { // Make sure we write BE numbers.
- Flip4 ( &newCr8r.magic );
- Flip4 ( &newCr8r.size );
- Flip2 ( &newCr8r.majorVer );
- Flip2 ( &newCr8r.minorVer );
- Flip4 ( &newCr8r.creatorCode );
- Flip4 ( &newCr8r.appleEvent );
- }
-
- }
-
- if ( ! creatorCode.empty() ) {
- newCr8r.creatorCode = MakeUns32BE ( (XMP_Uns32) strtoul ( creatorCode.c_str(), 0, 0 ) );
- }
-
- if ( ! appleEvent.empty() ) {
- newCr8r.appleEvent = MakeUns32BE ( (XMP_Uns32) strtoul ( appleEvent.c_str(), 0, 0 ) );
- }
-
- if ( ! fileExt.empty() ) SetBufferedString ( newCr8r.fileExt, fileExt, sizeof ( newCr8r.fileExt ) );
- if ( ! appOptions.empty() ) SetBufferedString ( newCr8r.appOptions, appOptions, sizeof ( newCr8r.appOptions ) );
- if ( ! appName.empty() ) SetBufferedString ( newCr8r.appName, appName, sizeof ( newCr8r.appName ) );
-
- moovMgr->SetBox ( "moov/udta/Cr8r", &newCr8r, sizeof(newCr8r) );
-
-} // ExportCr8rItems
-
-// =================================================================================================
-// GetAtomInfo
-// ===========
-
-struct AtomInfo {
- XMP_Int64 atomSize;
- XMP_Uns32 atomType;
- bool hasLargeSize;
-};
-
-enum { // ! Do not rearrange, code depends on this order.
- kBadQT_NoError = 0, // No errors.
- kBadQT_SmallInner = 1, // An extra 1..7 bytes at the end of an inner span.
- kBadQT_LargeInner = 2, // More serious inner garbage, found as invalid atom length.
- kBadQT_SmallOuter = 3, // An extra 1..7 bytes at the end of the file.
- kBadQT_LargeOuter = 4 // More serious EOF garbage, found as invalid atom length.
-};
-typedef XMP_Uns8 QTErrorMode;
-
-static QTErrorMode GetAtomInfo ( const LFA_FileRef qtFile, XMP_Int64 spanSize, int nesting, AtomInfo * info )
-{
- QTErrorMode status = kBadQT_NoError;
- XMP_Uns8 buffer [8];
-
- info->hasLargeSize = false;
-
- LFA_Read ( qtFile, buffer, 8, kLFA_RequireAll ); // Will throw if 8 bytes aren't available.
- info->atomSize = GetUns32BE ( &buffer[0] ); // ! Yes, the initial size is big endian UInt32.
- info->atomType = GetUns32BE ( &buffer[4] );
-
- if ( info->atomSize == 0 ) { // Does the atom extend to EOF?
-
- if ( nesting != 0 ) return kBadQT_LargeInner;
- info->atomSize = spanSize; // This outer atom goes to EOF.
-
- } else if ( info->atomSize == 1 ) { // Does the atom have a 64-bit size?
-
- if ( spanSize < 16 ) { // Is there room in the span for the 16 byte header?
- status = kBadQT_LargeInner;
- if ( nesting == 0 ) status += 2; // Convert to "outer".
- return status;
- }
-
- LFA_Read ( qtFile, buffer, 8, kLFA_RequireAll );
- info->atomSize = (XMP_Int64) GetUns64BE ( &buffer[0] );
- info->hasLargeSize = true;
-
- }
-
- XMP_Assert ( status == kBadQT_NoError );
- return status;
-
-} // GetAtomInfo
-
-// =================================================================================================
-// CheckAtomList
-// =============
-//
-// Check that a sequence of atoms fills a given span. The I/O position must be at the start of the
-// span, it is left just past the span on success. Recursive checks are done for top level 'moov'
-// atoms, and second level 'udta' atoms ('udta' inside 'moov').
-//
-// Checking continues for "small inner" errors. They will be reported if no other kinds of errors
-// are found, otherwise the other error is reported. Checking is immediately aborted for any "large"
-// error. The rationale is that QuickTime can apparently handle small inner errors. They might be
-// arise from updates that shorten an atom by less than 8 bytes. Larger shrinkage should introduce a
-// 'free' atom.
-
-static QTErrorMode CheckAtomList ( const LFA_FileRef qtFile, XMP_Int64 spanSize, int nesting )
-{
- QTErrorMode status = kBadQT_NoError;
- AtomInfo info;
-
- const static XMP_Uns32 moovAtomType = 0x6D6F6F76; // ! Don't use MakeUns32BE, already big endian.
- const static XMP_Uns32 udtaAtomType = 0x75647461;
-
- for ( ; spanSize >= 8; spanSize -= info.atomSize ) {
-
- QTErrorMode atomStatus = GetAtomInfo ( qtFile, spanSize, nesting, &info );
- if ( atomStatus != kBadQT_NoError ) return atomStatus;
-
- XMP_Int64 headerSize = 8;
- if ( info.hasLargeSize ) headerSize = 16;
-
- if ( (info.atomSize < headerSize) || (info.atomSize > spanSize) ) {
- status = kBadQT_LargeInner;
- if ( nesting == 0 ) status += 2; // Convert to "outer".
- return status;
- }
-
- bool doChildren = false;
- if ( (nesting == 0) && (info.atomType == moovAtomType) ) doChildren = true;
- if ( (nesting == 1) && (info.atomType == udtaAtomType) ) doChildren = true;
-
- XMP_Int64 dataSize = info.atomSize - headerSize;
-
- if ( ! doChildren ) {
- LFA_Seek ( qtFile, dataSize, SEEK_CUR );
- } else {
- QTErrorMode innerStatus = CheckAtomList ( qtFile, dataSize, nesting+1 );
- if ( innerStatus > kBadQT_SmallInner ) return innerStatus; // Quit for serious errors.
- if ( status == kBadQT_NoError ) status = innerStatus; // Remember small inner errors.
- }
-
- }
-
- XMP_Assert ( status <= kBadQT_SmallInner ); // Else already returned.
- // ! Make sure inner kBadQT_SmallInner is propagated if this span is OK.
-
- if ( spanSize != 0 ) {
- LFA_Seek ( qtFile, spanSize, SEEK_CUR ); // ! Skip the trailing garbage of this span.
- status = kBadQT_SmallInner;
- if ( spanSize >= 8 ) status = kBadQT_LargeInner;
- if ( nesting == 0 ) status += 2; // Convert to "outer".
- }
-
- return status;
-
-} // CheckAtomList
-
-// =================================================================================================
-// AttemptFileRepair
-// =================
-
-static void AttemptFileRepair ( LFA_FileRef qtFile, XMP_Int64 fileSpace, QTErrorMode status )
-{
-
- 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 );
- }
-
- AtomInfo info;
- XMP_Int64 headerSize;
-
- // Process the top level atoms until an error is found.
-
- LFA_Seek ( qtFile, 0, SEEK_SET );
-
- for ( ; fileSpace >= 8; fileSpace -= info.atomSize ) {
-
- QTErrorMode atomStatus = GetAtomInfo ( qtFile, fileSpace, 0, &info );
-
- headerSize = 8; // ! Set this before checking atomStatus, used after the loop.
- if ( info.hasLargeSize ) headerSize = 16;
-
- if ( atomStatus != kBadQT_NoError ) break;
- if ( (info.atomSize < headerSize) || (info.atomSize > fileSpace) ) break;
-
- XMP_Int64 dataSize = info.atomSize - headerSize;
- LFA_Seek ( qtFile, dataSize, SEEK_CUR );
-
- }
-
- // 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 ) LFA_Seek ( qtFile, -headerSize, SEEK_CUR );
- XMP_Int64 currPos = LFA_Tell ( qtFile );
- LFA_Truncate ( qtFile, currPos );
-
-} // AttemptFileRepair
-
-// =================================================================================================
-// CheckQTFileStructure
-// ====================
-
-static void CheckQTFileStructure ( XMPFileHandler * thiz, bool doRepair )
-{
- XMPFiles * parent = thiz->parent;
- LFA_FileRef fileRef = parent->fileRef;
- XMP_Int64 fileSize = LFA_Measure ( fileRef );
-
- // Check the basic file structure and try to repair if asked.
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- QTErrorMode status = CheckAtomList ( fileRef, fileSize, 0 );
-
- if ( status != kBadQT_NoError ) {
- if ( doRepair || (status == kBadQT_SmallInner) || (status == kBadQT_SmallOuter) ) {
- AttemptFileRepair ( fileRef, fileSize, status ); // 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.
- }
- }
-
-} // CheckQTFileStructure;
-
-// =================================================================================================
-// CheckFinalBox
-// =============
-//
-// Before appending anything new, check if the final top level box has a "to EoF" length. If so, fix
-// it to have an explicit length.
-
-static void CheckFinalBox ( LFA_FileRef fileRef, XMP_AbortProc abortProc, void * abortArg )
-{
- const bool checkAbort = (abortProc != 0);
-
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
-
- // Find the last 2 boxes in the file. Need the previous to last in case it is an Apple 'wide' box.
-
- XMP_Uns64 prevPos, lastPos, nextPos;
- ISOMedia::BoxInfo prevBox, lastBox;
- XMP_Uns8 buffer [16]; // Enough to create an extended header.
-
- memset ( &prevBox, 0, sizeof(prevBox) ); // AUDIT: Using sizeof(prevBox) is safe.
- memset ( &lastBox, 0, sizeof(lastBox) ); // AUDIT: Using sizeof(lastBox) is safe.
- prevPos = lastPos = nextPos = 0;
- while ( nextPos != fileSize ) {
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "MPEG4_MetaHandler::CheckFinalBox - User abort", kXMPErr_UserAbort );
- }
- prevBox = lastBox;
- prevPos = lastPos;
- lastPos = nextPos;
- nextPos = ISOMedia::GetBoxInfo ( fileRef, lastPos, fileSize, &lastBox, true /* throw errors */ );
- }
-
- // See if the last box is valid and has a "to EoF" size.
-
- if ( lastBox.headerSize < 8 ) XMP_Throw ( "MPEG-4 final box is invalid", kXMPErr_EnforceFailure );
- LFA_Seek ( fileRef, lastPos, SEEK_SET );
- LFA_Read ( fileRef, buffer, 4 );
- XMP_Uns64 lastSize = GetUns32BE ( &buffer[0] ); // ! Yes, the file has a 32-bit value.
- if ( lastSize != 0 ) return;
-
- // Have a final "to EoF" box, try to write the explicit size.
-
- lastSize = lastBox.headerSize + lastBox.contentSize;
- if ( lastSize <= 0xFFFFFFFFUL ) {
-
- // Fill in the 32-bit exact size.
- PutUns32BE ( (XMP_Uns32)lastSize, &buffer[0] );
- LFA_Seek ( fileRef, lastPos, SEEK_SET );
- LFA_Write ( fileRef, buffer, 4 );
-
- } else {
-
- // Try to convert to using an extended header.
-
- if ( (prevBox.boxType != ISOMedia::k_wide) || (prevBox.headerSize != 8) || (prevBox.contentSize != 0) ) {
- XMP_Throw ( "Can't expand final box header", kXMPErr_EnforceFailure );
- }
- XMP_Assert ( prevPos == (lastPos - 8) );
-
- PutUns32BE ( 1, &buffer[0] );
- PutUns32BE ( lastBox.boxType, &buffer[4] );
- PutUns64BE ( lastSize, &buffer[8] );
- LFA_Seek ( fileRef, prevPos, SEEK_SET );
- LFA_Write ( fileRef, buffer, 16 );
-
- }
-
-} // CheckFinalBox
-
-// =================================================================================================
-// WriteBoxHeader
-// ==============
-
-static void WriteBoxHeader ( LFA_FileRef fileRef, XMP_Uns32 boxType, XMP_Uns64 boxSize )
-{
- XMP_Uns32 u32;
- XMP_Uns64 u64;
- XMP_Enforce ( boxSize >= 8 ); // The size must be the full size, not just the content.
-
- if ( boxSize <= 0xFFFFFFFF ) {
-
- u32 = MakeUns32BE ( (XMP_Uns32)boxSize );
- LFA_Write ( fileRef, &u32, 4 );
- u32 = MakeUns32BE ( boxType );
- LFA_Write ( fileRef, &u32, 4 );
-
- } else {
-
- u32 = MakeUns32BE ( 1 );
- LFA_Write ( fileRef, &u32, 4 );
- u32 = MakeUns32BE ( boxType );
- LFA_Write ( fileRef, &u32, 4 );
- u64 = MakeUns64BE ( boxSize );
- LFA_Write ( fileRef, &u64, 8 );
-
- }
-
-} // WriteBoxHeader
-
-// =================================================================================================
-// WipeBoxFree
-// ===========
-//
-// Change the box's type to 'free' (or create a 'free' box) and zero the content.
-
-static XMP_Uns8 kZeroes [64*1024]; // C semantics guarantee zero initialization.
-
-static void WipeBoxFree ( LFA_FileRef fileRef, XMP_Uns64 boxOffset, XMP_Uns32 boxSize )
-{
- if ( boxSize == 0 ) return;
- XMP_Enforce ( boxSize >= 8 );
-
- LFA_Seek ( fileRef, boxOffset, SEEK_SET );
- XMP_Uns32 u32;
- u32 = MakeUns32BE ( boxSize ); // ! The actual size should not change, but might have had a long header.
- LFA_Write ( fileRef, &u32, 4 );
- u32 = MakeUns32BE ( ISOMedia::k_free );
- LFA_Write ( fileRef, &u32, 4 );
-
- XMP_Uns32 ioCount = sizeof ( kZeroes );
- for ( boxSize -= 8; boxSize > 0; boxSize -= ioCount ) {
- if ( ioCount > boxSize ) ioCount = boxSize;
- LFA_Write ( fileRef, &kZeroes[0], ioCount );
- }
-
-} // WipeBoxFree
-
-// =================================================================================================
-// CreateFreeSpaceList
-// ===================
-
-struct SpaceInfo {
- XMP_Uns64 offset, size;
- SpaceInfo() : offset(0), size(0) {};
- SpaceInfo ( XMP_Uns64 _offset, XMP_Uns64 _size ) : offset(_offset), size(_size) {};
-};
-
-typedef std::vector<SpaceInfo> FreeSpaceList;
-
-static void CreateFreeSpaceList ( LFA_FileRef fileRef, XMP_Uns64 fileSize,
- XMP_Uns64 oldOffset, XMP_Uns32 oldSize, FreeSpaceList * spaceList )
-{
- XMP_Uns64 boxPos, boxNext, adjacentFree;
- ISOMedia::BoxInfo currBox;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- spaceList->clear();
-
- for ( boxPos = 0; boxPos < fileSize; boxPos = boxNext ) {
-
- boxNext = ISOMedia::GetBoxInfo ( fileRef, boxPos, fileSize, &currBox, true /* throw errors */ );
- XMP_Uns64 currSize = currBox.headerSize + currBox.contentSize;
-
- if ( (currBox.boxType == ISOMedia::k_free) ||
- (currBox.boxType == ISOMedia::k_skip) ||
- ((boxPos == oldOffset) && (currSize == oldSize)) ) {
-
- if ( spaceList->empty() || (boxPos != adjacentFree) ) {
- spaceList->push_back ( SpaceInfo ( boxPos, currSize ) );
- adjacentFree = boxPos + currSize;
- } else {
- SpaceInfo * lastSpace = &spaceList->back();
- lastSpace->size += currSize;
- }
-
- }
-
- }
-
-} // CreateFreeSpaceList
-
-// =================================================================================================
-// MPEG4_MetaHandler::CacheFileData
-// ================================
-//
-// There are 3 file variants: normal ISO Base Media, modern QuickTime, and classic QuickTime. The
-// XMP is placed differently between the ISO and two QuickTime forms, and there is different but not
-// colliding native metadata. The entire 'moov' subtree is cached, along with the top level 'uuid'
-// box of XMP if present.
-
-void MPEG4_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- XMPFiles * parent = this->parent;
- XMP_OptionBits openFlags = parent->openFlags;
-
- LFA_FileRef fileRef = parent->fileRef;
-
- XMP_AbortProc abortProc = parent->abortProc;
- void * abortArg = parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- // First do some special case repair to QuickTime files, based on bad files in the wild.
-
- 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.
- }
-
- // Cache the top level 'moov' and 'uuid'/XMP boxes.
-
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
-
- XMP_Uns64 boxPos, boxNext;
- ISOMedia::BoxInfo currBox;
-
- bool xmpOnly = XMP_OptionIsSet ( openFlags, kXMPFiles_OpenOnlyXMP );
- bool haveISOFile = (this->fileMode == MOOV_Manager::kFileIsNormalISO);
-
- bool uuidFound = (! haveISOFile); // Ignore the XMP 'uuid' box for QuickTime files.
- bool moovIgnored = (xmpOnly & haveISOFile); // Ignore the 'moov' box for XMP-only ISO files.
- bool moovFound = moovIgnored;
-
- for ( boxPos = 0; boxPos < fileSize; boxPos = boxNext ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "MPEG4_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
- }
-
-
- boxNext = ISOMedia::GetBoxInfo ( fileRef, boxPos, fileSize, &currBox );
-
- if ( (! moovFound) && (currBox.boxType == ISOMedia::k_moov) ) {
-
- XMP_Uns64 fullMoovSize = currBox.headerSize + currBox.contentSize;
- if ( fullMoovSize > moovBoxSizeLimit ) { // From here on we know 32-bit offsets are safe.
- XMP_Throw ( "Oversize 'moov' box", kXMPErr_EnforceFailure );
- }
-
- this->moovMgr.fullSubtree.assign ( (XMP_Uns32)fullMoovSize, 0 );
- LFA_Seek ( fileRef, boxPos, SEEK_SET );
- LFA_Read ( fileRef, &this->moovMgr.fullSubtree[0], (XMP_Uns32)fullMoovSize );
-
- this->moovBoxPos = boxPos;
- this->moovBoxSize = (XMP_Uns32)fullMoovSize;
- 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];
- LFA_Read ( fileRef, uuid, 16, kLFA_RequireAll );
- if ( memcmp ( uuid, ISOMedia::k_xmpUUID, 16 ) != 0 ) continue; // Check for the XMP GUID.
-
- XMP_Uns64 fullUuidSize = currBox.headerSize + currBox.contentSize;
- if ( fullUuidSize > moovBoxSizeLimit ) { // From here on we know 32-bit offsets are safe.
- XMP_Throw ( "Oversize XMP 'uuid' box", kXMPErr_EnforceFailure );
- }
-
- this->packetInfo.offset = boxPos + currBox.headerSize + 16; // The 16 is for the UUID.
- this->packetInfo.length = (XMP_Int32) (currBox.contentSize - 16);
-
- this->xmpPacket.assign ( this->packetInfo.length, ' ' );
- LFA_Read ( fileRef, (void*)this->xmpPacket.data(), this->packetInfo.length, kLFA_RequireAll );
-
- this->xmpBoxPos = boxPos;
- this->xmpBoxSize = (XMP_Uns32)fullUuidSize;
- uuidFound = true;
- if ( moovFound ) break; // Exit the loop when both are found.
-
- }
-
- }
-
- if ( (! moovFound) && (! moovIgnored) ) XMP_Throw ( "No 'moov' box", kXMPErr_BadFileFormat );
-
-} // MPEG4_MetaHandler::CacheFileData
-
-// =================================================================================================
-// MPEG4_MetaHandler::ProcessXMP
-// =============================
-
-void MPEG4_MetaHandler::ProcessXMP()
-{
- if ( this->processedXMP ) return;
- this->processedXMP = true; // Make sure only called once.
-
- XMPFiles * parent = this->parent;
- XMP_OptionBits openFlags = parent->openFlags;
-
- bool xmpOnly = XMP_OptionIsSet ( openFlags, kXMPFiles_OpenOnlyXMP );
- bool haveISOFile = (this->fileMode == MOOV_Manager::kFileIsNormalISO);
-
- // Process the cached XMP (from the 'uuid' box) if that is all we want and this is an ISO file.
-
- if ( xmpOnly & haveISOFile ) {
-
- this->containsXMP = this->havePreferredXMP = (this->packetInfo.length != 0);
-
- if ( this->containsXMP ) {
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->xmpObj.DeleteProperty ( kXMP_NS_XMP, "NativeDigests" ); // No longer used.
- }
-
- return;
-
- }
-
- // Parse the cached 'moov' subtree, parse the preferred XMP.
-
- if ( this->moovMgr.fullSubtree.empty() ) XMP_Throw ( "No 'moov' box", kXMPErr_BadFileFormat );
- this->moovMgr.ParseMemoryTree ( this->fileMode );
-
- if ( (this->xmpBoxPos == 0) || (! haveISOFile) ) {
-
- // Look for the QuickTime moov/uuid/XMP_ box.
-
- MOOV_Manager::BoxInfo xmpInfo;
- MOOV_Manager::BoxRef xmpRef = this->moovMgr.GetBox ( "moov/udta/XMP_", &xmpInfo );
-
- if ( (xmpRef != 0) && (xmpInfo.contentSize != 0) ) {
-
- this->xmpBoxPos = this->moovBoxPos + this->moovMgr.GetParsedOffset ( xmpRef );
- this->packetInfo.offset = this->xmpBoxPos + this->moovMgr.GetHeaderSize ( xmpRef );
- this->packetInfo.length = xmpInfo.contentSize;
-
- this->xmpPacket.assign ( (char*)xmpInfo.content, this->packetInfo.length );
- this->havePreferredXMP = (! haveISOFile);
-
- }
-
- }
-
- if ( this->xmpBoxPos != 0 ) {
- this->containsXMP = true;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->xmpObj.DeleteProperty ( kXMP_NS_XMP, "NativeDigests" ); // No longer used.
- }
-
- // Import the non-XMP items. Do the imports in reverse priority order, last import wins!
-
- MOOV_Manager::BoxInfo mvhdInfo;
- MOOV_Manager::BoxRef mvhdRef = this->moovMgr.GetBox ( "moov/mvhd", &mvhdInfo );
- bool mvhdFound = ((mvhdRef != 0) && (mvhdInfo.contentSize != 0));
-
- MOOV_Manager::BoxInfo udtaInfo;
- MOOV_Manager::BoxRef udtaRef = this->moovMgr.GetBox ( "moov/udta", &udtaInfo );
- std::vector<MOOV_Manager::BoxInfo> cprtBoxes;
-
- if ( udtaRef != 0 ) {
- for ( XMP_Uns32 i = 0; i < udtaInfo.childCount; ++i ) {
- MOOV_Manager::BoxInfo currInfo;
- MOOV_Manager::BoxRef currRef = this->moovMgr.GetNthChild ( udtaRef, i, &currInfo );
- if ( currRef == 0 ) break; // Sanity check, should not happen.
- if ( currInfo.boxType != ISOMedia::k_cprt ) continue;
- cprtBoxes.push_back ( currInfo );
- }
- }
- bool cprtFound = (! cprtBoxes.empty());
-
- bool tradQTFound = this->tradQTMgr.ParseCachedBoxes ( this->moovMgr );
- bool tmcdFound = this->ParseTimecodeTrack();
-
- if ( this->fileMode == MOOV_Manager::kFileIsNormalISO ) {
-
- if ( mvhdFound ) this->containsXMP |= ImportMVHDItems ( mvhdInfo, &this->xmpObj );
- if ( cprtFound ) this->containsXMP |= ImportISOCopyrights ( cprtBoxes, &this->xmpObj );
- } else { // This is a QuickTime file, either traditional or modern.
-
- if ( mvhdFound ) this->containsXMP |= ImportMVHDItems ( mvhdInfo, &this->xmpObj );
- if ( cprtFound ) this->containsXMP |= ImportISOCopyrights ( cprtBoxes, &this->xmpObj );
- if ( tmcdFound | tradQTFound ) {
- // Some of the timecode items are in the .../udta/©... set but handled by ImportTimecodeItems.
- this->containsXMP |= ImportTimecodeItems ( this->tmcdInfo, this->tradQTMgr, &this->xmpObj );
- }
-
- this->containsXMP |= ImportCr8rItems ( this->moovMgr, &this->xmpObj );
-
- }
-
-} // MPEG4_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// MPEG4_MetaHandler::ParseTimecodeTrack
-// =====================================
-
-bool MPEG4_MetaHandler::ParseTimecodeTrack()
-{
- MOOV_Manager::BoxRef stblRef = FindTimecodeTrack ( this->moovMgr );
- if ( stblRef == 0 ) return false;
-
- // Find the .../stbl/stsd box and process the first table entry.
-
- MOOV_Manager::BoxInfo stsdInfo;
- MOOV_Manager::BoxRef stsdRef;
-
- stsdRef = this->moovMgr.GetTypeChild ( stblRef, ISOMedia::k_stsd, &stsdInfo );
- if ( stsdRef == 0 ) return false;
- if ( stsdInfo.contentSize < (8 + sizeof ( MOOV_Manager::Content_stsd_entry )) ) return false;
- if ( GetUns32BE ( stsdInfo.content + 4 ) == 0 ) return false; // Make sure the entry count is non-zero.
-
- const MOOV_Manager::Content_stsd_entry * stsdRawEntry = (MOOV_Manager::Content_stsd_entry*) (stsdInfo.content + 8);
-
- XMP_Uns32 stsdEntrySize = GetUns32BE ( &stsdRawEntry->entrySize );
- if ( stsdEntrySize > (stsdInfo.contentSize - 4) ) stsdEntrySize = stsdInfo.contentSize - 4;
- if ( stsdEntrySize < sizeof ( MOOV_Manager::Content_stsd_entry ) ) return false;
-
- XMP_Uns32 stsdEntryFormat = GetUns32BE ( &stsdRawEntry->format );
- if ( stsdEntryFormat != ISOMedia::k_tmcd ) return false;
-
- this->tmcdInfo.timeScale = GetUns32BE ( &stsdRawEntry->timeScale );
- this->tmcdInfo.frameDuration = GetUns32BE ( &stsdRawEntry->frameDuration );
-
- XMP_Uns32 flags = GetUns32BE ( &stsdRawEntry->flags );
- this->tmcdInfo.isDropFrame = flags & 0x1;
-
- // Look for a trailing 'name' box on the first stsd table entry.
-
- XMP_Uns32 stsdTrailerSize = stsdEntrySize - sizeof ( MOOV_Manager::Content_stsd_entry );
- if ( stsdTrailerSize > 8 ) { // Room for a non-empty 'name' box?
-
- const XMP_Uns8 * trailerStart = stsdInfo.content + 8 + sizeof ( MOOV_Manager::Content_stsd_entry );
- const XMP_Uns8 * trailerLimit = trailerStart + stsdTrailerSize;
- const XMP_Uns8 * trailerPos;
- const XMP_Uns8 * trailerNext;
- ISOMedia::BoxInfo trailerInfo;
-
- for ( trailerPos = trailerStart; trailerPos < trailerLimit; trailerPos = trailerNext ) {
-
- trailerNext = ISOMedia::GetBoxInfo ( trailerPos, trailerLimit, &trailerInfo );
-
- if ( trailerInfo.boxType == ISOMedia::k_name ) {
-
- this->tmcdInfo.nameOffset = (XMP_Uns32) (trailerPos - stsdInfo.content);
-
- if ( trailerInfo.contentSize > 4 ) {
-
- XMP_Uns16 textLen = GetUns16BE ( trailerPos + trailerInfo.headerSize );
- this->tmcdInfo.macLang = GetUns16BE ( trailerPos + trailerInfo.headerSize + 2 );
-
- if ( trailerInfo.contentSize >= (XMP_Uns64)(textLen + 4) ) {
- const char * textPtr = (char*) (trailerPos + trailerInfo.headerSize + 4);
- this->tmcdInfo.macName.assign ( textPtr, textLen );
- }
-
- }
-
- break; // Done after finding the first 'name' box.
-
- }
-
- }
-
- }
-
- // Find the timecode sample.
-
- XMP_Uns64 sampleOffset = 0;
- MOOV_Manager::BoxInfo tempInfo;
- MOOV_Manager::BoxRef tempRef;
-
- tempRef = this->moovMgr.GetTypeChild ( stblRef, ISOMedia::k_stsc, &tempInfo );
- if ( tempRef == 0 ) return false;
- if ( tempInfo.contentSize < (8 + sizeof ( MOOV_Manager::Content_stsc_entry )) ) return false;
- if ( GetUns32BE ( tempInfo.content + 4 ) == 0 ) return false; // Make sure the entry count is non-zero.
-
- XMP_Uns32 firstChunkNumber = GetUns32BE ( tempInfo.content + 8 ); // Want first field of first entry.
-
- tempRef = this->moovMgr.GetTypeChild ( stblRef, ISOMedia::k_stco, &tempInfo );
-
- if ( tempRef != 0 ) {
-
- if ( tempInfo.contentSize < (8 + 4) ) return false;
- XMP_Uns32 stcoCount = GetUns32BE ( tempInfo.content + 4 );
- if ( stcoCount < firstChunkNumber ) return false;
- XMP_Uns32 * stcoPtr = (XMP_Uns32*) (tempInfo.content + 8);
- sampleOffset = GetUns32BE ( &stcoPtr[firstChunkNumber-1] ); // ! Chunk number is 1-based.
-
- } else {
-
- tempRef = this->moovMgr.GetTypeChild ( stblRef, ISOMedia::k_co64, &tempInfo );
- if ( (tempRef == 0) || (tempInfo.contentSize < (8 + 8)) ) return false;
- XMP_Uns32 co64Count = GetUns32BE ( tempInfo.content + 4 );
- if ( co64Count < firstChunkNumber ) return false;
- XMP_Uns64 * co64Ptr = (XMP_Uns64*) (tempInfo.content + 8);
- sampleOffset = GetUns64BE ( &co64Ptr[firstChunkNumber-1] ); // ! Chunk number is 1-based.
-
- }
-
- if ( sampleOffset != 0 ) {
-
- // Read the timecode sample. Need to reopen the file if the XMPFile was open for read-only,
- // normally all I/O is done within CacheFileData.
-
- bool openForRead = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OpenForRead);
-
- LFA_FileRef fileRef = this->parent->fileRef;
- if ( openForRead ) {
- XMP_Assert ( fileRef == 0 );
- fileRef = LFA_Open ( this->parent->filePath.c_str(), 'r' );
- }
-
- if ( fileRef != 0 ) { // The reopen might have failed.
- LFA_Seek ( fileRef, sampleOffset, SEEK_SET );
- LFA_Read ( fileRef, &this->tmcdInfo.timecodeSample, 4, kLFA_RequireAll );
- this->tmcdInfo.timecodeSample = MakeUns32BE ( this->tmcdInfo.timecodeSample );
- if ( openForRead ) LFA_Close ( fileRef );
- }
-
- }
-
- // Finally update this->tmcdInfo to remember (for update) that there is an OK timecode track.
-
- this->tmcdInfo.stsdBoxFound = true;
- this->tmcdInfo.sampleOffset = sampleOffset;
- return true;
-
-} // MPEG4_MetaHandler::ParseTimecodeTrack
-
-// =================================================================================================
-// MPEG4_MetaHandler::UpdateTopLevelBox
-// ====================================
-
-void MPEG4_MetaHandler::UpdateTopLevelBox ( XMP_Uns64 oldOffset, XMP_Uns32 oldSize,
- const XMP_Uns8 * newBox, XMP_Uns32 newSize )
-{
- if ( (oldSize == 0) && (newSize == 0) ) return; // Sanity check, should not happen.
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns64 oldFileSize = LFA_Measure ( fileRef );
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
-
- if ( newSize == oldSize ) {
-
- // Trivial case, update the existing box in-place.
- LFA_Seek ( fileRef, oldOffset, SEEK_SET );
- LFA_Write ( fileRef, newBox, oldSize );
-
- } else if ( (oldOffset + oldSize) == oldFileSize ) {
-
- // The old box was at the end, write the new and truncate the file if necessary.
- LFA_Seek ( fileRef, oldOffset, SEEK_SET );
- LFA_Write ( fileRef, newBox, newSize );
- LFA_Truncate ( fileRef, (oldOffset + newSize) ); // Does nothing if new size is bigger.
-
- } else if ( (newSize < oldSize) && ((oldSize - newSize) >= 8) ) {
-
- // The new size is smaller and there is enough room to create a free box.
- LFA_Seek ( fileRef, oldOffset, SEEK_SET );
- LFA_Write ( fileRef, newBox, newSize );
- WipeBoxFree ( fileRef, (oldOffset + newSize), (oldSize - newSize) );
-
- } else {
-
- // Look for a trailing free box with enough space. If not found, consider any free space.
- // If still not found, append the new box and make the old one free.
-
- ISOMedia::BoxInfo nextBoxInfo;
- (void) ISOMedia::GetBoxInfo ( fileRef, (oldOffset + oldSize), oldFileSize, &nextBoxInfo, true /* throw errors */ );
-
- XMP_Uns64 totalRoom = oldSize + nextBoxInfo.headerSize + nextBoxInfo.contentSize;
-
- bool nextIsFree = (nextBoxInfo.boxType == ISOMedia::k_free) || (nextBoxInfo.boxType == ISOMedia::k_skip);
- bool haveEnoughRoom = (newSize == totalRoom) ||
- ( (newSize < totalRoom) && ((totalRoom - newSize) >= 8) );
-
- if ( nextIsFree & haveEnoughRoom ) {
-
- LFA_Seek ( fileRef, oldOffset, SEEK_SET );
- LFA_Write ( fileRef, newBox, newSize );
-
- if ( newSize < totalRoom ) {
- // Don't wipe, at most 7 old bytes left, it will be covered by the free header.
- WriteBoxHeader ( fileRef, ISOMedia::k_free, (totalRoom - newSize) );
- }
-
- } else {
-
- // Create a list of all top level free space, including the old space as free. Use the
- // earliest space that fits. If none, append.
-
- FreeSpaceList spaceList;
- CreateFreeSpaceList ( fileRef, oldFileSize, oldOffset, oldSize, &spaceList );
-
- size_t freeSlot, limit;
- for ( freeSlot = 0, limit = spaceList.size(); freeSlot < limit; ++freeSlot ) {
- XMP_Uns64 freeSize = spaceList[freeSlot].size;
- if ( (newSize == freeSize) || ( (newSize < freeSize) && ((freeSize - newSize) >= 8) ) ) break;
- }
-
- if ( freeSlot == spaceList.size() ) {
-
- // No available free space, append the new box.
- CheckFinalBox ( fileRef, abortProc, abortArg );
- LFA_Seek ( fileRef, 0, SEEK_END );
- LFA_Write ( fileRef, newBox, newSize );
- WipeBoxFree ( fileRef, oldOffset, oldSize );
-
- } else {
-
- // Use the available free space. Wipe non-overlapping parts of the old box. The old
- // box is either included in the new space, or is fully disjoint.
-
- SpaceInfo & newSpace = spaceList[freeSlot];
-
- bool oldIsDisjoint = ((oldOffset + oldSize) <= newSpace.offset) || // Old is in front.
- ((newSpace.offset + newSpace.size) <= oldOffset); // Old is behind.
-
- XMP_Assert ( (newSize == newSpace.size) ||
- ( (newSize < newSpace.size) && ((newSpace.size - newSize) >= 8) ) );
-
- XMP_Assert ( oldIsDisjoint ||
- ( (newSpace.offset <= oldOffset) &&
- ((oldOffset + oldSize) <= (newSpace.offset + newSpace.size)) ) /* old is included */ );
-
- XMP_Uns64 newFreeOffset = newSpace.offset + newSize;
- XMP_Uns64 newFreeSize = newSpace.size - newSize;
-
- LFA_Seek ( fileRef, newSpace.offset, SEEK_SET );
- LFA_Write ( fileRef, newBox, newSize );
-
- if ( newFreeSize > 0 ) WriteBoxHeader ( fileRef, ISOMedia::k_free, newFreeSize );
-
- if ( oldIsDisjoint ) {
-
- WipeBoxFree ( fileRef, oldOffset, oldSize );
-
- } else {
-
- // Clear the exposed portion of the old box.
-
- XMP_Uns64 zeroStart = newFreeOffset + 8;
- if ( newFreeSize > 0xFFFFFFFF ) zeroStart += 8;
- if ( oldOffset > zeroStart ) zeroStart = oldOffset;
- XMP_Uns64 zeroEnd = newFreeOffset + newFreeSize;
- if ( (oldOffset + oldSize) < zeroEnd ) zeroEnd = oldOffset + oldSize;
-
- if ( zeroStart < zeroEnd ) { // The new box might cover the old.
- XMP_Assert ( (zeroEnd - zeroStart) <= (XMP_Uns64)oldSize );
- XMP_Uns32 zeroSize = (XMP_Uns32) (zeroEnd - zeroStart);
- LFA_Seek ( fileRef, zeroStart, SEEK_SET );
- for ( XMP_Uns32 ioCount = sizeof ( kZeroes ); zeroSize > 0; zeroSize -= ioCount ) {
- if ( ioCount > zeroSize ) ioCount = zeroSize;
- LFA_Write ( fileRef, &kZeroes[0], ioCount );
- }
- }
-
- }
-
- }
-
- }
-
- }
-
-} // MPEG4_MetaHandler::UpdateTopLevelBox
-
-// =================================================================================================
-// MPEG4_MetaHandler::UpdateFile
-// =============================
-//
-// Revamp notes:
-// The 'moov' subtree and possibly the XMP 'uuid' box get updated. Compose the new copy of each and
-// see if it fits in existing space, incorporating adjacent 'free' boxes if necessary. If that won't
-// work, look for a sufficient 'free' box anywhere in the file. As a last resort, append the new copy.
-// Assume no location sensitive data within 'moov', i.e. no offsets into it. This lets it be moved
-// and its children freely rearranged.
-
-void MPEG4_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) { // If needsUpdate is set then at least the XMP changed.
- return;
- }
-
- this->needsUpdate = false; // Make sure only called once.
- XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Uns64 fileSize = LFA_Measure ( fileRef );
-
- bool haveISOFile = (this->fileMode == MOOV_Manager::kFileIsNormalISO);
-
- // Update the 'moov' subtree with exports from the XMP, but not the XMP itself (for QT files).
-
- ExportMVHDItems ( this->xmpObj, &this->moovMgr );
- ExportISOCopyrights ( this->xmpObj, &this->moovMgr );
- ExportQuickTimeItems ( this->xmpObj, &this->tradQTMgr, &this->moovMgr );
- ExportTimecodeItems ( this->xmpObj, &this->tmcdInfo, &this->tradQTMgr, &this->moovMgr );
-
- if ( ! haveISOFile ) ExportCr8rItems ( this->xmpObj, &this->moovMgr );
-
- // Try to update the XMP in-place if that is all that changed, or if it is in a preferred 'uuid' box.
- // The XMP has already been serialized by common code to the appropriate length. Otherwise, update
- // the 'moov'/'udta'/'XMP_' box in the MOOV_Manager, or the 'uuid' XMP box in the file.
-
- bool useUuidXMP = (this->fileMode == MOOV_Manager::kFileIsNormalISO);
-
- if ( (this->xmpPacket.size() == (size_t)this->packetInfo.length) &&
- ( (useUuidXMP & this->havePreferredXMP) || (! this->moovMgr.IsChanged()) ) ) {
-
- // Update the existing XMP in-place.
- LFA_Seek ( fileRef, this->packetInfo.offset, SEEK_SET );
- LFA_Write ( fileRef, this->xmpPacket.c_str(), (XMP_Int32)this->xmpPacket.size() );
-
- } else if ( ! useUuidXMP ) {
-
- // Don't leave an old uuid XMP around (if we know about it).
- if ( (! havePreferredXMP) && (this->xmpBoxSize != 0) ) {
- WipeBoxFree ( fileRef, this->xmpBoxPos, this->xmpBoxSize );
- }
-
- // The udta form of XMP has just the XMP packet.
- this->moovMgr.SetBox ( "moov/udta/XMP_", this->xmpPacket.c_str(), (XMP_Uns32)this->xmpPacket.size() );
-
- } else {
-
- // Don't leave an old 'moov'/'udta'/'XMP_' box around.
- MOOV_Manager::BoxRef udtaRef = this->moovMgr.GetBox ( "moov/udta", 0 );
- if ( udtaRef != 0 ) this->moovMgr.DeleteTypeChild ( udtaRef, ISOMedia::k_XMP_ );
-
- // The uuid form of XMP has the 16-byte UUID in front of the XMP packet. Form the complete
- // box (including size/type header) for UpdateTopLevelBox.
- RawDataBlock uuidBox;
- XMP_Uns32 uuidSize = 4+4 + 16 + (XMP_Uns32)this->xmpPacket.size();
- uuidBox.assign ( uuidSize, 0 );
- PutUns32BE ( uuidSize, &uuidBox[0] );
- PutUns32BE ( ISOMedia::k_uuid, &uuidBox[4] );
- memcpy ( &uuidBox[8], ISOMedia::k_xmpUUID, 16 );
- memcpy ( &uuidBox[24], this->xmpPacket.c_str(), this->xmpPacket.size() );
- this->UpdateTopLevelBox ( this->xmpBoxPos, this->xmpBoxSize, &uuidBox[0], uuidSize );
-
- }
-
- // Update the 'moov' subtree if necessary, and finally update the timecode sample.
-
- if ( this->moovMgr.IsChanged() ) {
- this->moovMgr.UpdateMemoryTree();
- this->UpdateTopLevelBox ( moovBoxPos, moovBoxSize, &this->moovMgr.fullSubtree[0], (XMP_Uns32)this->moovMgr.fullSubtree.size() );
- }
-
- if ( this->tmcdInfo.sampleOffset != 0 ) {
- LFA_Seek ( fileRef, this->tmcdInfo.sampleOffset, SEEK_SET );
- XMP_Uns32 sample = MakeUns32BE ( this->tmcdInfo.timecodeSample );
- LFA_Write ( fileRef, &sample, 4 );
- }
-
-} // MPEG4_MetaHandler::UpdateFile
-
-// =================================================================================================
-// MPEG4_MetaHandler::WriteFile
-// ============================
-//
-// Since the XMP and legacy is probably a miniscule part of the entire file, and since we can't
-// change the offset of most of the boxes, just copy the entire source file to the dest file, then
-// do an in-place update to the destination file.
-
-void MPEG4_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- XMP_Assert ( this->needsUpdate );
-
- LFA_FileRef destRef = this->parent->fileRef;
-
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Seek ( destRef, 0, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, LFA_Measure ( sourceRef ),
- this->parent->abortProc, this->parent->abortArg );
-
- this->UpdateFile ( false );
-
-} // MPEG4_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/MPEG4_Handler.hpp b/source/XMPFiles/FileHandlers/MPEG4_Handler.hpp
deleted file mode 100644
index 9d00781..0000000
--- a/source/XMPFiles/FileHandlers/MPEG4_Handler.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef __MPEG4_Handler_hpp__
-#define __MPEG4_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "XMPFiles_Impl.hpp"
-
-#include "MOOV_Support.hpp"
-#include "QuickTime_Support.hpp"
-
-// ================================================================================================
-/// \file MPEG4_Handler.hpp
-/// \brief File format handler for MPEG-4.
-///
-/// This header ...
-///
-// ================================================================================================
-
-extern XMPFileHandler * MPEG4_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool MPEG4_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kMPEG4_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate
- );
-
-class MPEG4_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- MPEG4_MetaHandler ( XMPFiles * _parent );
- virtual ~MPEG4_MetaHandler();
-
- struct TimecodeTrackInfo { // Info about a QuickTime timecode track.
- bool stsdBoxFound, isDropFrame;
- XMP_Uns32 timeScale;
- XMP_Uns32 frameDuration;
- XMP_Uns32 timecodeSample;
- XMP_Uns64 sampleOffset; // Absolute file offset of the timecode sample, 0 if none.
- XMP_Uns32 nameOffset; // The offset of the 'name' box relative to the 'stsd' box content.
- XMP_Uns16 macLang; // The Mac language code of the trailing 'name' box.
- std::string macName; // The text part of the trailing 'name' box, in macLang encoding.
- TimecodeTrackInfo()
- : stsdBoxFound(false), isDropFrame(false), timeScale(0), frameDuration(0),
- timecodeSample(0), sampleOffset(0), nameOffset(0), macLang(0) {};
- };
-
-private:
-
- MPEG4_MetaHandler() : fileMode(0), havePreferredXMP(false),
- xmpBoxPos(0), moovBoxPos(0), xmpBoxSize(0), moovBoxSize(0) {}; // Hidden on purpose.
-
- bool ParseTimecodeTrack();
-
- void UpdateTopLevelBox ( XMP_Uns64 oldOffset, XMP_Uns32 oldSize, const XMP_Uns8 * newBox, XMP_Uns32 newSize );
-
- XMP_Uns8 fileMode;
- bool havePreferredXMP;
- XMP_Uns64 xmpBoxPos; // The file offset of the XMP box (the size field, not the content).
- XMP_Uns64 moovBoxPos; // The file offset of the 'moov' box (the size field, not the content).
- XMP_Uns32 xmpBoxSize, moovBoxSize; // The full size of the boxes, not just the content.
-
- MOOV_Manager moovMgr;
- TradQT_Manager tradQTMgr;
-
- TimecodeTrackInfo tmcdInfo;
-
-}; // MPEG4_MetaHandler
-
-// =================================================================================================
-
-#endif // __MPEG4_Handler_hpp__
diff --git a/source/XMPFiles/FileHandlers/P2_Handler.cpp b/source/XMPFiles/FileHandlers/P2_Handler.cpp
deleted file mode 100644
index 5e3af85..0000000
--- a/source/XMPFiles/FileHandlers/P2_Handler.cpp
+++ /dev/null
@@ -1,1363 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "P2_Handler.hpp"
-
-#include "MD5.h"
-#include <cmath>
-
-using namespace std;
-
-// =================================================================================================
-/// \file P2_Handler.cpp
-/// \brief Folder format handler for P2.
-///
-/// This handler is for the P2 video format. This is a pseudo-package, visible files but with a very
-/// well-defined layout and naming rules. A typical P2 example looks like:
-///
-/// .../MyMovie
-/// CONTENTS/
-/// CLIP/
-/// 0001AB.XML
-/// 0001AB.XMP
-/// 0002CD.XML
-/// 0002CD.XMP
-/// VIDEO/
-/// 0001AB.MXF
-/// 0002CD.MXF
-/// AUDIO/
-/// 0001AB00.MXF
-/// 0001AB01.MXF
-/// 0002CD00.MXF
-/// 0002CD01.MXF
-/// ICON/
-/// 0001AB.BMP
-/// 0002CD.BMP
-/// VOICE/
-/// 0001AB.WAV
-/// 0002CD.WAV
-/// PROXY/
-/// 0001AB.MP4
-/// 0002CD.MP4
-///
-/// From the user's point of view, .../MyMovie contains P2 stuff, in this case 2 clips whose raw
-/// names are 0001AB and 0002CD. There may be mapping information for nicer clip names to the raw
-/// names, but that can be ignored for now. Each clip is stored as a collection of files, each file
-/// holding some specific aspect of the clip's data.
-///
-/// The P2 handler operates on clips. The path from the client of XMPFiles can be either a logical
-/// clip path, like ".../MyMovie/0001AB", or a full path to one of the files. In the latter case the
-/// handler must figure out the intended clip, it must not blindly use the named file.
-///
-/// Once the P2 structure and intended clip are identified, the handler only deals with the .XMP and
-/// .XML files in the CLIP folder. The .XMP file, if present, contains the XMP for the clip. The .XML
-/// file must be present to define the existance of the clip. It contains a variety of information
-/// about the clip, including some legacy metadata.
-///
-// =================================================================================================
-
-static const char * kContentFolderNames[] = { "CLIP", "VIDEO", "AUDIO", "ICON", "VOICE", "PROXY", 0 };
-static int kNumRequiredContentFolders = 6; // All 6 of the above.
-
-static inline bool CheckContentFolderName ( const std::string & folderName )
-{
- for ( int i = 0; kContentFolderNames[i] != 0; ++i ) {
- if ( folderName == kContentFolderNames[i] ) return true;
- }
- return false;
-}
-
-// =================================================================================================
-// InternalMakeClipFilePath
-// ========================
-//
-// P2_CheckFormat can't use the member function.
-
-static void InternalMakeClipFilePath ( std::string * path,
- const std::string & rootPath,
- const std::string & clipName,
- XMP_StringPtr suffix )
-{
-
- *path = rootPath;
- *path += kDirChar;
- *path += "CONTENTS";
- *path += kDirChar;
- *path += "CLIP";
- *path += kDirChar;
- *path += clipName;
- *path += suffix;
-
-} // InternalMakeClipFilePath
-
-// =================================================================================================
-// P2_CheckFormat
-// ==============
-//
-// This version does fairly simple checks. The top level folder (.../MyMovie) must a child folder
-// called CONTENTS. This must have a subfolder called CLIP. It may also have subfolders called
-// VIDEO, AUDIO, ICON, VOICE, and PROXY. Any mixture of these additional folders is allowed, but no
-// other children are allowed in CONTENTS. The CLIP folder must contain a .XML file for the desired
-// clip. The name checks are case insensitive.
-//
-// The state of the string parameters depends on the form of the path passed by the client. If the
-// client passed a logical clip path, like ".../MyMovie/0001AB", the parameters are:
-// rootPath - ".../MyMovie"
-// gpName - empty
-// parentName - empty
-// leafName - "0001AB"
-// If the client passed a full file path, like ".../MyMovie/CONTENTS/VOICE/0001AB.WAV", they are:
-// rootPath - ".../MyMovie"
-// gpName - "CONTENTS"
-// parentName - "VOICE"
-// leafName - "0001AB"
-//
-// For most of the content files the base file name is the raw clip name. Files in the AUDIO and
-// VOICE folders have an extra 2 digits appended to the raw clip name. These must be trimmed.
-
-// ! The common code has shifted the gpName, parentName, and leafName strings to upper case. It has
-// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
-// ! file exists for a full file path.
-
-bool P2_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent )
-{
- XMP_FolderInfo folderInfo;
- std::string tempPath, childName;
-
- std::string clipName = leafName;
-
- // Do some basic checks on the gpName and parentName.
-
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- if ( ! gpName.empty() ) {
-
- if ( gpName != "CONTENTS" ) return false;
- if ( ! CheckContentFolderName ( parentName ) ) return false;
-
- if ( (parentName == "AUDIO") | (parentName == "VOICE") ) {
- if ( clipName.size() < 3 ) return false;
- clipName.erase ( clipName.size() - 2 );
- }
-
- }
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "CONTENTS";
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFolder ) return false;
-
- folderInfo.Open ( tempPath.c_str() );
- int numChildrenFound = 0;
- while ( ( folderInfo.GetNextChild ( &childName ) && ( numChildrenFound < kNumRequiredContentFolders ) ) ) { // Make sure the children of CONTENTS are legit.
- if ( CheckContentFolderName ( childName ) ) {
- folderInfo.GetFolderPath ( &tempPath );
- tempPath += kDirChar;
- tempPath += childName;
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFolder ) return false;
- ++numChildrenFound;
- }
- }
- folderInfo.Close();
-
- // Make sure the clip's .XML file exists.
-
- InternalMakeClipFilePath ( &tempPath, rootPath, clipName, ".XML" );
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFile ) return false;
-
- // Make a bogus path to pass the root path and clip name to the handler. A bit of a hack, but
- // the only way to get info from here to there.
-
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += clipName;
-
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for P2 clip path", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen ); // AUDIT: Safe, allocated above.
-
- return true;
-
-} // P2_CheckFormat
-
-// =================================================================================================
-// P2_MetaHandlerCTor
-// ==================
-
-XMPFileHandler * P2_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new P2_MetaHandler ( parent );
-
-} // P2_MetaHandlerCTor
-
-// =================================================================================================
-// P2_MetaHandler::P2_MetaHandler
-// ==============================
-
-P2_MetaHandler::P2_MetaHandler ( XMPFiles * _parent ) : expat(0), clipMetadata(0), clipContent(0)
-{
-
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kP2_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- // Extract the root path and clip name from tempPtr.
-
- XMP_Assert ( this->parent->tempPtr != 0 );
- this->rootPath = (char*)this->parent->tempPtr;
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- SplitLeafName ( &this->rootPath, &this->clipName );
-
-} // P2_MetaHandler::P2_MetaHandler
-
-// =================================================================================================
-// P2_MetaHandler::~P2_MetaHandler
-// ===============================
-
-P2_MetaHandler::~P2_MetaHandler()
-{
-
- this->CleanupLegacyXML();
- if ( this->parent->tempPtr != 0 ) {
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
- }
-
-} // P2_MetaHandler::~P2_MetaHandler
-
-// =================================================================================================
-// P2_MetaHandler::MakeClipFilePath
-// ================================
-
-void P2_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix )
-{
-
- InternalMakeClipFilePath ( path, this->rootPath, this->clipName, 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
-// =====================================
-
-void P2_MetaHandler::DigestLegacyRelations ( MD5_CTX & md5Context )
-{
- 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 ( legacyContext != 0 ) {
- this->DigestLegacyItem ( md5Context, legacyContext, "GlobalClipID" );
- }
-
- }
-
- }
-
-} // P2_MetaHandler::DigestLegacyRelations
-
-// =================================================================================================
-// P2_MetaHandler::SetXMPPropertyFromLegacyXML
-// ===========================================
-
-void P2_MetaHandler::SetXMPPropertyFromLegacyXML ( bool digestFound,
- XML_NodePtr legacyContext,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr legacyPropName,
- bool isLocalized )
-{
-
- 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() ) {
- if ( isLocalized ) {
- this->xmpObj.SetLocalizedText ( schemaNS, propName, "", "x-default", legacyProp->GetLeafContentValue(), kXMP_DeleteExisting );
- } else {
- this->xmpObj.SetProperty ( schemaNS, propName, legacyProp->GetLeafContentValue(), 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 ) {
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "relation" )) ) {
-
- XML_NodePtr legacyProp = legacyRelationContext->GetNamedElement ( p2NS, "GlobalShotID" );
- std::string relationString;
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- this->xmpObj.DeleteProperty ( kXMP_NS_DC, "relation" );
- relationString = std::string("globalShotID:") + legacyProp->GetLeafContentValue();
- 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 );
- }
- }
-
- }
-
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetRelationsFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetAudioInfoFromLegacyXML
-// =========================================
-
-void P2_MetaHandler::SetAudioInfoFromLegacyXML ( bool digestFound )
-{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyAudioContext = this->clipContent->GetNamedElement ( p2NS, "EssenceList" );
-
- if ( legacyAudioContext != 0 ) {
-
- legacyAudioContext = legacyAudioContext->GetNamedElement ( p2NS, "Audio" );
-
- if ( legacyAudioContext != 0 ) {
-
- this->SetXMPPropertyFromLegacyXML ( digestFound, legacyAudioContext, kXMP_NS_DM, "audioSampleRate", "SamplingRate", false );
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "audioSampleType" )) ) {
- XML_NodePtr legacyProp = legacyAudioContext->GetNamedElement ( p2NS, "BitsPerSample" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- const std::string p2BitsPerSample = legacyProp->GetLeafContentValue();
- std::string dmSampleType;
-
- if ( p2BitsPerSample == "16" ) {
- dmSampleType = "16Int";
- } else if ( p2BitsPerSample == "24" ) {
- dmSampleType = "32Int";
- }
-
- if ( ! dmSampleType.empty() ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "audioSampleType", dmSampleType, kXMP_DeleteExisting );
- this->containsXMP = true;
- }
-
- }
-
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetAudioInfoFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetVideoInfoFromLegacyXML
-// =========================================
-
-void P2_MetaHandler::SetVideoInfoFromLegacyXML ( bool digestFound )
-{
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyVideoContext = this->clipContent->GetNamedElement ( p2NS, "EssenceList" );
-
- if ( legacyVideoContext != 0 ) {
-
- legacyVideoContext = legacyVideoContext->GetNamedElement ( p2NS, "Video" );
-
- if ( legacyVideoContext != 0 ) {
- this->SetVideoFrameInfoFromLegacyXML ( legacyVideoContext, digestFound );
- this->SetStartTimecodeFromLegacyXML ( legacyVideoContext, digestFound );
- this->SetXMPPropertyFromLegacyXML ( digestFound, legacyVideoContext, kXMP_NS_DM, "videoFrameRate", "FrameRate", false );
- }
-
- }
-
-} // P2_MetaHandler::SetVideoInfoFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetDurationFromLegacyXML
-// ========================================
-
-void P2_MetaHandler::SetDurationFromLegacyXML ( bool digestFound )
-{
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "duration" )) ) {
-
- 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() ) {
-
- this->xmpObj.DeleteProperty ( kXMP_NS_DM, "duration" );
- this->xmpObj.SetStructField ( kXMP_NS_DM, "duration",
- kXMP_NS_DM, "value", legacyDurationProp->GetLeafContentValue() );
-
- this->xmpObj.SetStructField ( kXMP_NS_DM, "duration",
- kXMP_NS_DM, "scale", legacyEditUnitProp->GetLeafContentValue() );
- this->containsXMP = true;
-
- }
-
- }
-
-} // P2_MetaHandler::SetDurationFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetVideoFrameInfoFromLegacyXML
-// ==============================================
-
-void P2_MetaHandler::SetVideoFrameInfoFromLegacyXML ( XML_NodePtr legacyVideoContext, bool digestFound )
-{
-
- // 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();
- XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "Codec" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- const std::string p2Codec = legacyProp->GetLeafContentValue();
- std::string dmPixelAspectRatio, dmVideoCompressor, dmWidth, dmHeight;
-
- if ( p2Codec == "DV25_411" ) {
- dmWidth = "720";
- dmVideoCompressor = "DV25 4:1:1";
- } else if ( p2Codec == "DV25_420" ) {
- dmWidth = "720";
- dmVideoCompressor = "DV25 4:2:0";
- } else if ( p2Codec == "DV50_422" ) {
- dmWidth = "720";
- dmVideoCompressor = "DV50 4:2:2";
- } else if ( ( p2Codec == "DV100_1080/59.94i" ) || ( p2Codec == "DV100_1080/50i" ) ) {
- dmVideoCompressor = "DV100";
- dmHeight = "1080";
-
- if ( p2Codec == "DV100_1080/59.94i" ) {
- dmWidth = "1280";
- dmPixelAspectRatio = "3/2";
- } else {
- dmWidth = "1440";
- dmPixelAspectRatio = "1920/1440";
- }
- } else if ( ( p2Codec == "DV100_720/59.94p" ) || ( p2Codec == "DV100_720/50p" ) ) {
- dmVideoCompressor = "DV100";
- dmHeight = "720";
- dmWidth = "960";
- dmPixelAspectRatio = "1920/1440";
- } else if ( ( p2Codec.compare ( 0, 6, "AVC-I_" ) == 0 ) ) {
-
- // 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 ( XMP_LitMatch ( codecClass, "100" ) ) {
-
- dmVideoCompressor = "AVC-Intra 100";
- dmPixelAspectRatio = "1/1";
-
- if ( p2Codec.compare ( 6, 4, "1080" ) == 0 ) {
- dmHeight = "1080";
- dmWidth = "1920";
- } else if ( p2Codec.compare ( 6, 3, "720" ) == 0 ) {
- dmHeight = "720";
- dmWidth = "1280";
- }
-
- } else if ( XMP_LitMatch ( codecClass, "50" ) ) {
-
- dmVideoCompressor = "AVC-Intra 50";
- dmPixelAspectRatio = "1920/1440";
-
- if ( p2Codec.compare ( 6, 4, "1080" ) == 0 ) {
- dmHeight = "1080";
- dmWidth = "1440";
- } else if ( p2Codec.compare ( 6, 3, "720" ) == 0 ) {
- dmHeight = "720";
- dmWidth = "960";
- }
-
- } else {
- // Unknown codec class -- we don't have enough info to determine the
- // codec, PAR, or aspect ratio
- dmVideoCompressor = "AVC-Intra";
- }
- }
-
- if ( dmWidth == "720" ) {
-
- // This is SD footage -- calculate the frame height and pixel aspect ratio using the legacy P2
- // FrameRate and AspectRatio fields.
-
- legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "FrameRate" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- const std::string p2FrameRate = legacyProp->GetLeafContentValue();
-
- legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "AspectRatio" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- const std::string p2AspectRatio = legacyProp->GetLeafContentValue();
-
- if ( p2FrameRate == "50i" ) {
- // Standard Definition PAL.
- dmHeight = "576";
- if ( p2AspectRatio == "4:3" ) {
- dmPixelAspectRatio = "768/702";
- } else if ( p2AspectRatio == "16:9" ) {
- dmPixelAspectRatio = "1024/702";
- }
- } else if ( p2FrameRate == "59.94i" ) {
- // Standard Definition NTSC.
- dmHeight = "480";
- if ( p2AspectRatio == "4:3" ) {
- dmPixelAspectRatio = "10/11";
- } else if ( p2AspectRatio == "16:9" ) {
- dmPixelAspectRatio = "40/33";
- }
- }
-
- }
- }
- }
-
- if ( ! dmPixelAspectRatio.empty() ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "videoPixelAspectRatio", dmPixelAspectRatio, kXMP_DeleteExisting );
- this->containsXMP = true;
- }
-
- if ( ! dmVideoCompressor.empty() ) {
- this->xmpObj.SetProperty ( kXMP_NS_DM, "videoCompressor", dmVideoCompressor, kXMP_DeleteExisting );
- this->containsXMP = true;
- }
-
- if ( ( ! dmWidth.empty() ) && ( ! dmHeight.empty() ) ) {
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "w", dmWidth, 0 );
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "h", dmHeight, 0 );
- this->xmpObj.SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "unit", "pixel", 0 );
- this->containsXMP = true;
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetVideoFrameInfoFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetStartTimecodeFromLegacyXML
-// =============================================
-
-void P2_MetaHandler::SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoContext, bool digestFound )
-{
-
- // 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();
- XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "StartTimecode" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- std::string p2StartTimecode = legacyProp->GetLeafContentValue();
-
- legacyProp = legacyVideoContext->GetNamedElement ( p2NS, "FrameRate" );
-
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
-
- const std::string p2FrameRate = legacyProp->GetLeafContentValue();
- XMP_StringPtr p2DropFrameFlag = legacyProp->GetAttrValue ( "DropFrameFlag" );
- if ( p2DropFrameFlag == 0 ) p2DropFrameFlag = ""; // Make tests easier.
- std::string dmTimeFormat;
-
- if ( ( p2FrameRate == "50i" ) || ( p2FrameRate == "25p" ) ) {
-
- dmTimeFormat = "25Timecode";
-
- } else if ( p2FrameRate == "23.98p" ) {
-
- dmTimeFormat = "23976Timecode";
-
- } else if ( p2FrameRate == "50p" ) {
-
- dmTimeFormat = "50Timecode";
-
- } else if ( p2FrameRate == "59.94p" ) {
-
- if ( XMP_LitMatch ( p2DropFrameFlag, "true" ) ) {
- dmTimeFormat = "5994DropTimecode";
- } else if ( XMP_LitMatch ( p2DropFrameFlag, "false" ) ) {
- dmTimeFormat = "5994NonDropTimecode";
- }
-
- } else if ( (p2FrameRate == "59.94i") || (p2FrameRate == "29.97p") ) {
-
- if ( p2DropFrameFlag != 0 ) {
-
- if ( XMP_LitMatch ( p2DropFrameFlag, "false" ) ) {
-
- dmTimeFormat = "2997NonDropTimecode";
-
- } else if ( XMP_LitMatch ( p2DropFrameFlag, "true" ) ) {
-
- // Drop frame NTSC timecode uses semicolons instead of colons as separators.
- std::string::iterator currCharIt = p2StartTimecode.begin();
- const std::string::iterator charsEndIt = p2StartTimecode.end();
-
- for ( ; currCharIt != charsEndIt; ++currCharIt ) {
- if ( *currCharIt == ':' ) *currCharIt = ';';
- }
-
- dmTimeFormat = "2997DropTimecode";
-
- }
-
- }
-
- }
-
- if ( ( ! p2StartTimecode.empty() ) && ( ! dmTimeFormat.empty() ) ) {
- this->xmpObj.SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", p2StartTimecode, 0 );
- this->xmpObj.SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", dmTimeFormat, 0 );
- this->containsXMP = true;
- }
-
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetStartTimecodeFromLegacyXML
-
-
-// =================================================================================================
-// P2_MetaHandler::SetGPSPropertyFromLegacyXML
-// ===========================================
-
-void P2_MetaHandler::SetGPSPropertyFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound, XMP_StringPtr propName, XMP_StringPtr legacyPropName )
-{
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_EXIF, propName )) ) {
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyGPSProp = legacyLocationContext->GetNamedElement ( p2NS, legacyPropName );
-
- if ( ( legacyGPSProp != 0 ) && legacyGPSProp->IsLeafContentNode() ) {
-
- this->xmpObj.DeleteProperty ( kXMP_NS_EXIF, propName );
-
- const std::string legacyGPSValue = legacyGPSProp->GetLeafContentValue();
-
- if ( ! legacyGPSValue.empty() ) {
-
- // Convert from decimal to sexagesimal GPS coordinates
- char direction = '\0';
- double degrees = 0.0;
- const int numFieldsRead = sscanf ( legacyGPSValue.c_str(), "%c%lf", &direction, &degrees );
-
- if ( numFieldsRead == 2 ) {
- double wholeDegrees = 0.0;
- const double fractionalDegrees = modf ( degrees, &wholeDegrees );
- const double minutes = fractionalDegrees * 60.0;
- char xmpValue [128];
-
- sprintf ( xmpValue, "%d,%.5lf%c", static_cast<int>(wholeDegrees), minutes, direction );
- this->xmpObj.SetProperty ( kXMP_NS_EXIF, propName, xmpValue );
- this->containsXMP = true;
-
- }
-
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetGPSPropertyFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::SetAltitudeFromLegacyXML
-// ========================================
-
-void P2_MetaHandler::SetAltitudeFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound )
-{
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_EXIF, "GPSAltitude" )) ) {
-
- XMP_StringPtr p2NS = this->p2NS.c_str();
- XML_NodePtr legacyAltitudeProp = legacyLocationContext->GetNamedElement ( p2NS, "Altitude" );
-
- if ( ( legacyAltitudeProp != 0 ) && legacyAltitudeProp->IsLeafContentNode() ) {
-
- this->xmpObj.DeleteProperty ( kXMP_NS_EXIF, "GPSAltitude" );
-
- const std::string legacyGPSValue = legacyAltitudeProp->GetLeafContentValue();
-
- if ( ! legacyGPSValue.empty() ) {
-
- int altitude = 0;
-
- if ( sscanf ( legacyGPSValue.c_str(), "%d", &altitude ) == 1) {
-
- if ( altitude >= 0 ) {
- // At or above sea level.
- this->xmpObj.SetProperty ( kXMP_NS_EXIF, "GPSAltitudeRef", "0" );
- } else {
- // Below sea level.
- altitude = -altitude;
- this->xmpObj.SetProperty ( kXMP_NS_EXIF, "GPSAltitudeRef", "1" );
- }
-
- char xmpValue [128];
-
- sprintf ( xmpValue, "%d/1", altitude );
- this->xmpObj.SetProperty ( kXMP_NS_EXIF, "GPSAltitude", xmpValue );
- this->containsXMP = true;
-
- }
-
- }
-
- }
-
- }
-
-} // P2_MetaHandler::SetAltitudeFromLegacyXML
-
-// =================================================================================================
-// P2_MetaHandler::ForceChildElement
-// =================================
-
-XML_Node * P2_MetaHandler::ForceChildElement ( XML_Node * parent, XMP_StringPtr localName, int indent /* = 0 */ )
-{
- XML_Node * wsNode;
- XML_Node * childNode = parent->GetNamedElement ( this->p2NS.c_str(), localName );
-
- if ( childNode == 0 ) {
-
- // The indenting is a hack, assuming existing 2 spaces per level.
-
- wsNode = new XML_Node ( parent, "", kCDataNode );
- wsNode->value = " "; // Add 2 spaces to the existing WS before the parent's close tag.
- parent->content.push_back ( wsNode );
-
- childNode = new XML_Node ( parent, localName, kElemNode );
- childNode->ns = parent->ns;
- childNode->nsPrefixLen = parent->nsPrefixLen;
- childNode->name.insert ( 0, parent->name, 0, parent->nsPrefixLen );
- parent->content.push_back ( childNode );
-
- wsNode = new XML_Node ( parent, "", kCDataNode );
- wsNode->value = '\n';
- for ( ; indent > 1; --indent ) wsNode->value += " "; // Indent less 1, to "outdent" the parent's close.
- parent->content.push_back ( wsNode );
-
- }
-
- return childNode;
-
-} // 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::CacheFileData
-// =============================
-
-void P2_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- // Make sure the clip's .XMP file exists.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, ".XMP" );
-
- if ( GetFileMode ( xmpPath.c_str() ) != kFMode_IsFile ) return; // No XMP.
-
- // Read the entire .XMP file.
-
- bool openForUpdate = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OpenForUpdate );
- char openMode = 'r';
- if ( openForUpdate ) openMode = 'w';
-
- LFA_FileRef xmpFile = LFA_Open ( xmpPath.c_str(), openMode );
- if ( xmpFile == 0 ) return; // The open failed.
-
- XMP_Int64 xmpLen = LFA_Measure ( xmpFile );
- if ( xmpLen > 100*1024*1024 ) {
- XMP_Throw ( "P2 XMP is outrageously large", kXMPErr_InternalFailure ); // Sanity check.
- }
-
- this->xmpPacket.erase();
- this->xmpPacket.reserve ( (size_t)xmpLen );
- this->xmpPacket.append ( (size_t)xmpLen, ' ' );
-
- XMP_Int32 ioCount = LFA_Read ( xmpFile, (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen, kLFA_RequireAll );
- XMP_Assert ( ioCount == xmpLen );
-
- this->packetInfo.offset = 0;
- this->packetInfo.length = (XMP_Int32)xmpLen;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- XMP_Assert ( this->parent->fileRef == 0 );
- if ( openMode == 'r' ) {
- LFA_Close ( xmpFile );
- } else {
- this->parent->fileRef = xmpFile;
- }
-
- this->containsXMP = true;
-
-} // P2_MetaHandler::CacheFileData
-
-// =================================================================================================
-// P2_MetaHandler::ProcessXMP
-// ==========================
-
-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" );
-
- AutoFile xmlFile;
- xmlFile.fileRef = LFA_Open ( xmlPath.c_str(), 'r' );
- if ( xmlFile.fileRef == 0 ) return; // The open failed.
-
- 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 = LFA_Read ( xmlFile.fileRef, 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.
-
- LFA_Close ( xmlFile.fileRef );
- xmlFile.fileRef = 0;
-
- // 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.
-
- 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
- }
-
- // 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 );
- this->SetDurationFromLegacyXML (digestFound );
- this->SetRelationsFromLegacyXML ( digestFound );
- this->SetXMPPropertyFromLegacyXML ( digestFound, this->clipMetadata, kXMP_NS_DM, "shotName", "UserClipName", false );
- this->SetAudioInfoFromLegacyXML ( digestFound );
- this->SetVideoInfoFromLegacyXML ( digestFound );
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Access" );
- if ( legacyContext == 0 ) CleanupAndExit
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "creator" )) ) {
- legacyProp = legacyContext->GetNamedElement ( p2NS, "Creator" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- this->xmpObj.DeleteProperty ( kXMP_NS_DC, "creator" );
- this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered,
- legacyProp->GetLeafContentValue() );
- this->containsXMP = true;
- }
- }
-
- this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_XMP, "CreateDate", "CreationDate", false );
- 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" );
- if ( (legacyProp == 0) || (! legacyProp->IsLeafContentNode()) ) {
- this->xmpObj.DeleteProperty ( kXMP_NS_DM, "good" );
- } else {
- XMP_StringPtr markValue = legacyProp->GetLeafContentValue();
- if ( markValue == 0 ) {
- this->xmpObj.DeleteProperty ( kXMP_NS_DM, "good" );
- } else if ( XMP_LitMatch ( markValue, "true" ) || XMP_LitMatch ( markValue, "1" ) ) {
- this->xmpObj.SetProperty_Bool ( kXMP_NS_DM, "good", true, kXMP_DeleteExisting );
- this->containsXMP = true;
- } else if ( XMP_LitMatch ( markValue, "false" ) || XMP_LitMatch ( markValue, "0" ) ) {
- this->xmpObj.SetProperty_Bool ( kXMP_NS_DM, "good", false, kXMP_DeleteExisting );
- this->containsXMP = true;
- }
- }
- }
-
- legacyContext = this->clipMetadata->GetNamedElement ( p2NS, "Shoot" );
- if ( legacyContext != 0 ) {
- this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_TIFF, "Artist", "Shooter", false );
- legacyContext = legacyContext->GetNamedElement ( p2NS, "Location" );
- }
-
- if ( legacyContext != 0 ) {
- this->SetXMPPropertyFromLegacyXML ( digestFound, legacyContext, kXMP_NS_DM, "shotLocation", "PlaceName", false );
- this->SetGPSPropertyFromLegacyXML ( legacyContext, digestFound, "GPSLongitude", "Longitude" );
- this->SetGPSPropertyFromLegacyXML ( legacyContext, digestFound, "GPSLatitude", "Latitude" );
- this->SetAltitudeFromLegacyXML ( legacyContext, digestFound );
- }
-
- legacyContext = this->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" );
- 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
-
-} // P2_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// P2_MetaHandler::UpdateFile
-// ==========================
-//
-// Note that UpdateFile is only called from XMPFiles::CloseFile, so it is OK to close the file here.
-
-void P2_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- this->needsUpdate = false; // Make sure only called once.
-
- LFA_FileRef oldFile = 0;
- std::string filePath, tempPath;
-
- // Update the internal legacy XML tree if we have one, and set the digest in the XMP.
- // *** This is just a minimal prototype.
-
- bool updateLegacyXML = false;
-
- if ( this->clipMetadata != 0 ) {
-
- XMP_Assert ( this->expat != 0 );
-
- bool xmpFound;
- std::string xmpValue;
- XML_Node * xmlNode;
-
- xmpFound = this->xmpObj.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &xmpValue, 0 );
-
- if ( xmpFound ) {
-
- xmlNode = this->ForceChildElement ( this->clipContent, "ClipName", 3 );
-
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
- }
-
- }
-
- xmpFound = this->xmpObj.GetArrayItem ( kXMP_NS_DC, "creator", 1, &xmpValue, 0 );
-
- if ( xmpFound ) {
- xmlNode = this->ForceChildElement ( this->clipMetadata, "Access", 3 );
- xmlNode = this->ForceChildElement ( xmlNode, "Creator", 4 );
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
- }
- }
-
- }
-
- 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() );
-
- // Update the legacy XML file if necessary.
-
- if ( updateLegacyXML ) {
-
- std::string legacyXML;
- this->expat->tree.Serialize ( &legacyXML );
-
- this->MakeClipFilePath ( &filePath, ".XML" );
- oldFile = LFA_Open ( filePath.c_str(), 'w' );
-
- if ( oldFile == 0 ) {
-
- // The XML does not exist yet.
-
- this->MakeClipFilePath ( &filePath, ".XML" );
- oldFile = LFA_Create ( filePath.c_str() );
- if ( oldFile == 0 ) XMP_Throw ( "Failure creating P2 legacy XML file", kXMPErr_ExternalFailure );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XML file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- this->MakeClipFilePath ( &filePath, ".XML" );
-
- CreateTempFile ( filePath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( filePath.c_str() );
- LFA_Rename ( tempPath.c_str(), filePath.c_str() );
-
- }
-
- }
-
- // Update the XMP file.
-
- oldFile = this->parent->fileRef;
-
- if ( oldFile == 0 ) {
-
- // The XMP does not exist yet.
-
- this->MakeClipFilePath ( &filePath, ".XMP" );
- oldFile = LFA_Create ( filePath.c_str() );
- if ( oldFile == 0 ) XMP_Throw ( "Failure creating P2 XMP file", kXMPErr_ExternalFailure );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XMP file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- this->MakeClipFilePath ( &filePath, ".XMP" );
-
- CreateTempFile ( filePath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( filePath.c_str() );
- LFA_Rename ( tempPath.c_str(), filePath.c_str() );
-
- }
-
- this->parent->fileRef = 0;
-
-} // P2_MetaHandler::UpdateFile
-
-// =================================================================================================
-// P2_MetaHandler::WriteFile
-// =========================
-
-void P2_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- // ! WriteFile is not supposed to be called for handlers that own the file.
- XMP_Throw ( "P2_MetaHandler::WriteFile should not be called", kXMPErr_InternalFailure );
-
-} // P2_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/P2_Handler.hpp b/source/XMPFiles/FileHandlers/P2_Handler.hpp
deleted file mode 100644
index 3d0cd96..0000000
--- a/source/XMPFiles/FileHandlers/P2_Handler.hpp
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __P2_Handler_hpp__
-#define __P2_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#include "ExpatAdapter.hpp"
-
-#include "MD5.h"
-
-// =================================================================================================
-/// \file P2_Handler.hpp
-/// \brief Folder format handler for P2.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler * P2_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool P2_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kP2_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_UsesSidecarXMP |
- kXMPFiles_FolderBasedFormat);
-
-class P2_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions() // *** These should be standard for standalone XMP files.
- { return (kXMP_UseCompactFormat | kXMP_OmitPacketWrapper); };
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- P2_MetaHandler ( XMPFiles * _parent );
- virtual ~P2_MetaHandler();
-
-private:
-
- P2_MetaHandler() : expat(0), clipMetadata(0), clipContent(0) {}; // Hidden on purpose.
-
- void MakeClipFilePath ( std::string * path, XMP_StringPtr suffix );
- void MakeLegacyDigest ( std::string * digestStr );
- void CleanupLegacyXML();
-
- void DigestLegacyItem ( MD5_CTX & md5Context, XML_NodePtr legacyContext, XMP_StringPtr legacyPropName );
- void DigestLegacyRelations ( MD5_CTX & md5Context );
-
- void SetXMPPropertyFromLegacyXML ( bool digestFound,
- XML_NodePtr legacyContext,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr legacyPropName,
- bool isLocalized );
-
- void SetRelationsFromLegacyXML ( bool digestFound );
- void SetAudioInfoFromLegacyXML ( bool digestFound );
- void SetVideoInfoFromLegacyXML ( bool digestFound );
- void SetDurationFromLegacyXML ( bool digestFound );
-
- void SetVideoFrameInfoFromLegacyXML ( XML_NodePtr legacyVideoContext, bool digestFound );
- void SetStartTimecodeFromLegacyXML ( XML_NodePtr legacyVideoContext, bool digestFound );
- void SetGPSPropertyFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound, XMP_StringPtr propName, XMP_StringPtr legacyPropName );
- void SetAltitudeFromLegacyXML ( XML_NodePtr legacyLocationContext, bool digestFound );
-
- XML_Node * ForceChildElement ( XML_Node * parent, XMP_StringPtr localName, int indent = 0 );
-
- std::string rootPath, clipName, p2NS;
-
- 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_MetaHandler
-
-// =================================================================================================
-
-#endif /* __P2_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PNG_Handler.cpp b/source/XMPFiles/FileHandlers/PNG_Handler.cpp
deleted file mode 100644
index 0185fce..0000000
--- a/source/XMPFiles/FileHandlers/PNG_Handler.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "PNG_Handler.hpp"
-
-#include "PNG_Support.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file PNG_Handler.hpp
-/// \brief File format handler for PNG.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// PNG_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * PNG_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new PNG_MetaHandler ( parent );
-
-} // PNG_MetaHandlerCTor
-
-// =================================================================================================
-// PNG_CheckFormat
-// ===============
-
-bool PNG_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_PNGFile );
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, PNG_SIGNATURE_LEN ) ) return false; // We need at least 8, the buffer is filled anyway.
-
- if ( ! CheckBytes ( ioBuf.ptr, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN ) ) return false;
-
- return true;
-
-} // PNG_CheckFormat
-
-// =================================================================================================
-// PNG_MetaHandler::PNG_MetaHandler
-// ==================================
-
-PNG_MetaHandler::PNG_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kPNG_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-}
-
-// =================================================================================================
-// PNG_MetaHandler::~PNG_MetaHandler
-// ===================================
-
-PNG_MetaHandler::~PNG_MetaHandler()
-{
-}
-
-// =================================================================================================
-// PNG_MetaHandler::CacheFileData
-// ===============================
-
-void PNG_MetaHandler::CacheFileData()
-{
-
- this->containsXMP = false;
-
- LFA_FileRef fileRef ( this->parent->fileRef );
- if ( fileRef == 0) return;
-
- PNG_Support::ChunkState chunkState;
- long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState );
- if ( numChunks == 0 ) return;
-
- if (chunkState.xmpLen != 0)
- {
- // XMP present
-
- this->xmpPacket.reserve(chunkState.xmpLen);
- this->xmpPacket.assign(chunkState.xmpLen, ' ');
-
- if (PNG_Support::ReadBuffer ( fileRef, chunkState.xmpPos, chunkState.xmpLen, const_cast<char *>(this->xmpPacket.data()) ))
- {
- this->packetInfo.offset = chunkState.xmpPos;
- this->packetInfo.length = chunkState.xmpLen;
- this->containsXMP = true;
- }
- }
- else
- {
- // no XMP
- }
-
-} // PNG_MetaHandler::CacheFileData
-
-// =================================================================================================
-// PNG_MetaHandler::ProcessXMP
-// ============================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-
-void PNG_MetaHandler::ProcessXMP()
-{
- this->processedXMP = true; // Make sure we only come through here once.
-
- // Process the XMP packet.
-
- if ( ! this->xmpPacket.empty() ) {
-
- XMP_Assert ( this->containsXMP );
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
-
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
-
- this->containsXMP = true;
-
- }
-
-} // PNG_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// PNG_MetaHandler::UpdateFile
-// ============================
-
-void PNG_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- bool updated = false;
-
- if ( ! this->needsUpdate ) return;
- if ( doSafeUpdate ) XMP_Throw ( "PNG_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
-
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
- if ( packetLen == 0 ) return;
-
- LFA_FileRef fileRef(this->parent->fileRef);
- if ( fileRef == 0 ) return;
-
- PNG_Support::ChunkState chunkState;
- long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState );
- if ( numChunks == 0 ) return;
-
- // write/update chunk
- if (chunkState.xmpLen == 0)
- {
- // no current chunk -> inject
- updated = SafeWriteFile();
- }
- else if (chunkState.xmpLen >= packetLen )
- {
- // current chunk size is sufficient -> write and update CRC (in place update)
- updated = PNG_Support::WriteBuffer(fileRef, chunkState.xmpPos, packetLen, packetStr );
- PNG_Support::UpdateChunkCRC(fileRef, chunkState.xmpChunk );
- }
- else if (chunkState.xmpLen < packetLen)
- {
- // XMP is too large for current chunk -> expand
- updated = SafeWriteFile();
- }
-
- if ( ! updated )return; // If there's an error writing the chunk, bail.
-
- this->needsUpdate = false;
-
-} // PNG_MetaHandler::UpdateFile
-
-// =================================================================================================
-// PNG_MetaHandler::WriteFile
-// ===========================
-
-void PNG_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- LFA_FileRef destRef = this->parent->fileRef;
-
- PNG_Support::ChunkState chunkState;
- long numChunks = PNG_Support::OpenPNG ( sourceRef, chunkState );
- if ( numChunks == 0 ) return;
-
- LFA_Truncate(destRef, 0);
- LFA_Write(destRef, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN);
-
- PNG_Support::ChunkIterator curPos = chunkState.chunks.begin();
- PNG_Support::ChunkIterator endPos = chunkState.chunks.end();
-
- for (; (curPos != endPos); ++curPos)
- {
- PNG_Support::ChunkData chunk = *curPos;
-
- // discard existing XMP chunk
- if (chunk.xmp)
- continue;
-
- // copy any other chunk
- PNG_Support::CopyChunk(sourceRef, destRef, chunk);
-
- // place XMP chunk immediately after IHDR-chunk
- if (PNG_Support::CheckIHDRChunkHeader(chunk))
- {
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
-
- PNG_Support::WriteXMPChunk(destRef, packetLen, packetStr );
- }
- }
-
-} // PNG_MetaHandler::WriteFile
-
-// =================================================================================================
-// PNG_MetaHandler::SafeWriteFile
-// ===========================
-
-bool PNG_MetaHandler::SafeWriteFile ()
-{
- bool ret = false;
-
- std::string origPath = this->parent->filePath;
- LFA_FileRef origRef = this->parent->fileRef;
-
- std::string updatePath;
- LFA_FileRef updateRef = 0;
-
- CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
-
- this->parent->filePath = updatePath;
- this->parent->fileRef = updateRef;
-
- try {
- this->WriteFile ( origRef, origPath );
- ret = true;
- } catch ( ... ) {
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = origRef;
- throw;
- }
-
- LFA_Close ( origRef );
- LFA_Delete ( origPath.c_str() );
-
- LFA_Close ( updateRef );
- LFA_Rename ( updatePath.c_str(), origPath.c_str() );
- this->parent->filePath = origPath;
-
- this->parent->fileRef = 0;
-
- return ret;
-
-} // PNG_MetaHandler::SafeWriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PNG_Handler.hpp b/source/XMPFiles/FileHandlers/PNG_Handler.hpp
deleted file mode 100644
index cc978c3..0000000
--- a/source/XMPFiles/FileHandlers/PNG_Handler.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef __PNG_Handler_hpp__
-#define __PNG_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "PNG_Support.hpp"
-
-// =================================================================================================
-/// \file PNG_Handler.hpp
-/// \brief File format handler for PNG.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler* PNG_MetaHandlerCTor ( XMPFiles* parent );
-
-extern bool PNG_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kPNG_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_NeedsReadOnlyPacket );
-
-class PNG_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string& sourcePath );
-
- bool SafeWriteFile ();
-
- PNG_MetaHandler ( XMPFiles* parent );
- virtual ~PNG_MetaHandler();
-
-}; // PNG_MetaHandler
-
-// =================================================================================================
-
-#endif /* __PNG_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PSD_Handler.cpp b/source/XMPFiles/FileHandlers/PSD_Handler.cpp
deleted file mode 100644
index b81ef0c..0000000
--- a/source/XMPFiles/FileHandlers/PSD_Handler.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "PSD_Handler.hpp"
-
-#include "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-#include "ReconcileLegacy.hpp"
-#include "Reconcile_Impl.hpp"
-
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file PSD_Handler.cpp
-/// \brief File format handler for PSD (Photoshop).
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// PSD_CheckFormat
-// ===============
-
-// For PSD we just check the "8BPS" signature, the following version, and that the file is at least
-// 34 bytes long. This covers the 26 byte header, the 4 byte color mode section length (which might
-// be 0), and the 4 byte image resource section length (which might be 0). The parsing logic in
-// CacheFileData will do further checks that the image resources actually exist. Those checks are
-// not needed to decide if this is a PSD file though, instead they decide if this is valid PSD.
-
-// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
-
-bool PSD_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_PhotoshopFile );
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 34 ) ) return false; // 34 = header plus 2 lengths
-
- if ( ! CheckBytes ( ioBuf.ptr, "8BPS", 4 ) ) return false;
- ioBuf.ptr += 4; // Move to the version.
- XMP_Uns16 version = GetUns16BE ( ioBuf.ptr );
- if ( (version != 1) && (version != 2) ) return false;
-
- return true;
-
-} // PSD_CheckFormat
-
-// =================================================================================================
-// PSD_MetaHandlerCTor
-// ===================
-
-XMPFileHandler * PSD_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new PSD_MetaHandler ( parent );
-
-} // PSD_MetaHandlerCTor
-
-// =================================================================================================
-// PSD_MetaHandler::PSD_MetaHandler
-// ================================
-
-PSD_MetaHandler::PSD_MetaHandler ( XMPFiles * _parent ) : iptcMgr(0), exifMgr(0), skipReconcile(false)
-{
- this->parent = _parent;
- this->handlerFlags = kPSD_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // PSD_MetaHandler::PSD_MetaHandler
-
-// =================================================================================================
-// PSD_MetaHandler::~PSD_MetaHandler
-// =================================
-
-PSD_MetaHandler::~PSD_MetaHandler()
-{
-
- if ( this->iptcMgr != 0 ) delete ( this->iptcMgr );
- if ( this->exifMgr != 0 ) delete ( this->exifMgr );
-
-} // PSD_MetaHandler::~PSD_MetaHandler
-
-// =================================================================================================
-// PSD_MetaHandler::CacheFileData
-// ==============================
-//
-// Find and parse the image resource section, everything we want is in there. Don't simply capture
-// the whole section, there could be lots of stuff we don't care about.
-
-// *** This implementation simply returns when an invalid file is encountered. Should we throw instead?
-
-void PSD_MetaHandler::CacheFileData()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- XMP_Assert ( ! this->containsXMP );
- // Set containsXMP to true here only if the XMP image resource is found.
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "PSD_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
- }
-
- XMP_Uns8 psdHeader[30];
- XMP_Int64 filePos;
- XMP_Uns32 ioLen, cmLen, psirLen;
-
- filePos = LFA_Seek ( fileRef, 0, SEEK_SET );
-
- ioLen = LFA_Read ( fileRef, psdHeader, 30 );
- if ( ioLen != 30 ) return; // Throw?
-
- this->imageHeight = GetUns32BE ( &psdHeader[14] );
- this->imageWidth = GetUns32BE ( &psdHeader[18] );
-
- cmLen = GetUns32BE ( &psdHeader[26] );
-
- XMP_Int64 psirOrigin = 26 + 4 + cmLen;
-
- filePos = LFA_Seek ( fileRef, psirOrigin, SEEK_SET );
- if ( filePos != psirOrigin ) return; // Throw?
-
- ioLen = LFA_Read ( fileRef, psdHeader, 4 );
- if ( ioLen != 4 ) return; // Throw?
-
- psirLen = GetUns32BE ( &psdHeader[0] );
-
- this->psirMgr.ParseFileResources ( fileRef, psirLen );
-
- PSIR_Manager::ImgRsrcInfo xmpInfo;
- bool found = this->psirMgr.GetImgRsrc ( kPSIR_XMP, &xmpInfo );
-
- if ( found ) {
-
- // printf ( "PSD_MetaHandler::CacheFileData - XMP packet offset %d (0x%X), size %d\n",
- // xmpInfo.origOffset, xmpInfo.origOffset, xmpInfo.dataLen );
- this->packetInfo.offset = xmpInfo.origOffset;
- this->packetInfo.length = xmpInfo.dataLen;
- this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
- this->packetInfo.charForm = kXMP_CharUnknown;
- this->packetInfo.writeable = true;
-
- this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );
-
- this->containsXMP = true;
-
- }
-
-} // PSD_MetaHandler::CacheFileData
-
-// =================================================================================================
-// PSD_MetaHandler::ProcessXMP
-// ===========================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-
-void PSD_MetaHandler::ProcessXMP()
-{
-
- this->processedXMP = true; // Make sure we only come through here once.
-
- // 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);
-
- if ( readOnly ) {
- this->iptcMgr = new IPTC_Reader();
- this->exifMgr = new TIFF_MemoryReader();
- } else {
- this->iptcMgr = new IPTC_Writer(); // ! Parse it later.
- this->exifMgr = new TIFF_FileWriter();
- }
-
- PSIR_Manager & psir = this->psirMgr; // Give the compiler help in recognizing non-aliases.
- IPTC_Manager & iptc = *this->iptcMgr;
- TIFF_Manager & exif = *this->exifMgr;
-
- PSIR_Manager::ImgRsrcInfo iptcInfo, exifInfo;
- bool haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );
- bool haveExif = psir.GetImgRsrc ( kPSIR_Exif, &exifInfo );
- int iptcDigestState = kDigestMatches;
-
- if ( haveExif ) exif.ParseMemoryStream ( exifInfo.dataPtr, exifInfo.dataLen );
-
- if ( haveIPTC ) {
-
- bool haveDigest = false;
- PSIR_Manager::ImgRsrcInfo digestInfo;
- haveDigest = psir.GetImgRsrc ( kPSIR_IPTCDigest, &digestInfo );
- if ( digestInfo.dataLen != 16 ) haveDigest = false;
-
- if ( ! haveDigest ) {
- iptcDigestState = kDigestMissing;
- } else {
- iptcDigestState = PhotoDataUtils::CheckIPTCDigest ( iptcInfo.dataPtr, iptcInfo.dataLen, digestInfo.dataPtr );
- }
-
- }
-
- XMP_OptionBits options = 0;
- if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
- if ( haveIPTC ) options |= k2XMP_FileHadIPTC;
- if ( haveExif ) options |= k2XMP_FileHadExif;
-
- // Process the XMP packet. If it fails to parse, do a forced legacy import but still throw an
- // exception. This tells the caller that an error happened, but gives them recovered legacy
- // should they want to proceed with that.
-
- bool haveXMP = false;
-
- if ( ! this->xmpPacket.empty() ) {
- XMP_Assert ( this->containsXMP );
- // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
- try {
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
- haveXMP = true;
- } catch ( ... ) {
- XMP_ClearOption ( options, k2XMP_FileHadXMP );
- if ( haveIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- if ( iptcDigestState == kDigestMatches ) iptcDigestState = kDigestMissing;
- ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
- throw; // ! Rethrow the exception, don't absorb it.
- }
- }
-
- // Process the legacy metadata.
-
- if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- ImportPhotoData ( exif, iptc, psir, iptcDigestState, &this->xmpObj, options );
- this->containsXMP = true; // Assume we now have something in the XMP.
-
-} // PSD_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// PSD_MetaHandler::UpdateFile
-// ===========================
-
-void PSD_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
-
- XMP_Int64 oldPacketOffset = this->packetInfo.offset;
- XMP_Int32 oldPacketLength = this->packetInfo.length;
-
- if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
- if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
-
- bool fileHadXMP = ((oldPacketOffset != 0) && (oldPacketLength != 0));
-
- // Update the IPTC-IIM and native TIFF/Exif metadata. ExportPhotoData also trips the tiff: and
- // exif: copies from the XMP, so reserialize the now final XMP packet.
-
- ExportPhotoData ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, this->iptcMgr, &this->psirMgr );
-
- try {
- XMP_OptionBits options = kXMP_UseCompactFormat;
- if ( fileHadXMP ) options |= kXMP_ExactPacketLength;
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, options, oldPacketLength );
- } catch ( ... ) {
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- // Decide whether to do an in-place update. This can only happen if all of the following are true:
- // - There is an XMP packet in the file.
- // - The are no changes to the legacy image resources. (The IPTC and EXIF are in the PSIR.)
- // - The new XMP can fit in the old space.
-
- bool doInPlace = (fileHadXMP && (this->xmpPacket.size() <= (size_t)oldPacketLength));
- if ( this->psirMgr.IsLegacyChanged() ) doInPlace = false;
-
- if ( doInPlace ) {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", PSD in-place update";
- #endif
-
- if ( this->xmpPacket.size() < (size_t)this->packetInfo.length ) {
- // They ought to match, cheap to be sure.
- size_t extraSpace = (size_t)this->packetInfo.length - this->xmpPacket.size();
- this->xmpPacket.append ( extraSpace, ' ' );
- }
-
- LFA_FileRef liveFile = this->parent->fileRef;
-
- XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
-
- // printf ( "PSD_MetaHandler::UpdateFile - XMP in-place packet offset %lld (0x%llX), size %d\n",
- // oldPacketOffset, oldPacketOffset, this->xmpPacket.size() );
- LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
- LFA_Write ( liveFile, this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
-
- } else {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", PSD copy update";
- #endif
-
- std::string origPath = this->parent->filePath;
- LFA_FileRef origRef = this->parent->fileRef;
-
- std::string updatePath;
- LFA_FileRef updateRef = 0;
-
- CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
-
- this->parent->filePath = updatePath;
- this->parent->fileRef = updateRef;
-
- try {
- XMP_Assert ( ! this->skipReconcile );
- this->skipReconcile = true;
- this->WriteFile ( origRef, origPath );
- this->skipReconcile = false;
- } catch ( ... ) {
- this->skipReconcile = false;
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = origRef;
- throw;
- }
-
- LFA_Close ( origRef );
- LFA_Delete ( origPath.c_str() );
-
- LFA_Close ( updateRef );
- LFA_Rename ( updatePath.c_str(), origPath.c_str() );
- this->parent->filePath = origPath;
- this->parent->fileRef = 0;
-
- }
-
- this->needsUpdate = false;
-
-} // PSD_MetaHandler::UpdateFile
-
-// =================================================================================================
-// PSD_MetaHandler::WriteFile
-// ==========================
-
-// The metadata parts of a Photoshop file are all in the image resources. The PSIR_Manager's
-// UpdateFileResources method will take care of the image resource portion of the file, updating
-// those resources that have changed and preserving those that have not.
-
-void PSD_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- LFA_FileRef destRef = this->parent->fileRef;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- XMP_Uns64 sourceLen = LFA_Measure ( sourceRef );
- if ( sourceLen == 0 ) return; // Tolerate empty files.
-
- // Reconcile the legacy metadata, unless this is called from UpdateFile. Reserialize the XMP to
- // get standard padding, PutXMP has probably done an in-place serialize. Set the XMP image resource.
-
- if ( ! skipReconcile ) {
- // Update the IPTC-IIM and native TIFF/Exif metadata, and reserialize the now final XMP packet.
- ExportPhotoData ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->iptcMgr, &this->psirMgr );
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- this->packetInfo.offset = kXMPFiles_UnknownOffset;
- this->packetInfo.length = (XMP_StringLen)this->xmpPacket.size();
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- this->psirMgr.SetImgRsrc ( kPSIR_XMP, this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
-
- // Copy the file header and color mode section, then write the updated image resource section,
- // and copy the tail of the source file (layer and mask section to EOF).
-
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Truncate (destRef, 0 );
-
- LFA_Copy ( sourceRef, destRef, 26 ); // Copy the file header.
-
- XMP_Uns32 cmLen;
- LFA_Read ( sourceRef, &cmLen, 4 );
- LFA_Write ( destRef, &cmLen, 4 ); // Copy the color mode section length.
- cmLen = GetUns32BE ( &cmLen );
- LFA_Copy ( sourceRef, destRef, cmLen ); // Copy the color mode section contents.
-
- XMP_Uns32 irLen;
- LFA_Read ( sourceRef, &irLen, 4 ); // Get the source image resource section length.
- irLen = GetUns32BE ( &irLen );
-
- this->psirMgr.UpdateFileResources ( sourceRef, destRef, 0, abortProc, abortArg );
-
- XMP_Uns64 tailOffset = 26 + 4 + cmLen + 4 + irLen;
- XMP_Uns64 tailLength = sourceLen - tailOffset;
-
- LFA_Seek ( sourceRef, tailOffset, SEEK_SET );
- LFA_Seek ( destRef, 0, SEEK_END );
- LFA_Copy ( sourceRef, destRef, tailLength ); // Copy the tail of the file.
-
- this->needsUpdate = false;
-
-} // PSD_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PSD_Handler.hpp b/source/XMPFiles/FileHandlers/PSD_Handler.hpp
deleted file mode 100644
index 7ac56b5..0000000
--- a/source/XMPFiles/FileHandlers/PSD_Handler.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef __PSD_Handler_hpp__
-#define __PSD_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-
-// =================================================================================================
-/// \file PSD_Handler.hpp
-/// \brief File format handler for PSD (Photoshop).
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler * PSD_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool PSD_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kPSD_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate);
-
-class PSD_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- bool skipReconcile; // ! Used between UpdateFile and WriteFile.
-
- PSD_MetaHandler ( XMPFiles * parent );
- virtual ~PSD_MetaHandler();
-
-private:
-
- PSD_MetaHandler() : iptcMgr(0), exifMgr(0), skipReconcile(false) {}; // Hidden on purpose.
-
- PSIR_FileWriter psirMgr; // Don't need a pointer, the PSIR part is always file-based.
- IPTC_Manager * iptcMgr; // Need to use pointers so we can properly select between read-only
- TIFF_Manager * exifMgr; // and read-write modes of usage.
-
- XMP_Uns32 imageWidth, imageHeight; // Pixel dimensions, used with thumbnail info.
-
-}; // PSD_MetaHandler
-
-// =================================================================================================
-
-#endif /* __PSD_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PostScript_Handler.cpp b/source/XMPFiles/FileHandlers/PostScript_Handler.cpp
deleted file mode 100644
index e925833..0000000
--- a/source/XMPFiles/FileHandlers/PostScript_Handler.cpp
+++ /dev/null
@@ -1,574 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "XMPScanner.hpp"
-
-#include "Scanner_Handler.hpp"
-#include "PostScript_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file PostScript_Handler.cpp
-/// \brief File format handler for PostScript and EPS files.
-///
-/// This header ...
-///
-// =================================================================================================
-
-static const char * kPSFileTag = "%!PS-Adobe-";
-static const size_t kPSFileTagLen = strlen ( kPSFileTag );
-
-// =================================================================================================
-// PostScript_MetaHandlerCTor
-// ==========================
-
-XMPFileHandler * PostScript_MetaHandlerCTor ( XMPFiles * parent )
-{
- XMPFileHandler * newHandler = new PostScript_MetaHandler ( parent );
-
- return newHandler;
-
-} // PostScript_MetaHandlerCTor
-
-// =================================================================================================
-// PostScript_CheckFormat
-// ======================
-
-bool PostScript_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(filePath); IgnoreParam(parent);
- XMP_Assert ( (format == kXMP_EPSFile) || (format == kXMP_PostScriptFile) );
-
- IOBuffer ioBuf;
-
- XMP_Int64 psOffset;
- size_t psLength;
- XMP_Uns32 temp1, temp2;
-
- // Check for the binary EPSF preview header.
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false;
- temp1 = GetUns32BE ( ioBuf.ptr );
-
- if ( temp1 == 0xC5D0D3C6 ) {
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 30 ) ) return false;
-
- psOffset = GetUns32LE ( ioBuf.ptr+4 ); // PostScript offset.
- psLength = GetUns32LE ( ioBuf.ptr+8 ); // PostScript length.
-
- bool ok;
- LFA_Seek ( fileRef, psOffset, SEEK_SET, &ok );
- if ( ! ok ) return false; // Don't throw for a failure.
-
- ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
- RefillBuffer ( fileRef, &ioBuf );
- if ( (ioBuf.len < kIOBufferSize) && (ioBuf.len < psLength) ) return false; // Not enough PostScript.
-
- }
-
- // Check the start of the PostScript DSC header comment.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, (kPSFileTagLen + 3 + 1) ) ) return false;
- if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSFileTag), kPSFileTagLen ) ) return false;
- ioBuf.ptr += kPSFileTagLen;
-
- // Check the PostScript DSC major version number.
-
- temp1 = 0;
- while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
- temp1 = (temp1 * 10) + (*ioBuf.ptr - '0');
- if ( temp1 > 1000 ) return false; // Overflow.
- ioBuf.ptr += 1;
- }
- if ( temp1 < 3 ) return false; // The version must be at least 3.0.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return false;
- if ( *ioBuf.ptr != '.' ) return false; // No minor number.
- ioBuf.ptr += 1;
-
- // Check the PostScript DSC minor version number.
-
- temp2 = 0;
- while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
- temp2 = (temp2 * 10) + (*ioBuf.ptr - '0');
- if ( temp2 > 1000 ) return false; // Overflow.
- ioBuf.ptr += 1;
- }
- // We don't care about the actual minor version number.
-
- if ( format == kXMP_PostScriptFile ) {
-
- // Almost done for plain PostScript, check for whitespace.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return false;
- if ( (*ioBuf.ptr != ' ') && (*ioBuf.ptr != kLF) && (*ioBuf.ptr != kCR) ) return false;
- ioBuf.ptr += 1;
-
- } else {
-
- // Check for the EPSF keyword on the header comment.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 6+3+1 ) ) return false;
- if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(" EPSF-"), 6 ) ) return false;
- ioBuf.ptr += 6;
-
- // Check the EPS major version number.
-
- temp1 = 0;
- while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
- temp1 = (temp1 * 10) + (*ioBuf.ptr - '0');
- if ( temp1 > 1000 ) return false; // Overflow.
- ioBuf.ptr += 1;
- }
- if ( temp1 < 3 ) return false; // The version must be at least 3.0.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return false;
- if ( *ioBuf.ptr != '.' ) return false; // No minor number.
- ioBuf.ptr += 1;
-
- // Check the EPS minor version number.
-
- temp2 = 0;
- while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
- temp2 = (temp2 * 10) + (*ioBuf.ptr - '0');
- if ( temp2 > 1000 ) return false; // Overflow.
- ioBuf.ptr += 1;
- }
- // We don't care about the actual minor version number.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return false;
- if ( (*ioBuf.ptr != kLF) && (*ioBuf.ptr != kCR) ) return false;
- ioBuf.ptr += 1;
-
- }
-
- return true;
-
-} // PostScript_CheckFormat
-
-// =================================================================================================
-// PostScript_MetaHandler::PostScript_MetaHandler
-// ==============================================
-
-PostScript_MetaHandler::PostScript_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kPostScript_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
- this->psHint = kPSHint_NoMarker;
-
-} // PostScript_MetaHandler::PostScript_MetaHandler
-
-// =================================================================================================
-// PostScript_MetaHandler::~PostScript_MetaHandler
-// ===============================================
-
-PostScript_MetaHandler::~PostScript_MetaHandler()
-{
- // ! Inherit the base cleanup.
-
-} // PostScript_MetaHandler::~PostScript_MetaHandler
-
-// =================================================================================================
-// PostScript_MetaHandler::FindPostScriptHint
-// ==========================================
-//
-// Search for "%ADO_ContainsXMP:" at the beginning of a line, it must be before "%%EndComments". If
-// the XMP marker is found, look for the MainFirst/MainLast/NoMain options.
-
-static const char * kPSContainsXMPString = "%ADO_ContainsXMP:";
-static const size_t kPSContainsXMPLength = strlen ( kPSContainsXMPString );
-
-static const char * kPSEndCommentString = "%%EndComments"; // ! Assumed shorter than kPSContainsXMPString.
-static const size_t kPSEndCommentLength = strlen ( kPSEndCommentString );
-
-int PostScript_MetaHandler::FindPostScriptHint()
-{
- bool found = false;
- IOBuffer ioBuf;
- XMP_Uns8 ch;
-
- LFA_FileRef fileRef = this->parent->fileRef;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- // Check for the binary EPSF preview header.
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false;
- XMP_Uns32 temp1 = GetUns32BE ( ioBuf.ptr );
-
- if ( temp1 == 0xC5D0D3C6 ) {
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 30 ) ) return false;
-
- size_t psOffset = GetUns32LE ( ioBuf.ptr+4 ); // PostScript offset.
- size_t psLength = GetUns32LE ( ioBuf.ptr+8 ); // PostScript length.
-
- bool ok;
- LFA_Seek ( fileRef, psOffset, SEEK_SET, &ok );
- if ( ! ok ) return false; // Don't throw for a failure.
-
- ioBuf.ptr = ioBuf.limit; // Force the next check to refill the buffer.
-
- }
-
- // Look for the ContainsXMP comment.
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "PostScript_MetaHandler::FindPostScriptHint - User abort", kXMPErr_UserAbort );
- }
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, kPSContainsXMPLength ) ) return kPSHint_NoMarker;
-
- if ( CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSEndCommentString), kPSEndCommentLength ) ) {
-
- // Found "%%EndComments", don't look any further.
- return kPSHint_NoMarker;
-
- } else if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSContainsXMPString), kPSContainsXMPLength ) ) {
-
- // Not "%%EndComments" or "%ADO_ContainsXMP:", skip past the end of this line.
- do {
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMarker;
- ch = *ioBuf.ptr;
- ++ioBuf.ptr;
- } while ( ! IsNewline ( ch ) );
-
- } else {
-
- // Found "%ADO_ContainsXMP:", look for the main packet location option.
-
- ioBuf.ptr += kPSContainsXMPLength;
- int xmpHint = kPSHint_NoMain; // ! From here on, a failure means "no main", not "no marker".
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
- if ( ! IsSpaceOrTab ( *ioBuf.ptr ) ) return kPSHint_NoMain;
-
- while ( true ) {
-
- while ( true ) { // Skip leading spaces and tabs.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
- if ( ! IsSpaceOrTab ( *ioBuf.ptr ) ) break;
- ++ioBuf.ptr;
- }
- if ( IsNewline ( *ioBuf.ptr ) ) return kPSHint_NoMain; // Reached the end of the ContainsXMP comment.
-
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 6 ) ) return kPSHint_NoMain;
-
- if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("NoMain"), 6 ) ) {
-
- ioBuf.ptr += 6;
- xmpHint = kPSHint_NoMain;
- break;
-
- } else if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("MainFi"), 6 ) ) {
-
- ioBuf.ptr += 6;
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return kPSHint_NoMain;
- if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("rst"), 3 ) ) {
- ioBuf.ptr += 3;
- xmpHint = kPSHint_MainFirst;
- }
- break;
-
- } else if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("MainLa"), 6 ) ) {
-
- ioBuf.ptr += 6;
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return kPSHint_NoMain;
- if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("st"), 2 ) ) {
- ioBuf.ptr += 2;
- xmpHint = kPSHint_MainLast;
- }
- break;
-
- } else {
-
- while ( true ) { // Skip until whitespace.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
- if ( IsWhitespace ( *ioBuf.ptr ) ) break;
- ++ioBuf.ptr;
- }
-
- }
-
- } // Look for the main packet location option.
-
- // Make sure we found exactly a known option.
- if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
- if ( ! IsWhitespace ( *ioBuf.ptr ) ) return kPSHint_NoMain;
- return xmpHint;
-
- } // Found "%ADO_ContainsXMP:".
-
- } // Outer marker loop.
-
- return kPSHint_NoMarker; // Should never reach here.
-
-} // PostScript_MetaHandler::FindPostScriptHint
-
-
-// =================================================================================================
-// PostScript_MetaHandler::FindFirstPacket
-// =======================================
-//
-// Run the packet scanner until we find a valid packet. The first one is the main. For simplicity,
-// the state of all snips is checked after each buffer is read. In theory only the last of the
-// previous snips might change from partial to valid, but then we would have to special case the
-// first pass when there is no previous set of snips. Since we have to get a full report to look at
-// the last snip anyway, it costs virtually nothing extra to recheck all of the snips.
-
-bool PostScript_MetaHandler::FindFirstPacket()
-{
- int snipCount;
- bool found = false;
- size_t bufPos, bufLen;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Int64 fileLen = LFA_Measure ( fileRef );
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- XMPScanner scanner ( fileLen );
- XMPScanner::SnipInfoVector snips;
-
- enum { kBufferSize = 64*1024 };
- XMP_Uns8 buffer [kBufferSize];
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- bufPos = 0;
- bufLen = 0;
-
- LFA_Seek ( fileRef, 0, SEEK_SET ); // Seek back to the beginning of the file.
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "PostScript_MetaHandler::FindFirstPacket - User abort", kXMPErr_UserAbort );
- }
-
- bufPos += bufLen;
- bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
- if ( bufLen == 0 ) return false; // Must be at EoF, no packets found.
-
- scanner.Scan ( buffer, bufPos, bufLen );
- snipCount = scanner.GetSnipCount();
- scanner.Report ( snips );
-
- for ( int i = 0; i < snipCount; ++i ) {
- if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
- if ( snips[i].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindFirstPacket: Oversize packet", kXMPErr_BadXMP );
- packetInfo.offset = snips[i].fOffset;
- packetInfo.length = (XMP_Int32)snips[i].fLength;
- packetInfo.charForm = snips[i].fCharForm;
- packetInfo.writeable = (snips[i].fAccess == 'w');
- return true;
- }
- }
-
- }
-
- return false;
-
-} // FindFirstPacket
-
-
-// =================================================================================================
-// PostScript_MetaHandler::FindLastPacket
-// ======================================
-//
-// Run the packet scanner backwards until we find the start of a packet, or a valid packet. If we
-// found a packet start, resume forward scanning to see if it is a valid packet. For simplicity, all
-// of the snips are checked on each pass, for much the same reasons as in FindFirstPacket.
-
-#if 1
-
-// *** Doing this right (as described above) requires out of order scanning support which isn't
-// *** implemented yet. For now we scan the whole file and pick the last valid packet.
-
-bool PostScript_MetaHandler::FindLastPacket()
-{
- int pkt;
- size_t bufPos, bufLen;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Int64 fileLen = LFA_Measure ( fileRef );
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- // ------------------------------------------------------
- // Scan the entire file to find all of the valid packets.
-
- XMPScanner scanner ( fileLen );
-
- enum { kBufferSize = 64*1024 };
- XMP_Uns8 buffer [kBufferSize];
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- LFA_Seek ( fileRef, 0, SEEK_SET ); // Seek back to the beginning of the file.
-
- for ( bufPos = 0; bufPos < (size_t)fileLen; bufPos += bufLen ) {
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "PostScript_MetaHandler::FindLastPacket - User abort", kXMPErr_UserAbort );
- }
- bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
- if ( bufLen == 0 ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
- scanner.Scan ( buffer, bufPos, bufLen );
- }
-
- // -------------------------------
- // Pick the last the valid packet.
-
- int snipCount = scanner.GetSnipCount();
-
- XMPScanner::SnipInfoVector snips ( snipCount );
- scanner.Report ( snips );
-
- for ( pkt = snipCount-1; pkt >= 0; --pkt ) {
- if ( snips[pkt].fState == XMPScanner::eValidPacketSnip ) break;
- }
-
- if ( pkt >= 0 ) {
- if ( snips[pkt].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Oversize packet", kXMPErr_BadXMP );
- packetInfo.offset = snips[pkt].fOffset;
- packetInfo.length = (XMP_Int32)snips[pkt].fLength;
- packetInfo.charForm = snips[pkt].fCharForm;
- packetInfo.writeable = (snips[pkt].fAccess == 'w');
- return true;
- }
-
- return false;
-
-} // PostScript_MetaHandler::FindLastPacket
-
-#else
-
-bool PostScript_MetaHandler::FindLastPacket()
-{
- int err, snipCount;
- bool found = false;
- XMP_Int64 backPos, backLen;
- size_t ioCount;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_Int64 fileLen = LFA_Measure ( fileRef );
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- XMPScanner scanner ( fileLen );
- XMPScanner::SnipInfoVector snips;
-
- enum { kBufferSize = 64*1024 };
- XMP_Uns8 buffer [kBufferSize];
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- backPos = fileLen;
- backLen = 0;
-
- while ( true ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "PostScript_MetaHandler::FindLastPacket - User abort", kXMPErr_UserAbort );
- }
-
- backLen = kBufferSize;
- if ( backPos < kBufferSize ) backLen = backPos;
- if ( backLen == 0 ) return false; // Must be at BoF, no packets found.
-
- backPos -= backLen;
- LFA_Seek ( fileRef, backPos, SEEK_SET ); // Seek back to the start of the next buffer.
-
- #error "ioCount is 32 bits, backLen is 64"
- ioCount = LFA_Read ( fileRef, buffer, backLen );
- if ( ioCount != backLen ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
-
- scanner.Scan ( buffer, backPos, backLen );
- snipCount = scanner.GetSnipCount();
- scanner.Report ( snips );
-
- for ( int i = snipCount-1; i >= 0; --i ) {
-
- if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
-
- return VerifyMainPacket ( fileRef, snips[i].fOffset, snips[i].fLength, format, beLenient, mainInfo );
-
- } else if ( snips[i].fState == XMPScanner::ePartialPacketSnip ) {
-
- // This part is a tad tricky. We have a partial packet, so we need to scan
- // forward from its ending to see if it is a valid packet. Snips won't recombine,
- // the partial snip will change state. Be careful with the I/O to not clobber the
- // backward scan positions, so that it can be resumed if necessary.
-
- size_t fwdPos = snips[i].fOffset + snips[i].fLength;
- LFA_Seek ( fileRef, fwdPos, SEEK_SET ); // Seek to the end of the partial snip.
-
- while ( (fwdPos < fileLen) && (snips[i].fState == XMPScanner::ePartialPacketSnip) ) {
- ioCount = LFA_Read ( fileRef, buffer, kBufferSize );
- if ( ioCount == 0 ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
- scanner.Scan ( buffer, fwdPos, ioCount );
- scanner.Report ( snips );
- fwdPos += ioCount;
- }
-
- if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
- if ( snips[i].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Oversize packet", kXMPErr_BadXMP );
- packetInfo.offset = snips[i].fOffset;
- packetInfo.length = (XMP_Int32)snips[i].fLength;
- packetInfo.charForm = snips[i].fCharForm;
- packetInfo.writeable = (snips[i].fAccess == 'w');
- return true;
- }
-
- }
-
- } // Backwards snip loop.
-
- } // Backwards read loop.
-
- return false; // Should never get here.
-
-} // PostScript_MetaHandler::FindLastPacket
-
-#endif
-
-// =================================================================================================
-// PostScript_MetaHandler::CacheFileData
-// =====================================
-
-void PostScript_MetaHandler::CacheFileData()
-{
- this->containsXMP = false;
- this->psHint = FindPostScriptHint();
-
- if ( this->psHint == kPSHint_MainFirst ) {
- this->containsXMP = FindFirstPacket();
- } else if ( this->psHint == kPSHint_MainLast ) {
- this->containsXMP = FindLastPacket();
- }
-
- if ( this->containsXMP ) ReadXMPPacket ( this );
-
-} // PostScript_MetaHandler::CacheFileData
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PostScript_Handler.hpp b/source/XMPFiles/FileHandlers/PostScript_Handler.hpp
deleted file mode 100644
index c0d4e37..0000000
--- a/source/XMPFiles/FileHandlers/PostScript_Handler.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef __PostScript_Handler_hpp__
-#define __PostScript_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "Trivial_Handler.hpp"
-
-// =================================================================================================
-/// \file PostScript_Handler.hpp
-/// \brief File format handler for PostScript and EPS files.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** This probably could be derived from Basic_Handler, buffer the file tail in a temp file.
-
-extern XMPFileHandler * PostScript_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool PostScript_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kPostScript_HandlerFlags = kTrivial_HandlerFlags;
-
-enum {
- kPSHint_NoMarker = 0,
- kPSHint_NoMain = 1,
- kPSHint_MainFirst = 2,
- kPSHint_MainLast = 3
-};
-
-class PostScript_MetaHandler : public Trivial_MetaHandler
-{
-public:
-
- PostScript_MetaHandler ( XMPFiles * parent );
- ~PostScript_MetaHandler();
-
- void CacheFileData();
-
- int psHint;
-
-protected:
-
- int FindPostScriptHint();
-
- bool FindFirstPacket();
- bool FindLastPacket();
-
-}; // PostScript_MetaHandler
-
-// =================================================================================================
-
-#endif /* __PostScript_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/RIFF_Handler.cpp b/source/XMPFiles/FileHandlers/RIFF_Handler.cpp
deleted file mode 100644
index daa4455..0000000
--- a/source/XMPFiles/FileHandlers/RIFF_Handler.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 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 "RIFF.hpp"
-#include "RIFF_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file RIFF_Handler.cpp
-/// \brief File format handler for RIFF.
-// =================================================================================================
-
-// =================================================================================================
-// RIFF_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * RIFF_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new RIFF_MetaHandler ( parent );
-}
-
-// =================================================================================================
-// RIFF_CheckFormat
-// ===============
-//
-// An RIFF file must begin with "RIFF", a 4 byte length, then the chunkType (AVI or WAV)
-// The specified length MUST (in practice: SHOULD) match fileSize-8, but we don't bother checking this here.
-
-bool RIFF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef file,
- XMPFiles* parent )
-{
- IgnoreParam(format); IgnoreParam(parent);
- XMP_Assert ( (format == kXMP_AVIFile) || (format == kXMP_WAVFile) );
- LFA_Rewind( file );
-
- XMP_Uns8 chunkID[12];
- LFA_Read( file, chunkID, 12, true );
- if ( ! CheckBytes( &chunkID[0], "RIFF", 4 )) return false;
-
- if ( CheckBytes(&chunkID[8],"AVI ",4) && format == kXMP_AVIFile ) return true;
- if ( CheckBytes(&chunkID[8],"WAVE",4) && format == kXMP_WAVFile ) return true;
-
- return false;
-} // RIFF_CheckFormat
-
-// =================================================================================================
-// RIFF_MetaHandler::RIFF_MetaHandler
-// ================================
-
-RIFF_MetaHandler::RIFF_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kRIFF_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- this->oldFileSize = this->newFileSize = this->trailingGarbageSize = 0;
- this->level = 0;
- this->listInfoChunk = this->listTdatChunk = 0;
- this->dispChunk = this->bextChunk = this->cr8rChunk = this->prmlChunk = 0;
- this->xmpChunk = 0;
- this->lastChunk = 0;
- this->hasListInfoINAM = false;
-}
-
-// =================================================================================================
-// RIFF_MetaHandler::~RIFF_MetaHandler
-// =================================
-
-RIFF_MetaHandler::~RIFF_MetaHandler()
-{
- while ( ! this->riffChunks.empty() )
- {
- delete this->riffChunks.back();
- this->riffChunks.pop_back();
- }
-}
-
-// =================================================================================================
-// RIFF_MetaHandler::CacheFileData
-// ==============================
-
-void RIFF_MetaHandler::CacheFileData()
-{
- this->containsXMP = false; //assume for now
-
- LFA_FileRef file = this->parent->fileRef;
- this->oldFileSize = LFA_Measure( file );
- if ( (this->parent->format == kXMP_WAVFile) && (this->oldFileSize > 0xFFFFFFFF) )
- XMP_Throw ( "RIFF_MetaHandler::CacheFileData: WAV Files larger 4GB not supported", kXMPErr_Unimplemented );
-
- LFA_Rewind( file );
- this->level = 0;
-
- // parse top-level chunks (most likely just one, except large avi files)
- XMP_Int64 filePos = 0;
- while ( filePos < this->oldFileSize )
- {
-
- this->riffChunks.push_back( (RIFF::ContainerChunk*) RIFF::getChunk( NULL, this ) );
-
- // Tolerate limited forms of trailing garbage in a file. Some apps append private data.
-
- filePos = LFA_Tell( file );
- XMP_Int64 fileTail = this->oldFileSize - filePos;
-
- if ( fileTail != 0 ) {
-
- if ( fileTail < 12 ) {
-
- this->oldFileSize = filePos; // Pretend the file is smaller.
- this->trailingGarbageSize = fileTail;
-
- } else if ( this->parent->format == kXMP_WAVFile ) {
-
- if ( fileTail < 1024*1024 ) {
- this->oldFileSize = filePos; // Pretend the file is smaller.
- this->trailingGarbageSize = fileTail;
- } else {
- XMP_Throw ( "Excessive garbage at end of file", kXMPErr_BadFileFormat )
- }
-
- } else {
-
- XMP_Int32 chunkInfo [3];
- LFA_Read ( file, &chunkInfo, 12, kLFA_RequireAll );
- LFA_Seek ( file, -12, SEEK_CUR );
- if ( (GetUns32LE ( &chunkInfo[0] ) != RIFF::kChunk_RIFF) || (GetUns32LE ( &chunkInfo[2] ) != RIFF::kType_AVIX) ) {
- if ( fileTail < 1024*1024 ) {
- this->oldFileSize = filePos; // Pretend the file is smaller.
- this->trailingGarbageSize = fileTail;
- } else {
- XMP_Throw ( "Excessive garbage at end of file", kXMPErr_BadFileFormat )
- }
- }
-
- }
-
- }
-
- }
-
- // covered before => internal error if it occurs
- XMP_Validate( LFA_Tell( file ) == this->oldFileSize,
- "RIFF_MetaHandler::CacheFileData: unknown data at end of file",
- kXMPErr_InternalFailure );
-
-} // RIFF_MetaHandler::CacheFileData
-
-// =================================================================================================
-// RIFF_MetaHandler::ProcessXMP
-// ============================
-
-void RIFF_MetaHandler::ProcessXMP()
-{
- SXMPUtils::RemoveProperties ( &this->xmpObj, 0, 0, kXMPUtil_DoAllProperties );
- // process physical packet first
- if ( this->containsXMP ) this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- // then import native properties:
- RIFF::importProperties( this );
- this->processedXMP = true;
-}
-
-// =================================================================================================
-// RIFF_MetaHandler::UpdateFile
-// ===========================
-
-void RIFF_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- XMP_Validate( this->needsUpdate, "nothing to update", kXMPErr_InternalFailure );
-
- ////////////////////////////////////////////////////////////////////////////////////////
- //////////// PASS 1: basics, exports, packet reserialze
- LFA_FileRef file = this->parent->fileRef;
- RIFF::containerVect *rc = &this->riffChunks;
-
- //temptemp
- //printf( "BEFORE:\n%s\n", rc->at(0)->toString().c_str() );
-
- XMP_Enforce( rc->size() >= 1);
- RIFF::ContainerChunk* mainChunk = rc->at(0);
- this->lastChunk = rc->at( rc->size() - 1 ); // (may or may not coincide with mainChunk: )
- XMP_Enforce( mainChunk != NULL );
-
- RIFF::relocateWronglyPlacedXMPChunk( this );
- // [2435625] lifted disablement for AVI
- RIFF::exportAndRemoveProperties( this );
-
- // always rewrite both LISTs (implicit size changes, e.g. through 0-term corrections may
- // have very well led to size changes...)
- // set XMP packet info, re-serialize
- this->packetInfo.charForm = stdCharForm;
- this->packetInfo.writeable = true;
- this->packetInfo.offset = kXMPFiles_UnknownOffset;
- this->packetInfo.length = kXMPFiles_UnknownLength;
-
- // re-serialization ( needed because of above exportAndRemoveProperties() )
- try {
- if ( this->xmpChunk == 0 ) // new chunk? pad with 2K
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_NoOptions , 2048 );
- else // otherwise try to match former size
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_ExactPacketLength , (XMP_Uns32) this->xmpChunk->oldSize-8 );
- } catch ( ... ) { // if that fails, be happy with whatever.
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_NoOptions );
- }
-
- if ( (this->xmpPacket.size() & 1) == 1 ) this->xmpPacket += ' '; // Force the XMP to have an even size.
-
- // if missing, add xmp packet at end:
- if( this->xmpChunk == 0 )
- this->xmpChunk = new RIFF::XMPChunk( this->lastChunk );
- // * parenting happens within this call.
- // * size computation will happen in XMPChunk::changesAndSize()
- // * actual data will be set in XMPChunk::write()
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // PASS 2: compute sizes, optimize container structure (no writing yet)
- {
- this->newFileSize = 0;
-
- // note: going through forward (not vice versa) is an important condition,
- // so that parking LIST:Tdat,Cr8r, PrmL to last chunk is doable
- // when encountered en route
- for ( XMP_Uns32 chunkNo = 0; chunkNo < rc->size(); chunkNo++ )
- {
- RIFF::Chunk* cur = rc->at(chunkNo);
- cur->changesAndSize( this );
- this->newFileSize += cur->newSize;
- if ( this->newFileSize % 2 == 1 ) this->newFileSize++; // pad byte
- }
- this->newFileSize += this->trailingGarbageSize;
- } // PASS2
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // PASS 2a: verify no chunk violates 2GB boundaries
- switch( this->parent->format )
- {
- // NB: <4GB for ALL chunks asserted before in ContainerChunk::changesAndSize()
-
- case kXMP_AVIFile:
- // ensure no chunk (single or multi, no matter) crosses 2 GB ...
- for ( XMP_Int32 chunkNo = 0; chunkNo < (XMP_Int32)rc->size(); chunkNo++ )
- {
- if ( rc->at(chunkNo)->oldSize <= 0x80000000LL ) // ... if <2GB before
- XMP_Validate( rc->at(chunkNo)->newSize <= 0x80000000LL,
- "Chunk grew beyond 2 GB", kXMPErr_Unimplemented );
- }
-
- // compatibility: if single-chunk AND below <1GB, ensure <1GB
- if ( ( rc->size() > 1 ) && ( rc->at(0)->oldSize < 0x40000000 ) )
- {
- XMP_Validate( rc->at(0)->newSize < 0x40000000LL, "compatibility: mainChunk must remain < 1GB" , kXMPErr_Unimplemented );
- }
-
- // [2473381] compatibility: if single-chunk AND >2GB,<4GB, ensure <4GB
- if ( ( rc->size() > 1 ) &&
- ( rc->at(0)->oldSize > 0x80000000LL ) && // 2GB
- ( rc->at(0)->oldSize < 0x100000000LL ) ) // 4GB
- {
- XMP_Validate( rc->at(0)->newSize < 0x100000000LL, "compatibility: mainChunk must remain < 4GB" , kXMPErr_Unimplemented );
- }
-
- break;
-
- case kXMP_WAVFile:
- XMP_Validate( 1 == rc->size(), "WAV must be single-chunk", kXMPErr_InternalFailure );
- XMP_Validate( rc->at(0)->newSize <= 0xFFFFFFFFLL, "WAV above 4 GB not supported", kXMPErr_Unimplemented );
- break;
-
- default:
- XMP_Throw( "unknown format", kXMPErr_InternalFailure );
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // PASS 3: write avix chunk(s) if applicable (shrinks or stays)
- // and main chunk. -- operation order depends on mainHasShrunk.
- {
- // if needed, extend file beforehand
- if ( this->newFileSize > this->oldFileSize ) LFA_Extend( file, newFileSize );
-
- RIFF::Chunk* mainChunk = rc->at(0);
-
- XMP_Int64 mainGrowth = mainChunk->newSize - mainChunk->oldSize;
- XMP_Enforce( mainGrowth >= 0 ); // main always stays or grows
-
- //temptemp
- //printf( "AFTER:\n%s\n", rc->at(0)->toString().c_str() );
-
- if ( rc->size() > 1 ) // [2457482]
- XMP_Validate( mainGrowth == 0, "mainChunk must not grow, if multiple RIFF chunks", kXMPErr_InternalFailure );
-
- // back to front:
-
- XMP_Int64 avixStart = newFileSize; // count from the back
-
- if ( this->trailingGarbageSize != 0 ) {
- XMP_Int64 goodDataEnd = this->newFileSize - this->trailingGarbageSize;
- LFA_Move ( file, this->oldFileSize, file, goodDataEnd, this->trailingGarbageSize );
- avixStart = goodDataEnd;
- }
-
- for ( XMP_Int32 chunkNo = ((XMP_Int32)rc->size()) -1; chunkNo >= 0; chunkNo-- )
- {
- RIFF::Chunk* cur = rc->at(chunkNo);
-
- avixStart -= cur->newSize;
- if ( avixStart % 2 == 1 ) // rewind one more
- avixStart -= 1;
-
- LFA_Seek( file, avixStart , SEEK_SET );
-
- if ( cur->hasChange ) // need explicit write-out ?
- cur->write( this, file, chunkNo == 0 );
- else // or will a simple move do?
- {
- XMP_Enforce( cur->oldSize == cur->newSize );
- if ( cur->oldPos != avixStart ) // important optimization: only move if there's a need to
- LFA_Move( file, cur->oldPos, file, avixStart, cur->newSize );
- }
- }
-
- // if needed, shrink file afterwards
- if ( this->newFileSize < this->oldFileSize ) LFA_Truncate( file, this->newFileSize );
- } // PASS 3
-
- this->needsUpdate = false; //do last for safety
-} // RIFF_MetaHandler::UpdateFile
-
-// =================================================================================================
-// RIFF_MetaHandler::WriteFile
-// ==========================
-
-void RIFF_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
- const std::string & sourcePath )
-{
- IgnoreParam(sourceRef); IgnoreParam(sourcePath);
- XMP_Throw ( "RIFF_MetaHandler::WriteFile: Not supported (must go through UpdateFile", kXMPErr_Unavailable );
-}
-
diff --git a/source/XMPFiles/FileHandlers/RIFF_Handler.hpp b/source/XMPFiles/FileHandlers/RIFF_Handler.hpp
deleted file mode 100644
index 093fd63..0000000
--- a/source/XMPFiles/FileHandlers/RIFF_Handler.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-#ifndef __RIFF_Handler_hpp__
-#define __RIFF_Handler_hpp__ 1
-
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "RIFF_Support.hpp"
-
-// =================================================================================================
-/// \file RIFF_Handler.hpp
-/// \brief File format handler for RIFF (AVI, WAV).
-// =================================================================================================
-
-extern XMPFileHandler * RIFF_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool RIFF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kRIFF_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_CanReconcile
- );
-
-class RIFF_MetaHandler : public XMPFileHandler
-{
-public:
- RIFF_MetaHandler ( XMPFiles* parent );
- ~RIFF_MetaHandler();
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- ////////////////////////////////////////////////////////////////////////////////////
- // instance vars
- // most often just one RIFF:* (except for AVI,[AVIX] >1 GB)
- std::vector<RIFF::ContainerChunk*> riffChunks;
- XMP_Int64 oldFileSize, newFileSize, trailingGarbageSize;
-
- // state variables, needed during parsing
- XMP_Uns8 level;
-
- RIFF::ContainerChunk *listInfoChunk, *listTdatChunk;
- RIFF::ValueChunk* dispChunk;
- RIFF::ValueChunk* bextChunk;
- RIFF::ValueChunk* cr8rChunk;
- RIFF::ValueChunk* prmlChunk;
- RIFF::XMPChunk* xmpChunk;
- RIFF::ContainerChunk* lastChunk;
- bool hasListInfoINAM; // needs to be known for the special 3-way merge around dc:title
-
-}; // RIFF_MetaHandler
-
-// =================================================================================================
-
-#endif /* __RIFF_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/SWF_Handler.cpp b/source/XMPFiles/FileHandlers/SWF_Handler.cpp
deleted file mode 100644
index 9ae2b25..0000000
--- a/source/XMPFiles/FileHandlers/SWF_Handler.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "SWF_Handler.hpp"
-
-#include "SWF_Support.hpp"
-
-
-using namespace std;
-
-// =================================================================================================
-/// \file SWF_Handler.hpp
-/// \brief File format handler for SWF.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// SWF_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * SWF_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new SWF_MetaHandler ( parent );
-
-} // SWF_MetaHandlerCTor
-
-// =================================================================================================
-// SWF_CheckFormat
-// ===============
-
-bool SWF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_SWFFile );
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, SWF_SIGNATURE_LEN ) ) return false;
-
- if ( !(CheckBytes ( ioBuf.ptr, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ||
- CheckBytes(ioBuf.ptr, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN)) )
- return false;
-
- return true;
-
-} // SWF_CheckFormat
-
-// =================================================================================================
-// SWF_MetaHandler::SWF_MetaHandler
-// ==================================
-
-SWF_MetaHandler::SWF_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kSWF_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-}
-
-// =================================================================================================
-// SWF_MetaHandler::~SWF_MetaHandler
-// ===================================
-
-SWF_MetaHandler::~SWF_MetaHandler()
-{
-}
-
-// =================================================================================================
-// SWF_MetaHandler::CacheFileData
-// ===============================
-
-void SWF_MetaHandler::CacheFileData()
-{
-
- this->containsXMP = false;
-
- LFA_FileRef fileRef ( this->parent->fileRef );
- if ( fileRef == 0) return;
-
- SWF_Support::FileInfo fileInfo(fileRef, this->parent->filePath);
- IO::InputStream * is = NULL;
- if(fileInfo.IsCompressed())
- {
- XMP_Uns32 fileSize = fileInfo.GetSize();
- is = new IO::ZIP::DeflateInputStream(fileRef, fileSize);
-
- IO::ZIP::DeflateInputStream * in = dynamic_cast<IO::ZIP::DeflateInputStream*>(is);
- in->Skip(SWF_COMPRESSION_BEGIN, IO::ZIP::DEFLATE_NO);
- }
- else
- {
- is = new IO::FileInputStream(fileRef);
- is->Skip(SWF_COMPRESSION_BEGIN);
- }
-
- SWF_Support::TagState tagState;
- //important flag to stop iteration over all tags when xmp flag within FileAttributeTag isn't set
- tagState.cachingFile = true;
-
- long numTags = SWF_Support::OpenSWF ( is, tagState );
-
- is->Close();
- delete is;
-
- if ( numTags == 0 ) return;
-
- if (tagState.hasXMP && tagState.xmpLen != 0)
- {
- this->xmpPacket.assign(tagState.xmpPacket);
- this->containsXMP = true;
- }
- else
- {
- // no XMP
- }
-
-
-} // SWF_MetaHandler::CacheFileData
-
-// =================================================================================================
-// SWF_MetaHandler::ProcessXMP
-// ============================
-//
-// Process the raw XMP and legacy metadata that was previously cached.
-
-void SWF_MetaHandler::ProcessXMP()
-{
-
- this->processedXMP = true; // Make sure we only come through here once.
-
- // Process the XMP packet.
-
- if ( ! this->xmpPacket.empty() ) {
-
- XMP_Assert ( this->containsXMP );
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
-
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
-
- this->containsXMP = true;
-
- }
-
-} // SWF_MetaHandler::ProcessXMP
-
-
-// =================================================================================================
-// XMPFileHandler::GetSerializeOptions
-// ===================================
-//
-// Override default implementation to ensure omitting xmp wrapper
-//
-XMP_OptionBits SWF_MetaHandler::GetSerializeOptions()
-{
- return (kXMP_OmitPacketWrapper | kXMP_OmitAllFormatting | kXMP_OmitXMPMetaElement);
-} // XMPFileHandler::GetSerializeOptions
-
-
-// =================================================================================================
-// SWF_MetaHandler::UpdateFile
-// ============================
-
-void SWF_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- bool updated = false;
-
- if ( ! this->needsUpdate ) return;
- if ( doSafeUpdate ) XMP_Throw ( "SWF_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
-
- LFA_FileRef sourceRef = this->parent->fileRef;
- std::string sourcePath = this->parent->filePath;
-
- SWF_Support::FileInfo fileInfo(sourceRef, sourcePath);
-
- if(fileInfo.IsCompressed())
- sourceRef = fileInfo.Decompress();
-
- IO::InputStream * is = new IO::FileInputStream(sourceRef);
- //processing SWF starts after byte SWF_COMPRESSION_BEGIN - currently 8 bytes
- is->Skip(SWF_COMPRESSION_BEGIN);
-
- SWF_Support::TagState tagState;
-
- long numTags = SWF_Support::OpenSWF ( is, tagState );
-
- //clean objects
- is->Close();
- delete is;
-
- bool foundTag = false;
- SWF_Support::TailBufferDef tailBuffer;
-
-
- //find end position to measure tail buffer
- tailBuffer.tailEndPosition = LFA_Seek(sourceRef, 0, SEEK_END);
-
- SWF_Support::TagIterator curPos = tagState.tags.begin();
- SWF_Support::TagIterator endPos = tagState.tags.end();
-
- for( ;(curPos != endPos) && ! foundTag; ++curPos)
- {
- SWF_Support::TagData tag = *curPos;
-
- //write XMP Tag at the beginning of the file
- if(! tagState.hasXMP && ! tagState.hasFileAttrTag)
- {
- tailBuffer.tailStartPosition = tag.pos;
- tailBuffer.writePosition = tag.pos;
- foundTag = true;
- }
- //update existing XMP Tag
- if(tagState.hasXMP && (tagState.xmpTag.pos == tag.pos))
- {
- ++curPos;
- SWF_Support::TagData nextTag = *curPos;
- tailBuffer.tailStartPosition = nextTag.pos;
- tailBuffer.writePosition = tagState.xmpTag.pos;
- foundTag = true;
- }
- //write XMP Tag after FileAttribute Tag
- else if(! tagState.hasXMP && (tag.id == SWF_TAG_ID_FILEATTRIBUTES))
- {
- ++curPos;
- SWF_Support::TagData nextTag = *curPos;
- tailBuffer.tailStartPosition = nextTag.pos;
- tailBuffer.writePosition = nextTag.pos;
- foundTag = true;
- }
- }
-
- //cache tail of file
- XMP_Assert(tailBuffer.tailEndPosition > tailBuffer.tailStartPosition);
- XMP_Uns32 tailSize = tailBuffer.GetTailSize();
- XMP_Uns8 * buffer = new XMP_Uns8[tailSize];
- SWF_Support::ReadBuffer(sourceRef, tailBuffer.tailStartPosition, tailSize, buffer);
-
- //write new XMP packet
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
-
- LFA_Seek(sourceRef, tailBuffer.writePosition, SEEK_SET);
- SWF_Support::WriteXMPTag(sourceRef, packetLen, packetStr);
-
- // truncate to minimal size
- LFA_Truncate(sourceRef, LFA_Tell(sourceRef));
-
- //move tail of the file
- LFA_Write(sourceRef, buffer, tailSize);
-
- //cleaning buffer
- delete [] buffer;
-
- //update FileAttribute Tag if exists
- if(tagState.hasFileAttrTag)
- SWF_Support::UpdateFileAttrTag(sourceRef, tagState.fileAttrTag, tagState);
-
-
- //update File Size
- SWF_Support::UpdateHeader(sourceRef);
-
- //compress file after writing XMP
- if(fileInfo.IsCompressed())
- {
- fileInfo.Compress(sourceRef, this->parent->fileRef);
- fileInfo.Clean();
- }
-
-
- if ( ! updated )return; // If there's an error writing the chunk, bail.
-
- this->needsUpdate = false;
-
-} // SWF_MetaHandler::UpdateFile
-
-// =================================================================================================
-// SWF_MetaHandler::WriteFile
-// ===========================
-
-void SWF_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- LFA_FileRef destRef = this->parent->fileRef;
-
- SWF_Support::TagState tagState;
-
- LFA_FileRef origRef(destRef);
- std::string updatePath;
-
-
- SWF_Support::FileInfo fileInfo(sourceRef, sourcePath);
-
- if(fileInfo.IsCompressed())
- {
- sourceRef = fileInfo.Decompress();
- CreateTempFile ( sourcePath, &updatePath, kCopyMacRsrc );
- destRef = LFA_Open ( updatePath.c_str(), 'w' );
- }
-
- IO::InputStream * is = NULL;
-
- is = new IO::FileInputStream(sourceRef);
- is->Skip(SWF_COMPRESSION_BEGIN);
-
- long numTags = SWF_Support::OpenSWF( is, tagState );
-
- is->Close();
- delete is;
-
- if ( numTags == 0 ) return;
-
- LFA_Truncate(destRef, 0);
- SWF_Support::CopyHeader(sourceRef, destRef, tagState);
-
- SWF_Support::TagIterator curPos = tagState.tags.begin();
- SWF_Support::TagIterator endPos = tagState.tags.end();
-
- XMP_StringPtr packetStr = xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)xmpPacket.size();
-
- bool copying = true;
- bool isXMPTagWritten = false;
-
- for (; (curPos != endPos); ++curPos)
- {
- SWF_Support::TagData tag = *curPos;
-
- // write XMP tag right after FileAttribute Tag if no XMP tag exists
- if (! tagState.hasXMP && (tag.id == SWF_TAG_ID_FILEATTRIBUTES))
- SWF_Support::WriteXMPTag(destRef, packetLen, packetStr );
-
- //no FileAttribute Tag and no XMP tag write XMP Tag at the beginning of the file
- if(!tagState.hasXMP && !tagState.hasFileAttrTag && ! isXMPTagWritten)
- {
- isXMPTagWritten = true;
- SWF_Support::WriteXMPTag(destRef, packetLen, packetStr );
- }
-
- // write XMP tag where old XMP exists
- if(tagState.hasXMP && (tag.pos == tagState.xmpTag.pos))
- {
- copying = false;
- SWF_Support::WriteXMPTag(destRef, packetLen, packetStr );
- }
-
- // copy any other chunk
- if(copying)
- SWF_Support::CopyTag(sourceRef, destRef, tag);
-
- copying = true;
- }
-
- // update FileAttribute Tag in new file
- if(tagState.hasFileAttrTag)
- SWF_Support::UpdateFileAttrTag(destRef, tagState.fileAttrTag, tagState);
-
-
- // update file header by measuring new file size
- SWF_Support::UpdateHeader(origRef);
-
- //compress re-written file
- if(fileInfo.IsCompressed())
- {
- fileInfo.Compress(destRef, origRef);
- fileInfo.Clean();
- LFA_Close(destRef);
- LFA_Delete(updatePath.c_str());
- }
-
-
-
-
-} // SWF_MetaHandler::WriteFile
-
diff --git a/source/XMPFiles/FileHandlers/SWF_Handler.hpp b/source/XMPFiles/FileHandlers/SWF_Handler.hpp
deleted file mode 100644
index 91ad760..0000000
--- a/source/XMPFiles/FileHandlers/SWF_Handler.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __SWF_Handler_hpp__
-#define __SWF_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-//#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-//#include "SWF_Support.hpp"
-
-// =================================================================================================
-/// \file SWF_Handler.hpp
-/// \brief File format handler for SWF.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler* SWF_MetaHandlerCTor ( XMPFiles* parent );
-
-extern bool SWF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kSWF_HandlerFlags = ( kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket );
-
-class SWF_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string& sourcePath );
-
- SWF_MetaHandler ( XMPFiles* parent );
- virtual ~SWF_MetaHandler();
-
-}; // SWF_MetaHandler
-
-// =================================================================================================
-
-#endif /* __SWF_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Scanner_Handler.cpp b/source/XMPFiles/FileHandlers/Scanner_Handler.cpp
deleted file mode 100644
index 1af7326..0000000
--- a/source/XMPFiles/FileHandlers/Scanner_Handler.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 <vector>
-
-#include "XMPScanner.hpp"
-
-#include "Scanner_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file Scanner_Handler.cpp
-/// \brief File format handler for packet scanning.
-///
-/// This header ...
-///
-// =================================================================================================
-
-struct CandidateInfo {
- XMP_PacketInfo packetInfo;
- std::string xmpPacket;
- SXMPMeta * xmpObj;
-};
-
-// =================================================================================================
-// Scanner_MetaHandlerCTor
-// =======================
-
-XMPFileHandler * Scanner_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new Scanner_MetaHandler ( parent );
-
-} // Scanner_MetaHandlerCTor
-
-// =================================================================================================
-// Scanner_MetaHandler::Scanner_MetaHandler
-// ========================================
-
-Scanner_MetaHandler::Scanner_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kScanner_HandlerFlags;
-
-} // Scanner_MetaHandler::Scanner_MetaHandler
-
-// =================================================================================================
-// Scanner_MetaHandler::~Scanner_MetaHandler
-// =========================================
-
-Scanner_MetaHandler::~Scanner_MetaHandler()
-{
- // ! Inherit the base cleanup.
-
-} // Scanner_MetaHandler::~Scanner_MetaHandler
-
-// =================================================================================================
-// PickMainPacket
-// ==============
-//
-// Pick the main packet from the vector of candidates. The rules:
-// 1. Use the manifest find containment. Prune contained packets.
-// 2. Use the metadata date to pick the most recent.
-// 3. if lenient, pick the last writeable packet, or the last if all are read only.
-
-static int
-PickMainPacket ( std::vector<CandidateInfo>& candidates, bool beLenient )
-{
- int pkt; // ! Must be signed.
- int main = -1; // Assume the worst.
- XMP_OptionBits options;
-
- int metaCount = (int)candidates.size();
- if ( metaCount == 0 ) return -1;
- if ( metaCount == 1 ) return 0;
-
- // ---------------------------------------------------------------------------------------------
- // 1. Look at each packet to see if it has a manifest. If it does, prune all of the others that
- // this one says it contains. Hopefully we'll end up with just one packet. Note that we have to
- // mark all the children first, then prune. Pruning on the fly means that we won't do a proper
- // tree discovery if we prune a parent before a child. This would happen if we happened to visit
- // a grandparent first.
-
- int child;
-
- std::vector<bool> pruned ( metaCount, false );
-
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
-
- // First see if this candidate has a manifest.
-
- try {
- std::string voidValue;
- bool found = candidates[pkt].xmpObj->GetProperty ( kXMP_NS_XMP_MM, "Manifest", &voidValue, &options );
- if ( (! found) || (! XMP_PropIsArray ( options )) ) continue; // No manifest, or not an array.
- } catch ( ... ) {
- continue; // No manifest.
- };
-
- // Mark all other candidates that are referred to in this manifest.
-
- for ( child = 0; child < (int)candidates.size(); ++child ) {
- if ( pruned[child] || (child == pkt) ) continue; // Skip already pruned ones and self.
- }
-
- }
-
- // Go ahead and actually remove the marked packets.
-
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
- if ( pruned[pkt] ) {
- delete candidates[pkt].xmpObj;
- candidates[pkt].xmpObj = 0;
- metaCount -= 1;
- }
- }
-
- // We're done if the containment pruning left us with 0 or 1 candidate.
-
- if ( metaCount == 0 ) {
- XMP_Throw ( "GetMainPacket/PickMainPacket: Recursive containment", kXMPErr_BadXMP );
- } else if ( metaCount == 1 ) {
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
- if ( candidates[pkt].xmpObj != 0 ) {
- main = pkt;
- break;
- }
- }
- }
-
- if ( main != -1 ) return main; // We found the main.
-
- // -------------------------------------------------------------------------------------------
- // 2. Pick the packet with the most recent metadata date. If we are being lenient then missing
- // dates are older than any real date, and equal dates pick the last packet. If we are being
- // strict then any missing or equal dates mean we can't pick.
-
- XMP_DateTime latestTime, currTime;
-
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
-
- if ( candidates[pkt].xmpObj == 0 ) continue; // This was pruned in the manifest stage.
-
- bool haveDate = candidates[pkt].xmpObj->GetProperty_Date ( kXMP_NS_XMP, "MetadataDate", &currTime, &options );
-
- if ( ! haveDate ) {
-
- if ( ! beLenient ) return -1;
- if ( main == -1 ) {
- main = pkt;
- memset ( &latestTime, 0, sizeof(latestTime) );
- }
-
- } else if ( main == -1 ) {
-
- main = pkt;
- latestTime = currTime;
-
- } else {
-
- int timeOp = SXMPUtils::CompareDateTime ( currTime, latestTime );
-
- if ( timeOp > 0 ) {
- main = pkt;
- latestTime = currTime;
- } else if ( timeOp == 0 ) {
- if ( ! beLenient ) return -1;
- main = pkt;
- latestTime = currTime;
- }
-
- }
-
- }
-
- if ( main != -1 ) return main; // We found the main.
-
- // --------------------------------------------------------------------------------------------
- // 3. If we're being lenient, pick the last writeable packet, or the last if all are read only.
-
- if ( beLenient ) {
-
- for ( pkt = (int)candidates.size()-1; pkt >= 0; --pkt ) {
- if ( candidates[pkt].xmpObj == 0 ) continue; // This was pruned in the manifest stage.
- if ( candidates[pkt].packetInfo.writeable ) {
- main = pkt;
- break;
- }
- }
-
- if ( main == -1 ) {
- for ( pkt = (int)candidates.size()-1; pkt >= 0; --pkt ) {
- if ( candidates[pkt].xmpObj != 0 ) {
- main = pkt;
- break;
- }
- }
- }
-
- }
-
- return main;
-
-} // PickMainPacket
-
-// =================================================================================================
-// Scanner_MetaHandler::CacheFileData
-// ==================================
-
-void Scanner_MetaHandler::CacheFileData()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
- bool beLenient = XMP_OptionIsClear ( this->parent->openFlags, kXMPFiles_OpenStrictly );
-
- int pkt;
- XMP_Int64 bufPos;
- size_t bufLen;
- SXMPMeta * newMeta;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- std::vector<CandidateInfo> candidates; // ! These have SXMPMeta* fields, don't leak on exceptions.
-
- this->containsXMP = false;
-
- try {
-
- // ------------------------------------------------------
- // Scan the entire file to find all of the valid packets.
-
- XMP_Int64 fileLen = LFA_Measure ( fileRef );
- XMPScanner scanner ( fileLen );
-
- enum { kBufferSize = 64*1024 };
- XMP_Uns8 buffer [kBufferSize];
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
-
- for ( bufPos = 0; bufPos < fileLen; bufPos += bufLen ) {
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
- }
- bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
- if ( bufLen == 0 ) XMP_Throw ( "Scanner_MetaHandler::LocateXMP: Read failure", kXMPErr_ExternalFailure );
- scanner.Scan ( buffer, bufPos, bufLen );
- }
-
- // --------------------------------------------------------------
- // Parse the valid packet snips, building a vector of candidates.
-
- long snipCount = scanner.GetSnipCount();
-
- XMPScanner::SnipInfoVector snips ( snipCount );
- scanner.Report ( snips );
-
- for ( pkt = 0; pkt < snipCount; ++pkt ) {
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
- }
-
- // Seek to the packet then try to parse it.
-
- if ( snips[pkt].fState != XMPScanner::eValidPacketSnip ) continue;
- LFA_Seek ( fileRef, snips[pkt].fOffset, SEEK_SET );
- newMeta = new SXMPMeta();
- std::string xmpPacket;
- xmpPacket.reserve ( (size_t)snips[pkt].fLength );
-
- try {
- for ( bufPos = 0; bufPos < snips[pkt].fLength; bufPos += bufLen ) {
- bufLen = kBufferSize;
- if ( (bufPos + bufLen) > (size_t)snips[pkt].fLength ) bufLen = size_t ( snips[pkt].fLength - bufPos );
- (void) LFA_Read ( fileRef, buffer, (XMP_Int32)bufLen, kLFA_RequireAll );
- xmpPacket.append ( (const char *)buffer, bufLen );
- newMeta->ParseFromBuffer ( (char *)buffer, (XMP_StringLen)bufLen, kXMP_ParseMoreBuffers );
- }
- newMeta->ParseFromBuffer ( 0, 0, kXMP_NoOptions );
- } catch ( ... ) {
- delete newMeta;
- if ( beLenient ) continue; // Skip if we're being lenient, else rethrow.
- throw;
- }
-
- // It parsed OK, add it to the array of candidates.
-
- candidates.push_back ( CandidateInfo() );
- CandidateInfo & newInfo = candidates.back();
- newInfo.xmpObj = newMeta;
- newInfo.xmpPacket.swap ( xmpPacket );
- newInfo.packetInfo.offset = snips[pkt].fOffset;
- newInfo.packetInfo.length = (XMP_Int32)snips[pkt].fLength;
- newInfo.packetInfo.charForm = snips[pkt].fCharForm;
- newInfo.packetInfo.writeable = (snips[pkt].fAccess == 'w');
-
- }
-
- // ----------------------------------------
- // Figure out which packet is the main one.
-
- int main = PickMainPacket ( candidates, beLenient );
-
- if ( main != -1 ) {
- this->packetInfo = candidates[main].packetInfo;
- this->xmpPacket.swap ( candidates[main].xmpPacket );
- this->xmpObj = *candidates[main].xmpObj;
- this->containsXMP = true;
- this->processedXMP = true;
- }
-
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
- if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
- }
-
- } catch ( ... ) {
-
- // Clean up the SXMPMeta* fields from the vector of candidates.
- for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
- if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
- }
- throw;
-
- }
-
-} // Scanner_MetaHandler::CacheFileData
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Scanner_Handler.hpp b/source/XMPFiles/FileHandlers/Scanner_Handler.hpp
deleted file mode 100644
index a6f23b5..0000000
--- a/source/XMPFiles/FileHandlers/Scanner_Handler.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __Scanner_Handler_hpp__
-#define __Scanner_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "Trivial_Handler.hpp"
-
-// =================================================================================================
-/// \file Scanner_Handler.hpp
-/// \brief File format handler for packet scanning.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * Scanner_MetaHandlerCTor ( XMPFiles * parent );
-
-static const XMP_OptionBits kScanner_HandlerFlags = kTrivial_HandlerFlags;
-
-class Scanner_MetaHandler : public Trivial_MetaHandler
-{
-public:
-
- Scanner_MetaHandler () {};
- Scanner_MetaHandler ( XMPFiles * parent );
-
- ~Scanner_MetaHandler();
-
- void CacheFileData();
-
-}; // Scanner_MetaHandler
-
-// =================================================================================================
-
-#endif /* __Scanner_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/SonyHDV_Handler.cpp b/source/XMPFiles/FileHandlers/SonyHDV_Handler.cpp
deleted file mode 100644
index d3758da..0000000
--- a/source/XMPFiles/FileHandlers/SonyHDV_Handler.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "SonyHDV_Handler.hpp"
-
-#include "MD5.h"
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-using namespace std;
-
-// =================================================================================================
-/// \file SonyHDV_Handler.cpp
-/// \brief Folder format handler for Sony HDV.
-///
-/// This handler is for the Sony HDV video format. This is a pseudo-package, visible files but with
-/// a very well-defined layout and naming rules.
-///
-/// A typical Sony HDV layout looks like:
-///
-/// .../MyMovie/
-/// VIDEO/
-/// HDV/
-/// 00_0001_2007-08-06_165555.IDX
-/// 00_0001_2007-08-06_165555.M2T
-/// 00_0001_2007-08-06_171740.M2T
-/// 00_0001_2007-08-06_171740.M2T.ese
-/// tracks.dat
-///
-/// The logical clip name can be "00_0001" or "00_0001_" plus anything. We'll find the .IDX file,
-/// which defines the existence of the clip. Full file names as input will pull out the camera/clip
-/// parts and match in the same way. The .XMP file will use the date/time suffix from the .IDX file.
-// =================================================================================================
-
-// =================================================================================================
-// SonyHDV_CheckFormat
-// ===================
-//
-// This version does fairly simple checks. The top level folder (.../MyMovie) must contain the
-// VIDEO/HVR subtree. The HVR folder must contain a .IDX file for the desired clip. The name checks
-// are case insensitive.
-//
-// The state of the string parameters depends on the form of the path passed by the client. If the
-// client passed a logical clip path, like ".../MyMovie/00_0001", the parameters are:
-// rootPath - ".../MyMovie"
-// gpName - empty
-// parentName - empty
-// leafName - "00_0001"
-//
-// If the client passed a full file path, like ".../MyMovie/VIDEO/HVR/00_0001_2007-08-06_165555.M2T",
-// they are:
-// rootPath - ".../MyMovie"
-// gpName - "VIDEO"
-// parentName - "HVR"
-// leafName - "00_0001_2007-08-06_165555.M2T"
-//
-// The logical clip name can be short like "00_0001", or long like "00_0001_2007-08-06_165555". We
-// only key off of the portion before a second underscore.
-
-// ! The common code has shifted the gpName, parentName, and leafName strings to upper case. It has
-// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
-// ! file exists for a full file path.
-
-bool SonyHDV_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent )
-{
- // Do some basic checks on the root path and component names.
-
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- std::string tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "VIDEO";
-
- if ( gpName.empty() ) {
- // This is the logical clip path case. Look for VIDEO/HVR subtree.
- if ( GetChildMode ( tempPath, "HVR" ) != kFMode_IsFolder ) return false;
- } else {
- // This is the existing file case. Check the parent and grandparent names.
- if ( (gpName != "VIDEO") || (parentName != "HVR") ) return false;
- }
-
- // Look for the clip's .IDX file. If found use that as the full clip name.
-
- tempPath += kDirChar;
- tempPath += "HVR";
-
- std::string clipName = leafName;
- int usCount = 0;
- size_t i, limit = leafName.size();
- for ( i = 0; i < limit; ++i ) {
- if ( clipName[i] == '_' ) {
- ++usCount;
- if ( usCount == 2 ) break;
- }
- }
- if ( i < limit ) clipName.erase ( i );
- clipName += '_'; // Make sure a final '_' is there for the search comparisons.
-
- XMP_FolderInfo folderInfo;
- std::string childName;
- bool found = false;
-
- folderInfo.Open ( tempPath.c_str() );
- while ( (! found) && folderInfo.GetNextChild ( &childName ) ) {
- size_t childLen = childName.size();
- if ( childLen < 4 ) continue;
- MakeUpperCase ( &childName );
- if ( childName.compare ( childLen-4, 4, ".IDX" ) != 0 ) continue;
- if ( childName.compare ( 0, clipName.size(), clipName ) == 0 ) {
- found = true;
- clipName = childName;
- clipName.erase ( childLen-4 );
- }
- }
- if ( ! found ) return false;
-
-
- // Disabled until Sony HDV clip spanning is supported.
- // Since segments of spanned clips are currently considered separate entities,
- // information such as frame count needs to be considered on a per segment basis. JPM
- clipName = leafName;
-
- // Set tempPath to <root>/<clip-name>, e.g. ".../MyMovie/00_0001_2007-08-06_165555". This is
- // passed to the handler via the tempPtr hackery.
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += clipName;
-
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for SonyHDV clip info", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen ); // AUDIT: Safe, allocated above.
-
- return true;
-
-} // SonyHDV_CheckFormat
-
-// =================================================================================================
-// ReadIDXFile
-// ===========
-
-#define ExtractTimeCodeByte(ch,mask) ( (((ch & mask) >> 4) * 10) + (ch & 0xF) )
-
-static bool ReadIDXFile ( const std::string& idxPath,
- const std::string& clipName,
- SXMPMeta* xmpObj,
- bool& containsXMP,
- MD5_CTX* md5Context,
- bool digestFound )
-{
- bool result = true;
- containsXMP = false;
-
- if ( clipName.size() != 25 ) return false;
-
- try {
-
-
- AutoFile idxFile;
- idxFile.fileRef = LFA_Open ( idxPath.c_str(), 'r' );
- if ( idxFile.fileRef == 0 ) return false; // The open failed.
-
- struct SHDV_HeaderBlock
- {
- char mHeader[8];
- unsigned char mValidFlag;
- unsigned char mReserved;
- unsigned char mECCTB;
- unsigned char mSignalMode;
- unsigned char mFileThousands;
- unsigned char mFileHundreds;
- unsigned char mFileTens;
- unsigned char mFileUnits;
- };
-
- SHDV_HeaderBlock hdvHeaderBlock;
- memset ( &hdvHeaderBlock, 0, sizeof(SHDV_HeaderBlock) );
-
- LFA_Read ( idxFile.fileRef, hdvHeaderBlock.mHeader, 8 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mValidFlag, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mReserved, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mECCTB, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mSignalMode, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mFileThousands, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mFileHundreds, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mFileTens, 1 );
- LFA_Read ( idxFile.fileRef, &hdvHeaderBlock.mFileUnits, 1 );
-
- const int fileCount = (hdvHeaderBlock.mFileThousands - '0') * 1000 +
- (hdvHeaderBlock.mFileHundreds - '0') * 100 +
- (hdvHeaderBlock.mFileTens - '0') * 10 +
- (hdvHeaderBlock.mFileUnits - '0');
-
- // Read file info block.
- struct SHDV_FileBlock
- {
- char mDT[2];
- unsigned char mFileNameYear;
- unsigned char mFileNameMonth;
- unsigned char mFileNameDay;
- unsigned char mFileNameHour;
- unsigned char mFileNameMinute;
- unsigned char mFileNameSecond;
- unsigned char mStartTimeCode[4];
- unsigned char mTotalFrame[4];
- };
-
- SHDV_FileBlock hdvFileBlock;
- memset ( &hdvFileBlock, 0, sizeof(SHDV_FileBlock) );
-
- char filenameBuffer[256];
- std::string fileDateAndTime = clipName.substr(8);
-
- bool foundFileBlock = false;
-
- for ( int i=0; ((i < fileCount) && (! foundFileBlock)); ++i ) {
-
- LFA_Read ( idxFile.fileRef, hdvFileBlock.mDT, 2 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameYear, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameMonth, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameDay, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameHour, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameMinute, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mFileNameSecond, 1 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mStartTimeCode, 4 );
- LFA_Read ( idxFile.fileRef, &hdvFileBlock.mTotalFrame, 4 );
-
- // Compose file name we expect from file contents and break out on match.
- sprintf ( filenameBuffer, "%02d-%02d-%02d_%02d%02d%02d",
- hdvFileBlock.mFileNameYear + 2000,
- hdvFileBlock.mFileNameMonth,
- hdvFileBlock.mFileNameDay,
- hdvFileBlock.mFileNameHour,
- hdvFileBlock.mFileNameMinute,
- hdvFileBlock.mFileNameSecond );
-
- foundFileBlock = (fileDateAndTime==filenameBuffer);
-
- }
-
- LFA_Close ( idxFile.fileRef );
- idxFile.fileRef = 0;
-
- if ( ! foundFileBlock ) return false;
-
- // If digest calculation requested, calculate it and return.
- if ( md5Context != 0 ) {
- MD5Update ( md5Context, (XMP_Uns8*)(&hdvHeaderBlock), sizeof(SHDV_HeaderBlock) );
- MD5Update ( md5Context, (XMP_Uns8*)(&hdvFileBlock), sizeof(SHDV_FileBlock) );
- }
-
- // The xmpObj parameter must be provided in order to extract XMP
- if ( xmpObj == 0 ) return (md5Context != 0);
-
- // Standard def?
- const bool isSD = ((hdvHeaderBlock.mSignalMode == 0x80) || (hdvHeaderBlock.mSignalMode == 0));
-
- // Progressive vs interlaced extracted from high bit of ECCTB byte
- const bool clipIsProgressive = ((hdvHeaderBlock.mECCTB & 0x80) != 0);
-
- // Lowest three bits contain frame rate information
- const int sfr = (hdvHeaderBlock.mECCTB & 7) + (clipIsProgressive ? 0 : 8);
-
- // Sample scale and sample size.
- int clipSampleScale = 0;
- int clipSampleSize = 0;
- std::string frameRate;
-
- // Frame rate
- switch ( sfr ) {
- case 0 : break; // Not valid in spec, but it's happening in test files.
- case 1 : clipSampleScale = 24000; clipSampleSize = 1001; frameRate = "23.98p"; break;
- case 3 : clipSampleScale = 25; clipSampleSize = 1; frameRate = "25p"; break;
- case 4 : clipSampleScale = 30000; clipSampleSize = 1001; frameRate = "29.97p"; break;
- case 11 : clipSampleScale = 25; clipSampleSize = 1; frameRate = "50i"; break;
- case 12 : clipSampleScale = 30000; clipSampleSize = 1001; frameRate = "59.94i"; break;
- }
-
- containsXMP = true;
-
- // Frame size and PAR for HD (not clear on SD yet).
- std::string xmpString;
- XMP_StringPtr xmpValue = 0;
-
- if ( ! isSD ) {
-
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoFrameSize" )) ) {
-
- xmpValue = "1440";
- xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "w", &xmpString, 0 );
- if ( xmpString != xmpValue ) {
- xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "w", xmpValue, 0 );
- }
-
- xmpValue = "1080";
- xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "h", &xmpString, 0 );
- if ( xmpString != xmpValue ) {
- xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "h", xmpValue, 0 );
- }
-
- xmpValue = "pixels";
- xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "unit", &xmpString, 0 );
- if ( xmpString != xmpValue ) {
- xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "unit", xmpValue, 0 );
- }
- }
-
- xmpValue = "4/3";
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoPixelAspectRatio" )) ) {
- xmpObj->SetProperty ( kXMP_NS_DM, "videoPixelAspectRatio", xmpValue, kXMP_DeleteExisting );
- }
-
- }
-
- // Sample size and scale.
- if ( clipSampleScale != 0 ) {
-
- char buffer[255];
-
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimeScale" )) ) {
- sprintf(buffer, "%d", clipSampleScale);
- xmpValue = buffer;
- xmpObj->SetProperty ( kXMP_NS_DM, "startTimeScale", xmpValue, kXMP_DeleteExisting );
- }
-
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimeSampleSize" )) ) {
- sprintf(buffer, "%d", clipSampleSize);
- xmpValue = buffer;
- xmpObj->SetProperty ( kXMP_NS_DM, "startTimeSampleSize", xmpValue, kXMP_DeleteExisting );
- }
-
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "duration" )) ) {
-
- const int frameCount = (hdvFileBlock.mTotalFrame[0] << 24) + (hdvFileBlock.mTotalFrame[1] << 16) +
- (hdvFileBlock.mTotalFrame[2] << 8) + hdvFileBlock.mTotalFrame[3];
-
- sprintf ( buffer, "%d", frameCount );
- xmpValue = buffer;
- xmpObj->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "value", xmpValue, 0 );
-
- sprintf ( buffer, "%d/%d", clipSampleSize, clipSampleScale );
- xmpValue = buffer;
- xmpObj->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "scale", xmpValue, 0 );
-
- }
-
- }
-
- // Time Code.
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimecode" )) ) {
-
- if ( (clipSampleScale != 0) && (clipSampleSize != 0) ) {
-
- const bool dropFrame = ( (0x40 & hdvFileBlock.mStartTimeCode[0]) != 0 ) && ( sfr == 4 || sfr == 12 );
- const char chDF = dropFrame ? ';' : ':';
- const int tcFrames = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[0], 0x30 );
- const int tcSeconds = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[1], 0x70 );
- const int tcMinutes = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[2], 0x70 );
- const int tcHours = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[3], 0x30 );
-
- // HH:MM:SS:FF or HH;MM;SS;FF
- char timecode[256];
- sprintf ( timecode, "%02d%c%02d%c%02d%c%02d", tcHours, chDF, tcMinutes, chDF, tcSeconds, chDF, tcFrames );
- std::string sonyTimeString = timecode;
-
- xmpObj->GetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", &xmpString, 0 );
- if ( xmpString != sonyTimeString ) {
-
- xmpObj->SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", sonyTimeString, 0 );
-
- std::string timeFormat;
- if ( clipSampleSize == 1 ) {
-
- // 24, 25, 40, 50, 60
- switch ( clipSampleScale ) {
- case 24 : timeFormat = "24"; break;
- case 25 : timeFormat = "25"; break;
- case 50 : timeFormat = "50"; break;
- default : XMP_Assert ( false );
- }
-
- timeFormat += "Timecode";
-
- } else {
-
- // 23.976, 29.97, 59.94
- XMP_Assert ( clipSampleSize == 1001 );
- switch ( clipSampleScale ) {
- case 24000 : timeFormat = "23976"; break;
- case 30000 : timeFormat = "2997"; break;
- case 60000 : timeFormat = "5994"; break;
- default : XMP_Assert( false ); break;
- }
-
- timeFormat += dropFrame ? "DropTimecode" : "NonDropTimecode";
-
- }
-
- xmpObj->SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", timeFormat, 0 );
-
- }
-
- }
-
- }
-
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "CreateDate" )) ) {
-
- // Clip has date and time in the case of DT (otherwise date and time haven't been set).
- bool clipHasDate = ((hdvFileBlock.mDT[0] == 'D') && (hdvFileBlock.mDT[1] == 'T'));
-
- // Creation date
- if ( clipHasDate ) {
-
- // YYYY-MM-DDThh:mm:ssZ
- char date[256];
- sprintf ( date, "%4d-%02d-%02dT%02d:%02d:%02dZ",
- hdvFileBlock.mFileNameYear + 2000,
- hdvFileBlock.mFileNameMonth,
- hdvFileBlock.mFileNameDay,
- hdvFileBlock.mFileNameHour,
- hdvFileBlock.mFileNameMinute,
- hdvFileBlock.mFileNameSecond );
-
- XMP_StringPtr xmpDate = date;
- xmpObj->SetProperty ( kXMP_NS_XMP, "CreateDate", xmpDate, kXMP_DeleteExisting );
-
- }
-
- }
-
- // Frame rate.
- if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoFrameRate" )) ) {
-
- if ( frameRate.size() != 0 ) {
- xmpString = frameRate;
- xmpObj->SetProperty ( kXMP_NS_DM, "videoFrameRate", xmpString, kXMP_DeleteExisting );
- }
-
- }
-
- } catch ( ... ) {
-
- result = false;
-
- }
-
- return result;
-
-} // ReadIDXFile
-
-// =================================================================================================
-// SonyHDV_MetaHandlerCTor
-// =======================
-
-XMPFileHandler * SonyHDV_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new SonyHDV_MetaHandler ( parent );
-
-} // SonyHDV_MetaHandlerCTor
-
-// =================================================================================================
-// SonyHDV_MetaHandler::SonyHDV_MetaHandler
-// ========================================
-
-SonyHDV_MetaHandler::SonyHDV_MetaHandler ( XMPFiles * _parent )
-{
-
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kSonyHDV_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- // Extract the root path and clip name.
-
- XMP_Assert ( this->parent->tempPtr != 0 );
-
- this->rootPath.assign ( (char*) this->parent->tempPtr );
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- SplitLeafName ( &this->rootPath, &this->clipName );
-
-} // SonyHDV_MetaHandler::SonyHDV_MetaHandler
-
-// =================================================================================================
-// SonyHDV_MetaHandler::~SonyHDV_MetaHandler
-// =========================================
-
-SonyHDV_MetaHandler::~SonyHDV_MetaHandler()
-{
-
- if ( this->parent->tempPtr != 0 ) {
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
- }
-
-} // SonyHDV_MetaHandler::~SonyHDV_MetaHandler
-
-// =================================================================================================
-// SonyHDV_MetaHandler::MakeClipFilePath
-// =====================================
-
-void SonyHDV_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix )
-{
-
- *path = this->rootPath;
- *path += kDirChar;
- *path += "VIDEO";
- *path += kDirChar;
- *path += "HVR";
- *path += kDirChar;
- *path += this->clipName;
- *path += suffix;
-
-} // SonyHDV_MetaHandler::MakeClipFilePath
-
-// =================================================================================================
-// SonyHDV_MetaHandler::MakeIndexFilePath
-// ======================================
-
-bool SonyHDV_MetaHandler::MakeIndexFilePath ( std::string& idxPath, const std::string& rootPath, const std::string& leafName )
-{
- std::string tempPath;
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "VIDEO";
- tempPath += kDirChar;
- tempPath += "HVR";
-
- idxPath = tempPath;
- idxPath += kDirChar;
- idxPath += leafName;
- idxPath += ".IDX";
-
- // Default case
- if ( GetFileMode ( idxPath.c_str() ) == kFMode_IsFile ) return true;
-
- // Spanned clip case
-
- // Scanning code taken from SonyHDV_CheckFormat
- // Can be isolated to a separate function.
-
- std::string clipName = leafName;
- int usCount = 0;
- size_t i, limit = leafName.size();
-
- for ( i = 0; i < limit; ++i ) {
- if ( clipName[i] == '_' ) {
- ++usCount;
- if ( usCount == 2 ) break;
- }
- }
-
- if ( i < limit ) clipName.erase ( i );
- clipName += '_'; // Make sure a final '_' is there for the search comparisons.
-
- XMP_FolderInfo folderInfo;
- std::string childName;
- bool found = false;
-
- folderInfo.Open ( tempPath.c_str() );
- while ( (! found) && folderInfo.GetNextChild ( &childName ) ) {
- size_t childLen = childName.size();
- if ( childLen < 4 ) continue;
- MakeUpperCase ( &childName );
- if ( childName.compare ( childLen-4, 4, ".IDX" ) != 0 ) continue;
- if ( childName.compare ( 0, clipName.size(), clipName ) == 0 ) {
- found = true;
- clipName = childName;
- clipName.erase ( childLen-4 );
- }
- }
- if ( ! found ) return false;
-
- idxPath = tempPath;
- idxPath += kDirChar;
- idxPath += clipName;
- idxPath += ".IDX";
-
- return true;
-}
-
-// =================================================================================================
-// SonyHDV_MetaHandler::MakeLegacyDigest
-// =====================================
-
-#define kHexDigits "0123456789ABCDEF"
-
-void SonyHDV_MetaHandler::MakeLegacyDigest ( std::string * digestStr )
-{
- std::string idxPath;
- if ( ! this->MakeIndexFilePath ( idxPath, this->rootPath, this->clipName ) ) return;
-
- MD5_CTX context;
- unsigned char digestBin [16];
- bool dummy = false;
- MD5Init ( &context );
- ReadIDXFile ( idxPath, this->clipName, 0, dummy, &context, false );
- MD5Final ( digestBin, &context );
-
- 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->erase();
- digestStr->append ( buffer, 32 );
-
-} // MakeLegacyDigest
-
-// =================================================================================================
-// SonyHDV_MetaHandler::CacheFileData
-// ==================================
-
-void SonyHDV_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- // See if the clip's .XMP file exists.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, ".XMP" );
- if ( GetFileMode ( xmpPath.c_str() ) != kFMode_IsFile ) return; // No XMP.
-
- // Read the entire .XMP file.
-
- char openMode = 'r';
- if ( this->parent->openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- LFA_FileRef xmpFile = LFA_Open ( xmpPath.c_str(), openMode );
- if ( xmpFile == 0 ) return; // The open failed.
-
- XMP_Int64 xmpLen = LFA_Measure ( xmpFile );
- if ( xmpLen > 100*1024*1024 ) {
- XMP_Throw ( "SonyHDV XMP is outrageously large", kXMPErr_InternalFailure ); // Sanity check.
- }
-
- this->xmpPacket.erase();
- this->xmpPacket.reserve ( (size_t)xmpLen );
- this->xmpPacket.append ( (size_t)xmpLen, ' ' );
-
- XMP_Int32 ioCount = LFA_Read ( xmpFile, (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen, kLFA_RequireAll );
- XMP_Assert ( ioCount == xmpLen );
-
- this->packetInfo.offset = 0;
- this->packetInfo.length = (XMP_Int32)xmpLen;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- XMP_Assert ( this->parent->fileRef == 0 );
- if ( openMode == 'r' ) {
- LFA_Close ( xmpFile );
- } else {
- this->parent->fileRef = xmpFile;
- }
-
- this->containsXMP = true;
-
-} // SonyHDV_MetaHandler::CacheFileData
-
-// =================================================================================================
-// SonyHDV_MetaHandler::ProcessXMP
-// ===============================
-
-void SonyHDV_MetaHandler::ProcessXMP()
-{
- 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() );
- }
-
- // Check the legacy digest.
- std::string oldDigest, newDigest;
- bool digestFound;
- digestFound = this->xmpObj.GetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "SonyHDV", &oldDigest, 0 );
- if ( digestFound ) {
- this->MakeLegacyDigest ( &newDigest );
- if ( oldDigest == newDigest ) return;
- }
-
- // Read the IDX legacy.
- std::string idxPath;
- if ( ! this->MakeIndexFilePath ( idxPath, this->rootPath, this->clipName ) ) return;
- ReadIDXFile ( idxPath, this->clipName, &this->xmpObj, this->containsXMP, 0, digestFound );
-
-} // SonyHDV_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// SonyHDV_MetaHandler::UpdateFile
-// ===============================
-//
-// Note that UpdateFile is only called from XMPFiles::CloseFile, so it is OK to close the file here.
-
-void SonyHDV_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- this->needsUpdate = false; // Make sure only called once.
-
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "SonyHDV", newDigest.c_str(), kXMP_DeleteExisting );
-
- LFA_FileRef oldFile = this->parent->fileRef;
-
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() );
-
- if ( oldFile == 0 ) {
-
- // The XMP does not exist yet.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, ".XMP" );
-
- LFA_FileRef xmpFile = LFA_Create ( xmpPath.c_str() );
- if ( xmpFile == 0 ) XMP_Throw ( "Failure creating SonyHDV XMP file", kXMPErr_ExternalFailure );
- LFA_Write ( xmpFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( xmpFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XMP file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- std::string xmpPath, tempPath;
-
- this->MakeClipFilePath ( &xmpPath, ".XMP" );
-
- CreateTempFile ( xmpPath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( xmpPath.c_str() );
- LFA_Rename ( tempPath.c_str(), xmpPath.c_str() );
-
- }
-
- this->parent->fileRef = 0;
-
-} // SonyHDV_MetaHandler::UpdateFile
-
-// =================================================================================================
-// SonyHDV_MetaHandler::WriteFile
-// ==============================
-
-void SonyHDV_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- // ! WriteFile is not supposed to be called for handlers that own the file.
- XMP_Throw ( "SonyHDV_MetaHandler::WriteFile should not be called", kXMPErr_InternalFailure );
-
-} // SonyHDV_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/SonyHDV_Handler.hpp b/source/XMPFiles/FileHandlers/SonyHDV_Handler.hpp
deleted file mode 100644
index 2af4ffc..0000000
--- a/source/XMPFiles/FileHandlers/SonyHDV_Handler.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef __SonyHDV_Handler_hpp__
-#define __SonyHDV_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#include "ExpatAdapter.hpp"
-
-// =================================================================================================
-/// \file SonyHDV_Handler.hpp
-/// \brief Folder format handler for SonyHDV.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * SonyHDV_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool SonyHDV_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kSonyHDV_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_FolderBasedFormat);
-
-class SonyHDV_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions() // *** These should be standard for standalone XMP files.
- { return (kXMP_UseCompactFormat | kXMP_OmitPacketWrapper); };
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- SonyHDV_MetaHandler ( XMPFiles * _parent );
- virtual ~SonyHDV_MetaHandler();
-
-private:
-
- SonyHDV_MetaHandler() {}; // Hidden on purpose.
-
- void MakeClipFilePath ( std::string * path, XMP_StringPtr suffix );
- bool MakeIndexFilePath ( std::string& idxPath, const std::string& rootPath, const std::string& leafName );
- void MakeLegacyDigest ( std::string * digestStr );
-
- std::string rootPath, clipName;
-
-}; // SonyHDV_MetaHandler
-
-// =================================================================================================
-
-#endif /* __SonyHDV_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/TIFF_Handler.cpp b/source/XMPFiles/FileHandlers/TIFF_Handler.cpp
deleted file mode 100644
index 15332e6..0000000
--- a/source/XMPFiles/FileHandlers/TIFF_Handler.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Handler.hpp"
-
-#include "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-#include "ReconcileLegacy.hpp"
-#include "Reconcile_Impl.hpp"
-
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file TIFF_Handler.cpp
-/// \brief File format handler for TIFF.
-///
-/// This handler ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// TIFF_CheckFormat
-// ================
-
-// For TIFF we just check for the II/42 or MM/42 in the first 4 bytes and that there are at least
-// 26 bytes of data (4+4+2+12+4).
-//
-// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
-
-bool TIFF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
- XMP_Assert ( format == kXMP_TIFFFile );
-
- enum { kMinimalTIFFSize = 4+4+2+12+4 }; // Header plus IFD with 1 entry.
-
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( ! CheckFileSpace ( fileRef, &ioBuf, kMinimalTIFFSize ) ) return false;
-
- bool leTIFF = CheckBytes ( ioBuf.ptr, "\x49\x49\x2A\x00", 4 );
- bool beTIFF = CheckBytes ( ioBuf.ptr, "\x4D\x4D\x00\x2A", 4 );
-
- return (leTIFF | beTIFF);
-
-} // TIFF_CheckFormat
-
-// =================================================================================================
-// TIFF_MetaHandlerCTor
-// ====================
-
-XMPFileHandler * TIFF_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new TIFF_MetaHandler ( parent );
-
-} // TIFF_MetaHandlerCTor
-
-// =================================================================================================
-// TIFF_MetaHandler::TIFF_MetaHandler
-// ==================================
-
-TIFF_MetaHandler::TIFF_MetaHandler ( XMPFiles * _parent ) : psirMgr(0), iptcMgr(0)
-{
- this->parent = _parent;
- this->handlerFlags = kTIFF_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
-} // TIFF_MetaHandler::TIFF_MetaHandler
-
-// =================================================================================================
-// TIFF_MetaHandler::~TIFF_MetaHandler
-// ===================================
-
-TIFF_MetaHandler::~TIFF_MetaHandler()
-{
-
- if ( this->psirMgr != 0 ) delete ( this->psirMgr );
- if ( this->iptcMgr != 0 ) delete ( this->iptcMgr );
-
-} // TIFF_MetaHandler::~TIFF_MetaHandler
-
-// =================================================================================================
-// TIFF_MetaHandler::CacheFileData
-// ===============================
-//
-// The data caching for TIFF is easy to explain and implement, but does more processing than one
-// might at first expect. This seems unavoidable given the need to close the disk file after calling
-// CacheFileData. We parse the TIFF stream and cache the values for all tags of interest, and note
-// whether XMP is present. We do not parse the XMP, Photoshop image resources, or IPTC datasets.
-
-// *** This implementation simply returns when invalid TIFF is encountered. Should we throw instead?
-
-void TIFF_MetaHandler::CacheFileData()
-{
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
-
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
- const bool checkAbort = (abortProc != 0);
-
- XMP_Assert ( ! this->containsXMP );
- // Set containsXMP to true here only if the XMP tag is found.
-
- if ( checkAbort && abortProc(abortArg) ) {
- XMP_Throw ( "TIFF_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
- }
-
- this->tiffMgr.ParseFileStream ( fileRef );
-
- TIFF_Manager::TagInfo dngInfo;
- if ( this->tiffMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_DNGVersion, &dngInfo ) ) {
-
- // Reject DNG files that are version 2.0 or beyond, this is being written at the time of
- // DNG version 1.2. The DNG team says it is OK to use 2.0, not strictly 1.2. Use the
- // DNGBackwardVersion if it is present, else the DNGVersion. Note that the version value is
- // supposed to be type BYTE, so the file order is always essentially big endian.
-
- XMP_Uns8 majorVersion = *((XMP_Uns8*)dngInfo.dataPtr); // Start with DNGVersion.
- if ( this->tiffMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_DNGBackwardVersion, &dngInfo ) ) {
- majorVersion = *((XMP_Uns8*)dngInfo.dataPtr); // Use DNGBackwardVersion if possible.
- }
- if ( majorVersion > 1 ) XMP_Throw ( "DNG version beyond 1.x", kXMPErr_BadTIFF );
-
- }
-
- TIFF_Manager::TagInfo xmpInfo;
- bool found = this->tiffMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, &xmpInfo );
-
- if ( found ) {
-
- this->packetInfo.offset = this->tiffMgr.GetValueOffset ( kTIFF_PrimaryIFD, kTIFF_XMP );
- this->packetInfo.length = xmpInfo.dataLen;
- this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
- this->packetInfo.charForm = kXMP_CharUnknown;
- this->packetInfo.writeable = true;
-
- this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );
-
- this->containsXMP = true;
-
- }
-
-} // TIFF_MetaHandler::CacheFileData
-
-// =================================================================================================
-// TIFF_MetaHandler::ProcessXMP
-// ============================
-//
-// Process the raw XMP and legacy metadata that was previously cached. The legacy metadata in TIFF
-// is messy because there are 2 copies of the IPTC and because of a Photoshop 6 bug/quirk in the way
-// Exif metadata is saved.
-
-void TIFF_MetaHandler::ProcessXMP()
-{
-
- this->processedXMP = true; // Make sure we only come through here once.
-
- // 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.
-
- // ! Photoshop 6 wrote annoyingly wacky TIFF files. It buried a lot of the Exif metadata inside
- // ! image resource 1058, itself inside of tag 34377 in the 0th IFD. Take care of this before
- // ! doing any of the legacy metadata presence or priority analysis. Delete image resource 1058
- // ! to get rid of the buried Exif, but don't mark the XMPFiles object as changed. This change
- // ! should not trigger an update, but should be included as part of a normal update.
-
- bool found;
- bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
-
- if ( readOnly ) {
- this->psirMgr = new PSIR_MemoryReader();
- this->iptcMgr = new IPTC_Reader();
- } else {
- this->psirMgr = new PSIR_FileWriter();
- this->iptcMgr = new IPTC_Writer(); // ! Parse it later.
- }
-
- TIFF_Manager & tiff = this->tiffMgr; // Give the compiler help in recognizing non-aliases.
- PSIR_Manager & psir = *this->psirMgr;
- IPTC_Manager & iptc = *this->iptcMgr;
-
- TIFF_Manager::TagInfo psirInfo;
- bool havePSIR = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_PSIR, &psirInfo );
-
- if ( havePSIR ) { // ! Do the Photoshop 6 integration before other legacy analysis.
- psir.ParseMemoryResources ( psirInfo.dataPtr, psirInfo.dataLen );
- PSIR_Manager::ImgRsrcInfo buriedExif;
- found = psir.GetImgRsrc ( kPSIR_Exif, &buriedExif );
- if ( found ) {
- tiff.IntegrateFromPShop6 ( buriedExif.dataPtr, buriedExif.dataLen );
- if ( ! readOnly ) psir.DeleteImgRsrc ( kPSIR_Exif );
- }
- }
-
- TIFF_Manager::TagInfo iptcInfo;
- bool haveIPTC = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_IPTC, &iptcInfo ); // The TIFF IPTC tag.
- int iptcDigestState = kDigestMatches;
-
- if ( haveIPTC ) {
-
- bool haveDigest = false;
- PSIR_Manager::ImgRsrcInfo digestInfo;
- if ( havePSIR ) haveDigest = psir.GetImgRsrc ( kPSIR_IPTCDigest, &digestInfo );
- if ( digestInfo.dataLen != 16 ) haveDigest = false;
-
- if ( ! haveDigest ) {
-
- iptcDigestState = kDigestMissing;
-
- } else {
-
- // Older versions of Photoshop wrote tag 33723 with type LONG, but ignored the trailing
- // zero padding for the IPTC digest. If the full digest differs, recheck without the padding.
-
- iptcDigestState = PhotoDataUtils::CheckIPTCDigest ( iptcInfo.dataPtr, iptcInfo.dataLen, digestInfo.dataPtr );
-
- if ( (iptcDigestState == kDigestDiffers) && (kTIFF_TypeSizes[iptcInfo.type] > 1) ) {
- XMP_Uns8 * endPtr = (XMP_Uns8*)iptcInfo.dataPtr + iptcInfo.dataLen - 1;
- XMP_Uns8 * minPtr = endPtr - kTIFF_TypeSizes[iptcInfo.type] + 1;
- while ( (endPtr >= minPtr) && (*endPtr == 0) ) --endPtr;
- XMP_Uns32 unpaddedLen = (XMP_Uns32) (endPtr - (XMP_Uns8*)iptcInfo.dataPtr + 1);
- iptcDigestState = PhotoDataUtils::CheckIPTCDigest ( iptcInfo.dataPtr, unpaddedLen, digestInfo.dataPtr );
- }
-
- }
-
- }
-
- XMP_OptionBits options = k2XMP_FileHadExif; // TIFF files are presumed to have Exif legacy.
- if ( haveIPTC ) options |= k2XMP_FileHadIPTC;
- if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
-
- // Process the XMP packet. If it fails to parse, do a forced legacy import but still throw an
- // exception. This tells the caller that an error happened, but gives them recovered legacy
- // should they want to proceed with that.
-
- bool haveXMP = false;
-
- if ( ! this->xmpPacket.empty() ) {
- XMP_Assert ( this->containsXMP );
- // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
- XMP_StringPtr packetStr = this->xmpPacket.c_str();
- XMP_StringLen packetLen = (XMP_StringLen)this->xmpPacket.size();
- try {
- this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
- haveXMP = true;
- } catch ( ... ) {
- XMP_ClearOption ( options, k2XMP_FileHadXMP );
- if ( haveIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- if ( iptcDigestState == kDigestMatches ) iptcDigestState = kDigestMissing;
- ImportPhotoData ( tiff, iptc, psir, iptcDigestState, &this->xmpObj, options );
- throw; // ! Rethrow the exception, don't absorb it.
- }
- }
-
- // Process the legacy metadata.
-
- if ( haveIPTC && (! haveXMP) && (iptcDigestState == kDigestMatches) ) iptcDigestState = kDigestMissing;
- bool parseIPTC = (iptcDigestState != kDigestMatches) || (! readOnly);
- if ( parseIPTC ) iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
- ImportPhotoData ( tiff, iptc, psir, iptcDigestState, &this->xmpObj, options );
-
- this->containsXMP = true; // Assume we now have something in the XMP.
-
-} // TIFF_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// TIFF_MetaHandler::UpdateFile
-// ============================
-//
-// There is very little to do directly in UpdateFile. ExportXMPtoJTP takes care of setting all of
-// the necessary TIFF tags, including things like the 2nd copy of the IPTC in the Photoshop image
-// resources in tag 34377. TIFF_FileWriter::UpdateFileStream does all of the update-by-append I/O.
-
-// *** Need to pass the abort proc and arg to TIFF_FileWriter::UpdateFileStream.
-
-void TIFF_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
-
- LFA_FileRef destRef = this->parent->fileRef;
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
-
- XMP_Int64 oldPacketOffset = this->packetInfo.offset;
- XMP_Int32 oldPacketLength = this->packetInfo.length;
-
- if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
- if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
-
- bool fileHadXMP = ((oldPacketOffset != 0) && (oldPacketLength != 0));
-
- // Update the IPTC-IIM and native TIFF/Exif metadata. ExportPhotoData also trips the tiff: and
- // exif: copies from the XMP, so reserialize the now final XMP packet.
-
- ExportPhotoData ( kXMP_TIFFFile, &this->xmpObj, &this->tiffMgr, this->iptcMgr, this->psirMgr );
-
- try {
- XMP_OptionBits options = kXMP_UseCompactFormat;
- if ( fileHadXMP ) options |= kXMP_ExactPacketLength;
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, options, oldPacketLength );
- } catch ( ... ) {
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
- }
-
- // Decide whether to do an in-place update. This can only happen if all of the following are true:
- // - There is an XMP packet in the file.
- // - The are no changes to the legacy tags. (The IPTC and PSIR are in the TIFF tags.)
- // - The new XMP can fit in the old space.
-
- bool doInPlace = (fileHadXMP && (this->xmpPacket.size() <= (size_t)oldPacketLength));
- if ( this->tiffMgr.IsLegacyChanged() ) doInPlace = false;
-
- if ( ! doInPlace ) {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", TIFF append update";
- #endif
-
- this->tiffMgr.SetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, kTIFF_UndefinedType, (XMP_Uns32)this->xmpPacket.size(), this->xmpPacket.c_str() );
- this->tiffMgr.UpdateFileStream ( destRef );
-
- } else {
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", TIFF in-place update";
- #endif
-
- if ( this->xmpPacket.size() < (size_t)this->packetInfo.length ) {
- // They ought to match, cheap to be sure.
- size_t extraSpace = (size_t)this->packetInfo.length - this->xmpPacket.size();
- this->xmpPacket.append ( extraSpace, ' ' );
- }
-
- LFA_FileRef liveFile = this->parent->fileRef;
-
- XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
-
- LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
- LFA_Write ( liveFile, this->xmpPacket.c_str(), (XMP_Int32)this->xmpPacket.size() );
-
- }
-
- this->needsUpdate = false;
-
-} // TIFF_MetaHandler::UpdateFile
-
-// =================================================================================================
-// TIFF_MetaHandler::WriteFile
-// ===========================
-//
-// The structure of TIFF makes it hard to do a sequential source-to-dest copy with interleaved
-// updates. So, copy the existing source to the destination and call UpdateFile.
-
-void TIFF_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- LFA_FileRef destRef = this->parent->fileRef;
- XMP_AbortProc abortProc = this->parent->abortProc;
- void * abortArg = this->parent->abortArg;
-
- XMP_Int64 fileLen = LFA_Measure ( sourceRef );
- if ( fileLen > 0xFFFFFFFFLL ) { // Check before making a copy of the file.
- XMP_Throw ( "TIFF fles can't exceed 4GB", kXMPErr_BadTIFF );
- }
-
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Truncate ( destRef, 0 );
- LFA_Copy ( sourceRef, destRef, fileLen, abortProc, abortArg );
-
- this->UpdateFile ( false );
-
-} // TIFF_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/TIFF_Handler.hpp b/source/XMPFiles/FileHandlers/TIFF_Handler.hpp
deleted file mode 100644
index aabb509..0000000
--- a/source/XMPFiles/FileHandlers/TIFF_Handler.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef __TIFF_Handler_hpp__
-#define __TIFF_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-
-// =================================================================================================
-/// \file TIFF_Handler.hpp
-/// \brief File format handler for TIFF.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// *** Could derive from Basic_Handler - buffer file tail in a temp file.
-
-extern XMPFileHandler * TIFF_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool TIFF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kTIFF_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate);
-
-class TIFF_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- TIFF_MetaHandler ( XMPFiles * parent );
- virtual ~TIFF_MetaHandler();
-
-private:
-
- TIFF_MetaHandler() : psirMgr(0), iptcMgr(0) {}; // Hidden on purpose.
-
- TIFF_FileWriter tiffMgr; // The TIFF part is always file-based.
- PSIR_Manager * psirMgr; // Need to use pointers so we can properly select between read-only and
- IPTC_Manager * iptcMgr; // read-write modes of usage.
-
-}; // TIFF_MetaHandler
-
-// =================================================================================================
-
-#endif /* __TIFF_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Trivial_Handler.cpp b/source/XMPFiles/FileHandlers/Trivial_Handler.cpp
deleted file mode 100644
index 3ebdb67..0000000
--- a/source/XMPFiles/FileHandlers/Trivial_Handler.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "Trivial_Handler.hpp"
-
-using namespace std;
-
-// =================================================================================================
-/// \file Trivial_Handler.cpp
-/// \brief Base class for trivial handlers that only process in-place XMP.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// Trivial_MetaHandler::~Trivial_MetaHandler
-// =========================================
-
-Trivial_MetaHandler::~Trivial_MetaHandler()
-{
- // Nothing to do.
-
-} // Trivial_MetaHandler::~Trivial_MetaHandler
-
-// =================================================================================================
-// Trivial_MetaHandler::UpdateFile
-// ===============================
-
-void Trivial_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- IgnoreParam ( doSafeUpdate );
- XMP_Assert ( ! doSafeUpdate ); // Not supported at this level.
- if ( ! this->needsUpdate ) return;
-
- LFA_FileRef fileRef = this->parent->fileRef;
- XMP_PacketInfo & packetInfo = this->packetInfo;
- std::string & xmpPacket = this->xmpPacket;
-
- LFA_Seek ( fileRef, packetInfo.offset, SEEK_SET );
- LFA_Write ( fileRef, xmpPacket.c_str(), packetInfo.length );
- XMP_Assert ( xmpPacket.size() == (size_t)packetInfo.length );
-
- this->needsUpdate = false;
-
-} // Trivial_MetaHandler::UpdateFile
-
-// =================================================================================================
-// Trivial_MetaHandler::WriteFile
-// ==============================
-
-void Trivial_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- IgnoreParam ( sourceRef ); IgnoreParam ( sourcePath );
-
- XMP_Throw ( "Trivial_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
-
-} // Trivial_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Trivial_Handler.hpp b/source/XMPFiles/FileHandlers/Trivial_Handler.hpp
deleted file mode 100644
index 9db851c..0000000
--- a/source/XMPFiles/FileHandlers/Trivial_Handler.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __Trivial_Handler_hpp__
-#define __Trivial_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "XMPFiles_Impl.hpp"
-
-// =================================================================================================
-/// \file Trivial_Handler.hpp
-/// \brief Base class for trivial handlers that only process in-place XMP.
-///
-/// This header ...
-///
-/// \note There is no general promise here about crash-safe I/O. An update to an existing file might
-/// have invalid partial state while rewriting existing XMP in-place. Crash-safe updates are managed
-/// at a higher level of XMPFiles, using a temporary file and final swap of file content.
-///
-// =================================================================================================
-
-static const XMP_OptionBits kTrivial_HandlerFlags = ( kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_AllowsSafeUpdate );
-
-class Trivial_MetaHandler : public XMPFileHandler
-{
-public:
-
- Trivial_MetaHandler() {};
- ~Trivial_MetaHandler();
-
- virtual void CacheFileData() = 0;
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
-}; // Trivial_MetaHandler
-
-// =================================================================================================
-
-#endif /* __Trivial_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/UCF_Handler.cpp b/source/XMPFiles/FileHandlers/UCF_Handler.cpp
deleted file mode 100644
index cea781e..0000000
--- a/source/XMPFiles/FileHandlers/UCF_Handler.cpp
+++ /dev/null
@@ -1,850 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// ===============================================================================================
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-#include "UCF_Handler.hpp"
-
-#include "zlib.h"
-
-#include <time.h>
-
-#ifdef DYNAMIC_CRC_TABLE
- #error "unexpectedly DYNAMIC_CRC_TABLE defined."
- //Must implement get_crc_table prior to any multi-threading (see notes there)
-#endif
-
-using namespace std;
-
-// =================================================================================================
-/// \file UCF_Handler.cpp
-/// \brief UCF handler class
-// =================================================================================================
-const XMP_Uns16 xmpFilenameLen = 21;
-const char* xmpFilename = "META-INF/metadata.xml";
-
-// =================================================================================================
-// UCF_MetaHandlerCTor
-// ====================
-XMPFileHandler* UCF_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new UCF_MetaHandler ( parent );
-} // UCF_MetaHandlerCTor
-
-// =================================================================================================
-// UCF_CheckFormat
-// ================
-// * lenght must at least be 114 bytes
-// * first bytes must be \x50\x4B\x03\x04 for *any* zip file
-// * at offset 30 it must spell "mimetype"
-
-#define MIN_UCF_LENGTH 114
-// zip minimum considerations:
-// the shortest legal zip is 100 byte:
-// 30+1* bytes file header
-//+ 0 byte content file (uncompressed)
-//+ 46+1* bytes central directory file header
-//+ 22 byte end of central directory record
-//-------
-//100 bytes
-//
-//1 byte is the shortest legal filename. anything below is no valid zip.
-//
-//==> the mandatory+first "mimetype" content file has a filename length of 8 bytes,
-// thus even if empty (arguably incorrect but tolerable),
-// the shortest legal UCF is 114 bytes (30 + 8 + 0 + 46 + 8 + 22 )
-// anything below is with certainty not a valid ucf.
-
-bool UCF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent )
-{
- // *not* using buffer functionality here, all we need
- // to detect UCF securely is in the first 38 bytes...
- IgnoreParam(filePath); IgnoreParam(parent); //suppress warnings
- XMP_Assert ( format == kXMP_UCFFile ); //standard assert
-
- XMP_Uns8 buffer[MIN_UCF_LENGTH];
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- if ( MIN_UCF_LENGTH != LFA_Read ( fileRef, buffer, MIN_UCF_LENGTH) ) //NO requireall (->no throw), just return false
- return false;
- if ( !CheckBytes ( &buffer[0], "\x50\x4B\x03\x04", 4 ) ) // "PK 03 04"
- return false;
- // UCF spec says: there must be a content file mimetype, and be first and be uncompressed...
- if ( !CheckBytes ( &buffer[30], "mimetype", 8 ) )
- return false;
-
- //////////////////////////////////////////////////////////////////////////////
- //figure out mimetype, decide on writeability
- // grab mimetype
- LFA_Seek( fileRef, 18, SEEK_SET );
- XMP_Uns32 mimeLength = LFA_ReadUns32_LE ( fileRef );
- XMP_Uns32 mimeCompressedLength = LFA_ReadUns32_LE ( fileRef ); // must be same since uncompressed
-
- XMP_Validate( mimeLength == mimeCompressedLength,
- "mimetype compressed and uncompressed length differ",
- kXMPErr_BadFileFormat );
-
- XMP_Validate( mimeLength != 0, "0-byte mimetype", kXMPErr_BadFileFormat );
-
- // determine writability based on mimetype
- LFA_Seek( fileRef, 30 + 8, SEEK_SET );
- char* mimetype = new char[ mimeLength + 1 ];
- LFA_Read( fileRef, mimetype, mimeLength, true );
- mimetype[mimeLength] = '\0';
-
- bool okMimetype;
-
- // be lenient on extraneous CR (0xA) [non-XMP bug #16980028]
- if ( mimeLength > 0 ) //avoid potential crash (will properly fail below anyhow)
- if ( mimetype[mimeLength-1] == 0xA )
- mimetype[mimeLength-1] = '\0';
-
- if (
- XMP_LitMatch( mimetype, "application/vnd.adobe.xfl" ) || //Flash Diesel team
- XMP_LitMatch( mimetype, "application/vnd.adobe.xfl+zip") || //Flash Diesel team
- XMP_LitMatch( mimetype, "application/vnd.adobe.x-mars" ) || //Mars plugin(labs only), Acrobat8
- XMP_LitMatch( mimetype, "application/vnd.adobe.pdfxml" ) || //Mars plugin(labs only), Acrobat 9
- XMP_LitMatch( mimetype, "vnd.adobe.x-asnd" ) || //Adobe Sound Document (Soundbooth Team)
- XMP_LitMatch( mimetype, "application/vnd.adobe.indesign-idml-package" ) || //inCopy (inDesign) IDML Document
- XMP_LitMatch( mimetype, "application/vnd.adobe.incopy-package" ) || // InDesign Document
- XMP_LitMatch( mimetype, "application/vnd.adobe.indesign-package" ) || // InDesign Document
-
- false ) // "sentinel"
-
- // *** ==> unknown are also treated as not acceptable
- okMimetype = true;
- else
- okMimetype = false;
-
- // not accepted (neither read nor write
- //.air - Adobe Air Files
- //application/vnd.adobe.air-application-installer-package+zip
- //.airi - temporary Adobe Air Files
- //application/vnd.adobe.air-application-intermediate-package+zip
-
- delete [] mimetype;
- return okMimetype;
-
-} // UCF_CheckFormat
-
-// =================================================================================================
-// UCF_MetaHandler::UCF_MetaHandler
-// ==================================
-
-UCF_MetaHandler::UCF_MetaHandler ( XMPFiles * _parent )
-{
- this->parent = _parent;
- this->handlerFlags = kUCF_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-} // UCF_MetaHandler::UCF_MetaHandler
-
-// =================================================================================================
-// UCF_MetaHandler::~UCF_MetaHandler
-// =====================================
-
-UCF_MetaHandler::~UCF_MetaHandler()
-{
- // nothing
-}
-
-// =================================================================================================
-// UCF_MetaHandler::CacheFileData
-// ===============================
-//
-void UCF_MetaHandler::CacheFileData()
-{
- //*** abort procedures
- this->containsXMP = false; //assume no XMP for now (beware of exceptions...)
- LFA_FileRef file = this->parent->fileRef;
- XMP_PacketInfo &packetInfo = this->packetInfo;
-
- // clear file positioning info ---------------------------------------------------
- b=0;b2=0;x=0;x2=0;cd=0;cd2=0;cdx=0;cdx2=0;h=0;h2=0,fl=0;f2l=0;
- al=0;bl=0;xl=0;x2l=0;cdl=0;cd2l=0;cdxl=0;cdx2l=0;hl=0,z=0,z2=0,z2l=0;
- numCF=0;numCF2=0;
- wasCompressed = false;
-
- // -------------------------------------------------------------------------------
- fl=LFA_Measure( file );
- if ( fl < MIN_UCF_LENGTH ) XMP_Throw("file too short, can't be correct UCF",kXMPErr_Unimplemented);
-
- //////////////////////////////////////////////////////////////////////////////
- // find central directory before optional comment
- // things have to go bottom-up, since description headers are allowed in UCF
- // "scan backwards" until feasible field found (plus sig sanity check)
- // OS buffering should be smart enough, so not doing anything on top
- // plus almost all comments will be zero or rather short
-
- //no need to check anything but the 21 chars of "METADATA-INF/metadata.xml"
- char filenameToTest[22];
- filenameToTest[21]='\0';
-
- XMP_Int32 zipCommentLen = 0;
- for ( ; zipCommentLen <= EndOfDirectory::COMMENT_MAX; zipCommentLen++ )
- {
- LFA_Seek( file, -zipCommentLen -2, SEEK_END );
- if ( LFA_ReadUns16_LE( file ) == zipCommentLen ) //found it?
- {
- //double check, might just look like comment length (actually be 'evil' comment)
- LFA_Seek( file , - EndOfDirectory::FIXED_SIZE, SEEK_CUR );
- if ( LFA_ReadUns32_LE( file ) == EndOfDirectory::ID ) break; //heureka, directory ID
- // 'else': pretend nothing happended, just go on
- }
- }
- //was it a break or just not found ?
- if ( zipCommentLen > EndOfDirectory::COMMENT_MAX ) XMP_Throw( "zip broken near end or invalid comment" , kXMPErr_BadFileFormat );
-
- ////////////////////////////////////////////////////////////////////////////
- //read central directory
- hl = zipCommentLen + EndOfDirectory::FIXED_SIZE;
- h = fl - hl;
- LFA_Seek( file , h , SEEK_SET );
-
- if ( LFA_ReadUns32_LE( file ) != EndOfDirectory::ID )
- XMP_Throw("directory header id not found. or broken comment",kXMPErr_BadFileFormat);
- if ( LFA_ReadUns16_LE( file ) != 0 )
- XMP_Throw("UCF must be 'first' zip volume",kXMPErr_BadFileFormat);
- if ( LFA_ReadUns16_LE( file ) != 0 )
- XMP_Throw("UCF must be single-volume zip",kXMPErr_BadFileFormat);
-
- numCF = LFA_ReadUns16_LE( file ); //number of content files
- if ( numCF != LFA_ReadUns16_LE( file ) )
- XMP_Throw( "per volume and total number of dirs differ" , kXMPErr_BadFileFormat );
- cdl = LFA_ReadUns32_LE( file );
- cd = LFA_ReadUns32_LE( file );
- LFA_Seek( file, 2,SEEK_CUR ); //skip comment len, needed since next LFA is SEEK_CUR !
-
- //////////////////////////////////////////////////////////////////////////////
- // check for zip64-end-of-CD-locator/ zip64-end-of-CD
- // to to central directory
- if ( cd == 0xffffffff )
- { // deal with zip 64, otherwise continue
- XMP_Int64 tmp = LFA_Seek( file,
- - EndOfDirectory::FIXED_SIZE - Zip64Locator::TOTAL_SIZE,
- SEEK_CUR ); //go to begining of zip64 locator
- //relative movement , absolute would imho only require another -zipCommentLen
-
- if ( Zip64Locator::ID == LFA_ReadUns32_LE(file) ) // prevent 'coincidental length' ffffffff
- {
- XMP_Validate( 0 == LFA_ReadUns32_LE(file),
- "zip64 CD disk must be 0", kXMPErr_BadFileFormat );
-
- z = LFA_ReadUns64_LE(file);
- XMP_Validate( z < 0xffffffffffffLL, "file in terrabyte range?", kXMPErr_BadFileFormat ); // 3* ffff, sanity test
-
- XMP_Uns32 totalNumOfDisks = LFA_ReadUns32_LE(file);
- /* tolerated while pkglib bug #1742179 */
- XMP_Validate( totalNumOfDisks == 0 || totalNumOfDisks == 1,
- "zip64 total num of disks must be 0", kXMPErr_BadFileFormat );
-
- ///////////////////////////////////////////////
- /// on to end-of-CD itself
- LFA_Seek( file, z, SEEK_SET );
- XMP_Validate( Zip64EndOfDirectory::ID == LFA_ReadUns32_LE(file),
- "invalid zip64 end of CD sig", kXMPErr_BadFileFormat );
-
- XMP_Int64 sizeOfZip64EOD = LFA_ReadUns64_LE(file);
- LFA_Seek(file, 12, SEEK_CUR );
- //yes twice "total" and "per disk"
- XMP_Int64 tmp64 = LFA_ReadUns64_LE(file);
- XMP_Validate( tmp64 == numCF, "num of content files differs to zip64 (1)", kXMPErr_BadFileFormat );
- tmp64 = LFA_ReadUns64_LE(file);
- XMP_Validate( tmp64 == numCF, "num of content files differs to zip64 (2)", kXMPErr_BadFileFormat );
- // cd length verification
- tmp64 = LFA_ReadUns64_LE(file);
- XMP_Validate( tmp64 == cdl, "CD length differs in zip64", kXMPErr_BadFileFormat );
-
- cd = LFA_ReadUns64_LE(file); // wipe out invalid 0xffffffff with the real thing
- //ignoring "extensible data sector (would need fullLength - fixed length) for now
- }
- } // of zip64 fork
- /////////////////////////////////////////////////////////////////////////////
- // parse central directory
- // 'foundXMP' <=> cdx != 0
-
- LFA_Seek( file, cd, SEEK_SET );
- XMP_Int64 cdx_suspect=0;
- XMP_Int64 cdxl_suspect=0;
- CDFileHeader curCDHeader;
-
- for ( XMP_Uns16 entryNum=1 ; entryNum <= numCF ; entryNum++ )
- {
- cdx_suspect = LFA_Tell( file ); //just suspect for now
- curCDHeader.read( file );
-
- if ( GetUns32LE( &curCDHeader.fields[CDFileHeader::o_sig] ) != 0x02014b50 )
- XMP_Throw("&invalid file header",kXMPErr_BadFileFormat);
-
- cdxl_suspect = curCDHeader.FIXED_SIZE +
- GetUns16LE(&curCDHeader.fields[CDFileHeader::o_fileNameLength]) +
- GetUns16LE(&curCDHeader.fields[CDFileHeader::o_extraFieldLength]) +
- GetUns16LE(&curCDHeader.fields[CDFileHeader::o_commentLength]);
-
- // we only look 21 characters, that's META-INF/metadata.xml, no \0 attached
- if ( curCDHeader.filenameLen == xmpFilenameLen /*21*/ )
- if( XMP_LitNMatch( curCDHeader.filename , "META-INF/metadata.xml", 21 ) )
- {
- cdx = cdx_suspect;
- cdxl = cdxl_suspect;
- break;
- }
- //hop to next
- LFA_Seek( file, cdx_suspect + cdxl_suspect , SEEK_SET );
- } //for-loop, iterating *all* central directory headers (also beyond found)
-
- if ( !cdx ) // not found xmp
- {
- // b and bl remain 0, x and xl remain 0
- // ==> a is everything before directory
- al = cd;
- return;
- }
-
- // from here is if-found-only
- //////////////////////////////////////////////////////////////////////////////
- //CD values needed, most serve counter-validation purposes (below) only
- // read whole object (incl. all 3 fields) again properly
- // to get extra Fields, etc
- LFA_Seek( file, cdx, SEEK_SET );
- xmpCDHeader.read( file );
-
- XMP_Validate( xmpFilenameLen == GetUns16LE( &xmpCDHeader.fields[CDFileHeader::o_fileNameLength]),
- "content file length not ok", kXMPErr_BadFileFormat );
-
- XMP_Uns16 CD_compression = GetUns16LE( &xmpCDHeader.fields[CDFileHeader::o_compression] );
- XMP_Validate(( CD_compression == 0 || CD_compression == 0x08),
- "illegal compression, must be flate or none", kXMPErr_BadFileFormat );
- XMP_Uns16 CD_flags = GetUns16LE( &xmpCDHeader.fields[CDFileHeader::o_flags] );
- XMP_Uns32 CD_crc = GetUns32LE( &xmpCDHeader.fields[CDFileHeader::o_crc32] );
-
- // parse (actual, non-CD!) file header ////////////////////////////////////////////////
- x = xmpCDHeader.offsetLocalHeader;
- LFA_Seek( file , x ,SEEK_SET);
- xmpFileHeader.read( file );
- xl = xmpFileHeader.sizeHeader() + xmpCDHeader.sizeCompressed;
-
- //values needed
- XMP_Uns16 fileNameLength = GetUns16LE( &xmpFileHeader.fields[FileHeader::o_fileNameLength] );
- XMP_Uns16 extraFieldLength = GetUns16LE( &xmpFileHeader.fields[FileHeader::o_extraFieldLength] );
- XMP_Uns16 compression = GetUns16LE( &xmpFileHeader.fields[FileHeader::o_compression] );
- XMP_Uns32 sig = GetUns32LE( &xmpFileHeader.fields[FileHeader::o_sig] );
- XMP_Uns16 flags = GetUns16LE( &xmpFileHeader.fields[FileHeader::o_flags] );
- XMP_Uns32 sizeCompressed = GetUns32LE( &xmpFileHeader.fields[FileHeader::o_sizeCompressed] );
- XMP_Uns32 sizeUncompressed = GetUns32LE( &xmpFileHeader.fields[FileHeader::o_sizeUncompressed] );
- XMP_Uns32 crc = GetUns32LE( &xmpFileHeader.fields[FileHeader::o_crc32] );
-
- // check filename
- XMP_Validate( fileNameLength == 21, "filename size contradiction" , kXMPErr_BadFileFormat );
- XMP_Enforce ( xmpFileHeader.filename != 0 );
- XMP_Validate( !memcmp( "META-INF/metadata.xml", xmpFileHeader.filename , xmpFilenameLen ) , "filename is cf header is not META-INF/metadata.xml" , kXMPErr_BadFileFormat );
-
- // deal with data descriptor if needed
- if ( flags & FileHeader::kdataDescriptorFlag )
- {
- if ( sizeCompressed!=0 || sizeUncompressed!=0 || crc!=0 ) XMP_Throw("data descriptor must mean 3x zero",kXMPErr_BadFileFormat);
- LFA_Seek( file, xmpCDHeader.sizeCompressed + fileNameLength + xmpCDHeader.extraFieldLen, SEEK_CUR); //skip actual data to get to descriptor
- crc = LFA_ReadUns32_LE( file );
- if ( crc == 0x08074b50 ) //data descriptor may or may not have signature (see spec)
- {
- crc = LFA_ReadUns32_LE( file ); //if it does, re-read
- }
- sizeCompressed = LFA_ReadUns32_LE( file );
- sizeUncompressed = LFA_ReadUns32_LE( file );
- // *** cater for zip64 plus 'streamed' data-descriptor stuff
- }
-
- // more integrity checks (post data descriptor handling)
- if ( sig != 0x04034b50 ) XMP_Throw("invalid content file header",kXMPErr_BadFileFormat);
- if ( compression != CD_compression ) XMP_Throw("compression contradiction",kXMPErr_BadFileFormat);
- if ( sizeUncompressed != xmpCDHeader.sizeUncompressed ) XMP_Throw("contradicting uncompressed lengths",kXMPErr_BadFileFormat);
- if ( sizeCompressed != xmpCDHeader.sizeCompressed ) XMP_Throw("contradicting compressed lengths",kXMPErr_BadFileFormat);
- if ( sizeUncompressed == 0 ) XMP_Throw("0-byte uncompressed size", kXMPErr_BadFileFormat );
-
- ////////////////////////////////////////////////////////////////////
- // packet Info
- this->packetInfo.charForm = stdCharForm;
- this->packetInfo.writeable = false;
- this->packetInfo.offset = kXMPFiles_UnknownOffset; // checksum!, hide position to not give funny ideas
- this->packetInfo.length = kXMPFiles_UnknownLength;
-
- ////////////////////////////////////////////////////////////////////
- // prepare packet (compressed or not)
- this->xmpPacket.erase();
- this->xmpPacket.reserve( sizeUncompressed );
- this->xmpPacket.append( sizeUncompressed, ' ' );
- XMP_StringPtr packetStr = XMP_StringPtr ( xmpPacket.c_str() ); // only set after reserving the space!
-
- // go to packet offset
- LFA_Seek ( file, x + xmpFileHeader.FIXED_SIZE + fileNameLength + extraFieldLength , SEEK_SET);
-
- // compression fork --------------------------------------------------
- switch (compression)
- {
- case 0x8: // FLATE
- {
- wasCompressed = true;
- XMP_Uns32 bytesRead = 0;
- XMP_Uns32 bytesWritten = 0; // for writing into packetString
- const unsigned int CHUNK = 16384;
-
- int ret;
- unsigned int have; //added type
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- // does need this intermediate stage, no direct compressio to packetStr possible,
- // since also partially filled buffers must be picked up. That's how it works.
- // in addition: internal zlib variables might have 16 bit limits...
-
- /* allocate inflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
-
- /* must use windowBits = -15, for raw inflate, no zlib header */
- ret = inflateInit2(&strm,-MAX_WBITS);
-
- if (ret != Z_OK)
- XMP_Throw("zlib error ",kXMPErr_ExternalFailure);
-
- /* decompress until deflate stream ends or end of file */
- do {
- // must take care here not to read too much, thus whichever is smaller:
- XMP_Int32 bytesRemaining = sizeCompressed - bytesRead;
- if ( (XMP_Int32)CHUNK < bytesRemaining ) bytesRemaining = (XMP_Int32)CHUNK;
- strm.avail_in=LFA_Read( file , in , bytesRemaining , true );
- bytesRead += strm.avail_in; // NB: avail_in is "unsigned_int", so might be 16 bit (not harmfull)
-
- if (strm.avail_in == 0) break;
- strm.next_in = in;
-
- do {
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = inflate(&strm, Z_NO_FLUSH);
- XMP_Assert( ret != Z_STREAM_ERROR ); /* state not clobbered */
- switch (ret)
- {
- case Z_NEED_DICT:
- (void)inflateEnd(&strm);
- XMP_Throw("zlib error: Z_NEED_DICT",kXMPErr_ExternalFailure);
- case Z_DATA_ERROR:
- (void)inflateEnd(&strm);
- XMP_Throw("zlib error: Z_DATA_ERROR",kXMPErr_ExternalFailure);
- case Z_MEM_ERROR:
- (void)inflateEnd(&strm);
- XMP_Throw("zlib error: Z_MEM_ERROR",kXMPErr_ExternalFailure);
- }
-
- have = CHUNK - strm.avail_out;
- memcpy( (unsigned char*) packetStr + bytesWritten , out , have );
- bytesWritten += have;
-
- } while (strm.avail_out == 0);
-
- /* it's done when inflate() says it's done */
- } while (ret != Z_STREAM_END);
-
- /* clean up and return */
- (void)inflateEnd(&strm);
- if (ret != Z_STREAM_END)
- XMP_Throw("zlib error ",kXMPErr_ExternalFailure);
- break;
- }
- case 0x0: // no compression - read directly into the right place
- {
- wasCompressed = false;
- XMP_Enforce( LFA_Read ( file, (char*)packetStr, sizeUncompressed, kLFA_RequireAll ) );
- 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
-}
-
-
-// =================================================================================================
-// UCF_MetaHandler::ProcessXMP
-// ============================
-
-void UCF_MetaHandler::ProcessXMP()
-{
- // we have no legacy, CacheFileData did all that was needed
- // ==> default implementation is fine
- XMPFileHandler::ProcessXMP();
-}
-
-// =================================================================================================
-// UCF_MetaHandler::UpdateFile
-// =============================
-
-// TODO: xmp packet with data descriptor
-
-void UCF_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- //sanity
- XMP_Enforce( (x!=0) == (cdx!=0) );
- if (!cdx)
- xmpCDHeader.setXMPFilename(); //if new, set filename (impacts length, thus before computation)
- if ( ! this->needsUpdate )
- return;
-
- // ***
- if ( doSafeUpdate ) XMP_Throw ( "UCF_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
-
- LFA_FileRef file = this->parent->fileRef;
-
- // final may mean compressed or not, whatever is to-be-embedded
- uncomprPacketStr = xmpPacket.c_str();
- uncomprPacketLen = (XMP_StringLen) xmpPacket.size();
- finalPacketStr = uncomprPacketStr; // will be overriden if compressedXMP==true
- finalPacketLen = uncomprPacketLen;
- std::string compressedPacket; // moot if non-compressed, still here for scope reasons (having to keep a .c_str() alive)
-
- if ( !x ) // if new XMP...
- {
- xmpFileHeader.clear();
- xmpFileHeader.setXMPFilename();
- // ZIP64 TODO: extra Fields, impact on cdxl2 and x2l
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // COMPRESSION DECISION
-
- // for large files compression is bad:
- // a) size of XMP becomes irrelevant on large files ==> why worry over compression ?
- // b) more importantly: no such thing as padding possible, compression == ever changing sizes
- // => never in-place rewrites, *ugly* performance impact on large files
- inPlacePossible = false; //assume for now
-
- if ( !x ) // no prior XMP? -> decide on filesize
- compressXMP = ( fl > 1024*50 /* 100 kB */ ) ? false : true;
- else
- compressXMP = wasCompressed; // don't change a thing
-
- if ( !wasCompressed && !compressXMP &&
- ( GetUns32LE( &xmpFileHeader.fields[FileHeader::o_sizeUncompressed] ) == uncomprPacketLen ))
- {
- inPlacePossible = true;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // COMPRESS XMP
- if ( compressXMP )
- {
- const unsigned int CHUNK = 16384;
- int ret, flush;
- unsigned int have;
- z_stream strm;
- unsigned char out[CHUNK];
-
- /* allocate deflate state */
- strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL;
- if ( deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8 /*memlevel*/, Z_DEFAULT_STRATEGY) )
- XMP_Throw("zlib error ",kXMPErr_ExternalFailure);
-
- //write at once, since we got it in mem anyway:
- strm.avail_in = uncomprPacketLen;
- flush = Z_FINISH; // that's all, folks
- strm.next_in = (unsigned char*) uncomprPacketStr;
-
- do {
- strm.avail_out = CHUNK;
- strm.next_out = out;
-
- ret = deflate(&strm, flush); /* no bad return value (!=0 acceptable) */
- XMP_Enforce(ret != Z_STREAM_ERROR); /* state not clobbered */
- //fwrite(buffer,size,count,file)
- have = CHUNK - strm.avail_out;
- compressedPacket.append( (const char*) out, have);
- } while (strm.avail_out == 0);
-
- if (ret != Z_STREAM_END)
- XMP_Throw("zlib stream incomplete ",kXMPErr_ExternalFailure);
- XMP_Enforce(strm.avail_in == 0); // all input will be used
- (void)deflateEnd(&strm); //clean up (do prior to checks)
-
- finalPacketStr = compressedPacket.c_str();
- finalPacketLen = (XMP_StringLen)compressedPacket.size();
- }
-
- PutUns32LE ( uncomprPacketLen, &xmpFileHeader.fields[FileHeader::o_sizeUncompressed] );
- PutUns32LE ( finalPacketLen, &xmpFileHeader.fields[FileHeader::o_sizeCompressed] );
- PutUns16LE ( compressXMP ? 8:0, &xmpFileHeader.fields[FileHeader::o_compression] );
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // CRC (always of uncompressed data)
- XMP_Uns32 crc = crc32( 0 , (Bytef*)uncomprPacketStr, uncomprPacketLen );
- PutUns32LE( crc, &xmpFileHeader.fields[FileHeader::o_crc32] );
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // TIME calculation for timestamp
- // will be applied both to xmp content file and CD header
- XMP_Uns16 lastModTime, lastModDate;
- XMP_DateTime time;
- SXMPUtils::CurrentDateTime( &time );
-
- if ( (time.year - 1900) < 80)
- {
- lastModTime = 0; // 1.1.1980 00:00h
- lastModDate = 21;
- }
-
- // typedef unsigned short ush; //2 bytes
- lastModDate = (XMP_Uns16) (((time.year) - 1980 ) << 9 | ((time.month) << 5) | time.day);
- lastModTime = ((XMP_Uns16)time.hour << 11) | ((XMP_Uns16)time.minute << 5) | ((XMP_Uns16)time.second >> 1);
-
- PutUns16LE ( lastModDate, &xmpFileHeader.fields[FileHeader::o_lastmodDate] );
- PutUns16LE ( lastModTime, &xmpFileHeader.fields[FileHeader::o_lastmodTime] );
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // adjustments depending on 4GB Border,
- // decisions on in-place update
- // so far only z, zl have been determined
-
- // Zip64 related assurances, see (15)
- XMP_Enforce(!z2);
- XMP_Enforce(h+hl == fl );
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // COMPUTE MISSING VARIABLES
- // A - based on xmp existence
- //
- // already known: x, xl, cd
- // most left side vars,
- //
- // finalPacketStr, finalPacketLen
-
- if ( x ) // previous xmp?
- {
- al = x;
- b = x + xl;
- bl = cd - b;
- }
- else
- {
- al = cd;
- //b,bl left at zero
- }
-
- if ( inPlacePossible )
- { // leave xmp right after A
- x2 = al;
- x2l = xmpFileHeader.sizeTotalCF(); //COULDDO: assert (x2l == xl)
- if (b) b2 = x2 + x2l; // b follows x as last content part
- cd2 = b2 + bl; // CD follows B2
- }
- else
- { // move xmp to end
- if (b) b2 = al; // b follows
- // x follows as last content part (B existing or not)
- x2 = al + bl;
- x2l = xmpFileHeader.sizeTotalCF();
- cd2 = x2 + x2l; // CD follows X
- }
-
- /// create new XMP header ///////////////////////////////////////////////////
- // written into actual fields + generation of extraField at .write()-time...
- // however has impact on .size() computation -- thus enter before cdx2l computation
- xmpCDHeader.sizeUncompressed = uncomprPacketLen;
- xmpCDHeader.sizeCompressed = finalPacketLen;
- xmpCDHeader.offsetLocalHeader = x2;
- PutUns32LE ( crc, &xmpCDHeader.fields[CDFileHeader::o_crc32] );
- PutUns16LE ( compressXMP ? 8:0, &xmpCDHeader.fields[CDFileHeader::o_compression] );
- PutUns16LE ( lastModDate, &xmpCDHeader.fields[CDFileHeader::o_lastmodDate] );
- PutUns16LE ( lastModTime, &xmpCDHeader.fields[CDFileHeader::o_lastmodTime] );
-
- // for
- if ( inPlacePossible )
- {
- cdx2 = cdx; //same, same
- writeOut( file, file, false, true );
- return;
- }
-
- ////////////////////////////////////////////////////////////////////////
- // temporarily store (those few, small) trailing things that might not survive the move around:
- LFA_Seek(file, cd, SEEK_SET); // seek to central directory
- cdEntries.clear(); //mac precaution
-
- //////////////////////////////////////////////////////////////////////////////
- // parse headers
- // * stick together output header list
- cd2l = 0; //sum up below
-
- CDFileHeader tempHeader;
- for( XMP_Uns16 pos=1 ; pos <= numCF ; pos++ )
- {
- if ( (cdx) && (LFA_Tell( file ) == cdx) )
- {
- tempHeader.read( file ); //read, even if not use, to advance file pointer
- }
- else
- {
- tempHeader.read( file );
- // adjust b2 offset for files that were behind the xmp:
- // may (if xmp moved to back)
- // or may not (inPlace Update) make a difference
- if ( (x) && ( tempHeader.offsetLocalHeader > x) ) // if xmp existed before and this was a file behind it
- tempHeader.offsetLocalHeader += b2 - b;
- cd2l += tempHeader.size(); // prior offset change might have impact
- cdEntries.push_back( tempHeader );
- }
- }
-
- //push in XMP packet as last one (new or not)
- cdEntries.push_back( xmpCDHeader );
- cdx2l = xmpCDHeader.size();
- cd2l += cdx2l; // true, no matter which order
-
- //OLD cd2l = : cdl - cdxl + cdx2l; // (NB: cdxl might be 0)
- numCF2 = numCF + ( (cdx)?0:1 ); //xmp packet for the first time? -> add one more CF
-
- XMP_Validate( numCF2 > 0, "no content files", kXMPErr_BadFileFormat );
- XMP_Validate( numCF2 <= 0xFFFE, "max number of 0xFFFE entries reached", kXMPErr_BadFileFormat );
-
- cdx2 = cd2 + cd2l - cdx2l; // xmp content entry comes last (since beyond inPlace Update)
-
- // zip64 decision
- if ( ( cd2 + cd2l + hl ) > 0xffffffff ) // predict non-zip size ==> do we need a zip-64?
- {
- z2 = cd2 + cd2l;
- z2l = Zip64EndOfDirectory::FIXED_SIZE + Zip64Locator::TOTAL_SIZE;
- }
-
- // header and output length,
- h2 = cd2 + cd2l + z2l; // (z2l might be 0)
- f2l = h2 + hl;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // read H (endOfCD), correct offset
- LFA_Seek(file, h, SEEK_SET);
-
- endOfCD.read( file );
- if ( cd2 <= 0xffffffff )
- PutUns32LE( (XMP_Int32) cd2 , &endOfCD.fields[ endOfCD.o_CdOffset ] );
- else
- PutUns32LE( 0xffffffff , &endOfCD.fields[ endOfCD.o_CdOffset ] );
- PutUns16LE( numCF2, &endOfCD.fields[ endOfCD.o_CdNumEntriesDisk ] );
- PutUns16LE( numCF2, &endOfCD.fields[ endOfCD.o_CdNumEntriesTotal ] );
-
- XMP_Enforce( cd2l <= 0xffffffff ); // _size_ of directory itself certainly under 4GB
- PutUns32LE( (XMP_Uns32)cd2l, &endOfCD.fields[ endOfCD.o_CdSize ] );
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // MOVING
- writeOut( file, file, false, false );
-
- this->needsUpdate = false; //do last for safety reasons
-} // UCF_MetaHandler::UpdateFile
-
-// =================================================================================================
-// UCF_MetaHandler::WriteFile
-// ============================
-void UCF_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
- IgnoreParam ( sourcePath );
- XMP_Throw ( "UCF_MetaHandler::WriteFile: TO BE IMPLEMENTED", kXMPErr_Unimplemented );
-}
-
-// =================================================================================================
-// own approach to unify Update and WriteFile:
-// ============================
-
-void UCF_MetaHandler::writeOut( LFA_FileRef sourceFile, LFA_FileRef targetFile, bool isRewrite, bool isInPlace)
-{
- // isInPlace is only possible when it's not a complete rewrite
- XMP_Enforce( (!isInPlace) || (!isRewrite) );
-
- /////////////////////////////////////////////////////////
- // A
- if (isRewrite) //move over A block
- LFA_Move( sourceFile , 0 , targetFile, 0 , al );
-
- /////////////////////////////////////////////////////////
- // B / X (not necessarily in this order)
- if ( !isInPlace ) // B does not change a thing (important optimization)
- {
- LFA_Seek( targetFile , b2 , SEEK_SET );
- LFA_Move( sourceFile , b , targetFile, b2 , bl );
- }
-
- LFA_Seek( targetFile , x2 , SEEK_SET );
- xmpFileHeader.write( targetFile );
- LFA_Write( targetFile, finalPacketStr, finalPacketLen );
- //TODO: cover reverse case / inplace ...
-
- /////////////////////////////////////////////////////////
- // CD
- // No Seek here on purpose.
- // This assert must still be valid
-
- // if inPlace, the only thing that needs still correction is the CRC in CDX:
- if ( isInPlace )
- {
- XMP_Uns32 crc; //TEMP, not actually needed
- crc = GetUns32LE( &xmpFileHeader.fields[FileHeader::o_crc32] );
-
- // go there,
- // do the job (take value directly from (non-CD-)fileheader),
- // end of story.
- LFA_Seek( targetFile , cdx2 + CDFileHeader::o_crc32 , SEEK_SET );
- LFA_Write( targetFile, &xmpFileHeader.fields[FileHeader::o_crc32], 4);
-
- return;
- }
-
- LFA_Seek( targetFile , cd2 , SEEK_SET );
-
- std::vector<CDFileHeader>::iterator iter;
- int tmptmp=1;
- for( iter = cdEntries.begin(); iter != cdEntries.end(); iter++ ) {
- CDFileHeader* p=&(*iter);
- XMP_Int64 before = LFA_Tell(targetFile);
- p->write( targetFile );
- XMP_Int64 total = LFA_Tell(targetFile) - before;
- XMP_Int64 tmpSize = p->size();
- tmptmp++;
- }
-
- /////////////////////////////////////////////////////////
- // Z
- if ( z2 ) // yes, that simple
- {
- XMP_Assert( z2 == LFA_Tell(targetFile));
- LFA_Seek( targetFile , z2 , SEEK_SET );
-
- //no use in copying, always construct from scratch
- Zip64EndOfDirectory zip64EndOfDirectory( cd2, cd2l, numCF2) ;
- Zip64Locator zip64Locator( z2 );
-
- zip64EndOfDirectory.write( targetFile );
- zip64Locator.write( targetFile );
- }
-
- /////////////////////////////////////////////////////////
- // H
- XMP_Assert( h2 == LFA_Tell(targetFile));
- endOfCD.write( targetFile );
-
- XMP_Assert( f2l == LFA_Tell(targetFile));
- if ( f2l< fl)
- LFA_Truncate(targetFile,f2l); //file may have shrunk
-}
-
-
diff --git a/source/XMPFiles/FileHandlers/UCF_Handler.hpp b/source/XMPFiles/FileHandlers/UCF_Handler.hpp
deleted file mode 100644
index 2f9af5e..0000000
--- a/source/XMPFiles/FileHandlers/UCF_Handler.hpp
+++ /dev/null
@@ -1,716 +0,0 @@
-#ifndef __UCF_Handler_hpp__
-#define __UCF_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMPFiles_Impl.hpp"
-
-// =================================================================================================
-/// \file UCF_Handler.hpp
-//
-// underlying math:
-// __ 0 ______ 0 ______ __
-// | A | | A |
-// | | | |
-// al | | (a2l)| |
-// x |------| b2 |------|
-// xl | X | | B |_
-// b |------| (b2l)| | |
-// | B | x2 |------| | B2 could also be
-// bl | | x2l | X2 | | _after_ X2
-// cd |------| cd2 |------|<'
-// |//CD//| |//CD2/|
-// cdx |------| cdx2 |------|
-// cdxl|------| cdx2l|------|
-// cdl|//////| cd2l|//////|
-// z |------| z2|------|
-// | | | |
-// [zl]| Z | z2l | Z2 |
-// h |------| h2 |------|
-// fl | H | | H2 | f2l
-// __ hl |______| (h2l)|______| __
-//
-// fl file length pre (2 = post)
-// numCf number of content files prior to injection
-// numCf2 " post
-//
-//
-// l length variable, all else offset
-// [ ] variable is not needed
-// ( ) variable is identical to left
-// a content files prior to xmp (possibly: all)
-// b content files behind xmp (possibly: 0)
-// x xmp packet (possibly: 0)
-// cd central directory
-// h end of central directory
-//
-// z zip64 record and locator (if existing)
-//
-// general rules:
-// the bigger A, the less rewrite effort.
-// (also within the CD)
-// putting XMP at the end maximizes A.
-//
-// bool previousXMP == x!=0
-//
-// (x==0) == (cdx==0) == (xl==0) == (cdxl==0)
-//
-// std::vector<XMP_Uns32> cdOffsetsPre;
-//
-// -----------------
-// asserts:
-//( 1) a == a2 == 0, making these variables obsolete
-//( 2) a2l == al, this block is not touched
-//( 3) b2 <= b, b is only moved closer to the beginning of file
-//( 4) b2l == bl, b does not change in size
-//( 5) x2 >= x, b is only moved further down in the file
-//
-//( 6) x != 0, x2l != 0, cd != 0, cdl != 0
-// none of these blocks is at the beginning ('mimetype' by spec),
-// nor is any of them zero byte long
-//( 7) h!=0, hl >= 22 header is not at the beginning, minimum size 22
-//
-// file size computation:
-//( 8) al + bl + xl +cdl +hl = fl
-//( 9) al + bl + x2l+cd2l+hl = fl2
-//
-//(10) ( x==0 ) <=> ( cdx == 0 )
-// if there's a packet in the pre-file, or there isn't
-//(11) (x==0) => xl=0
-//(12) (cdx==0)=> cdx=0
-//
-//(13) x==0 ==> b,bl,b2,b2l==0
-// if there is no pre-xmp, B does not exist
-//(14) x!=0 ==> al:=x, b:=x+xl, bl:=cd-b
-//
-// zip 64:
-//(15) zl and z2l are basically equal, except _one_ of them is 0 :
-//
-//(16) b2l is indeed never different t
-//
-// FIXED_SIZE means the fixed (minimal) portion of a struct
-// TOTAL_SIZE indicates, that this struct indeed has a fixed, known total length
-//
-// =================================================================================================
-
-extern XMPFileHandler* UCF_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool UCF_CheckFormat ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-static const XMP_OptionBits kUCF_HandlerFlags = (
- kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- /* kXMPFiles_PrefersInPlace | removed, only reasonable for formats where difference is significant */
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- // *** kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_NeedsReadOnlyPacket //UCF/zip has checksums...
- );
-
-enum { // data descriptor
- // may or may not have a signature: 0x08074b50
- kUCF_DD_crc32 = 0,
- kUCF_DD_sizeCompressed = 4,
- kUCF_DD_sizeUncompressed = 8,
-};
-
-class UCF_MetaHandler : public XMPFileHandler
-{
-public:
- UCF_MetaHandler ( XMPFiles * _parent );
- ~UCF_MetaHandler();
-
- void CacheFileData();
- void ProcessXMP();
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
-protected:
- const static XMP_Uns16 xmpFilenameLen = 21;
- const static char* xmpFilename;
-
-private:
- class Zip64EndOfDirectory {
- private:
-
- public:
- const static XMP_Uns16 o_sig = 0; // 0x06064b50
- const static XMP_Uns16 o_size = 4; // of this, excluding leading 12 bytes
- // == FIXED_SIZE -12, since we're never creating the extensible data sector...
- const static XMP_Uns16 o_VersionMade = 12;
- const static XMP_Uns16 o_VersionNeededExtr = 14;
- const static XMP_Uns16 o_numDisk = 16; // force 0
- const static XMP_Uns16 o_numCDDisk = 20; // force 0
- const static XMP_Uns16 o_numCFsThisDisk = 24;
- const static XMP_Uns16 o_numCFsTotal = 32; // force equal
- const static XMP_Uns16 o_sizeOfCD = 40; // (regular one, not Z64)
- const static XMP_Uns16 o_offsetCD = 48; // "
-
- const static XMP_Int32 FIXED_SIZE = 56;
- char fields[FIXED_SIZE];
-
- const static XMP_Uns32 ID = 0x06064b50;
-
- Zip64EndOfDirectory( XMP_Int64 offsetCD, XMP_Int64 sizeOfCD, XMP_Uns64 numCFs )
- {
- memset(fields,'\0',FIXED_SIZE);
-
- PutUns32LE(ID ,&fields[o_sig] );
- PutUns64LE(FIXED_SIZE - 12, &fields[o_size] ); //see above
- PutUns16LE( 45 ,&fields[o_VersionMade] );
- PutUns16LE( 45 ,&fields[o_VersionNeededExtr] );
- // fine at 0: o_numDisk
- // fine at 0: o_numCDDisk
- PutUns64LE( numCFs, &fields[o_numCFsThisDisk] );
- PutUns64LE( numCFs, &fields[o_numCFsTotal] );
- PutUns64LE( sizeOfCD, &fields[o_sizeOfCD] );
- PutUns64LE( offsetCD, &fields[o_offsetCD] );
- }
-
- void write(LFA_FileRef file)
- {
- XMP_Validate( ID == GetUns32LE( &this->fields[o_sig] ), "invalid header on write", kXMPErr_BadFileFormat );
- LFA_Write( file , fields , FIXED_SIZE );
- }
-
- };
-
- class Zip64Locator {
- public:
- const static XMP_Uns16 o_sig = 0; // 0x07064b50
- const static XMP_Uns16 o_numDiskZ64CD = 4; // force 0
- const static XMP_Uns16 o_offsZ64EOD = 8;
- const static XMP_Uns16 o_numDisks = 16; // set 1, tolerate 0
-
- const static XMP_Int32 TOTAL_SIZE = 20;
- char fields[TOTAL_SIZE];
-
- const static XMP_Uns32 ID = 0x07064b50;
-
- Zip64Locator( XMP_Int64 offsetZ64EOD )
- {
- memset(fields,'\0',TOTAL_SIZE);
- PutUns32LE(ID, &fields[Zip64Locator::o_sig] );
- PutUns32LE(0, &fields[Zip64Locator::o_numDiskZ64CD] );
- PutUns64LE(offsetZ64EOD, &fields[Zip64Locator::o_offsZ64EOD] );
- PutUns32LE(1, &fields[Zip64Locator::o_numDisks] );
- }
-
- // writes structure to file (starting at current position)
- void write(LFA_FileRef file)
- {
- XMP_Validate( ID == GetUns32LE( &this->fields[o_sig] ), "invalid header on write", kXMPErr_BadFileFormat );
- LFA_Write( file , fields , TOTAL_SIZE );
- }
- };
-
- struct EndOfDirectory {
- public:
- const static XMP_Int32 FIXED_SIZE = 22; //32 bit type is important to not overrun on maxcomment
- const static XMP_Uns32 ID = 0x06054b50;
- const static XMP_Int32 COMMENT_MAX = 0xFFFF;
- //offsets
- const static XMP_Int32 o_CentralDirectorySize = 12;
- const static XMP_Int32 o_CentralDirectoryOffset = 16;
- };
-
- class FileHeader {
- private:
- //TODO intergrate in clear()
- void release() // avoid terminus free() since subject to a #define (mem-leak-check)
- {
- if (filename) delete filename;
- if (extraField) delete extraField;
- filename=0;
- extraField=0;
- }
-
- public:
- const static XMP_Uns32 SIG = 0x04034b50;
- const static XMP_Uns16 kdataDescriptorFlag = 0x8;
-
- const static XMP_Uns16 o_sig = 0;
- const static XMP_Uns16 o_extractVersion = 4;
- const static XMP_Uns16 o_flags = 6;
- const static XMP_Uns16 o_compression = 8;
- const static XMP_Uns16 o_lastmodTime = 10;
- const static XMP_Uns16 o_lastmodDate = 12;
- const static XMP_Uns16 o_crc32 = 14;
- const static XMP_Uns16 o_sizeCompressed = 18;
- const static XMP_Uns16 o_sizeUncompressed = 22;
- const static XMP_Uns16 o_fileNameLength = 26;
- const static XMP_Uns16 o_extraFieldLength = 28;
- // total 30
-
- const static int FIXED_SIZE = 30;
- char fields[FIXED_SIZE];
-
- char* filename;
- char* extraField;
- XMP_Uns16 filenameLen;
- XMP_Uns16 extraFieldLen;
-
- void clear()
- {
- this->release();
- memset(fields,'\0',FIXED_SIZE);
- //arm with minimal default values:
- PutUns32LE(0x04034b50, &fields[FileHeader::o_sig] );
- PutUns16LE(0x14, &fields[FileHeader::o_extractVersion] );
- }
-
- FileHeader() : filename(0),filenameLen(0),extraField(0),extraFieldLen(0)
- {
- clear();
- };
-
- // reads entire *FileHeader* structure from file (starting at current position)
- void read(LFA_FileRef file)
- {
- this->release();
-
- LFA_Read( file , fields , FIXED_SIZE , true );
-
- XMP_Uns32 tmp32 = GetUns32LE( &this->fields[FileHeader::o_sig] );
- XMP_Validate( SIG == tmp32, "invalid header", kXMPErr_BadFileFormat );
- filenameLen = GetUns16LE( &this->fields[FileHeader::o_fileNameLength] );
- extraFieldLen = GetUns16LE( &this->fields[FileHeader::o_extraFieldLength] );
-
- // nb unlike the CDFileHeader the FileHeader will in practice never have
- // extra fields. Reasoning: File headers never carry (their own) offsets,
- // (un)compressed size of XMP will hardly ever reach 4 GB
-
- if (filenameLen) {
- filename = new char[filenameLen];
- LFA_Read(file,filename,filenameLen,true);
- }
- if (extraFieldLen) {
- extraField = new char[extraFieldLen];
- LFA_Read(file,extraField,extraFieldLen,true);
- // *** NB: this WOULD need parsing for content files that are
- // compressed or uncompressed >4GB (VERY unlikely for XMP)
- }
- }
-
- // writes structure to file (starting at current position)
- void write(LFA_FileRef file)
- {
- XMP_Validate( SIG == GetUns32LE( &this->fields[FileHeader::o_sig] ), "invalid header on write", kXMPErr_BadFileFormat );
-
- filenameLen = GetUns16LE( &this->fields[FileHeader::o_fileNameLength] );
- extraFieldLen = GetUns16LE( &this->fields[FileHeader::o_extraFieldLength] );
-
- LFA_Write( file , fields , FIXED_SIZE );
- if (filenameLen) LFA_Write( file, filename, filenameLen );
- if (extraFieldLen) LFA_Write( file, extraField,extraFieldLen );
- }
-
- void transfer(const FileHeader &orig)
- {
- memcpy(fields,orig.fields,FIXED_SIZE);
- if (orig.extraField)
- {
- extraFieldLen=orig.extraFieldLen;
- extraField = new char[extraFieldLen];
- memcpy(extraField,orig.extraField,extraFieldLen);
- }
- if (orig.filename)
- {
- filenameLen=orig.filenameLen;
- filename = new char[filenameLen];
- memcpy(filename,orig.filename,filenameLen);
- }
- };
-
- void setXMPFilename()
- {
- // only needed for fresh structs, thus enforcing rather than catering to memory issues
- XMP_Enforce( (filenameLen==0) && (extraFieldLen == 0) );
- filenameLen = xmpFilenameLen;
- PutUns16LE(filenameLen, &fields[FileHeader::o_fileNameLength] );
- filename = new char[xmpFilenameLen];
- memcpy(filename,"META-INF/metadata.xml",xmpFilenameLen);
- }
-
- XMP_Uns32 sizeHeader()
- {
- return this->FIXED_SIZE + this->filenameLen + this->extraFieldLen;
- }
-
- XMP_Uns32 sizeTotalCF()
- {
- //*** not zip64 bit safe yet, use only for non-large xmp packet
- return this->sizeHeader() + GetUns32LE( &fields[FileHeader::o_sizeCompressed] );
- }
-
- ~FileHeader()
- {
- this->release();
- };
-
- }; //class FileHeader
-
- ////// yes, this needs an own class
- ////// offsets must be extracted, added, modified,
- ////// come&go depending on being >0xffffff
- ////class extraField {
- //// private:
-
-
- class CDFileHeader {
- private:
- void release() //*** needed or can go?
- {
- if (filename) delete filename;
- if (extraField) delete extraField;
- if (comment) delete comment;
- filename=0; filenameLen=0;
- extraField=0; extraFieldLen=0;
- comment=0; commentLen=0;
- }
-
- const static XMP_Uns32 SIG = 0x02014b50;
-
- public:
- const static XMP_Uns16 o_sig = 0; //0x02014b50
- const static XMP_Uns16 o_versionMadeBy = 4;
- const static XMP_Uns16 o_extractVersion = 6;
- const static XMP_Uns16 o_flags = 8;
- const static XMP_Uns16 o_compression = 10;
- const static XMP_Uns16 o_lastmodTime = 12;
- const static XMP_Uns16 o_lastmodDate = 14;
- const static XMP_Uns16 o_crc32 = 16;
- const static XMP_Uns16 o_sizeCompressed = 20; // 16bit stub
- const static XMP_Uns16 o_sizeUncompressed = 24; // 16bit stub
- const static XMP_Uns16 o_fileNameLength = 28;
- const static XMP_Uns16 o_extraFieldLength = 30;
- const static XMP_Uns16 o_commentLength = 32;
- const static XMP_Uns16 o_diskNo = 34;
- const static XMP_Uns16 o_internalAttribs = 36;
- const static XMP_Uns16 o_externalAttribs = 38;
- const static XMP_Uns16 o_offsetLocalHeader = 42; // 16bit stub
- // total size is 4+12+12+10+8=46
-
- const static int FIXED_SIZE = 46;
- char fields[FIXED_SIZE];
-
- // do not bet on any zero-freeness,
- // certainly no zero termination (pascal strings),
- // treat as data blocks
- char* filename;
- char* extraField;
- char* comment;
- XMP_Uns16 filenameLen;
- XMP_Uns16 extraFieldLen;
- XMP_Uns16 commentLen;
-
- // full, real, parsed 64 bit values
- XMP_Int64 sizeUncompressed;
- XMP_Int64 sizeCompressed;
- XMP_Int64 offsetLocalHeader;
-
- CDFileHeader() : filename(0),extraField(0),comment(0),filenameLen(0),
- extraFieldLen(0),commentLen(0),sizeUncompressed(0),sizeCompressed(0),offsetLocalHeader(0)
- {
- memset(fields,'\0',FIXED_SIZE);
- //already arm with appropriate values where applicable:
- PutUns32LE(0x02014b50, &fields[CDFileHeader::o_sig] );
- PutUns16LE(0x14, &fields[CDFileHeader::o_extractVersion] );
- };
-
- // copy constructor
- CDFileHeader(const CDFileHeader& orig) : filename(0),extraField(0),comment(0),filenameLen(0),
- extraFieldLen(0),commentLen(0),sizeUncompressed(0),sizeCompressed(0),offsetLocalHeader(0)
- {
- memcpy(fields,orig.fields,FIXED_SIZE);
- if (orig.extraField)
- {
- extraFieldLen=orig.extraFieldLen;
- extraField = new char[extraFieldLen];
- memcpy(extraField , orig.extraField , extraFieldLen);
- }
- if (orig.filename)
- {
- filenameLen=orig.filenameLen;
- filename = new char[filenameLen];
- memcpy(filename , orig.filename , filenameLen);
- }
- if (orig.comment)
- {
- commentLen=orig.commentLen;
- comment = new char[commentLen];
- memcpy(comment , orig.comment , commentLen);
- }
-
- filenameLen = orig.filenameLen;
- extraFieldLen = orig.extraFieldLen;
- commentLen = orig.commentLen;
-
- sizeUncompressed = orig.sizeUncompressed;
- sizeCompressed = orig.sizeCompressed;
- offsetLocalHeader = orig.offsetLocalHeader;
- }
-
- // Assignment operator
- CDFileHeader& operator=(const CDFileHeader& obj)
- {
- XMP_Throw("not supported",kXMPErr_Unimplemented);
- }
-
- // reads entire structure from file (starting at current position)
- void read(LFA_FileRef file)
- {
- this->release();
-
- LFA_Read(file,fields,FIXED_SIZE,true);
- XMP_Validate( SIG == GetUns32LE( &this->fields[CDFileHeader::o_sig] ), "invalid header", kXMPErr_BadFileFormat );
-
- filenameLen = GetUns16LE( &this->fields[CDFileHeader::o_fileNameLength] );
- extraFieldLen = GetUns16LE( &this->fields[CDFileHeader::o_extraFieldLength] );
- commentLen = GetUns16LE( &this->fields[CDFileHeader::o_commentLength] );
-
- if (filenameLen) {
- filename = new char[filenameLen];
- LFA_Read(file,filename,filenameLen,true);
- }
- if (extraFieldLen) {
- extraField = new char[extraFieldLen];
- LFA_Read(file,extraField,extraFieldLen,true);
- }
- if (commentLen) {
- comment = new char[commentLen];
- LFA_Read(file,comment,commentLen,true);
- }
-
- ////// GET ACTUAL 64 BIT VALUES //////////////////////////////////////////////
- // get 32bit goodies first, correct later
- sizeUncompressed = GetUns32LE( &fields[o_sizeUncompressed] );
- sizeCompressed = GetUns32LE( &fields[o_sizeCompressed] );
- offsetLocalHeader = GetUns32LE( &fields[o_offsetLocalHeader] );
-
- XMP_Int32 offset = 0;
- while ( offset < extraFieldLen )
- {
- XMP_Validate( (extraFieldLen - offset) >= 4, "need 4 bytes for next header ID+len", kXMPErr_BadFileFormat);
- XMP_Uns16 headerID = GetUns16LE( &extraField[offset] );
- XMP_Uns16 dataSize = GetUns16LE( &extraField[offset+2] );
- offset += 4;
-
- XMP_Validate( (extraFieldLen - offset) <= dataSize,
- "actual field lenght not given", kXMPErr_BadFileFormat);
- if ( headerID == 0x1 ) //we only care about "Zip64 extended information extra field"
- {
- XMP_Validate( offset < extraFieldLen, "extra field too short", kXMPErr_BadFileFormat);
- if (sizeUncompressed == 0xffffffff)
- {
- sizeUncompressed = GetUns64LE( &extraField[offset] );
- offset += 8;
- }
- if (sizeCompressed == 0xffffffff)
- {
- sizeCompressed = GetUns64LE( &extraField[offset] );
- offset += 8;
- }
- if (offsetLocalHeader == 0xffffffff)
- {
- offsetLocalHeader = GetUns64LE( &extraField[offset] );
- offset += 8;
- }
- }
- else
- {
- offset += dataSize;
- } // if
- } // while
- } // read()
-
- // writes structure to file (starting at current position)
- void write(LFA_FileRef file)
- {
- //// 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;
-
- if ( ( sizeUncompressed > 0xffffffff ) ||
- ( sizeCompressed > 0xffffffff ) ||
- ( offsetLocalHeader > 0xffffffff ) )
- {
- extraField = new char[64]; // actual maxlen is 32
- extraFieldLen = 4; //first fields are for ID, size
- if ( sizeUncompressed > 0xffffffff )
- {
- PutUns64LE( sizeUncompressed, &extraField[extraFieldLen] );
- extraFieldLen += 8;
- sizeUncompressed = 0xffffffff;
- }
- if ( sizeCompressed > 0xffffffff )
- {
- PutUns64LE( sizeCompressed, &extraField[extraFieldLen] );
- extraFieldLen += 8;
- sizeCompressed = 0xffffffff;
- }
- if ( offsetLocalHeader > 0xffffffff )
- {
- PutUns64LE( offsetLocalHeader, &extraField[extraFieldLen] );
- extraFieldLen += 8;
- offsetLocalHeader = 0xffffffff;
- }
-
- //write ID, dataSize
- PutUns16LE( 0x0001, &extraField[0] );
- PutUns16LE( extraFieldLen-4, &extraField[2] );
- //extraFieldSize
- PutUns16LE( extraFieldLen, &this->fields[CDFileHeader::o_extraFieldLength] );
- }
-
- // write out 32-bit ('ff-stubs' or not)
- PutUns32LE( (XMP_Uns32)sizeUncompressed, &fields[o_sizeUncompressed] );
- PutUns32LE( (XMP_Uns32)sizeCompressed, &fields[o_sizeCompressed] );
- PutUns32LE( (XMP_Uns32)offsetLocalHeader, &fields[o_offsetLocalHeader] );
-
- /// WRITE /////////////////////////////////////////////////////////////////
- XMP_Enforce( SIG == GetUns32LE( &this->fields[CDFileHeader::o_sig] ) );
-
- LFA_Write( file , fields , FIXED_SIZE );
- if (filenameLen) LFA_Write( file, filename , filenameLen );
- if (extraFieldLen) LFA_Write( file, extraField , extraFieldLen );
- if (commentLen) LFA_Write( file, extraField , extraFieldLen );
- }
-
- void setXMPFilename()
- {
- if (filename) delete filename;
- filenameLen = xmpFilenameLen;
- filename = new char[xmpFilenameLen];
- PutUns16LE(filenameLen, &fields[CDFileHeader::o_fileNameLength] );
- memcpy(filename,"META-INF/metadata.xml",xmpFilenameLen);
- }
-
- XMP_Int64 size()
- {
- XMP_Int64 r = this->FIXED_SIZE + this->filenameLen + this->commentLen;
- // predict serialization size
- if ( (sizeUncompressed > 0xffffffff)||(sizeCompressed > 0xffffffff)||(offsetLocalHeader>0xffffffff) )
- {
- r += 4; //extra fields necessary
- if (sizeUncompressed > 0xffffffff) r += 8;
- if (sizeCompressed > 0xffffffff) r += 8;
- if (offsetLocalHeader > 0xffffffff) r += 8;
- }
- return r;
- }
-
- ~CDFileHeader()
- {
- this->release();
- };
- }; // class CDFileHeader
-
- class EndOfCD {
- private:
- const static XMP_Uns32 SIG = 0x06054b50;
- void UCFECD_Free()
- {
- if(commentLen) delete comment;
- commentLen = 0;
- }
- public:
- const static XMP_Int32 o_Sig = 0;
- const static XMP_Int32 o_CdNumEntriesDisk = 8; // same-same for UCF, since single-volume
- const static XMP_Int32 o_CdNumEntriesTotal = 10;// must update both
- const static XMP_Int32 o_CdSize = 12;
- const static XMP_Int32 o_CdOffset = 16;
- const static XMP_Int32 o_CommentLen = 20;
-
- const static int FIXED_SIZE = 22;
- char fields[FIXED_SIZE];
-
- char* comment;
- XMP_Uns16 commentLen;
-
- EndOfCD() : comment(0), commentLen(0)
- {
- //nothing
- };
-
- void read (LFA_FileRef file)
- {
- UCFECD_Free();
-
- LFA_Read(file,fields,FIXED_SIZE,true);
- XMP_Validate( this->SIG == GetUns32LE( &this->fields[o_Sig] ), "invalid header", kXMPErr_BadFileFormat );
-
- commentLen = GetUns16LE( &this->fields[o_CommentLen] );
- if(commentLen)
- {
- comment = new char[commentLen];
- LFA_Read(file,comment,commentLen,true);
- }
- };
-
- void write(LFA_FileRef file)
- {
- XMP_Enforce( this->SIG == GetUns32LE( &this->fields[o_Sig] ) );
- commentLen = GetUns16LE( &this->fields[o_CommentLen] );
- LFA_Write( file , fields , FIXED_SIZE );
- if (commentLen)
- LFA_Write ( file, comment, commentLen );
- }
-
- ~EndOfCD()
- {
- if (comment) delete comment;
- };
- }; //class EndOfCD
-
- ////////////////////////////////////////////////////////////////////////////////////
- // EMBEDDING MATH
- //
- // a = content files before xmp (always 0 thus ommited)
- // b/b2 = content files behind xmp (before/after injection)
- // x/x2 = offset xmp content header + content file (before/after injection)
- // cd/cd = central directory
- // h/h2 = end of central directory record
- XMP_Int64 b,b2,x,x2,cd,cd2,cdx,cdx2,z,z2,h,h2,
- // length thereof ('2' only where possibly different)
- // using XMP_Int64 here also for length (not XMP_Int32),
- // to be prepared for zip64, our LFA functions might need things in multiple chunks...
- al,bl,xl,x2l,cdl,cd2l,cdxl,cdx2l,z2l,hl,fl,f2l;
- XMP_Uns16 numCF,numCF2;
-
- bool wasCompressed; // ..before, false if no prior xmp
- bool compressXMP; // compress this time?
- bool inPlacePossible;
- /* bool isZip64; <=> z2 != 0 */
-
- FileHeader xmpFileHeader;
- CDFileHeader xmpCDHeader;
-
- XMP_StringPtr uncomprPacketStr;
- XMP_StringLen uncomprPacketLen;
- XMP_StringPtr finalPacketStr;
- XMP_StringLen finalPacketLen;
- std::vector<CDFileHeader> cdEntries;
- EndOfCD endOfCD;
- void writeOut( LFA_FileRef sourceFile, LFA_FileRef targetFile, bool isRewrite, bool isInPlace);
-
-}; // UCF_MetaHandler
-
-// =================================================================================================
-
-#endif /* __UCF_Handler_hpp__ */
-
-
diff --git a/source/XMPFiles/FileHandlers/XDCAMEX_Handler.cpp b/source/XMPFiles/FileHandlers/XDCAMEX_Handler.cpp
deleted file mode 100644
index 009ced0..0000000
--- a/source/XMPFiles/FileHandlers/XDCAMEX_Handler.cpp
+++ /dev/null
@@ -1,809 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XDCAMEX_Handler.hpp"
-#include "XDCAM_Support.hpp"
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file XDCAMEX_Handler.cpp
-/// \brief Folder format handler for XDCAMEX.
-///
-/// This handler is for the XDCAMEX video format.
-///
-/// .../MyMovie/
-/// BPAV/
-/// MEDIAPRO.XML
-/// MEDIAPRO.BUP
-/// CLPR/
-/// 709_001_01/
-/// 709_001_01.SMI
-/// 709_001_01.MP4
-/// 709_001_01M01.XML
-/// 709_001_01R01.BIM
-/// 709_001_01I01.PPN
-/// 709_001_02/
-/// 709_002_01/
-/// 709_003_01/
-/// TAKR/
-/// 709_001/
-/// 709_001.SMI
-/// 709_001M01.XML
-///
-/// The Backup files (.BUP) are optional. No files or directories other than those listed are
-/// allowed in the BPAV directory. The CLPR (clip root) directory may contain only clip directories,
-/// which may only contain the clip files listed. The TAKR (take root) direcory may contail only
-/// take directories, which may only contain take files. The take root directory can be empty.
-/// MEDIPRO.XML contains information on clip and take management.
-///
-/// Each clip directory contains a media file (.MP4), a clip info file (.SMI), a real time metadata
-/// file (.BIM), a non real time metadata file (.XML), and a picture pointer file (.PPN). A take
-/// directory conatins a take info and non real time take metadata files.
-// =================================================================================================
-
-// =================================================================================================
-// XDCAMEX_CheckFormat
-// ===================
-//
-// This version checks for the presence of a top level BPAV directory, and the required files and
-// directories immediately within it. The CLPR and TAKR subfolders are required, as is MEDIAPRO.XML.
-//
-// The state of the string parameters depends on the form of the path passed by the client. If the
-// client passed a logical clip path, like ".../MyMovie/012_3456_01", the parameters are:
-// rootPath - ".../MyMovie"
-// gpName - empty
-// parentName - empty
-// leafName - "012_3456_01"
-// If the client passed a full file path, like ".../MyMovie/BPAV/CLPR/012_3456_01/012_3456_01M01.XML", they are:
-// rootPath - ".../MyMovie/BPAV"
-// gpName - "CLPR"
-// parentName - "012_3456_01"
-// leafName - "012_3456_01M01"
-
-// ! The common code has shifted the gpName, parentName, and leafName strings to upper case. It has
-// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
-// ! file exists for a full file path.
-
-// ! Using explicit '/' as a separator when creating paths, it works on Windows.
-
-bool XDCAMEX_CheckFormat ( XMP_FileFormat format,
- const std::string & _rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & _leafName,
- XMPFiles * parent )
-{
- std::string rootPath = _rootPath;
- std::string clipName = _leafName;
- std::string grandGPName;
-
- std::string bpavPath ( rootPath );
-
- // Do some initial checks on the gpName and parentName.
-
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- if ( gpName.empty() ) {
-
- // This is the logical clip path case. Make sure .../MyMovie/BPAV/CLPR is a folder.
- bpavPath += kDirChar; // The rootPath was just ".../MyMovie".
- bpavPath += "BPAV";
- if ( GetChildMode ( bpavPath, "CLPR" ) != kFMode_IsFolder ) return false;
-
- } else {
-
- // This is the explicit file case. Make sure the ancestry is OK. Set the clip name from the
- // parent folder name.
-
- if ( gpName != "CLPR" ) return false;
- SplitLeafName ( &rootPath, &grandGPName );
- MakeUpperCase ( &grandGPName );
- if ( grandGPName != "BPAV" ) return false;
- if ( ! XMP_LitNMatch ( parentName.c_str(), clipName.c_str(), parentName.size() ) ) return false;
-
- clipName = parentName;
-
- }
-
- // Check the rest of the required general structure.
- if ( GetChildMode ( bpavPath, "TAKR" ) != kFMode_IsFolder ) return false;
- if ( GetChildMode ( bpavPath, "MEDIAPRO.XML" ) != kFMode_IsFile ) return false;
-
- // Make sure the clip's .MP4 and .SMI files exist.
- std::string tempPath ( bpavPath );
- tempPath += kDirChar;
- tempPath += "CLPR";
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += ".MP4";
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFile ) return false;
- tempPath.erase ( tempPath.size()-3 );
- tempPath += "SMI";
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFile ) return false;
-
- // And now save the psuedo path for the handler object.
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += clipName;
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for XDCAMEX clip info", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen );
-
- return true;
-
-} // XDCAMEX_CheckFormat
-
-// =================================================================================================
-// XDCAMEX_MetaHandlerCTor
-// =======================
-
-XMPFileHandler * XDCAMEX_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new XDCAMEX_MetaHandler ( parent );
-
-} // XDCAMEX_MetaHandlerCTor
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::XDCAMEX_MetaHandler
-// ========================================
-
-XDCAMEX_MetaHandler::XDCAMEX_MetaHandler ( XMPFiles * _parent ) : expat(0)
-{
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kXDCAMEX_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- // Extract the root path and clip name from tempPtr.
-
- XMP_Assert ( this->parent->tempPtr != 0 );
-
- this->rootPath.assign ( (char*) this->parent->tempPtr );
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- SplitLeafName ( &this->rootPath, &this->clipName );
-
-} // XDCAMEX_MetaHandler::XDCAMEX_MetaHandler
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::~XDCAMEX_MetaHandler
-// =========================================
-
-XDCAMEX_MetaHandler::~XDCAMEX_MetaHandler()
-{
-
- this->CleanupLegacyXML();
- if ( this->parent->tempPtr != 0 ) {
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
- }
-
-} // XDCAMEX_MetaHandler::~XDCAMEX_MetaHandler
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::MakeClipFilePath
-// =====================================
-
-void XDCAMEX_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix )
-{
-
- *path = this->rootPath;
- *path += kDirChar;
- *path += "BPAV";
- *path += kDirChar;
- *path += "CLPR";
- *path += kDirChar;
- *path += this->clipName;
- *path += kDirChar;
- *path += this->clipName;
- *path += suffix;
-
-} // XDCAMEX_MetaHandler::MakeClipFilePath
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::MakeLegacyDigest
-// =====================================
-
-// *** Early hack version.
-
-#define kHexDigits "0123456789ABCDEF"
-
-void XDCAMEX_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 xdcNS = this->xdcNS.c_str();
- XML_NodePtr legacyContext, legacyProp;
-
- legacyContext = this->clipMetadata->GetNamedElement ( xdcNS, "Access" );
- if ( legacyContext == 0 ) return;
-
- MD5_CTX context;
- unsigned char digestBin [16];
- MD5Init ( &context );
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "Creator" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "CreationDate" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "LastUpdateDate" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- MD5Final ( digestBin, &context );
-
- 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 );
-
-} // XDCAMEX_MetaHandler::MakeLegacyDigest
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::CleanupLegacyXML
-// =====================================
-
-void XDCAMEX_MetaHandler::CleanupLegacyXML()
-{
-
- if ( this->expat != 0 ) { delete ( this->expat ); this->expat = 0; }
-
- clipMetadata = 0; // ! Was a pointer into the expat tree.
-
-} // XDCAMEX_MetaHandler::CleanupLegacyXML
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::CacheFileData
-// ==================================
-
-void XDCAMEX_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- // See if the clip's .XMP file exists.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
- if ( GetFileMode ( xmpPath.c_str() ) != kFMode_IsFile ) return; // No XMP.
-
- // Read the entire .XMP file.
-
- char openMode = 'r';
- if ( this->parent->openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- LFA_FileRef xmpFile = LFA_Open ( xmpPath.c_str(), openMode );
- if ( xmpFile == 0 ) return; // The open failed.
-
- XMP_Int64 xmpLen = LFA_Measure ( xmpFile );
- if ( xmpLen > 100*1024*1024 ) {
- XMP_Throw ( "XDCAMEX XMP is outrageously large", kXMPErr_InternalFailure ); // Sanity check.
- }
-
- this->xmpPacket.erase();
- this->xmpPacket.reserve ( (size_t)xmpLen );
- this->xmpPacket.append ( (size_t)xmpLen, ' ' );
-
- XMP_Int32 ioCount = LFA_Read ( xmpFile, (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen, kLFA_RequireAll );
- XMP_Assert ( ioCount == xmpLen );
-
- this->packetInfo.offset = 0;
- this->packetInfo.length = (XMP_Int32)xmpLen;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- XMP_Assert ( this->parent->fileRef == 0 );
- if ( openMode == 'r' ) {
- LFA_Close ( xmpFile );
- } else {
- this->parent->fileRef = xmpFile;
- }
-
- this->containsXMP = true;
-
-} // XDCAMEX_MetaHandler::CacheFileData
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::GetTakeDuration
-// ====================================
-
-void XDCAMEX_MetaHandler::GetTakeDuration ( const std::string & takeURI, std::string & duration )
-{
-
- // Some versions of gcc can't tolerate goto's across declarations.
- // *** Better yet, avoid this cruft with self-cleaning objects.
- #define CleanupAndExit \
- { \
- if (expat != 0) delete expat; \
- if (takeXMLFile.fileRef != 0) LFA_Close ( takeXMLFile.fileRef ); \
- return; \
- }
-
- duration.clear();
-
- // Build a directory string to the take .xml file.
-
- std::string takeDir ( takeURI );
- takeDir.erase ( 0, 1 ); // Change the leading "//" to "/", then all '/' to kDirChar.
- if ( kDirChar != '/' ) {
- for ( size_t i = 0, limit = takeDir.size(); i < limit; ++i ) {
- if ( takeDir[i] == '/' ) takeDir[i] = kDirChar;
- }
- }
-
- std::string takePath ( this->rootPath );
- takePath += kDirChar;
- takePath += "BPAV";
- takePath += takeDir;
-
- // Replace .SMI with M01.XML.
- if ( takePath.size() > 4 ) {
- takePath.erase ( takePath.size() - 4, 4 );
- takePath += "M01.XML";
- }
-
- // Parse MEDIAPRO.XML
-
- XML_NodePtr takeRootElem = 0;
- XML_NodePtr context = 0;
- AutoFile takeXMLFile;
-
- takeXMLFile.fileRef = LFA_Open ( takePath.c_str(), 'r' );
- if ( takeXMLFile.fileRef == 0 ) return; // The open failed.
-
- ExpatAdapter * expat = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
- if ( this->expat == 0 ) return;
-
- XMP_Uns8 buffer [64*1024];
- while ( true ) {
- XMP_Int32 ioCount = LFA_Read ( takeXMLFile.fileRef, buffer, sizeof(buffer) );
- if ( ioCount == 0 ) break;
- expat->ParseBuffer ( buffer, ioCount, false /* not the end */ );
- }
-
- expat->ParseBuffer ( 0, 0, true ); // End the parse.
- LFA_Close ( takeXMLFile.fileRef );
- takeXMLFile.fileRef = 0;
-
- // Get the root node of the XML tree.
-
- XML_Node & mediaproXMLTree = expat->tree;
- for ( size_t i = 0, limit = mediaproXMLTree.content.size(); i < limit; ++i ) {
- if ( mediaproXMLTree.content[i]->kind == kElemNode ) {
- takeRootElem = mediaproXMLTree.content[i];
- }
- }
- if ( takeRootElem == 0 ) CleanupAndExit
-
- XMP_StringPtr rlName = takeRootElem->name.c_str() + takeRootElem->nsPrefixLen;
- if ( ! XMP_LitMatch ( rlName, "NonRealTimeMeta" ) ) CleanupAndExit
-
- // MediaProfile, Contents
- XMP_StringPtr ns = takeRootElem->ns.c_str();
- context = takeRootElem->GetNamedElement ( ns, "Duration" );
- if ( context != 0 ) {
- XMP_StringPtr durationValue = context->GetAttrValue ( "value" );
- if ( durationValue != 0 ) duration = durationValue;
- }
-
- CleanupAndExit
- #undef CleanupAndExit
-
-}
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::GetTakeUMID
-// ================================
-
-void XDCAMEX_MetaHandler::GetTakeUMID ( const std::string& clipUMID,
- std::string& takeUMID,
- std::string& takeXMLURI )
-{
-
- // Some versions of gcc can't tolerate goto's across declarations.
- // *** Better yet, avoid this cruft with self-cleaning objects.
- #define CleanupAndExit \
- { \
- if (expat != 0) delete expat; \
- if (mediaproXMLFile.fileRef != 0) LFA_Close ( mediaproXMLFile.fileRef ); \
- return; \
- }
-
- takeUMID.clear();
- takeXMLURI.clear();
-
- // Build a directory string to the MEDIAPRO file.
-
- std::string mediapropath ( this->rootPath );
- mediapropath += kDirChar;
- mediapropath += "BPAV";
- mediapropath += kDirChar;
- mediapropath += "MEDIAPRO.XML";
-
- // Parse MEDIAPRO.XML.
-
- XML_NodePtr mediaproRootElem = 0;
- XML_NodePtr contentContext = 0, materialContext = 0;
-
- AutoFile mediaproXMLFile;
- mediaproXMLFile.fileRef = LFA_Open ( mediapropath.c_str(), 'r' );
- if ( mediaproXMLFile.fileRef == 0 ) return; // The open failed.
-
- ExpatAdapter * expat = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
- if ( this->expat == 0 ) return;
-
- XMP_Uns8 buffer [64*1024];
- while ( true ) {
- XMP_Int32 ioCount = LFA_Read ( mediaproXMLFile.fileRef, buffer, sizeof(buffer) );
- if ( ioCount == 0 ) break;
- expat->ParseBuffer ( buffer, ioCount, false /* not the end */ );
- }
-
- expat->ParseBuffer ( 0, 0, true ); // End the parse.
- LFA_Close ( mediaproXMLFile.fileRef );
- mediaproXMLFile.fileRef = 0;
-
- // Get the root node of the XML tree.
-
- XML_Node & mediaproXMLTree = expat->tree;
- for ( size_t i = 0, limit = mediaproXMLTree.content.size(); i < limit; ++i ) {
- if ( mediaproXMLTree.content[i]->kind == kElemNode ) {
- mediaproRootElem = mediaproXMLTree.content[i];
- }
- }
-
- if ( mediaproRootElem == 0 ) CleanupAndExit
- XMP_StringPtr rlName = mediaproRootElem->name.c_str() + mediaproRootElem->nsPrefixLen;
- if ( ! XMP_LitMatch ( rlName, "MediaProfile" ) ) CleanupAndExit
-
- // MediaProfile, Contents
-
- XMP_StringPtr ns = mediaproRootElem->ns.c_str();
- contentContext = mediaproRootElem->GetNamedElement ( ns, "Contents" );
-
- if ( contentContext != 0 ) {
-
- size_t numMaterialElems = contentContext->CountNamedElements ( ns, "Material" );
-
- for ( size_t i = 0; i < numMaterialElems; ++i ) { // Iterate over Material tags.
-
- XML_NodePtr materialElement = contentContext->GetNamedElement ( ns, "Material", i );
- XMP_Assert ( materialElement != 0 );
-
- XMP_StringPtr umid = materialElement->GetAttrValue ( "umid" );
- XMP_StringPtr uri = materialElement->GetAttrValue ( "uri" );
-
- if ( umid == 0 ) umid = "";
- if ( uri == 0 ) uri = "";
-
- size_t numComponents = materialElement->CountNamedElements ( ns, "Component" );
-
- for ( size_t j = 0; j < numComponents; ++j ) {
-
- XML_NodePtr componentElement = materialElement->GetNamedElement ( ns, "Component", j );
- XMP_Assert ( componentElement != 0 );
-
- XMP_StringPtr compUMID = componentElement->GetAttrValue ( "umid" );
-
- if ( (compUMID != 0) && (compUMID == clipUMID) ) {
- takeUMID = umid;
- takeXMLURI = uri;
- break;
- }
-
- }
-
- if ( ! takeUMID.empty() ) break;
-
- }
-
- }
-
- CleanupAndExit
- #undef CleanupAndExit
-
-}
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::ProcessXMP
-// ===============================
-
-void XDCAMEX_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() );
- }
-
- // NonRealTimeMeta -> XMP by schema.
- std::string thisUMID, takeUMID, takeXMLURI, takeDuration;
- std::string xmlPath;
- this->MakeClipFilePath ( &xmlPath, "M01.XML" );
-
- AutoFile xmlFile;
- xmlFile.fileRef = LFA_Open ( xmlPath.c_str(), 'r' );
- if ( xmlFile.fileRef == 0 ) return; // The open failed.
-
- this->expat = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
- if ( this->expat == 0 ) XMP_Throw ( "XDCAMEX_MetaHandler: Can't create Expat adapter", kXMPErr_NoMemory );
-
- XMP_Uns8 buffer [64*1024];
- while ( true ) {
- XMP_Int32 ioCount = LFA_Read ( xmlFile.fileRef, 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.
-
- LFA_Close ( xmlFile.fileRef );
- xmlFile.fileRef = 0;
-
- // The root element should be NonRealTimeMeta in some namespace. 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, "NonRealTimeMeta" ) ) CleanupAndExit
-
- this->legacyNS = rootElem->ns;
-
- // Check the legacy digest.
-
- XMP_StringPtr legacyNS = this->legacyNS.c_str();
- this->clipMetadata = rootElem; // ! Save the NonRealTimeMeta pointer for other use.
-
- std::string oldDigest, newDigest;
- bool digestFound = this->xmpObj.GetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "XDCAMEX", &oldDigest, 0 );
- if ( digestFound ) {
- this->MakeLegacyDigest ( &newDigest );
- if ( oldDigest == newDigest ) CleanupAndExit
- }
-
- // 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->containsXMP = XDCAM_Support::GetLegacyMetaData ( &this->xmpObj, rootElem, legacyNS, digestFound, thisUMID );
-
- // If this clip is part of a take, add the take number to the relation field, and get the
- // duration from the take metadata.
- GetTakeUMID ( thisUMID, takeUMID, takeXMLURI );
-
- // If this clip is part of a take, update the duration to reflect the take duration rather than
- // the clip duration, and add the take name as a shot name.
-
- if ( ! takeXMLURI.empty() ) {
-
- // Update duration. This property already exists from clip legacy metadata.
- GetTakeDuration ( takeXMLURI, takeDuration );
- if ( ! takeDuration.empty() ) {
- this->xmpObj.SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "value", takeDuration );
- containsXMP = true;
- }
-
- if ( digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DM, "shotName" )) ) {
-
- std::string takeName;
- SplitLeafName ( &takeXMLURI, &takeName );
-
- // Check for the xml suffix, and delete if it exists.
- size_t pos = takeName.rfind(".SMI");
- if ( pos != std::string::npos ) {
-
- takeName.erase ( pos );
-
- // delete the take number suffix if it exists.
- if ( takeName.size() > 3 ) {
-
- size_t suffix = takeName.size() - 3;
- char c1 = takeName[suffix];
- char c2 = takeName[suffix+1];
- char c3 = takeName[suffix+2];
- if ( ('U' == c1) && ('0' <= c2) && (c2 <= '9') && ('0' <= c3) && (c3 <= '9') ) {
- takeName.erase ( suffix );
- }
-
- this->xmpObj.SetProperty ( kXMP_NS_DM, "shotName", takeName, kXMP_DeleteExisting );
- containsXMP = true;
-
- }
-
- }
-
- }
-
- }
-
- if ( (! takeUMID.empty()) &&
- (digestFound || (! this->xmpObj.DoesPropertyExist ( kXMP_NS_DC, "relation" ))) ) {
- this->xmpObj.DeleteProperty ( kXMP_NS_DC, "relation" );
- this->xmpObj.AppendArrayItem ( kXMP_NS_DC, "relation", kXMP_PropArrayIsUnordered, takeUMID );
- this->containsXMP = true;
- }
-
- CleanupAndExit
- #undef CleanupAndExit
-
-} // XDCAMEX_MetaHandler::ProcessXMP
-
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::UpdateFile
-// ===============================
-//
-// Note that UpdateFile is only called from XMPFiles::CloseFile, so it is OK to close the file here.
-
-void XDCAMEX_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- this->needsUpdate = false; // Make sure only called once.
-
- LFA_FileRef oldFile = 0;
- std::string filePath, tempPath;
-
- // Update the internal legacy XML tree if we have one, and set the digest in the XMP.
-
- bool updateLegacyXML = false;
-
- if ( this->clipMetadata != 0 ) {
- updateLegacyXML = XDCAM_Support::SetLegacyMetaData ( this->clipMetadata, &this->xmpObj, this->legacyNS.c_str());
- }
-
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "XDCAMEX", newDigest.c_str(), kXMP_DeleteExisting );
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() );
-
- // Update the legacy XML file if necessary.
-
- if ( updateLegacyXML ) {
-
- std::string legacyXML;
- this->expat->tree.Serialize ( &legacyXML );
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
- oldFile = LFA_Open ( filePath.c_str(), 'w' );
-
- if ( oldFile == 0 ) {
-
- // The XML does not exist yet.
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
- oldFile = LFA_Create ( filePath.c_str() );
- if ( oldFile == 0 ) XMP_Throw ( "Failure creating XDCAMEX legacy XML file", kXMPErr_ExternalFailure );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XML file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
-
- CreateTempFile ( filePath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( filePath.c_str() );
- LFA_Rename ( tempPath.c_str(), filePath.c_str() );
-
- }
-
- }
-
- oldFile = this->parent->fileRef;
-
- if ( oldFile == 0 ) {
-
- // The XMP does not exist yet.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
-
- LFA_FileRef xmpFile = LFA_Create ( xmpPath.c_str() );
- if ( xmpFile == 0 ) XMP_Throw ( "Failure creating XDCAMEX XMP file", kXMPErr_ExternalFailure );
- LFA_Write ( xmpFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( xmpFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XMP file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- std::string xmpPath, tempPath;
-
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
-
- CreateTempFile ( xmpPath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( xmpPath.c_str() );
- LFA_Rename ( tempPath.c_str(), xmpPath.c_str() );
-
- }
-
- this->parent->fileRef = 0;
-
-} // XDCAMEX_MetaHandler::UpdateFile
-
-// =================================================================================================
-// XDCAMEX_MetaHandler::WriteFile
-// ==============================
-
-void XDCAMEX_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- // ! WriteFile is not supposed to be called for handlers that own the file.
- XMP_Throw ( "XDCAMEX_MetaHandler::WriteFile should not be called", kXMPErr_InternalFailure );
-
-} // XDCAMEX_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/XDCAMEX_Handler.hpp b/source/XMPFiles/FileHandlers/XDCAMEX_Handler.hpp
deleted file mode 100644
index ee7b23f..0000000
--- a/source/XMPFiles/FileHandlers/XDCAMEX_Handler.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef __XDCAMEX_Handler_hpp__
-#define __XDCAMEX_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#include "ExpatAdapter.hpp"
-
-// =================================================================================================
-/// \file XDCAMEX_Handler.hpp
-/// \brief Folder format handler for XDCAMEX.
-// =================================================================================================
-
-extern XMPFileHandler * XDCAMEX_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool XDCAMEX_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kXDCAMEX_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_FolderBasedFormat);
-
-class XDCAMEX_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions() // *** These should be standard for standalone XMP files.
- { return (kXMP_UseCompactFormat | kXMP_OmitPacketWrapper); };
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- XDCAMEX_MetaHandler ( XMPFiles * _parent );
- virtual ~XDCAMEX_MetaHandler();
-
-private:
-
- XDCAMEX_MetaHandler() : expat(0) {}; // Hidden on purpose.
-
- void MakeClipFilePath ( std::string * path, XMP_StringPtr suffix );
- void MakeLegacyDigest ( std::string * digestStr );
-
- void GetTakeUMID( const std::string& clipUMID, std::string& takeUMID, std::string& takeXMLURI );
- void GetTakeDuration( const std::string& takeUMID, std::string& duration );
-
- void CleanupLegacyXML();
-
- std::string rootPath, clipName, xdcNS, legacyNS, clipUMID;
-
- ExpatAdapter * expat;
- XML_Node * clipMetadata;
-
-}; // XDCAMEX_MetaHandler
-
-// =================================================================================================
-
-#endif /* __XDCAMEX_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/XDCAM_Handler.cpp b/source/XMPFiles/FileHandlers/XDCAM_Handler.cpp
deleted file mode 100644
index d88109e..0000000
--- a/source/XMPFiles/FileHandlers/XDCAM_Handler.cpp
+++ /dev/null
@@ -1,710 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XDCAM_Handler.hpp"
-#include "XDCAM_Support.hpp"
-#include "MD5.h"
-
-using namespace std;
-
-// =================================================================================================
-/// \file XDCAM_Handler.cpp
-/// \brief Folder format handler for XDCAM.
-///
-/// This handler is for the XDCAM video format. This is a pseudo-package, visible files but with a very
-/// well-defined layout and naming rules. There are 2 different layouts for XDCAM, called FAM and SAM.
-/// The FAM layout is used by "normal" XDCAM devices. The SAM layout is used by XDCAM-EX devices.
-///
-/// A typical FAM layout looks like (note mixed case for General, Clip, Edit, and Sub folders):
-///
-/// .../MyMovie/
-/// INDEX.XML
-/// DISCMETA.XML
-/// MEDIAPRO.XML
-/// General/
-/// unknown files
-/// Clip/
-/// C0001.MXF
-/// C0001M01.XML
-/// C0001M01.XMP
-/// C0002.MXF
-/// C0002M01.XML
-/// C0002M01.XMP
-/// Sub/
-/// C0001S01.MXF
-/// C0002S01.MXF
-/// Edit/
-/// E0001E01.SMI
-/// E0001M01.XML
-/// E0002E01.SMI
-/// E0002M01.XML
-///
-/// A typical SAM layout looks like:
-///
-/// .../MyMovie/
-/// GENERAL/
-/// unknown files
-/// PROAV/
-/// INDEX.XML
-/// INDEX.BUP
-/// DISCMETA.XML
-/// DISCINFO.XML
-/// DISCINFO.BUP
-/// CLPR/
-/// C0001/
-/// C0001C01.SMI
-/// C0001V01.MXF
-/// C0001A01.MXF
-/// C0001A02.MXF
-/// C0001R01.BIM
-/// C0001I01.PPN
-/// C0001M01.XML
-/// C0001M01.XMP
-/// C0001S01.MXF
-/// C0002/
-/// ...
-/// EDTR/
-/// E0001/
-/// E0001E01.SMI
-/// E0001M01.XML
-/// E0002/
-/// ...
-///
-/// Note that the Sony documentation uses the folder names "General", "Clip", "Sub", and "Edit". We
-/// use all caps here. Common code has already shifted the names, we want to be case insensitive.
-///
-/// From the user's point of view, .../MyMovie contains XDCAM stuff, in this case 2 clips whose raw
-/// names are C0001 and C0002. There may be mapping information for nicer clip names to the raw
-/// names, but that can be ignored for now. Each clip is stored as a collection of files, each file
-/// holding some specific aspect of the clip's data.
-///
-/// The XDCAM handler operates on clips. The path from the client of XMPFiles can be either a logical
-/// clip path, like ".../MyMovie/C0001", or a full path to one of the files. In the latter case the
-/// handler must figure out the intended clip, it must not blindly use the named file.
-///
-/// Once the XDCAM structure and intended clip are identified, the handler only deals with the .XMP
-/// and .XML files in the CLIP or CLPR/<clip> folders. The .XMP file, if present, contains the XMP
-/// for the clip. The .XML file must be present to define the existance of the clip. It contains a
-/// variety of information about the clip, including some legacy metadata.
-///
-// =================================================================================================
-
-// =================================================================================================
-// XDCAM_CheckFormat
-// =================
-//
-// This version does fairly simple checks. The top level folder (.../MyMovie) must have exactly 1
-// child, a folder called CONTENTS. This must have a subfolder called CLIP. It may also have
-// subfolders called VIDEO, AUDIO, ICON, VOICE, and PROXY. Any mixture of these additional folders
-// is allowed, but no other children are allowed in CONTENTS. The CLIP folder must contain a .XML
-// file for the desired clip. The name checks are case insensitive.
-//
-// The state of the string parameters depends on the form of the path passed by the client. If the
-// client passed a logical clip path, like ".../MyMovie/C0001", the parameters are:
-// rootPath - ".../MyMovie"
-// gpName - empty
-// parentName - empty
-// leafName - "C0001"
-//
-// If the client passed a FAM file path, like ".../MyMovie/Edit/E0001E01.SMI", they are:
-// rootPath - "..."
-// gpName - "MyMovie"
-// parentName - "EDIT" (common code has shifted the case)
-// leafName - "E0001E01"
-//
-// If the client passed a SAM file path, like ".../MyMovie/PROAV/CLPR/C0001/C0001A02.MXF", they are:
-// rootPath - ".../MyMovie/PROAV"
-// gpName - "CLPR"
-// parentName - "C0001"
-// leafName - "C0001A02"
-//
-// For both FAM and SAM the leading character of the leafName for an existing file might be coerced
-// to 'C' to form the logical clip name. And suffix such as "M01" must be removed for FAM. We don't
-// need to worry about that for SAM, that uses the <clip> folder name.
-
-// ! The FAM format supports general clip file names through an ALIAS.XML mapping file. The simple
-// ! existence check has an edge case bug, left to be fixed later. If the ALIAS.XML file exists, but
-// ! some of the clips still have "raw" names, and we're passed an existing file path in the EDIT
-// ! folder, we will fail to do the leading 'E' to 'C' coercion. We might also erroneously remove a
-// ! suffix from a mapped essence file with a name like ClipX01.MXF.
-
-// ! The common code has shifted the gpName, parentName, and leafName strings to uppercase. It has
-// ! also made sure that for a logical clip path the rootPath is an existing folder, and that the
-// ! file exists for a full file path.
-
-bool XDCAM_CheckFormat ( XMP_FileFormat format,
- const std::string & _rootPath,
- const std::string & _gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent )
-{
- std::string rootPath = _rootPath; // ! Need tweaking in the existing file cases (FAM and SAM).
- std::string gpName = _gpName;
-
- bool isFAM = false;
-
- std::string tempPath, childName;
- XMP_FolderInfo folderInfo;
-
- std::string clipName = leafName;
-
- // Do some basic checks on the root path and component names. Decide if this is FAM or SAM.
-
- if ( gpName.empty() != parentName.empty() ) return false; // Must be both empty or both non-empty.
-
- if ( gpName.empty() ) {
-
- // This is the logical clip path case. Just look for PROAV to see if this is FAM or SAM.
- if ( GetChildMode ( rootPath, "PROAV" ) != kFMode_IsFolder ) isFAM = true;
-
- } else {
-
- // This is the existing file case. See if this is FAM or SAM, tweak the clip name as needed.
-
- if ( (parentName == "CLIP") || (parentName == "EDIT") || (parentName == "SUB") ) {
- // ! The standard says Clip/Edit/Sub, but the caller has already shifted to upper case.
- isFAM = true;
- } else if ( (gpName != "CLPR") && (gpName != "EDTR") ) {
- return false;
- }
-
- if ( isFAM ) {
-
- // Put the proper root path together. Clean up the clip name if needed.
-
- if ( ! rootPath.empty() ) rootPath += kDirChar;
- rootPath += gpName;
- gpName.erase();
-
- if ( GetChildMode ( rootPath, "ALIAS.XML" ) != kFMode_IsFile ) {
- clipName[0] = 'C'; // ! See notes above about pending bug.
- }
-
- if ( clipName.size() > 3 ) {
- size_t clipMid = clipName.size() - 3;
- char c1 = clipName[clipMid];
- char c2 = clipName[clipMid+1];
- char c3 = clipName[clipMid+2];
- if ( ('A' <= c1) && (c1 <= 'Z') &&
- ('0' <= c2) && (c2 <= '9') && ('0' <= c3) && (c3 <= '9') ) {
- clipName.erase ( clipMid );
- }
- }
-
- } else {
-
- // Fix the clip name. Check for and strip the "PROAV" suffix on the root path.
-
- clipName = parentName; // ! We have a folder with the (almost) exact clip name.
- clipName[0] = 'C';
-
- std::string proav;
- SplitLeafName ( &rootPath, &proav );
- MakeUpperCase ( &proav );
- if ( (rootPath.empty()) || (proav != "PROAV") ) return false;
-
- }
-
- }
-
- // Make sure the general XDCAM package structure is legit. Set tempPath as a bogus path of the
- // form <root>/<FAM-or-SAM>/<clip>, e.g. ".../MyMovie/FAM/C0001". This is passed the handler via
- // the tempPtr hackery.
-
- if ( isFAM ) {
-
- if ( (format != kXMP_XDCAM_FAMFile) && (format != kXMP_UnknownFile) ) return false;
-
- tempPath = rootPath;
-
- if ( GetChildMode ( tempPath, "INDEX.XML" ) != kFMode_IsFile ) return false;
- if ( GetChildMode ( tempPath, "DISCMETA.XML" ) != kFMode_IsFile ) return false;
- if ( GetChildMode ( tempPath, "MEDIAPRO.XML" ) != kFMode_IsFile ) return false;
-
- tempPath += kDirChar;
- tempPath += "Clip"; // ! Yes, mixed case.
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += "M01.XML";
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFile ) return false;
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "FAM";
- tempPath += kDirChar;
- tempPath += clipName;
-
- } else {
-
- if ( (format != kXMP_XDCAM_SAMFile) && (format != kXMP_UnknownFile) ) return false;
-
- // We already know about the PROAV folder, just check below it.
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "PROAV";
-
- if ( GetChildMode ( tempPath, "INDEX.XML" ) != kFMode_IsFile ) return false;
- if ( GetChildMode ( tempPath, "DISCMETA.XML" ) != kFMode_IsFile ) return false;
- if ( GetChildMode ( tempPath, "DISCINFO.XML" ) != kFMode_IsFile ) return false;
- if ( GetChildMode ( tempPath, "CLPR" ) != kFMode_IsFolder ) return false;
-
- tempPath += kDirChar;
- tempPath += "CLPR";
- tempPath += kDirChar;
- tempPath += clipName;
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFolder ) return false;
-
- tempPath += kDirChar;
- tempPath += clipName;
- tempPath += "M01.XML";
- if ( GetFileMode ( tempPath.c_str() ) != kFMode_IsFile ) return false;
-
- tempPath = rootPath;
- tempPath += kDirChar;
- tempPath += "SAM";
- tempPath += kDirChar;
- tempPath += clipName;
-
- }
-
- // Save the pseudo-path for the handler object. A bit of a hack, but the only way to get info
- // from here to there.
-
- size_t pathLen = tempPath.size() + 1; // Include a terminating nul.
- parent->tempPtr = malloc ( pathLen );
- if ( parent->tempPtr == 0 ) XMP_Throw ( "No memory for XDCAM clip info", kXMPErr_NoMemory );
- memcpy ( parent->tempPtr, tempPath.c_str(), pathLen ); // AUDIT: Safe, allocated above.
-
- return true;
-
-} // XDCAM_CheckFormat
-
-// =================================================================================================
-// XDCAM_MetaHandlerCTor
-// =====================
-
-XMPFileHandler * XDCAM_MetaHandlerCTor ( XMPFiles * parent )
-{
- return new XDCAM_MetaHandler ( parent );
-
-} // XDCAM_MetaHandlerCTor
-
-// =================================================================================================
-// XDCAM_MetaHandler::XDCAM_MetaHandler
-// ====================================
-
-XDCAM_MetaHandler::XDCAM_MetaHandler ( XMPFiles * _parent ) : isFAM(false), expat(0)
-{
-
- this->parent = _parent; // Inherited, can't set in the prefix.
- this->handlerFlags = kXDCAM_HandlerFlags;
- this->stdCharForm = kXMP_Char8Bit;
-
- // Extract the root path, clip name, and FAM/SAM flag from tempPtr.
-
- XMP_Assert ( this->parent->tempPtr != 0 );
-
- this->rootPath.assign ( (char*) this->parent->tempPtr );
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
-
- SplitLeafName ( &this->rootPath, &this->clipName );
-
- std::string temp;
- SplitLeafName ( &this->rootPath, &temp );
- XMP_Assert ( (temp == "FAM") || (temp == "SAM") );
- if ( temp == "FAM" ) this->isFAM = true;
- XMP_Assert ( this->isFAM ? (this->parent->format == kXMP_XDCAM_FAMFile) : (this->parent->format == kXMP_XDCAM_SAMFile) );
-
-} // XDCAM_MetaHandler::XDCAM_MetaHandler
-
-// =================================================================================================
-// XDCAM_MetaHandler::~XDCAM_MetaHandler
-// =====================================
-
-XDCAM_MetaHandler::~XDCAM_MetaHandler()
-{
-
- this->CleanupLegacyXML();
- if ( this->parent->tempPtr != 0 ) {
- free ( this->parent->tempPtr );
- this->parent->tempPtr = 0;
- }
-
-} // XDCAM_MetaHandler::~XDCAM_MetaHandler
-
-// =================================================================================================
-// XDCAM_MetaHandler::MakeClipFilePath
-// ===================================
-
-void XDCAM_MetaHandler::MakeClipFilePath ( std::string * path, XMP_StringPtr suffix )
-{
-
- *path = this->rootPath;
- *path += kDirChar;
-
- if ( this->isFAM ) {
- *path += "Clip"; // ! Yes, mixed case.
- } else {
- *path += "PROAV";
- *path += kDirChar;
- *path += "CLPR";
- *path += kDirChar;
- *path += this->clipName;
- }
-
- *path += kDirChar;
- *path += this->clipName;
- *path += suffix;
-
-} // XDCAM_MetaHandler::MakeClipFilePath
-
-// =================================================================================================
-// XDCAM_MetaHandler::MakeLegacyDigest
-// ===================================
-
-// *** Early hack version.
-
-#define kHexDigits "0123456789ABCDEF"
-
-void XDCAM_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 xdcNS = this->xdcNS.c_str();
- XML_NodePtr legacyContext, legacyProp;
-
- legacyContext = this->clipMetadata->GetNamedElement ( xdcNS, "Access" );
- if ( legacyContext == 0 ) return;
-
- MD5_CTX context;
- unsigned char digestBin [16];
- MD5Init ( &context );
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "Creator" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "CreationDate" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- legacyProp = legacyContext->GetNamedElement ( xdcNS, "LastUpdateDate" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() && (! legacyProp->content.empty()) ) {
- const XML_Node * xmlValue = legacyProp->content[0];
- MD5Update ( &context, (XMP_Uns8*)xmlValue->value.c_str(), (unsigned int)xmlValue->value.size() );
- }
-
- MD5Final ( digestBin, &context );
-
- 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 );
-
-} // XDCAM_MetaHandler::MakeLegacyDigest
-
-// =================================================================================================
-// P2_MetaHandler::CleanupLegacyXML
-// ================================
-
-void XDCAM_MetaHandler::CleanupLegacyXML()
-{
-
- if ( this->expat != 0 ) { delete ( this->expat ); this->expat = 0; }
-
- clipMetadata = 0; // ! Was a pointer into the expat tree.
-
-} // XDCAM_MetaHandler::CleanupLegacyXML
-
-// =================================================================================================
-// XDCAM_MetaHandler::CacheFileData
-// ================================
-
-void XDCAM_MetaHandler::CacheFileData()
-{
- XMP_Assert ( ! this->containsXMP );
-
- // See if the clip's .XMP file exists.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
- if ( GetFileMode ( xmpPath.c_str() ) != kFMode_IsFile ) return; // No XMP.
-
- // Read the entire .XMP file.
-
- char openMode = 'r';
- if ( this->parent->openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- LFA_FileRef xmpFile = LFA_Open ( xmpPath.c_str(), openMode );
- if ( xmpFile == 0 ) return; // The open failed.
-
- XMP_Int64 xmpLen = LFA_Measure ( xmpFile );
- if ( xmpLen > 100*1024*1024 ) {
- XMP_Throw ( "XDCAM XMP is outrageously large", kXMPErr_InternalFailure ); // Sanity check.
- }
-
- this->xmpPacket.erase();
- this->xmpPacket.reserve ( (size_t)xmpLen );
- this->xmpPacket.append ( (size_t)xmpLen, ' ' );
-
- XMP_Int32 ioCount = LFA_Read ( xmpFile, (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen, kLFA_RequireAll );
- XMP_Assert ( ioCount == xmpLen );
-
- this->packetInfo.offset = 0;
- this->packetInfo.length = (XMP_Int32)xmpLen;
- FillPacketInfo ( this->xmpPacket, &this->packetInfo );
-
- XMP_Assert ( this->parent->fileRef == 0 );
- if ( openMode == 'r' ) {
- LFA_Close ( xmpFile );
- } else {
- this->parent->fileRef = xmpFile;
- }
-
- this->containsXMP = true;
-
-} // XDCAM_MetaHandler::CacheFileData
-
-// =================================================================================================
-// XDCAM_MetaHandler::ProcessXMP
-// =============================
-
-void XDCAM_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() );
- }
-
- // NonRealTimeMeta -> XMP by schema
- std::string xmlPath, umid;
- this->MakeClipFilePath ( &xmlPath, "M01.XML" );
-
- AutoFile xmlFile;
- xmlFile.fileRef = LFA_Open ( xmlPath.c_str(), 'r' );
- if ( xmlFile.fileRef == 0 ) return; // The open failed.
-
- this->expat = XMP_NewExpatAdapter ( ExpatAdapter::kUseLocalNamespaces );
- if ( this->expat == 0 ) XMP_Throw ( "XDCAM_MetaHandler: Can't create Expat adapter", kXMPErr_NoMemory );
-
- XMP_Uns8 buffer [64*1024];
- while ( true ) {
- XMP_Int32 ioCount = LFA_Read ( xmlFile.fileRef, 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.
-
- LFA_Close ( xmlFile.fileRef );
- xmlFile.fileRef = 0;
-
- // The root element should be NonRealTimeMeta in some namespace. 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, "NonRealTimeMeta" ) ) CleanupAndExit
-
- this->legacyNS = rootElem->ns;
-
- // Check the legacy digest.
-
- XMP_StringPtr legacyNS = this->legacyNS.c_str();
-
- this->clipMetadata = rootElem; // ! Save the NonRealTimeMeta pointer for other use.
-
- std::string oldDigest, newDigest;
- bool digestFound = this->xmpObj.GetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "XDCAM", &oldDigest, 0 );
- if ( digestFound ) {
- this->MakeLegacyDigest ( &newDigest );
- if ( oldDigest == newDigest ) CleanupAndExit
- }
-
- // 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->containsXMP = XDCAM_Support::GetLegacyMetaData ( &this->xmpObj, rootElem, legacyNS, digestFound, umid );
-
- CleanupAndExit
- #undef CleanupAndExit
-
-} // XDCAM_MetaHandler::ProcessXMP
-
-// =================================================================================================
-// XDCAM_MetaHandler::UpdateFile
-// =============================
-//
-// Note that UpdateFile is only called from XMPFiles::CloseFile, so it is OK to close the file here.
-
-void XDCAM_MetaHandler::UpdateFile ( bool doSafeUpdate )
-{
- if ( ! this->needsUpdate ) return;
- this->needsUpdate = false; // Make sure only called once.
-
- LFA_FileRef oldFile = 0;
- std::string filePath, tempPath;
-
- // Update the internal legacy XML tree if we have one, and set the digest in the XMP.
-
- bool updateLegacyXML = false;
-
- if ( this->clipMetadata != 0 ) {
- updateLegacyXML = XDCAM_Support::SetLegacyMetaData ( this->clipMetadata, &this->xmpObj, this->legacyNS.c_str());
- }
-
- std::string newDigest;
- this->MakeLegacyDigest ( &newDigest );
- this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "XDCAM", newDigest.c_str(), kXMP_DeleteExisting );
- this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() );
-
- // Update the legacy XML file if necessary.
-
- if ( updateLegacyXML ) {
-
- std::string legacyXML;
- this->expat->tree.Serialize ( &legacyXML );
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
- oldFile = LFA_Open ( filePath.c_str(), 'w' );
-
- if ( oldFile == 0 ) {
-
- // The XML does not exist yet.
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
- oldFile = LFA_Create ( filePath.c_str() );
- if ( oldFile == 0 ) XMP_Throw ( "Failure creating XDCAMEX legacy XML file", kXMPErr_ExternalFailure );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XML file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- this->MakeClipFilePath ( &filePath, "M01.XML" );
-
- CreateTempFile ( filePath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, legacyXML.data(), (XMP_StringLen)legacyXML.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( filePath.c_str() );
- LFA_Rename ( tempPath.c_str(), filePath.c_str() );
-
- }
-
- }
-
- oldFile = this->parent->fileRef;
-
- if ( oldFile == 0 ) {
-
- // The XMP does not exist yet.
-
- std::string xmpPath;
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
-
- LFA_FileRef xmpFile = LFA_Create ( xmpPath.c_str() );
- if ( xmpFile == 0 ) XMP_Throw ( "Failure creating XDCAM XMP file", kXMPErr_ExternalFailure );
- LFA_Write ( xmpFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( xmpFile );
-
- } else if ( ! doSafeUpdate ) {
-
- // Over write the existing XMP file.
-
- LFA_Seek ( oldFile, 0, SEEK_SET );
- LFA_Truncate ( oldFile, 0 );
- LFA_Write ( oldFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( oldFile );
-
- } else {
-
- // Do a safe update.
-
- // *** We really need an LFA_SwapFiles utility.
-
- std::string xmpPath, tempPath;
-
- this->MakeClipFilePath ( &xmpPath, "M01.XMP" );
-
- CreateTempFile ( xmpPath, &tempPath );
- LFA_FileRef tempFile = LFA_Open ( tempPath.c_str(), 'w' );
- LFA_Write ( tempFile, this->xmpPacket.data(), (XMP_StringLen)this->xmpPacket.size() );
- LFA_Close ( tempFile );
-
- LFA_Close ( oldFile );
- LFA_Delete ( xmpPath.c_str() );
- LFA_Rename ( tempPath.c_str(), xmpPath.c_str() );
-
- }
-
- this->parent->fileRef = 0;
-
-} // XDCAM_MetaHandler::UpdateFile
-
-// =================================================================================================
-// XDCAM_MetaHandler::WriteFile
-// ============================
-
-void XDCAM_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
-{
-
- // ! WriteFile is not supposed to be called for handlers that own the file.
- XMP_Throw ( "XDCAM_MetaHandler::WriteFile should not be called", kXMPErr_InternalFailure );
-
-} // XDCAM_MetaHandler::WriteFile
-
-// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/XDCAM_Handler.hpp b/source/XMPFiles/FileHandlers/XDCAM_Handler.hpp
deleted file mode 100644
index 55f61dc..0000000
--- a/source/XMPFiles/FileHandlers/XDCAM_Handler.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef __XDCAM_Handler_hpp__
-#define __XDCAM_Handler_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#include "ExpatAdapter.hpp"
-
-// =================================================================================================
-/// \file XDCAM_Handler.hpp
-/// \brief Folder format handler for XDCAM.
-///
-/// This header ...
-///
-// =================================================================================================
-
-extern XMPFileHandler * XDCAM_MetaHandlerCTor ( XMPFiles * parent );
-
-extern bool XDCAM_CheckFormat ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-static const XMP_OptionBits kXDCAM_HandlerFlags = (kXMPFiles_CanInjectXMP |
- kXMPFiles_CanExpand |
- kXMPFiles_CanRewrite |
- kXMPFiles_PrefersInPlace |
- kXMPFiles_CanReconcile |
- kXMPFiles_AllowsOnlyXMP |
- kXMPFiles_ReturnsRawPacket |
- kXMPFiles_HandlerOwnsFile |
- kXMPFiles_AllowsSafeUpdate |
- kXMPFiles_FolderBasedFormat);
-
-class XDCAM_MetaHandler : public XMPFileHandler
-{
-public:
-
- void CacheFileData();
- void ProcessXMP();
-
- XMP_OptionBits GetSerializeOptions() // *** These should be standard for standalone XMP files.
- { return (kXMP_UseCompactFormat | kXMP_OmitPacketWrapper); };
-
- void UpdateFile ( bool doSafeUpdate );
- void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
-
- XDCAM_MetaHandler ( XMPFiles * _parent );
- virtual ~XDCAM_MetaHandler();
-
-private:
-
- XDCAM_MetaHandler() : isFAM(false), expat(0), clipMetadata(0) {}; // Hidden on purpose.
-
- void MakeClipFilePath ( std::string * path, XMP_StringPtr suffix );
- void MakeLegacyDigest ( std::string * digestStr );
- void CleanupLegacyXML();
-
- std::string rootPath, clipName, xdcNS, legacyNS;
-
- bool isFAM;
-
- ExpatAdapter * expat;
- XML_Node * clipMetadata; // ! Don't delete, points into the Expat tree.
-
-}; // XDCAM_MetaHandler
-
-// =================================================================================================
-
-#endif /* __XDCAM_Handler_hpp__ */
diff --git a/source/XMPFiles/FormatSupport/ASF_Support.cpp b/source/XMPFiles/FormatSupport/ASF_Support.cpp
deleted file mode 100644
index 1180f9d..0000000
--- a/source/XMPFiles/FormatSupport/ASF_Support.cpp
+++ /dev/null
@@ -1,1436 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "ASF_Support.hpp"
-#include "UnicodeConversions.hpp"
-
-#if XMP_WinBuild
- #define snprintf _snprintf
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
- #pragma warning ( disable : 4267 ) // *** conversion (from size_t), possible loss of date (many 64 bit related)
-#endif
-
-// =============================================================================================
-
-// Platforms other than Win
-#if ! XMP_WinBuild
-int IsEqualGUID ( const GUID& guid1, const GUID& guid2 )
-{
- return (memcmp ( &guid1, &guid2, sizeof(GUID) ) == 0);
-}
-#endif
-
-ASF_Support::ASF_Support() : legacyManager(0), posFileSizeInfo(0) {}
-
-ASF_Support::ASF_Support ( ASF_LegacyManager* _legacyManager ) : posFileSizeInfo(0)
-{
- legacyManager = _legacyManager;
-}
-
-ASF_Support::~ASF_Support()
-{
- legacyManager = 0;
-}
-
-// =============================================================================================
-
-long ASF_Support::OpenASF ( LFA_FileRef fileRef, ObjectState & inOutObjectState )
-{
- XMP_Uns64 pos = 0;
- XMP_Uns64 len;
-
- try {
- pos = LFA_Seek ( fileRef, 0, SEEK_SET );
- } catch ( ... ) {}
-
- if ( pos != 0 ) return 0;
-
- // read first and following chunks
- while ( ReadObject ( fileRef, inOutObjectState, &len, pos) ) {}
-
- return inOutObjectState.objects.size();
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::ReadObject ( LFA_FileRef fileRef, ObjectState & inOutObjectState, XMP_Uns64 * objectLength, XMP_Uns64 & inOutPosition )
-{
-
- try {
-
- XMP_Uns64 startPosition = inOutPosition;
- long bytesRead;
- ASF_ObjectBase objectBase;
-
- bytesRead = LFA_Read ( fileRef, &objectBase, kASF_ObjectBaseLen, true );
- if ( bytesRead != kASF_ObjectBaseLen ) return false;
-
- *objectLength = GetUns64LE ( &objectBase.size );
- inOutPosition += *objectLength;
-
- ObjectData newObject;
-
- newObject.pos = startPosition;
- newObject.len = *objectLength;
- newObject.guid = objectBase.guid;
-
- // xmpIsLastObject indicates, that the XMP-object is the last top-level object
- // reset here, if any another object is read
- inOutObjectState.xmpIsLastObject = false;
-
- if ( IsEqualGUID ( ASF_Header_Object, newObject.guid ) ) {
-
- // header object ?
- this->ReadHeaderObject ( fileRef, inOutObjectState, newObject );
-
- } else if ( IsEqualGUID ( ASF_XMP_Metadata, newObject.guid ) ) {
-
- // check object for XMP GUID
- inOutObjectState.xmpPos = newObject.pos + kASF_ObjectBaseLen;
- inOutObjectState.xmpLen = newObject.len - kASF_ObjectBaseLen;
- inOutObjectState.xmpIsLastObject = true;
- inOutObjectState.xmpObject = newObject;
- newObject.xmp = true;
-
- }
-
- inOutObjectState.objects.push_back ( newObject );
-
- LFA_Seek ( fileRef, inOutPosition, SEEK_SET );
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::ReadHeaderObject ( LFA_FileRef fileRef, ObjectState& inOutObjectState, const ObjectData& newObject )
-{
- if ( ! IsEqualGUID ( ASF_Header_Object, newObject.guid) || (! legacyManager ) ) return false;
-
- std::string buffer;
-
- legacyManager->SetPadding(0);
-
- try {
-
- // read header-object structure
- XMP_Uns64 pos = newObject.pos;
- XMP_Uns32 bufferSize = kASF_ObjectBaseLen + 6;
-
- buffer.clear();
- buffer.reserve ( bufferSize );
- buffer.assign ( bufferSize, ' ' );
- LFA_Seek ( fileRef, pos, SEEK_SET );
- LFA_Read ( fileRef, const_cast<char*>(buffer.data()), bufferSize, true );
-
- XMP_Uns64 read = bufferSize;
- pos += bufferSize;
-
- // read contained header objects
- XMP_Uns32 numberOfHeaders = GetUns32LE ( &buffer[24] );
- ASF_ObjectBase objectBase;
-
- while ( read < newObject.len ) {
-
- LFA_Seek ( fileRef, pos, SEEK_SET );
- if ( kASF_ObjectBaseLen != LFA_Read ( fileRef, &objectBase, kASF_ObjectBaseLen, true ) ) break;
-
- LFA_Seek ( fileRef, pos, SEEK_SET );
- objectBase.size = GetUns64LE ( &objectBase.size );
-
- if ( IsEqualGUID ( ASF_File_Properties_Object, objectBase.guid) && (objectBase.size >= 104 ) ) {
-
- buffer.clear();
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( fileRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- // save position of filesize-information
- posFileSizeInfo = (pos + 40);
-
- // creation date
- std::string sub ( buffer.substr ( 48, 8 ) );
- legacyManager->SetField ( ASF_LegacyManager::fieldCreationDate, sub );
-
- // broadcast flag set ?
- XMP_Uns32 flags = GetUns32LE ( &buffer[88] );
- inOutObjectState.broadcast = (flags & 1);
- legacyManager->SetBroadcast ( inOutObjectState.broadcast );
-
- legacyManager->SetObjectExists ( ASF_LegacyManager::objectFileProperties );
-
- } else if ( IsEqualGUID ( ASF_Content_Description_Object, objectBase.guid) && (objectBase.size >= 34 ) ) {
-
- buffer.clear();
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( fileRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- XMP_Uns16 titleLen = GetUns16LE ( &buffer[24] );
- XMP_Uns16 authorLen = GetUns16LE ( &buffer[26] );
- XMP_Uns16 copyrightLen = GetUns16LE ( &buffer[28] );
- XMP_Uns16 descriptionLen = GetUns16LE ( &buffer[30] );
- XMP_Uns16 ratingLen = GetUns16LE ( &buffer[32] );
-
- XMP_Uns16 fieldPos = 34;
-
- std::string titleStr = buffer.substr ( fieldPos, titleLen );
- fieldPos += titleLen;
- legacyManager->SetField ( ASF_LegacyManager::fieldTitle, titleStr );
-
- std::string authorStr = buffer.substr ( fieldPos, authorLen );
- fieldPos += authorLen;
- legacyManager->SetField ( ASF_LegacyManager::fieldAuthor, authorStr );
-
- std::string copyrightStr = buffer.substr ( fieldPos, copyrightLen );
- fieldPos += copyrightLen;
- legacyManager->SetField ( ASF_LegacyManager::fieldCopyright, copyrightStr );
-
- std::string descriptionStr = buffer.substr ( fieldPos, descriptionLen );
- fieldPos += descriptionLen;
- legacyManager->SetField ( ASF_LegacyManager::fieldDescription, descriptionStr );
-
- /* rating is currently not part of reconciliation
- std::string ratingStr = buffer.substr ( fieldPos, ratingLen );
- fieldPos += ratingLen;
- legacyData.append ( titleStr );
- */
-
- legacyManager->SetObjectExists ( ASF_LegacyManager::objectContentDescription );
-
- } else if ( IsEqualGUID ( ASF_Content_Branding_Object, objectBase.guid ) ) {
-
- buffer.clear();
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( fileRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- XMP_Uns32 fieldPos = 28;
-
- // copyright URL is 3. element with variable size
- for ( int i = 1; i <= 3 ; ++i ) {
- XMP_Uns32 len = GetUns32LE ( &buffer[fieldPos] );
- if ( i == 3 ) {
- std::string copyrightURLStr = buffer.substr ( fieldPos + 4, len );
- legacyManager->SetField ( ASF_LegacyManager::fieldCopyrightURL, copyrightURLStr );
- }
- fieldPos += (len + 4);
- }
-
- legacyManager->SetObjectExists ( ASF_LegacyManager::objectContentBranding );
-
-#if ! Exclude_LicenseURL_Recon
-
- } else if ( IsEqualGUID ( ASF_Content_Encryption_Object, objectBase.guid ) ) {
-
- buffer.clear();
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( fileRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- XMP_Uns32 fieldPos = 24;
-
- // license URL is 4. element with variable size
- for ( int i = 1; i <= 4 ; ++i ) {
- XMP_Uns32 len = GetUns32LE ( &buffer[fieldPos] );
- if ( i == 4 ) {
- std::string licenseURLStr = buffer.substr ( fieldPos + 4, len );
- legacyManager->SetField ( ASF_LegacyManager::fieldLicenseURL, licenseURLStr );
- }
- fieldPos += (len + 4);
- }
-
- legacyManager->SetObjectExists ( objectContentEncryption );
-
-#endif
-
- } else if ( IsEqualGUID ( ASF_Padding_Object, objectBase.guid ) ) {
-
- legacyManager->SetPadding ( legacyManager->GetPadding() + (objectBase.size - 24) );
-
- } else if ( IsEqualGUID ( ASF_Header_Extension_Object, objectBase.guid ) ) {
-
- this->ReadHeaderExtensionObject ( fileRef, inOutObjectState, pos, objectBase );
-
- }
-
- pos += objectBase.size;
- read += objectBase.size;
- }
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- legacyManager->ComputeDigest();
-
- return true;
-}
-
-// =============================================================================================
-
-bool ASF_Support::WriteHeaderObject ( LFA_FileRef sourceRef, LFA_FileRef destRef, const ObjectData& object, ASF_LegacyManager& _legacyManager, bool usePadding )
-{
- if ( ! IsEqualGUID ( ASF_Header_Object, object.guid ) ) return false;
-
- bool ret = false;
-
- std::string buffer;
- XMP_Uns16 valueUns16LE;
- XMP_Uns32 valueUns32LE;
- XMP_Uns64 valueUns64LE;
-
- try {
-
- // read header-object structure
- XMP_Uns64 pos = object.pos;
- XMP_Uns32 bufferSize = kASF_ObjectBaseLen + 6;
-
- buffer.clear();
- buffer.reserve ( bufferSize );
- buffer.assign ( bufferSize, ' ' );
- LFA_Seek ( sourceRef, pos, SEEK_SET );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), bufferSize, true );
-
- XMP_Uns64 read = bufferSize;
- pos += bufferSize;
-
- // read contained header objects
- XMP_Uns32 numberOfHeaders = GetUns32LE ( &buffer[24] );
- ASF_ObjectBase objectBase;
-
- // prepare new header in memory
- std::string header;
-
- int changedObjects = _legacyManager.changedObjects();
- int exportedObjects = 0;
- int writtenObjects = 0;
-
- header.append ( buffer.c_str(), bufferSize );
-
- while ( read < object.len ) {
-
- LFA_Seek ( sourceRef, pos, SEEK_SET );
- if ( kASF_ObjectBaseLen != LFA_Read ( sourceRef, &objectBase, kASF_ObjectBaseLen, true ) ) break;
-
- LFA_Seek ( sourceRef, pos, SEEK_SET );
- objectBase.size = GetUns64LE ( &objectBase.size );
-
- int headerStartPos = header.size();
-
- // save position of filesize-information
- if ( IsEqualGUID ( ASF_File_Properties_Object, objectBase.guid ) ) {
- posFileSizeInfo = (headerStartPos + 40);
- }
-
- // write objects
- if ( IsEqualGUID ( ASF_File_Properties_Object, objectBase.guid ) &&
- (objectBase.size >= 104) && (changedObjects & ASF_LegacyManager::objectFileProperties) ) {
-
- // copy object and replace creation-date
- buffer.reserve ( XMP_Uns32 ( objectBase.size ) );
- buffer.assign ( XMP_Uns32 ( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
- header.append ( buffer, 0, XMP_Uns32( objectBase.size ) );
-
- if ( ! _legacyManager.GetBroadcast() ) {
- buffer = _legacyManager.GetField ( ASF_LegacyManager::fieldCreationDate );
- ReplaceString ( header, buffer, (headerStartPos + 48), 8 );
- }
-
- exportedObjects |= ASF_LegacyManager::objectFileProperties;
-
- } else if ( IsEqualGUID ( ASF_Content_Description_Object, objectBase.guid ) &&
- (objectBase.size >= 34) && (changedObjects & ASF_LegacyManager::objectContentDescription) ) {
-
- // re-create object with xmp-data
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
- // write header only
- header.append ( buffer, 0, XMP_Uns32( kASF_ObjectBaseLen ) );
-
- // write length fields
-
- XMP_Uns16 titleLen = _legacyManager.GetField ( ASF_LegacyManager::fieldTitle).size( );
- valueUns16LE = MakeUns16LE ( titleLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 authorLen = _legacyManager.GetField ( ASF_LegacyManager::fieldAuthor).size( );
- valueUns16LE = MakeUns16LE ( authorLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 copyrightLen = _legacyManager.GetField ( ASF_LegacyManager::fieldCopyright).size( );
- valueUns16LE = MakeUns16LE ( copyrightLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 descriptionLen = _legacyManager.GetField ( ASF_LegacyManager::fieldDescription).size( );
- valueUns16LE = MakeUns16LE ( descriptionLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- // retrieve existing overall length of preceding fields
- XMP_Uns16 precedingLen = 0;
- precedingLen += GetUns16LE ( &buffer[24] ); // Title
- precedingLen += GetUns16LE ( &buffer[26] ); // Author
- precedingLen += GetUns16LE ( &buffer[28] ); // Copyright
- precedingLen += GetUns16LE ( &buffer[30] ); // Description
- // retrieve existing 'Rating' length
- XMP_Uns16 ratingLen = GetUns16LE ( &buffer[32] ); // Rating
- valueUns16LE = MakeUns16LE ( ratingLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- // write field contents
-
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldTitle ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldAuthor ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldCopyright ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldDescription ) );
- header.append ( buffer, (34 + precedingLen), ratingLen );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- exportedObjects |= ASF_LegacyManager::objectContentDescription;
-
- } else if ( IsEqualGUID ( ASF_Content_Branding_Object, objectBase.guid ) &&
- (changedObjects & ASF_LegacyManager::objectContentBranding) ) {
-
- // re-create object with xmp-data
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- // calculate size of fields coming before 'Copyright URL'
- XMP_Uns32 length = 28;
- length += (GetUns32LE ( &buffer[length] ) + 4); // Banner Image Data
- length += (GetUns32LE ( &buffer[length] ) + 4); // Banner Image URL
-
- // write first part of header
- header.append ( buffer, 0, length );
-
- // copyright URL
- length = _legacyManager.GetField ( ASF_LegacyManager::fieldCopyrightURL).size( );
- valueUns32LE = MakeUns32LE ( length );
- header.append ( (const char*)&valueUns32LE, 4 );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldCopyrightURL ) );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- exportedObjects |= ASF_LegacyManager::objectContentBranding;
-
-#if ! Exclude_LicenseURL_Recon
-
- } else if ( IsEqualGUID ( ASF_Content_Encryption_Object, objectBase.guid ) &&
- (changedObjects & ASF_LegacyManager::objectContentEncryption) ) {
-
- // re-create object with xmp-data
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- // calculate size of fields coming before 'License URL'
- XMP_Uns32 length = 24;
- length += (GetUns32LE ( &buffer[length] ) + 4); // Secret Data
- length += (GetUns32LE ( &buffer[length] ) + 4); // Protection Type
- length += (GetUns32LE ( &buffer[length] ) + 4); // Key ID
-
- // write first part of header
- header.append ( buffer, 0, length );
-
- // License URL
- length = _legacyManager.GetField ( ASF_LegacyManager::fieldLicenseURL).size( );
- valueUns32LE = MakeUns32LE ( length );
- header.append ( (const char*)&valueUns32LE, 4 );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldLicenseURL ) );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- exportedObjects |= ASF_LegacyManager::objectContentEncryption;
-
-#endif
-
- } else if ( IsEqualGUID ( ASF_Header_Extension_Object, objectBase.guid ) && usePadding ) {
-
- // re-create object if padding needs to be used
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- ASF_Support::WriteHeaderExtensionObject ( buffer, &header, objectBase, 0 );
-
- } else if ( IsEqualGUID ( ASF_Padding_Object, objectBase.guid ) && usePadding ) {
-
- // eliminate padding (will be created as last object)
-
- } else {
-
- // simply copy all other objects
- buffer.reserve ( XMP_Uns32( objectBase.size ) );
- buffer.assign ( XMP_Uns32( objectBase.size ), ' ' );
- LFA_Read ( sourceRef, const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size), true );
-
- header.append ( buffer, 0, XMP_Uns32( objectBase.size ) );
-
- }
-
- pos += objectBase.size;
- read += objectBase.size;
-
- writtenObjects ++;
-
- }
-
- // any objects to create ?
- int newObjects = (changedObjects ^ exportedObjects);
-
- if ( newObjects ) {
-
- // create new objects with xmp-data
- int headerStartPos;
- ASF_ObjectBase newObjectBase;
- XMP_Uns32 length;
-
- if ( newObjects & ASF_LegacyManager::objectContentDescription ) {
-
- headerStartPos = header.size();
- newObjectBase.guid = ASF_Content_Description_Object;
- newObjectBase.size = 0;
-
- // write object header
- header.append ( (const char*)&newObjectBase, kASF_ObjectBaseLen );
-
- XMP_Uns16 titleLen = _legacyManager.GetField ( ASF_LegacyManager::fieldTitle).size( );
- valueUns16LE = MakeUns16LE ( titleLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 authorLen = _legacyManager.GetField ( ASF_LegacyManager::fieldAuthor).size( );
- valueUns16LE = MakeUns16LE ( authorLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 copyrightLen = _legacyManager.GetField ( ASF_LegacyManager::fieldCopyright).size( );
- valueUns16LE = MakeUns16LE ( copyrightLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 descriptionLen = _legacyManager.GetField ( ASF_LegacyManager::fieldDescription).size( );
- valueUns16LE = MakeUns16LE ( descriptionLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- XMP_Uns16 ratingLen = 0;
- valueUns16LE = MakeUns16LE ( ratingLen );
- header.append ( (const char*)&valueUns16LE, 2 );
-
- // write field contents
-
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldTitle ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldAuthor ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldCopyright ) );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldDescription ) );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- newObjects &= ~ASF_LegacyManager::objectContentDescription;
-
- writtenObjects ++;
-
- }
-
- if ( newObjects & ASF_LegacyManager::objectContentBranding ) {
-
- headerStartPos = header.size();
- newObjectBase.guid = ASF_Content_Branding_Object;
- newObjectBase.size = 0;
-
- // write object header
- header.append ( (const char*)&newObjectBase, kASF_ObjectBaseLen );
-
- // write 'empty' fields
- header.append ( 12, '\0' );
-
- // copyright URL
- length = _legacyManager.GetField ( ASF_LegacyManager::fieldCopyrightURL).size( );
- valueUns32LE = MakeUns32LE ( length );
- header.append ( (const char*)&valueUns32LE, 4 );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldCopyrightURL ) );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- newObjects &= ~ASF_LegacyManager::objectContentBranding;
-
- writtenObjects ++;
-
- }
-
-#if ! Exclude_LicenseURL_Recon
-
- if ( newObjects & ASF_LegacyManager::objectContentEncryption ) {
-
- headerStartPos = header.size();
- newObjectBase.guid = ASF_Content_Encryption_Object;
- newObjectBase.size = 0;
-
- // write object header
- header.append ( (const char*)&newObjectBase, kASF_ObjectBaseLen );
-
- // write 'empty' fields
- header.append ( 12, '\0' );
-
- // License URL
- length = _legacyManager.GetField ( ASF_LegacyManager::fieldLicenseURL).size( );
- valueUns32LE = MakeUns32LE ( length );
- header.append ( (const char*)&valueUns32LE, 4 );
- header.append ( _legacyManager.GetField ( ASF_LegacyManager::fieldLicenseURL ) );
-
- // update new object size
- valueUns64LE = MakeUns64LE ( header.size() - headerStartPos );
- std::string newSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newSize, (headerStartPos + 16), 8 );
-
- newObjects &= ~ASF_LegacyManager::objectContentEncryption;
-
- writtenObjects ++;
-
- }
-
-#endif
-
- }
-
- // create padding object ?
- if ( usePadding && (header.size ( ) < object.len ) ) {
- ASF_Support::CreatePaddingObject ( &header, (object.len - header.size()) );
- writtenObjects ++;
- }
-
- // update new header-object size
- valueUns64LE = MakeUns64LE ( header.size() );
- std::string newValue ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( header, newValue, 16, 8 );
-
- // update new number of Header objects
- valueUns32LE = MakeUns32LE ( writtenObjects );
- newValue = std::string ( (const char*)&valueUns32LE, 4 );
- ReplaceString ( header, newValue, 24, 4 );
-
- // if we are operating on the same file (in-place update), place pointer before writing
- if ( sourceRef == destRef ) LFA_Seek ( destRef, object.pos, SEEK_SET );
-
- // write header
- LFA_Write ( destRef, header.c_str(), header.size() );
-
- } catch ( ... ) {
-
- ret = false;
-
- }
-
- return ret;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::UpdateHeaderObject ( LFA_FileRef fileRef, const ObjectData& object, ASF_LegacyManager& _legacyManager )
-{
- return ASF_Support::WriteHeaderObject ( fileRef, fileRef, object, _legacyManager, true );
-}
-
-// =============================================================================================
-
-bool ASF_Support::UpdateFileSize ( LFA_FileRef fileRef )
-{
- if ( fileRef == 0 ) return false;
-
- XMP_Uns64 posCurrent = LFA_Seek ( fileRef, 0, SEEK_CUR );
- XMP_Uns64 newSizeLE = MakeUns64LE ( LFA_Measure ( fileRef ) );
-
- if ( this->posFileSizeInfo != 0 ) {
-
- LFA_Seek ( fileRef, this->posFileSizeInfo, SEEK_SET );
-
- } else {
-
- // The position of the file size field is not known, find it.
-
- ASF_ObjectBase objHeader;
-
- // Read the Header object at the start of the file.
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
- LFA_Read ( fileRef, &objHeader, kASF_ObjectBaseLen, kLFA_RequireAll );
- if ( ! IsEqualGUID ( ASF_Header_Object, objHeader.guid ) ) return false;
-
- XMP_Uns32 childCount;
- LFA_Read ( fileRef, &childCount, 4, kLFA_RequireAll );
- childCount = GetUns32LE ( &childCount );
-
- LFA_Seek ( fileRef, 2, SEEK_CUR ); // Skip the 2 reserved bytes.
-
- // Look for the File Properties object in the Header's children.
-
- for ( ; childCount > 0; --childCount ) {
- LFA_Read ( fileRef, &objHeader, kASF_ObjectBaseLen, kLFA_RequireAll );
- if ( IsEqualGUID ( ASF_File_Properties_Object, objHeader.guid ) ) break;
- XMP_Uns64 dataLen = GetUns64LE ( &objHeader.size ) - 24;
- LFA_Seek ( fileRef, dataLen, SEEK_CUR ); // Skip this object's data.
- }
- if ( childCount == 0 ) return false;
-
- // Seek to the file size field.
-
- XMP_Uns64 fpoSize = GetUns64LE ( &objHeader.size );
- if ( fpoSize < (16+8+16+8) ) return false;
- LFA_Seek ( fileRef, 16, SEEK_CUR ); // Skip to the file size field.
-
- }
-
- LFA_Write ( fileRef, &newSizeLE, 8 ); // Write the new file size.
-
- LFA_Seek ( fileRef, posCurrent, SEEK_SET );
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::ReadHeaderExtensionObject ( LFA_FileRef fileRef, ObjectState& inOutObjectState, const XMP_Uns64& _pos, const ASF_ObjectBase& _objectBase )
-{
- if ( ! IsEqualGUID ( ASF_Header_Extension_Object, _objectBase.guid) || (! legacyManager ) ) return false;
-
- try {
-
- // read extended header-object structure beginning at the data part (offset = 46)
- const XMP_Uns64 offset = 46;
- XMP_Uns64 read = 0;
- XMP_Uns64 data = (_objectBase.size - offset);
- XMP_Uns64 pos = (_pos + offset);
-
- ASF_ObjectBase objectBase;
-
- while ( read < data ) {
-
- LFA_Seek ( fileRef, pos, SEEK_SET );
- if ( kASF_ObjectBaseLen != LFA_Read ( fileRef, &objectBase, kASF_ObjectBaseLen, true ) ) break;
-
- objectBase.size = GetUns64LE ( &objectBase.size );
-
- if ( IsEqualGUID ( ASF_Padding_Object, objectBase.guid ) ) {
- legacyManager->SetPadding ( legacyManager->GetPadding() + (objectBase.size - 24) );
- }
-
- pos += objectBase.size;
- read += objectBase.size;
-
- }
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::WriteHeaderExtensionObject ( const std::string& buffer, std::string* header, const ASF_ObjectBase& _objectBase, const int /*reservePadding*/ )
-{
- if ( ! IsEqualGUID ( ASF_Header_Extension_Object, _objectBase.guid ) || (! header) || (buffer.size() < 46) ) return false;
-
- const XMP_Uns64 offset = 46;
- int startPos = header->size();
-
- // copy header base
- header->append ( buffer, 0, offset );
-
- // read extended header-object structure beginning at the data part (offset = 46)
- XMP_Uns64 read = 0;
- XMP_Uns64 data = (_objectBase.size - offset);
- XMP_Uns64 pos = offset;
-
- ASF_ObjectBase objectBase;
-
- while ( read < data ) {
-
- memcpy ( &objectBase, &buffer[int(pos)], kASF_ObjectBaseLen );
- objectBase.size = GetUns64LE ( &objectBase.size );
-
- if ( IsEqualGUID ( ASF_Padding_Object, objectBase.guid ) ) {
- // eliminate
- } else {
- // copy other objects
- header->append ( buffer, XMP_Uns32(pos), XMP_Uns32(objectBase.size) );
- }
-
- pos += objectBase.size;
- read += objectBase.size;
-
- }
-
- // update header extension data size
- XMP_Uns32 valueUns32LE = MakeUns32LE ( header->size() - startPos - offset );
- std::string newDataSize ( (const char*)&valueUns32LE, 4 );
- ReplaceString ( *header, newDataSize, (startPos + 42), 4 );
-
- // update new object size
- XMP_Uns64 valueUns64LE = MakeUns64LE ( header->size() - startPos );
- std::string newObjectSize ( (const char*)&valueUns64LE, 8 );
- ReplaceString ( *header, newObjectSize, (startPos + 16), 8 );
-
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::CreatePaddingObject ( std::string* header, const XMP_Uns64 size )
-{
- if ( ( ! header) || (size < 24) ) return false;
-
- ASF_ObjectBase newObjectBase;
-
- newObjectBase.guid = ASF_Padding_Object;
- newObjectBase.size = MakeUns64LE ( size );
-
- // write object header
- header->append ( (const char*)&newObjectBase, kASF_ObjectBaseLen );
-
- // write 'empty' padding
- header->append ( XMP_Uns32 ( size - 24 ), '\0' );
-
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::WriteXMPObject ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer )
-{
- bool ret = false;
-
- ASF_ObjectBase objectBase = { ASF_XMP_Metadata, 0 };
- objectBase.size = MakeUns64LE ( len + kASF_ObjectBaseLen );
-
- try {
- LFA_Write ( fileRef, &objectBase, kASF_ObjectBaseLen );
- LFA_Write ( fileRef, inBuffer, len );
- ret = true;
- } catch ( ... ) {}
-
- return ret;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::UpdateXMPObject ( LFA_FileRef fileRef, const ObjectData& object, XMP_Uns32 len, const char * inBuffer )
-{
- bool ret = false;
-
- ASF_ObjectBase objectBase = { ASF_XMP_Metadata, 0 };
- objectBase.size = MakeUns64LE ( len + kASF_ObjectBaseLen );
-
- try {
- LFA_Seek ( fileRef, object.pos, SEEK_SET );
- LFA_Write ( fileRef, &objectBase, kASF_ObjectBaseLen );
- LFA_Write ( fileRef, inBuffer, len );
- ret = true;
- } catch ( ... ) {}
-
- return ret;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::CopyObject ( LFA_FileRef sourceRef, LFA_FileRef destRef, const ObjectData& object )
-{
- try {
- LFA_Seek ( sourceRef, object.pos, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, object.len );
- } catch ( ... ) {
- return false;
- }
-
- return true;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns64 len, char * outBuffer )
-{
- try {
-
- if ( (fileRef == 0) || (outBuffer == 0) ) return false;
-
- LFA_Seek (fileRef, pos, SEEK_SET );
- long bytesRead = LFA_Read ( fileRef, outBuffer, XMP_Int32(len), true );
- if ( XMP_Uns32 ( bytesRead ) != len ) return false;
-
- return true;
-
- } catch ( ... ) {}
-
- return false;
-
-}
-
-// =============================================================================================
-
-bool ASF_Support::WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, const char * inBuffer )
-{
- try {
-
- if ( (fileRef == 0) || (inBuffer == 0) ) return false;
-
- LFA_Seek (fileRef, pos, SEEK_SET );
- LFA_Write( fileRef, inBuffer, len );
-
- return true;
-
- } catch ( ... ) {}
-
- return false;
-
-}
-
-// =================================================================================================
-
-std::string ASF_Support::ReplaceString ( std::string& operand, std::string& str, int offset, int count )
-{
- std::basic_string<char>::iterator iterF1, iterL1, iterF2, iterL2;
-
- iterF1 = operand.begin() + offset;
- iterL1 = operand.begin() + offset + count;
- iterF2 = str.begin();
- iterL2 = str.begin() + count;
-
- return operand.replace ( iterF1, iterL1, iterF2, iterL2 );
-
-}
-
-// =================================================================================================
-
-ASF_LegacyManager::ASF_LegacyManager() : fields(fieldLast), broadcastSet(false), digestComputed(false),
- imported(false), objectsExisting(0), objectsToExport(0), legacyDiff(0), padding(0)
-{
- // Nothing more to do.
-}
-
-// =================================================================================================
-
-ASF_LegacyManager::~ASF_LegacyManager()
-{
- // Nothing to do.
-}
-
-// =================================================================================================
-
-bool ASF_LegacyManager::SetField ( fieldType field, const std::string& value )
-{
- if ( field >= fieldLast ) return false;
-
- unsigned int maxSize = this->GetFieldMaxSize ( field );
-
- if (value.size ( ) <= maxSize ) {
- fields[field] = value;
- } else {
- fields[field] = value.substr ( 0, maxSize );
- }
-
- if ( field == fieldCopyrightURL ) NormalizeStringDisplayASCII ( fields[field] );
-
- #if ! Exclude_LicenseURL_Recon
- if ( field == fieldLicenseURL ) NormalizeStringDisplayASCII ( fields[field] );
- #endif
-
- return true;
-
-}
-
-// =================================================================================================
-
-std::string ASF_LegacyManager::GetField ( fieldType field )
-{
- if ( field >= fieldLast ) return std::string();
- return fields[field];
-}
-
-// =================================================================================================
-
-unsigned int ASF_LegacyManager::GetFieldMaxSize ( fieldType field )
-{
- unsigned int maxSize = 0;
-
- switch ( field ) {
-
- case fieldCreationDate :
- maxSize = 8;
- break;
-
- case fieldTitle :
- case fieldAuthor :
- case fieldCopyright :
- case fieldDescription :
- maxSize = 0xFFFF;
- break;
-
- case fieldCopyrightURL :
-#if ! Exclude_LicenseURL_Recon
- case fieldLicenseURL :
-#endif
- maxSize = 0xFFFFFFFF;
- break;
-
- default:
- break;
-
- }
-
- return maxSize;
-
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::SetObjectExists ( objectType object )
-{
- objectsExisting |= object;
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::SetBroadcast ( const bool broadcast )
-{
- broadcastSet = broadcast;
-}
-
-// =================================================================================================
-
-bool ASF_LegacyManager::GetBroadcast()
-{
- return broadcastSet;
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::ComputeDigest()
-{
- MD5_CTX context;
- MD5_Digest digest;
- char buffer[40];
-
- MD5Init ( &context );
- digestStr.clear();
- digestStr.reserve ( 160 );
-
- for ( int type=0; type < fieldLast; ++type ) {
-
- if (fields[type].size ( ) > 0 ) {
- snprintf ( buffer, sizeof(buffer), "%d,", type );
- digestStr.append ( buffer );
- MD5Update ( &context, (XMP_Uns8*)fields[type].data(), fields[type].size() );
- }
-
- }
-
- digestStr[digestStr.size()-1] = ';';
-
- MD5Final ( digest, &context );
-
- size_t in, out;
- for ( in = 0, out = 0; in < 16; in += 1, out += 2 ) {
- XMP_Uns8 byte = digest[in];
- buffer[out] = ReconcileUtils::kHexDigits [ byte >> 4 ];
- buffer[out+1] = ReconcileUtils::kHexDigits [ byte & 0xF ];
- }
- buffer[32] = 0;
-
- digestStr.append ( buffer );
-
- digestComputed = true;
-
-}
-
-// =================================================================================================
-
-bool ASF_LegacyManager::CheckDigest ( const SXMPMeta& xmp )
-{
- bool ret = false;
-
- if ( ! digestComputed ) this->ComputeDigest();
-
- std::string oldDigest;
-
- if ( xmp.GetProperty ( kXMP_NS_ASF, "NativeDigest", &oldDigest, 0 ) ) {
- ret = (digestStr == oldDigest);
- }
-
- return ret;
-
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::SetDigest ( SXMPMeta* xmp )
-{
- if ( ! digestComputed ) this->ComputeDigest();
-
- xmp->SetProperty ( kXMP_NS_ASF, "NativeDigest", digestStr.c_str() );
-
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::ImportLegacy ( SXMPMeta* xmp )
-{
- std::string utf8;
-
- if ( ! broadcastSet ) {
- ConvertMSDateToISODate ( fields[fieldCreationDate], &utf8 );
- if ( ! utf8.empty() ) xmp->SetProperty ( kXMP_NS_XMP, "CreateDate", utf8.c_str(), kXMP_DeleteExisting );
- }
-
- FromUTF16 ( (UTF16Unit*)fields[fieldTitle].c_str(), (fields[fieldTitle].size() / 2), &utf8, false );
- if ( ! utf8.empty() ) xmp->SetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", utf8.c_str(), kXMP_DeleteExisting );
-
- xmp->DeleteProperty ( kXMP_NS_DC, "creator" );
- FromUTF16 ( (UTF16Unit*)fields[fieldAuthor].c_str(), (fields[fieldAuthor].size() / 2), &utf8, false );
- if ( ! utf8.empty() ) SXMPUtils::SeparateArrayItems ( xmp, kXMP_NS_DC, "creator",
- (kXMP_PropArrayIsOrdered | kXMPUtil_AllowCommas), utf8.c_str() );
-
- FromUTF16 ( (UTF16Unit*)fields[fieldCopyright].c_str(), (fields[fieldCopyright].size() / 2), &utf8, false );
- if ( ! utf8.empty() ) xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", utf8.c_str(), kXMP_DeleteExisting );
-
- FromUTF16 ( (UTF16Unit*)fields[fieldDescription].c_str(), (fields[fieldDescription].size() / 2), &utf8, false );
- if ( ! utf8.empty() ) xmp->SetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", utf8.c_str(), kXMP_DeleteExisting );
-
- if ( ! utf8.empty() ) xmp->SetProperty ( kXMP_NS_XMP_Rights, "WebStatement", fields[fieldCopyrightURL].c_str(), kXMP_DeleteExisting );
-
-#if ! Exclude_LicenseURL_Recon
- if ( ! fields[fieldLicenseURL].empty() ) xmp->SetProperty ( kXMP_NS_XMP_Rights, "Certificate", fields[fieldLicenseURL].c_str(), kXMP_DeleteExisting );
-#endif
-
- imported = true;
-
-}
-
-// =================================================================================================
-
-int ASF_LegacyManager::ExportLegacy ( const SXMPMeta& xmp )
-{
- int changed = 0;
- objectsToExport = 0;
- legacyDiff = 0;
-
- std::string utf8;
- std::string utf16;
- XMP_OptionBits flags;
-
- if ( ! broadcastSet ) {
- if ( xmp.GetProperty ( kXMP_NS_XMP, "CreateDate", &utf8, &flags ) ) {
- std::string date;
- ConvertISODateToMSDate ( utf8, &date );
- if ( fields[fieldCreationDate] != date ) {
- legacyDiff += date.size();
- legacyDiff -= fields[fieldCreationDate].size();
- this->SetField ( fieldCreationDate, date );
- objectsToExport |= objectFileProperties;
- changed ++;
- }
- }
- }
-
- if ( xmp.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &utf8, &flags ) ) {
- NormalizeStringTrailingNull ( utf8 );
- ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
- if ( fields[fieldTitle] != utf16 ) {
- legacyDiff += utf16.size();
- legacyDiff -= fields[fieldTitle].size();
- this->SetField ( fieldTitle, utf16 );
- objectsToExport |= objectContentDescription;
- changed ++;
- }
- }
-
- utf8.clear();
- SXMPUtils::CatenateArrayItems ( xmp, kXMP_NS_DC, "creator", 0, 0, kXMPUtil_AllowCommas, &utf8 );
- if ( ! utf8.empty() ) {
- NormalizeStringTrailingNull ( utf8 );
- ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
- if ( fields[fieldAuthor] != utf16 ) {
- legacyDiff += utf16.size();
- legacyDiff -= fields[fieldAuthor].size();
- this->SetField ( fieldAuthor, utf16 );
- objectsToExport |= objectContentDescription;
- changed ++;
- }
- }
-
- if ( xmp.GetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", 0, &utf8, &flags ) ) {
- NormalizeStringTrailingNull ( utf8 );
- ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
- if ( fields[fieldCopyright] != utf16 ) {
- legacyDiff += utf16.size();
- legacyDiff -= fields[fieldCopyright].size();
- this->SetField ( fieldCopyright, utf16 );
- objectsToExport |= objectContentDescription;
- changed ++;
- }
- }
-
- if ( xmp.GetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", 0, &utf8, &flags ) ) {
- NormalizeStringTrailingNull ( utf8 );
- ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
- if ( fields[fieldDescription] != utf16 ) {
- legacyDiff += utf16.size();
- legacyDiff -= fields[fieldDescription].size();
- this->SetField ( fieldDescription, utf16 );
- objectsToExport |= objectContentDescription;
- changed ++;
- }
- }
-
- if ( xmp.GetProperty ( kXMP_NS_XMP_Rights, "WebStatement", &utf8, &flags ) ) {
- NormalizeStringTrailingNull ( utf8 );
- if ( fields[fieldCopyrightURL] != utf8 ) {
- legacyDiff += utf8.size();
- legacyDiff -= fields[fieldCopyrightURL].size();
- this->SetField ( fieldCopyrightURL, utf8 );
- objectsToExport |= objectContentBranding;
- changed ++;
- }
- }
-
-#if ! Exclude_LicenseURL_Recon
- if ( xmp.GetProperty ( kXMP_NS_XMP_Rights, "Certificate", &utf8, &flags ) ) {
- NormalizeStringTrailingNull ( utf8 );
- if ( fields[fieldLicenseURL] != utf8 ) {
- legacyDiff += utf8.size();
- legacyDiff -= fields[fieldLicenseURL].size();
- this->SetField ( fieldLicenseURL, utf8 );
- objectsToExport |= objectContentEncryption;
- changed ++;
- }
- }
-#endif
-
- // find objects, that would need to be created on legacy export
- int newObjects = (objectsToExport & !objectsExisting);
-
- // calculate minimum storage for new objects, that might be created on export
- if ( newObjects & objectContentDescription )
- legacyDiff += sizeContentDescription;
- if ( newObjects & objectContentBranding )
- legacyDiff += sizeContentBranding;
- if ( newObjects & objectContentEncryption )
- legacyDiff += sizeContentEncryption;
-
- ComputeDigest();
-
- return changed;
-
-}
-
-// =================================================================================================
-
-bool ASF_LegacyManager::hasLegacyChanged()
-{
- return (objectsToExport != 0);
-}
-
-// =================================================================================================
-
-XMP_Int64 ASF_LegacyManager::getLegacyDiff()
-{
- return (this->hasLegacyChanged() ? legacyDiff : 0);
-}
-
-// =================================================================================================
-
-int ASF_LegacyManager::changedObjects()
-{
- return objectsToExport;
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::SetPadding ( XMP_Int64 _padding )
-{
- padding = _padding;
-}
-
-// =================================================================================================
-
-XMP_Int64 ASF_LegacyManager::GetPadding()
-{
- return padding;
-}
-
-// =================================================================================================
-
-std::string ASF_LegacyManager::NormalizeStringDisplayASCII ( std::string& operand )
-{
- std::basic_string<char>::iterator current = operand.begin();
- std::basic_string<char>::iterator end = operand.end();;
-
- for ( ; (current != end); ++current ) {
- char element = *current;
- if ( ( (element < 0x21) && (element != 0x00)) || (element > 0x7e) ) {
- *current = '?';
- }
- }
-
- return operand;
-
-}
-
-// =================================================================================================
-
-std::string ASF_LegacyManager::NormalizeStringTrailingNull ( std::string& operand )
-{
- if ( ( operand.size() > 0) && (operand[operand.size() - 1] != '\0') ) {
- operand.append ( 1, '\0' );
- }
-
- return operand;
-
-}
-
-// =================================================================================================
-
-int ASF_LegacyManager::DaysInMonth ( XMP_Int32 year, XMP_Int32 month )
-{
-
- static short daysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
-
- int days = daysInMonth [ month ];
- if ( (month == 2) && IsLeapYear ( year ) ) days += 1;
-
- return days;
-
-}
-
-// =================================================================================================
-
-bool ASF_LegacyManager::IsLeapYear ( long year )
-{
-
- if ( year < 0 ) year = -year + 1; // Fold the negative years, assuming there is a year 0.
-
- if ( (year % 4) != 0 ) return false; // Not a multiple of 4.
- if ( (year % 100) != 0 ) return true; // A multiple of 4 but not a multiple of 100.
- if ( (year % 400) == 0 ) return true; // A multiple of 400.
-
- return false; // A multiple of 100 but not a multiple of 400.
-
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::ConvertMSDateToISODate ( std::string& source, std::string* dest )
-{
-
- XMP_Int64 creationDate = GetUns64LE ( source.c_str() );
- XMP_Int64 totalSecs = creationDate / (10*1000*1000);
- XMP_Int32 nanoSec = ( ( XMP_Int32) (creationDate - (totalSecs * 10*1000*1000)) ) * 100;
-
- XMP_Int32 days = (XMP_Int32) (totalSecs / 86400);
- totalSecs -= ( ( XMP_Int64)days * 86400 );
-
- XMP_Int32 hour = (XMP_Int32) (totalSecs / 3600);
- totalSecs -= ( ( XMP_Int64)hour * 3600 );
-
- XMP_Int32 minute = (XMP_Int32) (totalSecs / 60);
- totalSecs -= ( ( XMP_Int64)minute * 60 );
-
- XMP_Int32 second = (XMP_Int32)totalSecs;
-
- // A little more simple code converts this to an XMP date string:
-
- XMP_DateTime date;
- memset ( &date, 0, sizeof ( date ) );
-
- date.year = 1601; // The MS date origin.
- date.month = 1;
- date.day = 1;
-
- date.day += days; // Add in the delta.
- date.hour = hour;
- date.minute = minute;
- date.second = second;
- date.nanoSecond = nanoSec;
-
- date.hasTimeZone = true; // ! Needed for ConvertToUTCTime to do anything.
- SXMPUtils::ConvertToUTCTime ( &date ); // Normalize the date/time.
- SXMPUtils::ConvertFromDate ( date, dest ); // Convert to an ISO 8601 string.
-
-}
-
-// =================================================================================================
-
-void ASF_LegacyManager::ConvertISODateToMSDate ( std::string& source, std::string* dest )
-{
- XMP_DateTime date;
- SXMPUtils::ConvertToDate ( source, &date );
- SXMPUtils::ConvertToUTCTime ( &date );
-
- XMP_Int64 creationDate;
- creationDate = date.nanoSecond / 100;
- creationDate += (XMP_Int64 ( date.second) * (10*1000*1000) );
- creationDate += (XMP_Int64 ( date.minute) * 60 * (10*1000*1000) );
- creationDate += (XMP_Int64 ( date.hour) * 3600 * (10*1000*1000) );
-
- XMP_Int32 days = (date.day - 1);
-
- --date.month;
- while ( date.month >= 1 ) {
- days += DaysInMonth ( date.year, date.month );
- --date.month;
- }
-
- --date.year;
- while ( date.year >= 1601 ) {
- days += (IsLeapYear ( date.year) ? 366 : 365 );
- --date.year;
- }
-
- creationDate += (XMP_Int64 ( days) * 86400 * (10*1000*1000) );
-
- creationDate = GetUns64LE ( &creationDate );
- dest->assign ( (const char*)&creationDate, 8 );
-
-}
diff --git a/source/XMPFiles/FormatSupport/ASF_Support.hpp b/source/XMPFiles/FormatSupport/ASF_Support.hpp
deleted file mode 100644
index e170cb2..0000000
--- a/source/XMPFiles/FormatSupport/ASF_Support.hpp
+++ /dev/null
@@ -1,224 +0,0 @@
-#ifndef __ASF_Support_hpp__
-#define __ASF_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-#include "Reconcile_Impl.hpp"
-
-// currently exclude LicenseURL from reconciliation
-#define Exclude_LicenseURL_Recon 1
-#define EXCLUDE_LICENSEURL_RECON 1
-
-// Defines for platforms other than Win
-#if ! XMP_WinBuild
-
- typedef struct _GUID
- {
- XMP_Uns32 Data1;
- XMP_Uns16 Data2;
- XMP_Uns16 Data3;
- XMP_Uns8 Data4[8];
- } GUID;
-
- int IsEqualGUID ( const GUID& guid1, const GUID& guid2 );
-
- static const GUID GUID_NULL = { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
-
-#endif
-
-// header object
-static const GUID ASF_Header_Object = { MakeUns32LE(0x75b22630), MakeUns16LE(0x668e), MakeUns16LE(0x11cf), { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c } };
-// contains ...
-static const GUID ASF_File_Properties_Object = { MakeUns32LE(0x8cabdca1), MakeUns16LE(0xa947), MakeUns16LE(0x11cf), { 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 } };
-static const GUID ASF_Content_Description_Object = { MakeUns32LE(0x75b22633), MakeUns16LE(0x668e), MakeUns16LE(0x11cf), { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c } };
-static const GUID ASF_Content_Branding_Object = { MakeUns32LE(0x2211b3fa), MakeUns16LE(0xbd23), MakeUns16LE(0x11d2), { 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e } };
-static const GUID ASF_Content_Encryption_Object = { MakeUns32LE(0x2211b3fb), MakeUns16LE(0xbd23), MakeUns16LE(0x11d2), { 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e } };
-// padding
-// Remark: regarding to Microsofts spec only the ASF_Header_Object contains a ASF_Padding_Object
-// Real world files show, that the ASF_Header_Extension_Object contains a ASF_Padding_Object
-static const GUID ASF_Header_Extension_Object = { MakeUns32LE(0x5fbf03b5), MakeUns16LE(0xa92e), MakeUns16LE(0x11cf), { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 } };
-static const GUID ASF_Padding_Object = { MakeUns32LE(0x1806d474), MakeUns16LE(0xcadf), MakeUns16LE(0x4509), { 0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8 } };
-
-// data object
-static const GUID ASF_Data_Object = { MakeUns32LE(0x75b22636), MakeUns16LE(0x668e), MakeUns16LE(0x11cf), { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c } };
-
-// XMP object
-static const GUID ASF_XMP_Metadata = { MakeUns32LE(0xbe7acfcb), MakeUns16LE(0x97a9), MakeUns16LE(0x42e8), { 0x9c, 0x71, 0x99, 0x94, 0x91, 0xe3, 0xaf, 0xac } };
-
-static const int guidLen = sizeof(GUID);
-
-typedef struct _ASF_ObjectBase
-{
- GUID guid;
- XMP_Uns64 size;
-
-} ASF_ObjectBase;
-
-static const int kASF_ObjectBaseLen = sizeof(ASF_ObjectBase);
-
-// =================================================================================================
-
-class ASF_LegacyManager {
-public:
-
- enum objectType {
- objectFileProperties = 1 << 0,
- objectContentDescription = 1 << 1,
- objectContentBranding = 1 << 2,
- objectContentEncryption = 1 << 3
- };
-
- enum minObjectSize {
- sizeContentDescription = 34,
- sizeContentBranding = 40,
- sizeContentEncryption = 40
- };
-
- enum fieldType {
- // File_Properties_Object
- fieldCreationDate = 0,
- // Content_Description_Object
- fieldTitle,
- fieldAuthor,
- fieldCopyright,
- fieldDescription,
- // Content_Branding_Object
- fieldCopyrightURL,
- #if ! Exclude_LicenseURL_Recon
- // Content_Encryption_Object
- fieldLicenseURL,
- #endif
- // last
- fieldLast
- };
-
- ASF_LegacyManager();
- virtual ~ASF_LegacyManager();
-
- bool SetField ( fieldType field, const std::string& value );
- std::string GetField ( fieldType field );
- unsigned int GetFieldMaxSize ( fieldType field );
-
- void SetObjectExists ( objectType object );
-
- void SetBroadcast ( const bool broadcast );
- bool GetBroadcast();
-
- void ComputeDigest();
- bool CheckDigest ( const SXMPMeta& xmp );
- void SetDigest ( SXMPMeta* xmp );
-
- void ImportLegacy ( SXMPMeta* xmp );
- int ExportLegacy ( const SXMPMeta& xmp );
- bool hasLegacyChanged();
- XMP_Int64 getLegacyDiff();
- int changedObjects();
-
- void SetPadding ( XMP_Int64 padding );
- XMP_Int64 GetPadding();
-
-private:
-
- typedef std::vector<std::string> TFields;
- TFields fields;
- bool broadcastSet;
-
- std::string digestStr;
- bool digestComputed;
-
- bool imported;
- int objectsExisting;
- int objectsToExport;
- XMP_Int64 legacyDiff;
- XMP_Int64 padding;
-
- static std::string NormalizeStringDisplayASCII ( std::string& operand );
- static std::string NormalizeStringTrailingNull ( std::string& operand );
-
- static void ConvertMSDateToISODate ( std::string& source, std::string* dest );
- static void ConvertISODateToMSDate ( std::string& source, std::string* dest );
-
- static int DaysInMonth ( XMP_Int32 year, XMP_Int32 month );
- static bool IsLeapYear ( long year );
-
-}; // class ASF_LegacyManager
-
-// =================================================================================================
-
-class ASF_Support {
-public:
-
- class ObjectData {
- public:
- ObjectData() : pos(0), len(0), guid(GUID_NULL), xmp(false) {}
- virtual ~ObjectData() {}
- XMP_Uns64 pos; // file offset of object
- XMP_Uns64 len; // length of object data
- GUID guid; // object GUID
- bool xmp; // object with XMP ?
- };
-
- typedef std::vector<ObjectData> ObjectVector;
- typedef ObjectVector::iterator ObjectIterator;
-
- class ObjectState {
-
- public:
- ObjectState() : xmpPos(0), xmpLen(0), xmpIsLastObject(false), broadcast(false) {}
- virtual ~ObjectState() {}
- XMP_Uns64 xmpPos;
- XMP_Uns64 xmpLen;
- bool xmpIsLastObject;
- bool broadcast;
- ObjectData xmpObject;
- ObjectVector objects;
- };
-
- ASF_Support();
- ASF_Support ( ASF_LegacyManager* legacyManager );
- virtual ~ASF_Support();
-
- long OpenASF ( LFA_FileRef fileRef, ObjectState & inOutObjectState );
-
- bool ReadObject ( LFA_FileRef fileRef, ObjectState & inOutObjectState, XMP_Uns64 * objectLength, XMP_Uns64 & inOutPosition );
-
- bool ReadHeaderObject ( LFA_FileRef fileRef, ObjectState& inOutObjectState, const ObjectData& newObject );
- bool WriteHeaderObject ( LFA_FileRef sourceRef, LFA_FileRef destRef, const ObjectData& object, ASF_LegacyManager& legacyManager, bool usePadding );
- bool UpdateHeaderObject ( LFA_FileRef fileRef, const ObjectData& object, ASF_LegacyManager& legacyManager );
-
- bool UpdateFileSize ( LFA_FileRef fileRef );
-
- bool ReadHeaderExtensionObject ( LFA_FileRef fileRef, ObjectState& inOutObjectState, const XMP_Uns64& pos, const ASF_ObjectBase& objectBase );
- static bool WriteHeaderExtensionObject ( const std::string& buffer, std::string* header, const ASF_ObjectBase& objectBase, const int reservePadding );
-
- static bool CreatePaddingObject ( std::string* header, const XMP_Uns64 size );
-
- static bool WriteXMPObject ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer );
- static bool UpdateXMPObject ( LFA_FileRef fileRef, const ObjectData& object, XMP_Uns32 len, const char * inBuffer );
- static bool CopyObject ( LFA_FileRef sourceRef, LFA_FileRef destRef, const ObjectData& object );
-
- static bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns64 len, char * outBuffer );
- static bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, const char * inBuffer );
-
-private:
-
- ASF_LegacyManager* legacyManager;
- XMP_Uns64 posFileSizeInfo;
-
- static std::string ReplaceString ( std::string& operand, std::string& str, int offset, int count );
-
-}; // class ASF_Support
-
-// =================================================================================================
-
-#endif // __ASF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/ID3_Support.hpp b/source/XMPFiles/FormatSupport/ID3_Support.hpp
deleted file mode 100644
index e243d24..0000000
--- a/source/XMPFiles/FormatSupport/ID3_Support.hpp
+++ /dev/null
@@ -1,784 +0,0 @@
-#ifndef __ID3_Support_hpp__
-#define __ID3_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "UnicodeConversions.hpp"
-#include "Reconcile_Impl.hpp"
-#include <vector>
-
-#if XMP_WinBuild
- #define stricmp _stricmp
-#else
- static int stricmp ( const char * left, const char * right ) // Case insensitive ASCII compare.
- {
- char chL = *left; // ! Allow for 0 passes in the loop (one string is empty).
- char chR = *right; // ! Return -1 for stricmp ( "a", "Z" ).
-
- for ( ; (*left != 0) && (*right != 0); ++left, ++right ) {
- chL = *left;
- chR = *right;
- if ( chL == chR ) continue;
- if ( ('A' <= chL) && (chL <= 'Z') ) chL |= 0x20;
- if ( ('A' <= chR) && (chR <= 'Z') ) chR |= 0x20;
- if ( chL != chR ) break;
- }
-
- if ( chL == chR ) return 0;
- if ( chL < chR ) return -1;
- return 1;
- }
-#endif
-
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-namespace ID3_Support
-{
- // Genres
- static char Genres[128][32]={
- "Blues", // 0
- "Classic Rock", // 1
- "Country", // 2
- "Dance",
- "Disco",
- "Funk",
- "Grunge",
- "Hip-Hop",
- "Jazz", // 8
- "Metal",
- "New Age", // 10
- "Oldies",
- "Other", // 12
- "Pop",
- "R&B",
- "Rap",
- "Reggae", // 16
- "Rock", // 17
- "Techno",
- "Industrial",
- "Alternative",
- "Ska",
- "Death Metal",
- "Pranks",
- "Soundtrack", // 24
- "Euro-Techno",
- "Ambient",
- "Trip-Hop",
- "Vocal",
- "Jazz+Funk",
- "Fusion",
- "Trance",
- "Classical", // 32
- "Instrumental",
- "Acid",
- "House",
- "Game",
- "Sound Clip",
- "Gospel",
- "Noise",
- "AlternRock",
- "Bass",
- "Soul", //42
- "Punk",
- "Space",
- "Meditative",
- "Instrumental Pop",
- "Instrumental Rock",
- "Ethnic",
- "Gothic",
- "Darkwave",
- "Techno-Industrial",
- "Electronic",
- "Pop-Folk",
- "Eurodance",
- "Dream",
- "Southern Rock",
- "Comedy",
- "Cult",
- "Gangsta",
- "Top 40",
- "Christian Rap",
- "Pop/Funk",
- "Jungle",
- "Native American",
- "Cabaret",
- "New Wave", // 66
- "Psychadelic",
- "Rave",
- "Showtunes",
- "Trailer",
- "Lo-Fi",
- "Tribal",
- "Acid Punk",
- "Acid Jazz",
- "Polka",
- "Retro",
- "Musical",
- "Rock & Roll",
- "Hard Rock",
- "Folk", // 80
- "Folk-Rock",
- "National Folk",
- "Swing",
- "Fast Fusion",
- "Bebob",
- "Latin",
- "Revival",
- "Celtic",
- "Bluegrass", // 89
- "Avantgarde",
- "Gothic Rock",
- "Progressive Rock",
- "Psychedelic Rock",
- "Symphonic Rock",
- "Slow Rock",
- "Big Band",
- "Chorus",
- "Easy Listening",
- "Acoustic",
- "Humour", // 100
- "Speech",
- "Chanson",
- "Opera",
- "Chamber Music",
- "Sonata",
- "Symphony",
- "Booty Bass",
- "Primus",
- "Porn Groove",
- "Satire",
- "Slow Jam",
- "Club",
- "Tango",
- "Samba",
- "Folklore",
- "Ballad",
- "Power Ballad",
- "Rhythmic Soul",
- "Freestyle",
- "Duet",
- "Punk Rock",
- "Drum Solo",
- "A capella",
- "Euro-House",
- "Dance Hall",
- "Unknown" // 126
- };
-
- //////////////////////////////////////////////////////////
- // ID3 specific helper routines
- inline XMP_Int32 synchToInt32(XMP_Uns32 rawDataBE) // see part 6.2 of spec
- {
- XMP_Validate( 0 == (rawDataBE & 0x80808080),"input not synchsafe", kXMPErr_InternalFailure );
- XMP_Int32 r =
- ( rawDataBE & 0x0000007F )
- + ( rawDataBE >> 1 & 0x00003F80 )
- + ( rawDataBE >> 2 & 0x001FC000 )
- + ( rawDataBE >> 3 & 0x0FE00000 );
- return r;
- }
-
- inline XMP_Uns32 int32ToSynch(XMP_Int32 value)
- {
- XMP_Validate( 0 <= 0x0FFFFFFF, "value too big", kXMPErr_InternalFailure );
- XMP_Uns32 r =
- ( (value & 0x0000007F) << 0 )
- + ( (value & 0x00003F80) << 1 )
- + ( (value & 0x001FC000) << 2 )
- + ( (value & 0x0FE00000) << 3 );
- return r;
- }
-
- //////////////////////////////////////////////////////////
- // data structures
- class ID3Header
- {
- public:
- const static XMP_Uns16 o_id = 0;
- const static XMP_Uns16 o_version_major = 3;
- const static XMP_Uns16 o_version_minor = 4;
- const static XMP_Uns16 o_flags = 5;
- const static XMP_Uns16 o_size = 6;
-
- const static int FIXED_SIZE = 10;
- char fields[FIXED_SIZE];
-
- bool read(LFA_FileRef file)
- {
- LFA_Read( file, fields, FIXED_SIZE, true );
-
- if ( !CheckBytes( &fields[ID3Header::o_id], "ID3", 3 ) )
- {
- // chuck in default contents:
- const static char defaultHeader[FIXED_SIZE] = { 'I', 'D', '3', 3, 0, 0, 0, 0, 0, 0 };
- memcpy( this->fields, defaultHeader, FIXED_SIZE); // NBA: implicitly protected by FIXED_SIZE design.
-
- return false; // no header found (o.k.) thus stick with new, default header constructed above
- }
-
- XMP_Uns8 major = fields[o_version_major];
- XMP_Uns8 minor = fields[o_version_minor];
- XMP_Validate( major==3 || major==4, "invalid ID3 major version", kXMPErr_BadFileFormat );
- XMP_Validate( minor != 0xFF, "invalid ID3 minor version", kXMPErr_BadFileFormat );
-
- return true;
- }
-
- void write(LFA_FileRef file, XMP_Int64 tagSize)
- {
- XMP_Assert( tagSize < 0x10000000 ); // 256 MB limit due to synching.
- XMP_Assert( tagSize > 0x0 ); // 256 MB limit due to synching.
- PutUns32BE( ( int32ToSynch ( (XMP_Uns32)tagSize - 10 )), &this->fields[ID3Header::o_size] );
-
- LFA_Write( file, fields, FIXED_SIZE );
- }
-
- ~ID3Header()
- {
- //nothing
- };
- }; // ID3Header
-
-
- class ID3v2Frame
- {
- public:
- // fixed
- const static XMP_Uns16 o_id = 0;
- const static XMP_Uns16 o_size = 4; // size after unsync, excludes frame header.
- const static XMP_Uns16 o_flags = 8;
-
- const static int FIXED_SIZE = 10;
- char fields[FIXED_SIZE];
-
- XMP_Uns32 id;
- XMP_Uns16 flags;
-
- bool active; //default: true. flag is lowered, if another frame with replaces this one as "last meaningful frame of its kind"
- bool changed; //default: false. flag is raised, if setString() is used
-
- // variable-size frame content
- char* content;
- XMP_Int32 contentSize; // size of variable content, right as its stored in o_size (total size - 10)
-
- /**
- * a mere empty hull for reading in frames.
- */
- ID3v2Frame():id(0),content(0),contentSize(0),flags(0),active(true),changed(false)
- {
- memset(fields, 0, FIXED_SIZE);
- }
-
- /**
- * frame constructor
- */
- ID3v2Frame( XMP_Uns32 id ):id(0),content(0),contentSize(0),flags(0),active(true),changed(false)
- {
- memset(fields, 0, FIXED_SIZE);
-
- this->id = id;
- PutUns32BE( id, &fields[o_id]);
- this->flags = 0x0000;
- PutUns16BE( flags, &fields[o_flags]);
- }
-
- /**
- * copy constructor:
- */
- ID3v2Frame( const ID3v2Frame& orig)
- {
- XMP_Throw("not implemented",kXMPErr_InternalFailure);
- }
-
- /**
- * sets a new Content (aka property)
- */
- void setFrameValue( const std::string& rawvalue, bool needDescriptor = false , bool utf16le = false, bool isXMPPRIVFrame = false, bool needEncodingByte = true )
- {
- // the thing to insert
- std::string value;
- value.erase();
-
- if ( isXMPPRIVFrame )
- {
- // this flag must be used exclusive:
- XMP_Assert( ! needDescriptor );
- XMP_Assert( ! utf16le );
-
- value.append( "XMP\0", 4 );
- value.append( rawvalue );
- value.append( "\0", 1 ); // final zero byte
- }
- else // not an XMP Priv frame
- {
- if (needEncodingByte) // don't add encoding byte for example for WCOP
- {
- if ( utf16le )
- value.append( "\x1", 1 ); // 'unicode encoding' (must be UTF-16, be or le)
- else
- value.append( "\x0", 1 );
- }
-
- if ( needDescriptor ) // language descriptor
- value.append( "eng", 3 ); // language, empty content description
- if ( utf16le )
- {
- if ( needDescriptor )
- value.append( "\xFF\xFE\0\0", 4 ); // BOM, 16-bit zero (empty descriptor)
-
- value.append( "\xFF\xFE", 2 );
- std::string utf16str;
- ToUTF16( (XMP_Uns8*) rawvalue.c_str(), rawvalue.size(), &utf16str, false );
- value.append( utf16str );
- value.append( "\0\0", 2 );
- }
- else // write as plain Latin-1
- {
- std::string convertedValue; // just precaution (mostly used for plain ascii like numbers, etc)
- convertedValue.erase();
- ReconcileUtils::UTF8ToLatin1( rawvalue.c_str(), rawvalue.size(), &convertedValue );
-
- if ( needDescriptor )
- value.append( "\0", 1 ); // BOM, 16-bit zero (empty descriptor)
- value.append( convertedValue );
- value.append( "\0", 1 ); // final zero byte
- }
- } // of "not an XMP Priv frame"
-
- this->changed = true;
- this->release();
-
- XMP_StringPtr valueCStr = value.c_str();
- this->contentSize = (XMP_Int32) value.size();
- XMP_Validate( this->contentSize < 0xA00000, "XMP Property exceeds 20MB in size", kXMPErr_InternalFailure );
- content = new char[ this->contentSize ];
- memcpy( content , valueCStr , this->contentSize );
- }
-
- void write(LFA_FileRef file, XMP_Uns8 majorVersion)
- {
- // write back size field:
- if ( majorVersion < 4 )
- PutUns32BE( contentSize, &fields[o_size] );
- else
- PutUns32BE( int32ToSynch( contentSize ), &fields[o_size] );
-
- // write out fixed fields
- LFA_Write( file, this->fields, FIXED_SIZE);
- // write out contents
- LFA_Write( file, this->content, contentSize );
- }
-
- /**
- * majorVersion must be 3 or 4
- * @returns total size of frame
- */
- XMP_Int64 read(LFA_FileRef file, XMP_Uns8 majorVersion )
- {
- XMP_Assert( majorVersion == 3 || majorVersion == 4 );
- this->release(); // ensures/allows reuse of 'curFrame'
-
- XMP_Int64 start = LFA_Tell( file );
- LFA_Read( file, fields, FIXED_SIZE, true );
-
- id = GetUns32BE( &fields[o_id] );
-
- //only padding to come?
- if (id == 0x00000000)
- {
- LFA_Seek( file, -10, SEEK_CUR ); //rewind 10 byte
- return 0; // zero signals, not a valid frame
- }
- //verify id to be valid (4x A-Z and 0-9)
- XMP_Validate(
- (( fields[0]>0x40 && fields[0]<0x5B) || ( fields[0]>0x2F && fields[0]<0x3A)) && //A-Z,0-9
- (( fields[1]>0x40 && fields[1]<0x5B) || ( fields[1]>0x2F && fields[1]<0x3A)) &&
- (( fields[2]>0x40 && fields[2]<0x5B) || ( fields[2]>0x2F && fields[2]<0x3A)) &&
- (( fields[3]>0x40 && fields[3]<0x5B) || ( fields[3]>0x2F && fields[3]<0x3A))
- ,"invalid Frame ID", kXMPErr_BadFileFormat);
-
- flags = GetUns16BE( &fields[o_flags] );
- XMP_Validate( 0==(flags & 0xEE ),"invalid lower bits in frame flags",kXMPErr_BadFileFormat );
-
- //*** flag handling, spec :429ff aka line 431ff (i.e. Frame should be discarded)
- // compression and all of that..., unsynchronisation
- contentSize = ( majorVersion < 4) ?
- GetUns32BE( &fields[o_size] )
- : synchToInt32(GetUns32BE( &fields[o_size] ));
-
- XMP_Validate( contentSize >= 0, "negative frame size", kXMPErr_BadFileFormat );
- // >20MB in a single frame?, assume broken file
- XMP_Validate( contentSize < 0xA00000, "single frame exceeds 20MB", kXMPErr_BadFileFormat );
-
- content = new char[ contentSize ];
-
- LFA_Read( file, content, contentSize, true );
- XMP_Assert( (LFA_Tell( file ) - start) == FIXED_SIZE + contentSize ); //trivial
- return LFA_Tell( file ) - start;
- }
-
- /**
- * two types of COMM frames should be preserved but otherwise ignored
- * * a 6-field long header just having
- * encoding(1 byte),lang(3 bytes) and 0x00 31 (no descriptor, "1" as content")
- * perhaps only used to indicate client language
- * * COMM frames whose description begins with engiTun, these are iTunes flags
- *
- * returns true: job done as expted
- * false: do not use this frame, but preserve (i.e. iTunes marker COMM frame)
- */
- bool advancePastCOMMDescriptor(XMP_Int32& pos)
- {
- if ( (contentSize-pos) <= 3 )
- return false; // silent error, no room left behing language tag
-
- if ( !CheckBytes( &content[pos], "eng", 3 ) )
- return false; // not an error, but leave all non-eng tags alone...
-
- pos += 3; // skip lang tag
- if ( pos >= contentSize )
- return false; // silent error
-
- // skip past descriptor:
- while ( pos < contentSize )
- if ( content[pos++] == 0x00 )
- break;
- // skip yet-another double zero if applicable
- if ( (pos<contentSize) && (content[pos] == 0x00) )
- pos++;
-
- // check for "1" language indicator comment
- if (pos == 5)
- if ( contentSize == 6)
- if ( GetUns16BE(&content[4]) == 0x0031 )
- return false;
-
- // check for iTunes tag-comment
- if ( pos > 4 ) //there's a content descriptor ( 1 + 3 + zeroTerminator)
- {
- std::string descriptor = std::string(&content[4],pos-1);
- if ( 0 == descriptor.substr(0,4).compare( "iTun" )) // begins with engiTun ?
- return false; // leave alone, then
- }
-
- return true; //o.k., descriptor skipped, time for the real thing.
- }
-
- /*
- * returns the frame content as a proper UTF8 string
- * * w/o the initial encoding byte
- * * dealing with BOM's
- *
- * @returns: by value: character string with the value
- * as return value: false if frame is "not of intereset" despite a generally
- * "interesting" frame ID, these are
- * * iTunes-'marker' COMM frame
- */
- bool getFrameValue( XMP_Uns8 majorVersion, XMP_Uns32 frameID, std::string* utf8string )
- {
- XMP_Assert( contentSize >= 0 );
- XMP_Assert( contentSize < 0xA00000 ); // more than 20 MB per Propety would be very odd...
- XMP_Assert( content != 0 );
-
- if ( contentSize == 0)
- {
- utf8string->erase();
- return true; // ...it is "of interest", even if empty contents.
- }
-
- XMP_Int32 pos = 0; // going through input string
- XMP_Uns8 encByte = 0;
- // WCOP does not have an encoding byte
- // => for all others: use [0] as EncByte, advance pos
- if ( frameID != 0x57434F50 )
- {
- encByte = content[0];
- pos++;
- }
-
- // mode specific forks (so far only COMM)
- bool commMode = (
- ( frameID == 0x434F4D4D ) || // COMM
- ( frameID == 0x55534C54 ) // USLT
- );
-
- switch (encByte)
- {
- case 0: //ISO-8859-1, 0-terminated
- {
- if (commMode)
- if (! advancePastCOMMDescriptor( pos )) // do and check result
- return false; // not a frame of interest!
-
- char* localPtr = &content[pos];
- size_t localLen = contentSize - pos;
- ReconcileUtils::Latin1ToUTF8 ( localPtr, localLen, utf8string );
- }
- break;
- case 1: // Unicode, v2.4: UTF-16 (undetermined Endianess), with BOM, terminated 0x00 00
- case 2: // UTF-16BE without BOM, terminated 0x00 00
- {
- std::string tmp(this->content, this->contentSize);
-
- if (commMode)
- if (! advancePastCOMMDescriptor( pos )) // do and check result
- return false; // not a frame of interest!
-
- bool bigEndian = true; // assume for now (if no BOM follows)
- if ( GetUns16BE(&content[pos]) == 0xFEFF )
- {
- pos += 2;
- bigEndian = true;
- }
- else if ( GetUns16BE(&content[pos]) == 0xFFFE )
- {
- pos += 2;
- bigEndian = false;
- }
-
- FromUTF16( (UTF16Unit*)&content[pos], (contentSize - pos) / 2, utf8string, bigEndian );
- }
- break;
- case 3: // UTF-8 unicode, terminated \0
- // swallow any BOM, just in case
- if ( (GetUns32BE(&content[pos]) & 0xFFFFFF00 ) == 0xEFBBBF00 )
- pos += 3;
-
- if (commMode)
- if (! advancePastCOMMDescriptor( pos )) // do and check result
- return false; // not a frame of interest!
-
- utf8string->assign( &content[pos], contentSize - pos );
- break;
- default:
- XMP_Throw ( "unknown text encoding", kXMPErr_BadFileFormat); //COULDDO assume latin-1 or utf-8 as best-effort
- break;
- }
- return true;
- }
-
- ~ID3v2Frame()
- {
- this->release();
- }
-
- void release()
- {
- if ( content )
- delete content;
- content = 0;
- contentSize = 0;
- }
- }; // ID3Header
-
-
-
- class ID3v1Tag
- {
- public:
- // fixed
- const static XMP_Uns16 o_tag = 0; // must be "TAG"
- const static XMP_Uns16 o_title = 3;
- const static XMP_Uns16 o_artist = 33;
- const static XMP_Uns16 o_album = 63;
- const static XMP_Uns16 o_year = 93;
- const static XMP_Uns16 o_comment = 97;
- const static XMP_Uns16 o_genre = 127; // last by: index, or 255
-
- // optional (ID3v1.1) track number)
- const static XMP_Uns16 o_zero = 125; //must be zero, for trackNo to be valid
- const static XMP_Uns16 o_trackNo = 126; //trackNo
-
- const static int FIXED_SIZE = 128;
-
- /**
- * @returns returns true, if ID3v1 (or v1.1) exists, otherwise false.
- // sets XMP properties en route
- */
- bool read( LFA_FileRef file, SXMPMeta* meta )
- {
- if ( LFA_Measure( file ) <= 128 ) // ensure sufficient room
- return false;
- LFA_Seek( file, -128, SEEK_END);
-
- XMP_Uns32 tagID = LFA_ReadInt32_BE( file );
- tagID = tagID & 0xFFFFFF00; // wipe 4th byte
- if ( tagID != 0x54414700 )
- return false; // must be "TAG"
- LFA_Seek( file, -1, SEEK_CUR ); //rewind 1
-
- /////////////////////////////////////////////////////////
- XMP_Uns8 buffer[31]; // nothing is bigger here, than 30 bytes (offsets [0]-[29])
- buffer[30]=0; // wipe last byte
- std::string utf8string;
-
- // title //////////////////////////////////////////////////////
- LFA_Read( file, buffer, 30, true );
- std::string title( (char*) buffer ); //security: guaranteed to 0-terminate after 30 bytes
- if ( ! title.empty() )
- {
- ReconcileUtils::Latin1ToUTF8 ( title.c_str(), title.size(), &utf8string );
- meta->SetLocalizedText( kXMP_NS_DC, "title", "" , "x-default" , utf8string.c_str() );
- }
- // artist //////////////////////////////////////////////////////
- LFA_Read( file, buffer, 30, true );
- std::string artist( (char*) buffer );
- if ( ! artist.empty() )
- {
- ReconcileUtils::Latin1ToUTF8 ( artist.c_str(), artist.size(), &utf8string );
- meta->SetProperty( kXMP_NS_DM, "artist", utf8string.c_str() );
- }
- // album //////////////////////////////////////////////////////
- LFA_Read( file, buffer, 30, true );
- std::string album( (char*) buffer );
- if ( ! album.empty() )
- {
- ReconcileUtils::Latin1ToUTF8 ( album.c_str(), album.size(), &utf8string );
- meta->SetProperty( kXMP_NS_DM, "album", utf8string.c_str() );
- }
- // year //////////////////////////////////////////////////////
- LFA_Read( file, buffer, 4, true );
- buffer[4]=0; // ensure 0-term
- std::string year( (char*) buffer );
- if ( ! year.empty() )
- { // should be moot for a year, but let's be safe:
- ReconcileUtils::Latin1ToUTF8 ( year.c_str(), year.size(), &utf8string );
- meta->SetProperty( kXMP_NS_XMP, "CreateDate", utf8string.c_str() );
- }
- // comment //////////////////////////////////////////////////////
- LFA_Read( file, buffer, 30, true );
- std::string comment( (char*) buffer );
- if ( ! comment.empty() )
- {
- ReconcileUtils::Latin1ToUTF8 ( comment.c_str(), comment.size(), &utf8string );
- meta->SetProperty( kXMP_NS_DM, "logComment", utf8string.c_str() );
- }
- // trackNo (ID3v1.1) /////////////////////////////////////////////
- if ( buffer[28] == 0 )
- {
- XMP_Uns8 trackNo = buffer[29];
- if ( trackNo > 0 ) // 0 := unset
- {
- std::string trackStr;
- SXMPUtils::ConvertFromInt( trackNo, 0, &trackStr );
- meta->SetProperty( kXMP_NS_DM, "trackNumber", trackStr.c_str() );
- }
- }
- // genre //////////////////////////////////////////////////////
- XMP_Uns8 genreNo = LFA_ReadUns8( file );
- if ( (genreNo > 0) && (genreNo < 127) ) // 0 := unset, 127 := 'unknown'
- {
- meta->SetProperty( kXMP_NS_DM, "genre", Genres[genreNo] );
- }
-
- return true; // ID3Tag found
- }
-
- void write( LFA_FileRef file, SXMPMeta* meta )
- {
- // move in position (extension if applicable happens by caller)
- std::string zeros( 128, '\0' );
- std::string utf8, latin1;
-
- LFA_Seek( file, -128, SEEK_END);
- LFA_Write( file, zeros.data(), 128 );
-
- // TAG /////////////////////////////////////////////
- LFA_Seek( file, -128, SEEK_END);
- LFA_WriteUns8( file, 'T' );
- LFA_WriteUns8( file, 'A' );
- LFA_WriteUns8( file, 'G' );
-
- // title //////////////////////////////////////////////////////
- if ( meta->GetLocalizedText( kXMP_NS_DC, "title", "", "x-default", 0, &utf8, kXMP_NoOptions ))
- {
- LFA_Seek( file, -128 + 3, SEEK_END);
- ReconcileUtils::UTF8ToLatin1( utf8.c_str(), utf8.size(), &latin1 );
- LFA_Write( file, latin1.c_str(), MIN( 30, (XMP_Int32)latin1.size() ) );
- }
- // artist //////////////////////////////////////////////////////
- if ( meta->GetProperty( kXMP_NS_DM, "artist", &utf8, kXMP_NoOptions ))
- {
- LFA_Seek( file, -128 + 33, SEEK_END);
- ReconcileUtils::UTF8ToLatin1( utf8.c_str(), utf8.size(), &latin1 );
- LFA_Write( file, latin1.c_str(), MIN( 30, (XMP_Int32)latin1.size() ) );
- }
- // album //////////////////////////////////////////////////////
- if ( meta->GetProperty( kXMP_NS_DM, "album", &utf8, kXMP_NoOptions ))
- {
- LFA_Seek( file, -128 + 63, SEEK_END);
- ReconcileUtils::UTF8ToLatin1( utf8.c_str(), utf8.size(), &latin1 );
- LFA_Write( file, latin1.c_str(), MIN( 30, (XMP_Int32)latin1.size() ) );
- }
- // year //////////////////////////////////////////////////////
- if ( meta->GetProperty( kXMP_NS_XMP, "CreateDate", &utf8, kXMP_NoOptions ))
- {
- XMP_DateTime dateTime;
- SXMPUtils::ConvertToDate( utf8, &dateTime );
- if ( dateTime.hasDate )
- {
- SXMPUtils::ConvertFromInt ( dateTime.year, "", &latin1 );
- LFA_Seek ( file, -128 + 93, SEEK_END );
- LFA_Write ( file, latin1.c_str(), MIN ( 4, (XMP_Int32)latin1.size() ) );
- }
- }
- // comment (write 30 bytes first, see truncation later) ////////////
- if ( meta->GetProperty( kXMP_NS_DM, "logComment", &utf8, kXMP_NoOptions ))
- {
- LFA_Seek ( file, -128 + 97, SEEK_END );
- ReconcileUtils::UTF8ToLatin1 ( utf8.c_str(), utf8.size(), &latin1 );
- LFA_Write ( file, latin1.c_str(), MIN ( 30, (XMP_Int32)latin1.size() ) );
- }
- // genre ////////////////////////////////////////////////////////////////
- if ( meta->GetProperty( kXMP_NS_DM, "genre", &utf8, kXMP_NoOptions ))
- {
- XMP_Uns8 genreNo = 0;
-
- // try to find (case insensitive) match:
- int i;
- const char* genreCString = utf8.c_str();
- for ( i=0; i < 127; ++i ) {
- if ( (strlen( genreCString ) == strlen(Genres[i])) && //fixing buggy stricmp behaviour on PPC
- (stricmp( genreCString, Genres[i] ) == 0 )) {
- genreNo = i; // found
- break;
- } // if
- } // for
-
- LFA_Seek( file, -128 + 127, SEEK_END);
- LFA_WriteUns8( file, genreNo );
- }
-
- // trackNo ////////////////////////////////////////////////////////////
- if ( meta->GetProperty( kXMP_NS_DM, "trackNumber", &utf8, kXMP_NoOptions ))
- {
- XMP_Uns8 trackNo = 0;
- try
- {
- trackNo = (XMP_Uns8) SXMPUtils::ConvertToInt( utf8.c_str() );
-
- LFA_Seek( file, -128 + 125, SEEK_END);
- LFA_WriteUns8( file , 0 ); // ID3v1.1 extension
- LFA_WriteUns8( file, trackNo );
- }
- catch ( XMP_Error& )
- {
- // forgive, just don't set this one.
- }
- }
- }
-
- }; // ID3v1Tag
-
-} // namespace ID3_Support
-#endif // __ID3_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/IPTC_Support.cpp b/source/XMPFiles/FormatSupport/IPTC_Support.cpp
deleted file mode 100644
index b1514dd..0000000
--- a/source/XMPFiles/FormatSupport/IPTC_Support.cpp
+++ /dev/null
@@ -1,745 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "IPTC_Support.hpp"
-#include "EndianUtils.hpp"
-#include "Reconcile_Impl.hpp"
-
-// =================================================================================================
-/// \file IPTC_Support.cpp
-/// \brief XMPFiles support for IPTC (IIM) DataSets.
-///
-// =================================================================================================
-
-enum { kUTF8_IncomingMode = 0, kUTF8_LosslessMode = 1, kUTF8_AlwaysMode = 2 };
-#ifndef kUTF8_Mode
- #define kUTF8_Mode kUTF8_AlwaysMode
-#endif
-
-const DataSetCharacteristics kKnownDataSets[] =
- { { kIPTC_ObjectType, kIPTC_UnmappedText, 67, "", "" }, // Not mapped to XMP.
- { kIPTC_IntellectualGenre, kIPTC_MapSpecial, 68, kXMP_NS_IPTCCore, "IntellectualGenre" }, // Only the name part is in the XMP.
- { kIPTC_Title, kIPTC_MapLangAlt, 64, kXMP_NS_DC, "title" },
- { kIPTC_EditStatus, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
- { kIPTC_EditorialUpdate, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
- { kIPTC_Urgency, kIPTC_MapSimple, 1, kXMP_NS_Photoshop, "Urgency" },
- { kIPTC_SubjectCode, kIPTC_MapSpecial, 236, kXMP_NS_IPTCCore, "SubjectCode" }, // Only the reference number is in the XMP.
- { kIPTC_Category, kIPTC_MapSimple, 3, kXMP_NS_Photoshop, "Category" },
- { kIPTC_SuppCategory, kIPTC_MapArray, 32, kXMP_NS_Photoshop, "SupplementalCategories" },
- { kIPTC_FixtureIdentifier, kIPTC_UnmappedText, 32, "", "" }, // Not mapped to XMP.
- { kIPTC_Keyword, kIPTC_MapArray, 64, kXMP_NS_DC, "subject" },
- { kIPTC_ContentLocCode, kIPTC_UnmappedText, 3, "", "" }, // Not mapped to XMP.
- { kIPTC_ContentLocName, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
- { kIPTC_ReleaseDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP.
- { kIPTC_ReleaseTime, kIPTC_UnmappedText, 11, "", "" }, // Not mapped to XMP.
- { kIPTC_ExpDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP.
- { kIPTC_ExpTime, kIPTC_UnmappedText, 11, "", "" }, // Not mapped to XMP.
- { kIPTC_Instructions, kIPTC_MapSimple, 256, kXMP_NS_Photoshop, "Instructions" },
- { kIPTC_ActionAdvised, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
- { kIPTC_RefService, kIPTC_UnmappedText, 10, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
- { kIPTC_RefDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
- { kIPTC_RefNumber, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
- { kIPTC_DateCreated, kIPTC_MapSpecial, 8, kXMP_NS_Photoshop, "DateCreated" }, // ! Reformatted date. Combined with 2:60, TimeCreated.
- { kIPTC_TimeCreated, kIPTC_UnmappedText, 11, "", "" }, // ! Combined with 2:55, DateCreated.
- { kIPTC_DigitalCreateDate, kIPTC_Map3Way, 8, "", "" }, // ! 3 way Exif-IPTC-XMP date/time set. Combined with 2:63, DigitalCreateTime.
- { kIPTC_DigitalCreateTime, kIPTC_UnmappedText, 11, "", "" }, // ! Combined with 2:62, DigitalCreateDate.
- { kIPTC_OriginProgram, kIPTC_UnmappedText, 32, "", "" }, // Not mapped to XMP.
- { kIPTC_ProgramVersion, kIPTC_UnmappedText, 10, "", "" }, // Not mapped to XMP.
- { kIPTC_ObjectCycle, kIPTC_UnmappedText, 1, "", "" }, // Not mapped to XMP.
- { kIPTC_Creator, kIPTC_Map3Way, 32, "", "" }, // ! In the 3 way Exif-IPTC-XMP set.
- { kIPTC_CreatorJobtitle, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "AuthorsPosition" },
- { kIPTC_City, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "City" },
- { kIPTC_Location, kIPTC_MapSimple, 32, kXMP_NS_IPTCCore, "Location" },
- { kIPTC_State, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "State" },
- { kIPTC_CountryCode, kIPTC_MapSimple, 3, kXMP_NS_IPTCCore, "CountryCode" },
- { kIPTC_Country, kIPTC_MapSimple, 64, kXMP_NS_Photoshop, "Country" },
- { kIPTC_JobID, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "TransmissionReference" },
- { kIPTC_Headline, kIPTC_MapSimple, 256, kXMP_NS_Photoshop, "Headline" },
- { kIPTC_Provider, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "Credit" },
- { kIPTC_Source, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "Source" },
- { kIPTC_CopyrightNotice, kIPTC_Map3Way, 128, "", "" }, // ! In the 3 way Exif-IPTC-XMP set.
- { kIPTC_Contact, kIPTC_UnmappedText, 128, "", "" }, // Not mapped to XMP.
- { kIPTC_Description, kIPTC_Map3Way, 2000, "", "" }, // ! In the 3 way Exif-IPTC-XMP set.
- { kIPTC_DescriptionWriter, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "CaptionWriter" },
- { kIPTC_RasterizedCaption, kIPTC_UnmappedBin, 7360, "", "" }, // Not mapped to XMP. ! Binary data!
- { kIPTC_ImageType, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
- { kIPTC_ImageOrientation, kIPTC_UnmappedText, 1, "", "" }, // Not mapped to XMP.
- { kIPTC_LanguageID, kIPTC_UnmappedText, 3, "", "" }, // Not mapped to XMP.
- { kIPTC_AudioType, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
- { kIPTC_AudioSampleRate, kIPTC_UnmappedText, 6, "", "" }, // Not mapped to XMP.
- { kIPTC_AudioSampleRes, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
- { kIPTC_AudioDuration, kIPTC_UnmappedText, 6, "", "" }, // Not mapped to XMP.
- { kIPTC_AudioOutcue, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
- { kIPTC_PreviewFormat, kIPTC_UnmappedBin, 2, "", "" }, // Not mapped to XMP. ! Binary data!
- { kIPTC_PreviewFormatVers, kIPTC_UnmappedBin, 2, "", "" }, // Not mapped to XMP. ! Binary data!
- { kIPTC_PreviewData, kIPTC_UnmappedBin, 256000, "", "" }, // Not mapped to XMP. ! Binary data!
- { 255, kIPTC_MapSpecial, 0, 0, 0 } }; // ! Must be last as a sentinel.
-
-// A combination of the IPTC "Subject Reference System Guidelines" and IIMv4.1 Appendix G.
-const IntellectualGenreMapping kIntellectualGenreMappings[] =
-{ { "001", "Current" },
- { "002", "Analysis" },
- { "003", "Archive material" },
- { "004", "Background" },
- { "005", "Feature" },
- { "006", "Forecast" },
- { "007", "History" },
- { "008", "Obituary" },
- { "009", "Opinion" },
- { "010", "Polls and surveys" },
- { "010", "Polls & Surveys" },
- { "011", "Profile" },
- { "012", "Results listings and statistics" },
- { "012", "Results Listings & Tables" },
- { "013", "Side bar and supporting information" },
- { "013", "Side bar & Supporting information" },
- { "014", "Summary" },
- { "015", "Transcript and verbatim" },
- { "015", "Transcript & Verbatim" },
- { "016", "Interview" },
- { "017", "From the scene" },
- { "017", "From the Scene" },
- { "018", "Retrospective" },
- { "019", "Synopsis" },
- { "019", "Statistics" },
- { "020", "Update" },
- { "021", "Wrapup" },
- { "021", "Wrap-up" },
- { "022", "Press release" },
- { "022", "Press Release" },
- { "023", "Quote" },
- { "024", "Press-digest" },
- { "025", "Review" },
- { "026", "Curtain raiser" },
- { "027", "Actuality" },
- { "028", "Question and answer" },
- { "029", "Music" },
- { "030", "Response to a question" },
- { "031", "Raw sound" },
- { "032", "Scener" },
- { "033", "Text only" },
- { "034", "Voicer" },
- { "035", "Fixture" },
- { 0, 0 } }; // ! Must be last as a sentinel.
-
-// =================================================================================================
-// FindKnownDataSet
-// ================
-
-static const DataSetCharacteristics* FindKnownDataSet ( XMP_Uns8 id )
-{
- size_t i = 0;
-
- while ( kKnownDataSets[i].id < id ) ++i; // The list is short enough for a linear search.
-
- if ( kKnownDataSets[i].id != id ) return 0;
- return &kKnownDataSets[i];
-
-} // FindKnownDataSet
-
-// =================================================================================================
-// IPTC_Manager::ParseMemoryDataSets
-// =================================
-//
-// Parse the legacy IIM block. Offsets and lengths are kept for any 1:90 DataSet and all of Record 2.
-
-void IPTC_Manager::ParseMemoryDataSets ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
-{
- // Get rid of any existing data.
-
- DataSetMap::iterator dsPos = this->dataSets.begin();
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- for ( ; dsPos != dsEnd; ++dsPos ) this->DisposeLooseValue ( dsPos->second );
-
- this->dataSets.clear();
-
- if ( this->ownedContent ) free ( this->iptcContent );
- this->ownedContent = false; // Set to true later if the content is copied.
- this->iptcContent = 0;
- this->iptcLength = 0;
-
- this->changed = false;
-
- if ( length == 0 ) return;
- if ( *((XMP_Uns8*)data) != 0x1C ) XMP_Throw ( "Not valid IPTC, no leading 0x1C", kXMPErr_BadIPTC );
-
- // Allocate space for the full in-memory data and copy it.
-
- if ( length > 10*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based IPTC", kXMPErr_BadIPTC );
- this->iptcLength = length;
-
- if ( ! copyData ) {
- this->iptcContent = (XMP_Uns8*)data;
- } else {
- this->iptcContent = (XMP_Uns8*) malloc(length);
- if ( this->iptcContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( this->iptcContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
- this->ownedContent = true;
- }
-
- // Build the map of the 2:* DataSets.
-
- XMP_Uns8* iptcPtr = this->iptcContent;
- XMP_Uns8* iptcEnd = iptcPtr + length;
- XMP_Uns8* iptcLimit = iptcEnd - kMinDataSetSize;
- XMP_Uns32 dsLen; // ! The large form can have values up to 4GB in length.
-
- this->utf8Encoding = false;
-
- bool found190 = false;
- bool found2xx = false;
-
- for ( ; iptcPtr <= iptcLimit; iptcPtr += dsLen ) {
-
- XMP_Uns8* dsPtr = iptcPtr;
- XMP_Uns8 oneC = *iptcPtr;
- XMP_Uns8 recNum = *(iptcPtr+1);
- XMP_Uns8 dsNum = *(iptcPtr+2);
-
- if ( oneC != 0x1C ) break; // No more DataSets.
-
- dsLen = GetUns16BE ( iptcPtr+3 ); // ! Compute dsLen before any "continue", needed for loop increment!
- iptcPtr += 5; // Advance to the data (or extended length).
-
- if ( (dsLen & 0x8000) != 0 ) {
- XMP_Assert ( dsLen <= 0xFFFF );
- XMP_Uns32 lenLen = dsLen & 0x7FFF;
- if ( iptcPtr > iptcEnd-lenLen ) break; // Bad final DataSet. Throw instead?
- dsLen = 0;
- for ( XMP_Uns16 i = 0; i < lenLen; ++i, ++iptcPtr ) {
- dsLen = (dsLen << 8) + *iptcPtr;
- }
- }
-
- if ( iptcPtr > (iptcEnd - dsLen) ) break; // Bad final DataSet. Throw instead?
-
- if ( recNum == 0 ) continue; // Should not be a record 0. Throw instead?
-
- if ( recNum == 1 ) {
- if ( dsNum == 90 ) {
- found190 = true;
- this->offset190 = (XMP_Uns32) (dsPtr - this->iptcContent);
- this->length190 = 5 + dsLen;
- if ( (dsLen == 3) && (memcmp ( iptcPtr, "\x1B\x25\x47", 3 ) == 0) ) this->utf8Encoding = true;
- }
- continue; // Ignore all other record 1 DataSets.
- }
-
- if ( recNum == 2 ) {
- if ( ! found2xx ) {
- found2xx = true;
- this->offset2xx = (XMP_Uns32) (dsPtr - this->iptcContent);
- this->length2xx = this->iptcLength - this->offset2xx; // ! In case there are no other records.
- }
- } else {
- this->length2xx = (XMP_Uns32) (dsPtr - (this->iptcContent + this->offset2xx));
- break; // The records are in ascending order, done with 2:xx DataSets.
- }
-
- XMP_Assert ( recNum == 2 );
- if ( dsNum == 0 ) continue; // Ignore 2:00 when reading, it is created explicitly when writing.
-
- DataSetInfo dsInfo ( dsNum, dsLen, iptcPtr );
- DataSetMap::iterator dsPos = this->dataSets.find ( dsNum );
-
- bool repeatable = false;
-
- const DataSetCharacteristics* knownDS = FindKnownDataSet ( dsNum );
-
- if ( (knownDS == 0) || (knownDS->mapForm == kIPTC_MapArray) ) {
- repeatable = true; // Allow repeats for unknown DataSets.
- } else if ( (dsNum == kIPTC_Creator) || (dsNum == kIPTC_SubjectCode) ) {
- repeatable = true;
- }
-
- if ( repeatable || (dsPos == this->dataSets.end()) ) {
- DataSetMap::value_type mapValue ( dsNum, dsInfo );
- (void) this->dataSets.insert ( this->dataSets.upper_bound ( dsNum ), mapValue );
- } else {
- this->DisposeLooseValue ( dsPos->second );
- dsPos->second = dsInfo; // Keep the last copy of illegal repeats.
- }
-
- }
-
-} // IPTC_Manager::ParseMemoryDataSets
-
-// =================================================================================================
-// IPTC_Manager::GetDataSet
-// ========================
-
-size_t IPTC_Manager::GetDataSet ( XMP_Uns8 id, DataSetInfo* info, size_t which /* = 0 */ ) const
-{
-
- DataSetMap::const_iterator dsPos = this->dataSets.lower_bound ( id );
- if ( (dsPos == this->dataSets.end()) || (id != dsPos->second.id) ) return 0;
-
- size_t dsCount = this->dataSets.count ( id );
- if ( which >= dsCount ) return 0; // Valid range for which is 0 .. count-1.
-
- if ( info != 0 ) {
- for ( size_t i = 0; i < which; ++i ) ++dsPos; // Can't do "dsPos += which", no iter+int operator.
- *info = dsPos->second;
- }
-
- return dsCount;
-
-} // IPTC_Manager::GetDataSet
-
-// =================================================================================================
-// IPTC_Manager::GetDataSet_UTF8
-// =============================
-
-size_t IPTC_Manager::GetDataSet_UTF8 ( XMP_Uns8 id, std::string * utf8Str, size_t which /* = 0 */ ) const
-{
- if ( utf8Str != 0 ) utf8Str->erase();
-
- DataSetInfo dsInfo;
- size_t dsCount = GetDataSet ( id, &dsInfo, which );
- if ( dsCount == 0 ) return 0;
-
- if ( utf8Str != 0 ) {
- if ( this->utf8Encoding ) {
- utf8Str->assign ( (char*)dsInfo.dataPtr, dsInfo.dataLen );
- } else if ( ! ignoreLocalText ) {
- ReconcileUtils::LocalToUTF8 ( dsInfo.dataPtr, dsInfo.dataLen, utf8Str );
- } else if ( ReconcileUtils::IsASCII ( dsInfo.dataPtr, dsInfo.dataLen ) ) {
- utf8Str->assign ( (char*)dsInfo.dataPtr, dsInfo.dataLen );
- }
- }
-
- return dsCount;
-
-} // IPTC_Manager::GetDataSet_UTF8
-
-// =================================================================================================
-// IPTC_Manager::DisposeLooseValue
-// ===============================
-//
-// Dispose of loose values from SetDataSet calls after the last UpdateMemoryDataSets.
-
-// ! Don't try to make the DataSetInfo struct be self-cleaning. It is a primary public type, returned
-// ! from GetDataSet. Making it self-cleaning would get into nasty assignment and pointer ownership
-// ! issues, far worse than doing this explicit cleanup.
-
-void IPTC_Manager::DisposeLooseValue ( DataSetInfo & dsInfo )
-{
- if ( dsInfo.dataLen == 0 ) 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;
- }
-
-} // IPTC_Manager::DisposeLooseValue
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// IPTC_Writer::~IPTC_Writer
-// =========================
-//
-// Dispose of loose values from SetDataSet calls after the last UpdateMemoryDataSets.
-
-IPTC_Writer::~IPTC_Writer()
-{
- DataSetMap::iterator dsPos = this->dataSets.begin();
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- for ( ; dsPos != dsEnd; ++dsPos ) this->DisposeLooseValue ( dsPos->second );
-
-} // IPTC_Writer::~IPTC_Writer
-
-// =================================================================================================
-// IPTC_Writer::SetDataSet_UTF8
-// ============================
-
-void IPTC_Writer::SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which /* = -1 */ )
-{
- const DataSetCharacteristics* knownDS = FindKnownDataSet ( id );
- if ( knownDS == 0 ) XMP_Throw ( "Can only set known IPTC DataSets", kXMPErr_InternalFailure );
-
- // Decide which character encoding to use and get a temporary pointer to the value.
-
- XMP_Uns8 * tempPtr;
- XMP_Uns32 dataLen;
- std::string localStr;
-
- if ( kUTF8_Mode == kUTF8_AlwaysMode ) {
-
- // Always use UTF-8.
- if ( ! this->utf8Encoding ) this->ConvertToUTF8();
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
-
- } else if ( kUTF8_Mode == kUTF8_IncomingMode ) {
-
- // Only use UTF-8 if that was what the parsed block used.
- if ( this->utf8Encoding ) {
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
- } else if ( ! ignoreLocalText ) {
- ReconcileUtils::UTF8ToLocal ( utf8Ptr, utf8Len, &localStr );
- tempPtr = (XMP_Uns8*) localStr.data();
- dataLen = (XMP_Uns32) localStr.size();
- } else {
- if ( ! ReconcileUtils::IsASCII ( utf8Ptr, utf8Len ) ) return;
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
- }
-
- } else if ( kUTF8_Mode == kUTF8_LosslessMode ) {
-
- // Convert to UTF-8 if needed to prevent round trip loss.
- if ( this->utf8Encoding ) {
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
- } else if ( ! ignoreLocalText ) {
- std::string rtStr;
- ReconcileUtils::UTF8ToLocal ( utf8Ptr, utf8Len, &localStr );
- ReconcileUtils::LocalToUTF8 ( localStr.data(), localStr.size(), &rtStr );
- if ( (rtStr.size() == utf8Len) && (memcmp ( rtStr.data(), utf8Ptr, utf8Len ) == 0) ) {
- tempPtr = (XMP_Uns8*) localStr.data(); // No loss, keep local encoding.
- dataLen = (XMP_Uns32) localStr.size();
- } else {
- this->ConvertToUTF8(); // Had loss, change everything to UTF-8.
- XMP_Assert ( this->utf8Encoding );
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
- }
- } else {
- if ( ! ReconcileUtils::IsASCII ( utf8Ptr, utf8Len ) ) return;
- tempPtr = (XMP_Uns8*) utf8Ptr;
- dataLen = utf8Len;
- }
-
- }
-
- // Set the value for this DataSet, making a non-transient copy of the value. Respect UTF-8 character
- // boundaries when truncating. This is easy to check. If the first truncated byte has 10 in the
- // high order 2 bits then we are in the middle of a UTF-8 multi-byte character.
- // Back up to just before a byte with 11 in the high order 2 bits.
-
- if ( dataLen > knownDS->maxLen ) {
- dataLen = (XMP_Uns32)knownDS->maxLen;
- if ( this->utf8Encoding && ((tempPtr[dataLen] >> 6) == 2) ) {
- for ( ; (dataLen > 0) && ((tempPtr[dataLen] >> 6) != 3); --dataLen ) {}
- }
- }
-
- DataSetMap::iterator dsPos = this->dataSets.find ( id );
- long currCount = (long) this->dataSets.count ( id );
-
- bool repeatable = false;
-
- if ( knownDS->mapForm == kIPTC_MapArray ) {
- repeatable = true;
- } else if ( (id == kIPTC_Creator) || (id == kIPTC_SubjectCode) ) {
- repeatable = true;
- }
-
- if ( ! repeatable ) {
-
- if ( which > 0 ) XMP_Throw ( "Non-repeatable IPTC DataSet", kXMPErr_BadParam );
-
- } else {
-
- if ( which < 0 ) which = currCount; // The default is to append.
-
- if ( which > currCount ) {
- XMP_Throw ( "Invalid index for IPTC DataSet", kXMPErr_BadParam );
- } else if ( which == currCount ) {
- dsPos = this->dataSets.end(); // To make later checks do the right thing.
- } else {
- dsPos = this->dataSets.lower_bound ( id );
- for ( ; which > 0; --which ) ++dsPos;
- }
-
- }
-
- if ( dsPos != this->dataSets.end() ) {
- if ( (dsPos->second.dataLen == dataLen) && (memcmp ( dsPos->second.dataPtr, tempPtr, dataLen ) == 0) ) {
- return; // ! New value matches the old, don't update.
- }
- }
-
- XMP_Uns8 * dataPtr = (XMP_Uns8*) malloc ( dataLen );
- if ( dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( dataPtr, tempPtr, dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
-
- DataSetInfo dsInfo ( id, dataLen, dataPtr );
-
- if ( dsPos != this->dataSets.end() ) {
- this->DisposeLooseValue ( dsPos->second );
- dsPos->second = dsInfo;
- } else {
- DataSetMap::value_type mapValue ( id, dsInfo );
- (void) this->dataSets.insert ( this->dataSets.upper_bound ( id ), mapValue );
- }
-
- this->changed = true;
-
-} // IPTC_Writer::SetDataSet_UTF8
-
-// =================================================================================================
-// IPTC_Writer::DeleteDataSet
-// ==========================
-
-void IPTC_Writer::DeleteDataSet ( XMP_Uns8 id, long which /* = -1 */ )
-{
- DataSetMap::iterator dsBegin = this->dataSets.lower_bound ( id ); // Set for which == -1.
- DataSetMap::iterator dsEnd = this->dataSets.upper_bound ( id );
-
- if ( dsBegin == dsEnd ) return; // Nothing to delete.
-
- if ( which >= 0 ) {
- long currCount = (long) this->dataSets.count ( id );
- if ( which >= currCount ) return; // Nothing to delete.
- for ( ; which > 0; --which ) ++dsBegin;
- dsEnd = dsBegin; ++dsEnd; // ! Can't do "dsEnd = dsBegin+1"!
- }
-
- for ( DataSetMap::iterator dsPos = dsBegin; dsPos != dsEnd; ++dsPos ) {
- this->DisposeLooseValue ( dsPos->second );
- }
-
- this->dataSets.erase ( dsBegin, dsEnd );
- this->changed = true;
-
-} // IPTC_Writer::DeleteDataSet
-
-// =================================================================================================
-// IPTC_Writer::UpdateMemoryDataSets
-// =================================
-//
-// Reconstruct the entire IIM block. This does not include any final alignment padding, that is an
-// artifact of some specific wrappers such as Photoshop image resources.
-
-void IPTC_Writer::UpdateMemoryDataSets()
-{
- if ( ! this->changed ) return;
-
- DataSetMap::iterator dsPos;
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- if ( kUTF8_Mode == kUTF8_LosslessMode ) {
- if ( this->utf8Encoding ) {
- if ( ! this->CheckRoundTripLoss() ) this->ConvertToLocal();
- } else {
- if ( this->CheckRoundTripLoss() ) this->ConvertToUTF8();
- }
- }
-
- // Compute the length of the new IIM block, including space for records other than 2. All other
- // records are preserved as-is, except for 1:90. If local text is used then 1:90 is omitted,
- // if UTF-8 text is used then 1:90 is written.
-
- XMP_Uns32 midOffset = this->offset190 + this->length190;
- XMP_Uns32 midLength = this->offset2xx - midOffset;
-
- XMP_Uns32 suffixOffset = this->offset2xx + this->length2xx;
- XMP_Uns32 suffixLength = this->iptcLength - suffixOffset;
-
- XMP_Uns32 newLength = this->offset190 + (5+2); // For things before 1:90 and 2:0.
- if ( this->utf8Encoding ) newLength += (5+3); // For 1:90, if written.
- newLength += midLength; // For things between 1:90 and 2:xx.
- newLength += suffixLength; // For records after 2.
-
- for ( dsPos = this->dataSets.begin(); dsPos != dsEnd; ++dsPos ) { // Accumulate the 2:xx sizes.
- XMP_Uns32 dsLen = dsPos->second.dataLen;
- newLength += (5 + dsLen);
- if ( dsLen > 0x7FFF ) newLength += 4; // We always use a 4 byte extended length for big values.
- }
-
- // Allocate the new IIM block.
-
- XMP_Uns8* newContent = (XMP_Uns8*) malloc ( newLength );
- if ( newContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
-
- XMP_Uns8* dsPtr = newContent;
-
- // Write the 1:xx DataSets, including whatever is appropriate for 1:90.
-
- if ( this->offset190 > 0 ) { // Whatever was before an existing 1:90.
- memcpy ( dsPtr, this->iptcContent, this->offset190 ); // AUDIT: Within range of allocation.
- dsPtr += this->offset190;
- }
-
- if ( this->utf8Encoding ) { // Write 1:90 only if text is UTF-8.
- memcpy ( dsPtr, "\x1C\x01\x5A\x00\x03\x1B\x25\x47", (5+3) ); // AUDIT: Within range of allocation.
- dsPtr += (5+3);
- }
-
- if ( midLength > 0 ) { // Write the remainder before record 2.
- memcpy ( dsPtr, (this->iptcContent + midOffset), midLength ); // AUDIT: Within range of allocation.
- dsPtr += midLength;
- }
-
- // Write the 2:xx DataSets, starting with an explicit 2:00.
-
- if ( this->utf8Encoding ) {
- // Start with 2:00 for version 4.
- memcpy ( dsPtr, "\x1C\x02\x00\x00\x02\x00\x04", (5+2) ); // AUDIT: Within range of allocation.
- dsPtr += (5+2);
- } else {
- // Start with 2:00 for version 2.
- // *** We should probably write version 4 all the time. This is a late CS3 change, don't want
- // *** to risk breaking other apps that might be strict about version checking.
- memcpy ( dsPtr, "\x1C\x02\x00\x00\x02\x00\x02", (5+2) ); // AUDIT: Within range of allocation.
- dsPtr += (5+2);
- }
-
- // Fill in the record 2 DataSets that have values.
-
- for ( dsPos = this->dataSets.begin(); dsPos != dsEnd; ++dsPos ) {
-
- DataSetInfo & dsInfo = dsPos->second;
-
- dsPtr[0] = 0x1C;
- dsPtr[1] = 2;
- dsPtr[2] = dsInfo.id;
- dsPtr += 3;
-
- XMP_Uns32 dsLen = dsInfo.dataLen;
- if ( dsLen <= 0x7FFF ) {
- PutUns16BE ( (XMP_Uns16)dsLen, dsPtr );
- dsPtr += 2;
- } else {
- PutUns16BE ( 0x8004, dsPtr );
- PutUns32BE ( dsLen, dsPtr+2 );
- dsPtr += 6;
- }
-
- if ( dsLen > (newLength - (dsPtr - newContent)) ) {
- XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
- }
- memcpy ( dsPtr, dsInfo.dataPtr, dsLen ); // AUDIT: Protected by above check.
- dsPtr += dsLen;
-
- }
-
- if ( suffixLength > 0 ) { // Write the records after 2.
- memcpy ( dsPtr, (this->iptcContent + suffixOffset), suffixLength ); // AUDIT: Within range of allocation.
- dsPtr += suffixLength;
- }
-
- XMP_Assert ( dsPtr == (newContent + newLength) );
-
- // Parse the new block, it is the best way to reset internal info and rebuild the map.
-
- this->ParseMemoryDataSets ( newContent, newLength, false ); // Don't make another copy of the content.
- XMP_Assert ( this->iptcLength == newLength );
- this->ownedContent = (newLength > 0); // We really do own the new content, if not empty.
-
-} // IPTC_Writer::UpdateMemoryDataSets
-
-// =================================================================================================
-// IPTC_Writer::ConvertToUTF8
-// ==========================
-//
-// Convert the values of existing text DataSets to UTF-8. For now we only accept text DataSets.
-
-void IPTC_Writer::ConvertToUTF8()
-{
- XMP_Assert ( ! this->utf8Encoding );
- std::string utf8Str;
-
- DataSetMap::iterator dsPos = this->dataSets.begin();
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- for ( ; dsPos != dsEnd; ++dsPos ) {
-
- DataSetInfo & dsInfo = dsPos->second;
-
- ReconcileUtils::LocalToUTF8 ( dsInfo.dataPtr, dsInfo.dataLen, &utf8Str );
- this->DisposeLooseValue ( dsInfo );
-
- dsInfo.dataLen = (XMP_Uns32)utf8Str.size();
- dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
- if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( dsInfo.dataPtr, utf8Str.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
-
- }
-
- this->utf8Encoding = true;
-
-} // IPTC_Writer::ConvertToUTF8
-
-// =================================================================================================
-// IPTC_Writer::ConvertToLocal
-// ===========================
-//
-// Convert the values of existing text DataSets to local. For now we only accept text DataSets.
-
-void IPTC_Writer::ConvertToLocal()
-{
- XMP_Assert ( this->utf8Encoding );
- std::string localStr;
-
- DataSetMap::iterator dsPos = this->dataSets.begin();
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- for ( ; dsPos != dsEnd; ++dsPos ) {
-
- DataSetInfo & dsInfo = dsPos->second;
-
- ReconcileUtils::UTF8ToLocal ( dsInfo.dataPtr, dsInfo.dataLen, &localStr );
- this->DisposeLooseValue ( dsInfo );
-
- dsInfo.dataLen = (XMP_Uns32)localStr.size();
- dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
- if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( dsInfo.dataPtr, localStr.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
-
- }
-
- this->utf8Encoding = false;
-
-} // IPTC_Writer::ConvertToLocal
-
-// =================================================================================================
-// IPTC_Writer::CheckRoundTripLoss
-// ===============================
-//
-// See if we still need UTF-8 because of round-trip loss. Returns true if there is loss.
-
-bool IPTC_Writer::CheckRoundTripLoss()
-{
- XMP_Assert ( this->utf8Encoding );
- std::string localStr, rtStr;
-
- DataSetMap::iterator dsPos = this->dataSets.begin();
- DataSetMap::iterator dsEnd = this->dataSets.end();
-
- for ( ; dsPos != dsEnd; ++dsPos ) {
-
- DataSetInfo & dsInfo = dsPos->second;
-
- XMP_StringPtr utf8Ptr = (XMP_StringPtr) dsInfo.dataPtr;
- XMP_StringLen utf8Len = dsInfo.dataLen;
-
- ReconcileUtils::UTF8ToLocal ( utf8Ptr, utf8Len, &localStr );
- ReconcileUtils::LocalToUTF8 ( localStr.data(), localStr.size(), &rtStr );
-
- if ( (rtStr.size() != utf8Len) || (memcmp ( rtStr.data(), utf8Ptr, utf8Len ) != 0) ) {
- return true; // Had round-trip loss, keep UTF-8.
- }
-
- }
-
- return false; // No loss.
-
-} // IPTC_Writer::CheckRoundTripLoss
-
-// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/IPTC_Support.hpp b/source/XMPFiles/FormatSupport/IPTC_Support.hpp
deleted file mode 100644
index 470a6d4..0000000
--- a/source/XMPFiles/FormatSupport/IPTC_Support.hpp
+++ /dev/null
@@ -1,304 +0,0 @@
-#ifndef __IPTC_Support_hpp__
-#define __IPTC_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <map>
-
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "EndianUtils.hpp"
-
-// =================================================================================================
-/// \file IPTC_Support.hpp
-/// \brief XMPFiles support for IPTC (IIM) DataSets.
-///
-/// This header provides IPTC (IIM) DataSet support specific to the needs of XMPFiles. This is not
-/// intended for general purpose IPTC processing. There is a small tree of derived classes, 1
-/// virtual base class and 2 concrete leaf classes:
-/// \code
-/// IPTC_Manager - The root virtual base class.
-/// IPTC_Reader - A derived concrete leaf class for memory-based read-only access.
-/// IPTC_Writer - A derived concrete leaf class for memory-based read-write access.
-/// \endcode
-///
-/// \c IPTC_Manager declares all of the public methods except for specialized constructors in the
-/// leaf classes. The read-only classes throw an XMP_Error exception for output methods like
-/// \c SetDataSet. They return appropriate values for "safe" methods, \c IsChanged will return false
-/// for example.
-///
-/// The IPTC DataSet organization differs from TIFF tags and Photoshop image resources in allowing
-/// muultiple occurrences for some IDs. The C++ STL multimap is a natural data structure for IPTC.
-///
-/// Support is only provided for DataSet 1:90 to decide if local or UTF-8 text encoding is used, and
-/// the following text valued DataSets: 2:05, 2:10, 2:15, 2:20, 2:25, 2:40, 2:55, 2:80, 2:85, 2:90,
-/// 2:95, 2:101, 2:103, 2:105, 2:110, 2:115, 2:116, 2:120, and 2:122. DataSet 2:00 is ignored when
-/// reading but always written.
-///
-/// \note Unlike the TIFF_Manager and PSIR_Manager class trees, IPTC_Manager only provides in-memory
-/// implementations. The total size of IPTC data is small enough to make this reasonable.
-///
-/// \note These classes are for use only when directly compiled and linked. They should not be
-/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
-// =================================================================================================
-
-
-// =================================================================================================
-// =================================================================================================
-
-enum { // List of recognized 2:* IIM DataSets. The names are from IIMv4 and IPTC4XMP.
- kIPTC_ObjectType = 3,
- kIPTC_IntellectualGenre = 4,
- kIPTC_Title = 5,
- kIPTC_EditStatus = 7,
- kIPTC_EditorialUpdate = 8,
- kIPTC_Urgency = 10,
- kIPTC_SubjectCode = 12,
- kIPTC_Category = 15,
- kIPTC_SuppCategory = 20,
- kIPTC_FixtureIdentifier = 22,
- kIPTC_Keyword = 25,
- kIPTC_ContentLocCode = 26,
- kIPTC_ContentLocName = 27,
- kIPTC_ReleaseDate = 30,
- kIPTC_ReleaseTime = 35,
- kIPTC_ExpDate = 37,
- kIPTC_ExpTime = 38,
- kIPTC_Instructions = 40,
- kIPTC_ActionAdvised = 42,
- kIPTC_RefService = 45,
- kIPTC_RefDate = 47,
- kIPTC_RefNumber = 50,
- kIPTC_DateCreated = 55,
- kIPTC_TimeCreated = 60,
- kIPTC_DigitalCreateDate = 62,
- kIPTC_DigitalCreateTime = 63,
- kIPTC_OriginProgram = 65,
- kIPTC_ProgramVersion = 70,
- kIPTC_ObjectCycle = 75,
- kIPTC_Creator = 80,
- kIPTC_CreatorJobtitle = 85,
- kIPTC_City = 90,
- kIPTC_Location = 92,
- kIPTC_State = 95,
- kIPTC_CountryCode = 100,
- kIPTC_Country = 101,
- kIPTC_JobID = 103,
- kIPTC_Headline = 105,
- kIPTC_Provider = 110,
- kIPTC_Source = 115,
- kIPTC_CopyrightNotice = 116,
- kIPTC_Contact = 118,
- kIPTC_Description = 120,
- kIPTC_DescriptionWriter = 122,
- kIPTC_RasterizedCaption = 125,
- kIPTC_ImageType = 130,
- kIPTC_ImageOrientation = 131,
- kIPTC_LanguageID = 135,
- kIPTC_AudioType = 150,
- kIPTC_AudioSampleRate = 151,
- kIPTC_AudioSampleRes = 152,
- kIPTC_AudioDuration = 153,
- kIPTC_AudioOutcue = 154,
- kIPTC_PreviewFormat = 200,
- kIPTC_PreviewFormatVers = 201,
- kIPTC_PreviewData = 202
-};
-
-enum { // Forms of mapping legacy IPTC to XMP. Order is significant, see PhotoDataUtils::Import2WayIPTC!
- kIPTC_MapSimple, // The XMP is simple, the last DataSet occurrence is kept.
- kIPTC_MapLangAlt, // The XMP is a LangAlt x-default item, the last DataSet occurrence is kept.
- kIPTC_MapArray, // The XMP is an unordered array, all DataSets are kept.
- kIPTC_MapSpecial, // The mapping requires DataSet specific code.
- kIPTC_Map3Way, // Has a 3 way mapping between Exif, IPTC, and XMP.
- kIPTC_UnmappedText, // A text DataSet that is not mapped to XMP.
- kIPTC_UnmappedBin // A binary DataSet that is not mapped to XMP.
-};
-
-struct DataSetCharacteristics {
- XMP_Uns8 id;
- XMP_Uns8 mapForm;
- size_t maxLen;
- XMP_StringPtr xmpNS;
- XMP_StringPtr xmpProp;
-};
-
-extern const DataSetCharacteristics kKnownDataSets[];
-
-struct IntellectualGenreMapping {
- XMP_StringPtr refNum; // The reference number as a 3 digit string.
- XMP_StringPtr name; // The intellectual genre name.
-};
-
-extern const IntellectualGenreMapping kIntellectualGenreMappings[];
-
-// =================================================================================================
-// IPTC_Manager
-// ============
-
-class IPTC_Manager {
-public:
-
- // ---------------------------------------------------------------------------------------------
- // Types and constants.
-
- struct DataSetInfo {
- XMP_Uns8 id;
- XMP_Uns32 dataLen;
- XMP_Uns8 * dataPtr; // ! The data is read-only. Raw data pointer, beware of character encoding.
- DataSetInfo() : id(0), dataLen(0), dataPtr(0) {};
- DataSetInfo ( XMP_Uns8 _id, XMP_Uns32 _dataLen, XMP_Uns8 * _dataPtr )
- : id(_id), dataLen(_dataLen), dataPtr(_dataPtr) {};
- };
-
- // ---------------------------------------------------------------------------------------------
- // Parse a binary IPTC (IIM) block.
-
- void ParseMemoryDataSets ( const void* data, XMP_Uns32 length, bool copyData = true );
-
- // ---------------------------------------------------------------------------------------------
- // Get the information about a DataSet. Returns the number of occurrences. The "which" parameter
- // selects the occurrence, they are numbered from 0 to count-1. Returns 0 if which is too large.
-
- size_t GetDataSet ( XMP_Uns8 id, DataSetInfo* info, size_t which = 0 ) const;
-
- // ---------------------------------------------------------------------------------------------
- // Get the value of a text DataSet as UTF-8. The returned pointer must be treated as read-only.
- // Calls GetDataSet then does a local to UTF-8 conversion if necessary.
-
- size_t GetDataSet_UTF8 ( XMP_Uns8 id, std::string * utf8Str, size_t which = 0 ) const;
-
- // ---------------------------------------------------------------------------------------------
- // Set the value of a text DataSet from a UTF-8 string. Does a UTF-8 to local conversion if
- // necessary. If the encoding mode is currently local and this value has round-trip loss, then
- // the encoding mode will be changed to UTF-8 and all existing values will be converted.
- // Modifies an existing occurrence if "which" is within range. Adds an occurrence if which
- // equals the current count, or which is -1 and repeats are allowed. Throws an exception if
- // which is too large. The dataPtr provides the raw data, text must be in the right encoding.
-
- virtual void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 ) = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Delete an existing DataSet. Deletes all occurrences if which is -1.
-
- virtual void DeleteDataSet ( XMP_Uns8 id, long which = -1 ) = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Determine if any DataSets are changed.
-
- virtual bool IsChanged() = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Determine if UTF-8 or local text encoding is being used.
-
- bool UsingUTF8() const { return this->utf8Encoding; };
-
- // --------------------------------------------------
- // Update the DataSets to reflect the changed values.
-
- virtual void UpdateMemoryDataSets() = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Get the location and size of the full IPTC block. The client must call UpdateMemoryDataSets
- // first if appropriate. The returned dataPtr must be treated as read only. It exists until the
- // IPTC_Manager destructor is called.
-
- XMP_Uns32 GetBlockInfo ( void** dataPtr ) const
- { if ( dataPtr != 0 ) *dataPtr = this->iptcContent; return this->iptcLength; };
-
- // ---------------------------------------------------------------------------------------------
-
- virtual ~IPTC_Manager() { if ( this->ownedContent ) free ( this->iptcContent ); };
-
-protected:
-
- enum { kMinDataSetSize = 5 }; // 1+1+1+2
-
- typedef std::multimap<XMP_Uns16,DataSetInfo> DataSetMap;
-
- DataSetMap dataSets;
-
- XMP_Uns8* iptcContent;
- XMP_Uns32 iptcLength, offset190, length190, offset2xx, length2xx;
-
- bool changed;
- bool ownedContent; // True if IPTC_Manager destructor needs to release the content block.
- bool utf8Encoding; // True if text values are encoded as UTF-8.
-
- IPTC_Manager() : iptcContent(0), iptcLength(0), offset190(0), length190(0), offset2xx(0), length2xx(0),
- changed(false), ownedContent(false), utf8Encoding(false) {};
-
- void DisposeLooseValue ( DataSetInfo & dsInfo );
-
-}; // IPTC_Manager
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// IPTC_Reader
-// ===========
-
-class IPTC_Reader : public IPTC_Manager {
-public:
-
- IPTC_Reader() {};
-
- void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 ) { NotAppropriate(); };
-
- void DeleteDataSet ( XMP_Uns8 id, long which = -1 ) { NotAppropriate(); };
-
- bool IsChanged() { return false; };
-
- void UpdateMemoryDataSets() { NotAppropriate(); };
-
- virtual ~IPTC_Reader() {};
-
-private:
-
- static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for IPTC_Reader", kXMPErr_InternalFailure ); };
-
-}; // IPTC_Reader
-
-// =================================================================================================
-// IPTC_Writer
-// ===========
-
-class IPTC_Writer : public IPTC_Manager {
-public:
-
- void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 );
-
- void DeleteDataSet ( XMP_Uns8 id, long which = -1 );
-
- bool IsChanged() { return changed; };
-
- void UpdateMemoryDataSets ();
-
- IPTC_Writer() {};
-
- virtual ~IPTC_Writer();
-
-private:
-
- void ConvertToUTF8();
- void ConvertToLocal();
-
- bool CheckRoundTripLoss();
-
-}; // IPTC_Writer
-
-// =================================================================================================
-
-#endif // __IPTC_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.cpp b/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.cpp
deleted file mode 100644
index 7d94734..0000000
--- a/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "ISOBaseMedia_Support.hpp"
-#include "XMPFiles_Impl.hpp"
-
-// =================================================================================================
-/// \file ISOBaseMedia_Support.cpp
-/// \brief Manager for parsing and serializing ISO Base Media files ( MPEG-4 and JPEG-2000).
-///
-// =================================================================================================
-
-namespace ISOMedia {
-
-static BoxInfo voidInfo;
-
-// =================================================================================================
-// GetBoxInfo - from memory
-// ========================
-
-const XMP_Uns8 * GetBoxInfo ( const XMP_Uns8 * boxPtr, const XMP_Uns8 * boxLimit,
- BoxInfo * info, bool throwErrors /* = false */ )
-{
- XMP_Uns32 u32Size;
-
- if ( info == 0 ) info = &voidInfo;
- info->boxType = info->headerSize = 0;
- info->contentSize = 0;
-
- if ( boxPtr >= boxLimit ) XMP_Throw ( "Bad offset to GetBoxInfo", kXMPErr_InternalFailure );
-
- if ( (boxLimit - boxPtr) < 8 ) { // Is there enough space for a standard box header?
- if ( throwErrors ) XMP_Throw ( "No space for ISO box header", kXMPErr_BadFileFormat );
- info->headerSize = (XMP_Uns32) (boxLimit - boxPtr);
- return boxLimit;
- }
-
- u32Size = GetUns32BE ( boxPtr );
- info->boxType = GetUns32BE ( boxPtr+4 );
-
- if ( u32Size >= 8 ) {
- info->headerSize = 8; // Normal explicit size case.
- info->contentSize = u32Size - 8;
- } else if ( u32Size == 0 ) {
- info->headerSize = 8; // The box goes to EoF - treat it as "to limit".
- info->contentSize = (boxLimit - boxPtr) - 8;
- } else if ( u32Size != 1 ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO box size, 2..7", kXMPErr_BadFileFormat );
- info->headerSize = 8; // Bad total size in the range of 2..7, treat as 8.
- info->contentSize = 0;
- } else {
- if ( (boxLimit - boxPtr) < 16 ) { // Is there enough space for an extended box header?
- if ( throwErrors ) XMP_Throw ( "No space for ISO extended header", kXMPErr_BadFileFormat );
- info->headerSize = (XMP_Uns32) (boxLimit - boxPtr);
- return boxLimit;
- }
- XMP_Uns64 u64Size = GetUns64BE ( boxPtr+8 );
- if ( u64Size < 16 ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO extended box size, < 16", kXMPErr_BadFileFormat );
- u64Size = 16; // Treat bad total size as 16.
- }
- info->headerSize = 16;
- info->contentSize = u64Size - 16;
- }
-
- XMP_Assert ( (XMP_Uns64)(boxLimit - boxPtr) >= (XMP_Uns64)info->headerSize );
- if ( info->contentSize > (XMP_Uns64)((boxLimit - boxPtr) - info->headerSize) ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO box content size", kXMPErr_BadFileFormat );
- info->contentSize = ((boxLimit - boxPtr) - info->headerSize); // Trim a bad content size to the limit.
- }
-
- return (boxPtr + info->headerSize + info->contentSize);
-
-} // GetBoxInfo
-
-// =================================================================================================
-// GetBoxInfo - from a file
-// ========================
-
-XMP_Uns64 GetBoxInfo ( LFA_FileRef fileRef, const XMP_Uns64 boxOffset, const XMP_Uns64 boxLimit,
- BoxInfo * info, bool doSeek /* = true */, bool throwErrors /* = false */ )
-{
- XMP_Uns8 buffer [8];
- XMP_Uns32 u32Size;
-
- if ( info == 0 ) info = &voidInfo;
- info->boxType = info->headerSize = 0;
- info->contentSize = 0;
-
- if ( boxOffset >= boxLimit ) XMP_Throw ( "Bad offset to GetBoxInfo", kXMPErr_InternalFailure );
-
- if ( (boxLimit - boxOffset) < 8 ) { // Is there enough space for a standard box header?
- if ( throwErrors ) XMP_Throw ( "No space for ISO box header", kXMPErr_BadFileFormat );
- info->headerSize = (XMP_Uns32) (boxLimit - boxOffset);
- return boxLimit;
- }
-
- if ( doSeek ) LFA_Seek ( fileRef, boxOffset, SEEK_SET );
- (void) LFA_Read ( fileRef, buffer, 8, kLFA_RequireAll );
-
- u32Size = GetUns32BE ( &buffer[0] );
- info->boxType = GetUns32BE ( &buffer[4] );
-
- if ( u32Size >= 8 ) {
- info->headerSize = 8; // Normal explicit size case.
- info->contentSize = u32Size - 8;
- } else if ( u32Size == 0 ) {
- info->headerSize = 8; // The box goes to EoF.
- info->contentSize = LFA_Measure(fileRef) - (boxOffset + 8);
- } else if ( u32Size != 1 ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO box size, 2..7", kXMPErr_BadFileFormat );
- info->headerSize = 8; // Bad total size in the range of 2..7, treat as 8.
- info->contentSize = 0;
- } else {
- if ( (boxLimit - boxOffset) < 16 ) { // Is there enough space for an extended box header?
- if ( throwErrors ) XMP_Throw ( "No space for ISO extended header", kXMPErr_BadFileFormat );
- info->headerSize = (XMP_Uns32) (boxLimit - boxOffset);
- return boxLimit;
- }
- (void) LFA_Read ( fileRef, buffer, 8, kLFA_RequireAll );
- XMP_Uns64 u64Size = GetUns64BE ( &buffer[0] );
- if ( u64Size < 16 ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO extended box size, < 16", kXMPErr_BadFileFormat );
- u64Size = 16; // Treat bad total size as 16.
- }
- info->headerSize = 16;
- info->contentSize = u64Size - 16;
- }
-
- XMP_Assert ( (boxLimit - boxOffset) >= info->headerSize );
- if ( info->contentSize > (boxLimit - boxOffset - info->headerSize) ) {
- if ( throwErrors ) XMP_Throw ( "Bad ISO box content size", kXMPErr_BadFileFormat );
- info->contentSize = (boxLimit - boxOffset - info->headerSize); // Trim a bad content size to the limit.
- }
-
- return (boxOffset + info->headerSize + info->contentSize);
-
-} // GetBoxInfo
-
-} // namespace ISO_Media
-
-
-// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.hpp b/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.hpp
deleted file mode 100644
index 4f50df7..0000000
--- a/source/XMPFiles/FormatSupport/ISOBaseMedia_Support.hpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef __ISOBaseMedia_Support_hpp__
-#define __ISOBaseMedia_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMP_Const.h"
-#include "LargeFileAccess.hpp"
-
-// =================================================================================================
-/// \file ISOBaseMedia_Support.hpp
-/// \brief XMPFiles support for the ISO Base Media File Format.
-///
-/// \note These classes are for use only when directly compiled and linked. They should not be
-/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
-// =================================================================================================
-
-namespace ISOMedia {
-
- enum {
- k_ftyp = 0x66747970UL, // File header Box, no version/flags.
-
- k_mp41 = 0x6D703431UL, // Compatible brand codes
- k_mp42 = 0x6D703432UL,
- k_f4v = 0x66347620UL,
- 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_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_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.
- };
-
- static XMP_Uns32 k_xmpUUID [4] = { MakeUns32BE ( 0xBE7ACFCBUL ),
- 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".
- 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 );
-
- // 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 ( LFA_FileRef fileRef, const XMP_Uns64 boxOffset, const XMP_Uns64 boxLimit,
- BoxInfo * info, bool doSeek = true, bool throwErrors = false );
-
-// XMP_Uns32 CountChildBoxes ( LFA_FileRef fileRef, const XMP_Uns64 childOffset, const XMP_Uns64 childLimit );
-
-} // namespace ISO_Media
-
-// =================================================================================================
-
-#endif // __ISOBaseMedia_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/MOOV_Support.cpp b/source/XMPFiles/FormatSupport/MOOV_Support.cpp
deleted file mode 100644
index 1c89176..0000000
--- a/source/XMPFiles/FormatSupport/MOOV_Support.cpp
+++ /dev/null
@@ -1,542 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 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 "MOOV_Support.hpp"
-
-#include "ISOBaseMedia_Support.hpp"
-
-#include <string.h>
-
-// =================================================================================================
-/// \file MOOV_Support.cpp
-/// \brief XMPFiles support for the 'moov' box in MPEG-4 and QuickTime files.
-// =================================================================================================
-
-// =================================================================================================
-// =================================================================================================
-// MOOV_Manager - The parsing and reading routines are all commmon
-// =================================================================================================
-// =================================================================================================
-
-#ifndef TraceParseMoovTree
- #define TraceParseMoovTree 0
-#endif
-
-#ifndef TraceUpdateMoovTree
- #define TraceUpdateMoovTree 0
-#endif
-
-// =================================================================================================
-// MOOV_Manager::PickContentPtr
-// ============================
-
-XMP_Uns8 * MOOV_Manager::PickContentPtr ( const BoxNode & node ) const
-{
- if ( node.contentSize == 0 ) {
- return 0;
- } else if ( node.changed ) {
- return (XMP_Uns8*) &node.changedContent[0];
- } else {
- return (XMP_Uns8*) &this->fullSubtree[0] + node.offset + node.headerSize;
- }
-} // MOOV_Manager::PickContentPtr
-
-// =================================================================================================
-// MOOV_Manager::FillBoxInfo
-// =========================
-
-void MOOV_Manager::FillBoxInfo ( const BoxNode & node, BoxInfo * info ) const
-{
- if ( info == 0 ) return;
-
- info->boxType = node.boxType;
- info->childCount = (XMP_Uns32)node.children.size();
- info->contentSize = node.contentSize;
- info->content = PickContentPtr ( node );
-
-} // MOOV_Manager::FillBoxInfo
-
-// =================================================================================================
-// MOOV_Manager::GetBox
-// ====================
-//
-// Find a box given the type path. Pick the first child of each type.
-
-MOOV_Manager::BoxRef MOOV_Manager::GetBox ( const char * boxPath, BoxInfo * info ) const
-{
- size_t pathLen = strlen(boxPath);
- XMP_Assert ( (pathLen >= 4) && XMP_LitNMatch ( boxPath, "moov", 4 ) );
- if ( info != 0 ) memset ( info, 0, sizeof(BoxInfo) );
-
- const char * pathPtr = boxPath + 5; // Skip the "moov/" portion.
- const char * pathEnd = boxPath + pathLen;
-
- BoxRef currRef = &this->moovNode;
-
- while ( pathPtr < pathEnd ) {
-
- XMP_Assert ( (pathEnd - pathPtr) >= 4 );
- XMP_Uns32 boxType = GetUns32BE ( pathPtr );
- pathPtr += 5; // ! Don't care that the last step goes 1 too far.
-
- currRef = this->GetTypeChild ( currRef, boxType, 0 );
- if ( currRef == 0 ) return 0;
-
- }
-
- this->FillBoxInfo ( *((BoxNode*)currRef), info );
- return currRef;
-
-} // MOOV_Manager::GetBox
-
-// =================================================================================================
-// MOOV_Manager::GetNthChild
-// =========================
-
-MOOV_Manager::BoxRef MOOV_Manager::GetNthChild ( BoxRef parentRef, size_t childIndex, BoxInfo * info ) const
-{
- XMP_Assert ( parentRef != 0 );
- const BoxNode & parent = *((BoxNode*)parentRef);
- if ( info != 0 ) memset ( info, 0, sizeof(BoxInfo) );
-
- if ( childIndex >= parent.children.size() ) return 0;
-
- const BoxNode & currNode = parent.children[childIndex];
-
- this->FillBoxInfo ( currNode, info );
- return &currNode;
-
-} // MOOV_Manager::GetNthChild
-
-// =================================================================================================
-// MOOV_Manager::GetTypeChild
-// ==========================
-
-MOOV_Manager::BoxRef MOOV_Manager::GetTypeChild ( BoxRef parentRef, XMP_Uns32 childType, BoxInfo * info ) const
-{
- XMP_Assert ( parentRef != 0 );
- const BoxNode & parent = *((BoxNode*)parentRef);
- if ( info != 0 ) memset ( info, 0, sizeof(BoxInfo) );
- if ( parent.children.empty() ) return 0;
-
- size_t i = 0, limit = parent.children.size();
- for ( ; i < limit; ++i ) {
- const BoxNode & currNode = parent.children[i];
- if ( currNode.boxType == childType ) {
- this->FillBoxInfo ( currNode, info );
- return &currNode;
- }
- }
-
- return 0;
-
-} // MOOV_Manager::GetTypeChild
-
-// =================================================================================================
-// MOOV_Manager::GetParsedOffset
-// =============================
-
-XMP_Uns32 MOOV_Manager::GetParsedOffset ( BoxRef ref ) const
-{
- XMP_Assert ( ref != 0 );
- const BoxNode & node = *((BoxNode*)ref);
-
- if ( node.changed ) return 0;
- return node.offset;
-
-} // MOOV_Manager::GetParsedOffset
-
-// =================================================================================================
-// MOOV_Manager::GetHeaderSize
-// ===========================
-
-XMP_Uns32 MOOV_Manager::GetHeaderSize ( BoxRef ref ) const
-{
- XMP_Assert ( ref != 0 );
- const BoxNode & node = *((BoxNode*)ref);
-
- if ( node.changed ) return 0;
- return node.headerSize;
-
-} // MOOV_Manager::GetHeaderSize
-
-// =================================================================================================
-// MOOV_Manager::ParseMemoryTree
-// =============================
-//
-// Parse the fullSubtree data, building the BoxNode tree for the stuff that we care about. Tolerate
-// errors like content ending too soon, make a best effoert to parse what we can.
-
-void MOOV_Manager::ParseMemoryTree ( XMP_Uns8 fileMode )
-{
- this->fileMode = fileMode;
-
- this->moovNode.offset = this->moovNode.boxType = 0;
- this->moovNode.headerSize = this->moovNode.contentSize = 0;
- this->moovNode.children.clear();
- this->moovNode.changedContent.clear();
- this->moovNode.changed = false;
-
- if ( this->fullSubtree.empty() ) return;
-
- ISOMedia::BoxInfo moovInfo;
- const XMP_Uns8 * moovOrigin = &this->fullSubtree[0];
- const XMP_Uns8 * moovLimit = moovOrigin + this->fullSubtree.size();
-
- (void) ISOMedia::GetBoxInfo ( moovOrigin, moovLimit, &moovInfo );
- XMP_Enforce ( moovInfo.boxType == ISOMedia::k_moov );
-
- XMP_Uns64 fullMoovSize = moovInfo.headerSize + moovInfo.contentSize;
- if ( fullMoovSize > moovBoxSizeLimit ) { // From here on we know 32-bit offsets are safe.
- XMP_Throw ( "Oversize 'moov' box", kXMPErr_EnforceFailure );
- }
-
- this->moovNode.boxType = ISOMedia::k_moov;
- this->moovNode.headerSize = moovInfo.headerSize;
- this->moovNode.contentSize = (XMP_Uns32)moovInfo.contentSize;
-
- bool ignoreMetaBoxes = (fileMode == kFileIsTraditionalQT); // ! Don't want, these don't follow ISO spec.
- #if TraceParseMoovTree
- fprintf ( stderr, "Parsing 'moov' subtree, moovNode @ 0x%X, ignoreMetaBoxes = %d\n",
- &this->moovNode, ignoreMetaBoxes );
- #endif
- this->ParseNestedBoxes ( &this->moovNode, "moov", ignoreMetaBoxes );
-
-} // MOOV_Manager::ParseMemoryTree
-
-// =================================================================================================
-// MOOV_Manager::ParseNestedBoxes
-// ==============================
-//
-// Add the current level of child boxes to the parent node, recurse as appropriate.
-
-void MOOV_Manager::ParseNestedBoxes ( BoxNode * parentNode, const std::string & parentPath, bool ignoreMetaBoxes )
-{
- ISOMedia::BoxInfo isoInfo;
- const XMP_Uns8 * moovOrigin = &this->fullSubtree[0];
- const XMP_Uns8 * childOrigin = moovOrigin + parentNode->offset + parentNode->headerSize;
- const XMP_Uns8 * childLimit = childOrigin + parentNode->contentSize;
- const XMP_Uns8 * nextChild;
-
- parentNode->contentSize = 0; // Exclude nested box size.
- if ( parentNode->boxType == ISOMedia::k_meta ) { // ! The 'meta' box is a FullBox.
- parentNode->contentSize = 4;
- childOrigin += 4;
- }
-
- for ( const XMP_Uns8 * currChild = childOrigin; currChild < childLimit; currChild = nextChild ) {
-
- nextChild = ISOMedia::GetBoxInfo ( currChild, childLimit, &isoInfo );
- if ( (isoInfo.boxType == 0) &&
- (isoInfo.headerSize < 8) &&
- (isoInfo.contentSize == 0) ) continue; // Skip trailing padding that QT sometimes writes.
-
- XMP_Uns32 childOffset = (XMP_Uns32) (currChild - moovOrigin);
- parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns32)isoInfo.contentSize ) );
- BoxNode * newChild = &parentNode->children.back();
-
- #if TraceParseMoovTree
- size_t depth = (parentPath.size()+1) / 5;
- for ( size_t i = 0; i < depth; ++i ) fprintf ( stderr, " " );
- XMP_Uns32 be32 = MakeUns32BE ( newChild->boxType );
- XMP_Uns32 addr32 = (XMP_Uns32) this->PickContentPtr ( *newChild );
- fprintf ( stderr, " Parsed %s/%.4s, offset 0x%X, size %d, content @ 0x%X, BoxNode @ 0x%X\n",
- parentPath.c_str(), &be32, newChild->offset, newChild->contentSize, addr32, newChild );
- #endif
-
- const char * pathSuffix = 0; // Set to non-zero for boxes of interest.
- char buffer[6]; buffer[0] = 0;
-
- switch ( isoInfo.boxType ) { // Want these boxes regardless of parent.
- case ISOMedia::k_udta : pathSuffix = "/udta"; break;
- case ISOMedia::k_meta : pathSuffix = "/meta"; break;
- case ISOMedia::k_ilst : pathSuffix = "/ilst"; break;
- case ISOMedia::k_trak : pathSuffix = "/trak"; break;
- case ISOMedia::k_mdia : pathSuffix = "/mdia"; break;
- case ISOMedia::k_minf : pathSuffix = "/minf"; break;
- case ISOMedia::k_stbl : pathSuffix = "/stbl"; break;
- }
- if ( pathSuffix != 0 ) {
- this->ParseNestedBoxes ( newChild, (parentPath + pathSuffix), ignoreMetaBoxes );
- }
-
- }
-
-} // MOOV_Manager::ParseNestedBoxes
-
-// =================================================================================================
-// MOOV_Manager::NoteChange
-// ========================
-
-void MOOV_Manager::NoteChange()
-{
-
- this->moovNode.changed = true;
-
-} // MOOV_Manager::NoteChange
-
-// =================================================================================================
-// MOOV_Manager::SetBox
-// ====================
-//
-// Save the new data, set this box's changed flag, and set the top changed flag.
-
-void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size )
-{
- XMP_Enforce ( size < moovBoxSizeLimit );
- BoxNode * node = (BoxNode*)theBox;
-
- if ( node->contentSize == size ) {
-
- XMP_Uns8 * oldContent = PickContentPtr ( *node );
- if ( memcmp ( oldContent, dataPtr, size ) == 0 ) return; // No change.
- memcpy ( oldContent, dataPtr, size ); // Update the old content in-place
- this->moovNode.changed = true;
-
- #if TraceUpdateMoovTree
- XMP_Uns32 be32 = MakeUns32BE ( node->boxType );
- fprintf ( stderr, "Updated '%.4s', parse offset 0x%X, same size\n", &be32, node->offset );
- #endif
-
- } else {
-
- node->changedContent.assign ( size, 0 ); // Fill with 0's first to get the storage.
- memcpy ( &node->changedContent[0], dataPtr, size );
- node->contentSize = size;
- node->changed = true;
- this->moovNode.changed = true;
-
- #if TraceUpdateMoovTree
- XMP_Uns32 be32 = MakeUns32BE ( node->boxType );
- XMP_Uns32 addr32 = (XMP_Uns32) this->PickContentPtr ( *node );
- fprintf ( stderr, "Updated '%.4s', parse offset 0x%X, new size %d, new content @ 0x%X\n",
- &be32, node->offset, node->contentSize, addr32 );
- #endif
-
- }
-
-} // MOOV_Manager::SetBox
-
-// =================================================================================================
-// MOOV_Manager::SetBox
-// ====================
-//
-// Like above, but create the path to the box if necessary.
-
-void MOOV_Manager::SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size )
-{
- XMP_Enforce ( size < moovBoxSizeLimit );
-
- size_t pathLen = strlen(boxPath);
- XMP_Assert ( (pathLen >= 4) && XMP_LitNMatch ( boxPath, "moov", 4 ) );
-
- const char * pathPtr = boxPath + 5; // Skip the "moov/" portion.
- const char * pathEnd = boxPath + pathLen;
-
- BoxRef parentRef = 0;
- BoxRef currRef = &this->moovNode;
-
- while ( pathPtr < pathEnd ) {
-
- XMP_Assert ( (pathEnd - pathPtr) >= 4 );
- XMP_Uns32 boxType = GetUns32BE ( pathPtr );
- pathPtr += 5; // ! Don't care that the last step goes 1 too far.
-
- parentRef = currRef;
- currRef = this->GetTypeChild ( parentRef, boxType, 0 );
- if ( currRef == 0 ) currRef = this->AddChildBox ( parentRef, boxType, 0, 0 );
-
- }
-
- this->SetBox ( currRef, dataPtr, size );
-
-} // MOOV_Manager::SetBox
-
-// =================================================================================================
-// MOOV_Manager::AddChildBox
-// =========================
-
-MOOV_Manager::BoxRef MOOV_Manager::AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void* dataPtr, XMP_Uns32 size )
-{
- BoxNode * parent = (BoxNode*)parentRef;
- XMP_Assert ( parent != 0 );
-
- parent->children.push_back ( BoxNode ( 0, childType, 0, 0 ) );
- BoxNode * newNode = &parent->children.back();
- this->SetBox ( newNode, dataPtr, size );
-
- return newNode;
-
-} // MOOV_Manager::AddChildBox
-
-// =================================================================================================
-// MOOV_Manager::DeleteNthChild
-// ============================
-
-bool MOOV_Manager::DeleteNthChild ( BoxRef parentRef, size_t childIndex )
-{
- BoxNode * parent = (BoxNode*)parentRef;
-
- if ( childIndex >= parent->children.size() ) return false;
-
- parent->children.erase ( parent->children.begin() + childIndex );
- return true;
-
-} // MOOV_Manager::DeleteNthChild
-
-// =================================================================================================
-// MOOV_Manager::DeleteTypeChild
-// =============================
-
-bool MOOV_Manager::DeleteTypeChild ( BoxRef parentRef, XMP_Uns32 childType )
-{
- BoxNode * parent = (BoxNode*)parentRef;
-
- BoxListPos child = parent->children.begin();
- BoxListPos limit = parent->children.end();
-
- for ( ; child != limit; ++child ) {
- if ( child->boxType == childType ) {
- parent->children.erase ( child );
- this->moovNode.changed = true;
- return true;
- }
- }
-
- return false;
-
-} // MOOV_Manager::DeleteTypeChild
-
-// =================================================================================================
-// MOOV_Manager::NewSubtreeSize
-// ============================
-//
-// Determine the new (changed) size of a subtree. Ignore 'free' and 'wide' boxes.
-
-XMP_Uns32 MOOV_Manager::NewSubtreeSize ( const BoxNode & node, const std::string & parentPath )
-{
- XMP_Uns32 subtreeSize = 8 + node.contentSize; // All boxes will have 8 byte headers.
-
- if ( (node.boxType == ISOMedia::k_free) || (node.boxType == ISOMedia::k_wide) ) {
- }
-
- for ( size_t i = 0, limit = node.children.size(); i < limit; ++i ) {
-
- char suffix[6];
- suffix[0] = '/';
- PutUns32BE ( node.boxType, &suffix[1] );
- suffix[5] = 0;
- std::string nodePath = parentPath + suffix;
-
- subtreeSize += this->NewSubtreeSize ( node.children[i], nodePath );
- XMP_Enforce ( subtreeSize < moovBoxSizeLimit );
-
- }
-
- return subtreeSize;
-
-} // MOOV_Manager::NewSubtreeSize
-
-// =================================================================================================
-// MOOV_Manager::AppendNewSubtree
-// ==============================
-//
-// Append this node's header, content, and children. Because the 'meta' box is a FullBox with nested
-// boxes, there can be both content and children. Ignore 'free' and 'wide' boxes.
-
-#define IncrNewPtr(count) { newPtr += count; XMP_Enforce ( newPtr <= newEnd ); }
-
-#if TraceUpdateMoovTree
- static XMP_Uns8 * newOrigin;
-#endif
-
-XMP_Uns8 * MOOV_Manager::AppendNewSubtree ( const BoxNode & node, const std::string & parentPath,
- XMP_Uns8 * newPtr, XMP_Uns8 * newEnd )
-{
- if ( (node.boxType == ISOMedia::k_free) || (node.boxType == ISOMedia::k_wide) ) {
- }
-
- XMP_Assert ( (node.boxType != ISOMedia::k_meta) ? (node.children.empty() || (node.contentSize == 0)) :
- (node.children.empty() || (node.contentSize == 4)) );
-
- XMP_Enforce ( (XMP_Uns32)(newEnd - newPtr) >= (8 + node.contentSize) );
-
- #if TraceUpdateMoovTree
- XMP_Uns32 be32 = MakeUns32BE ( node.boxType );
- XMP_Uns32 newOffset = (XMP_Uns32) (newPtr - newOrigin);
- XMP_Uns32 addr32 = (XMP_Uns32) this->PickContentPtr ( node );
- fprintf ( stderr, " Appending %s/%.4s @ 0x%X, size %d, content @ 0x%X\n",
- parentPath.c_str(), &be32, newOffset, node.contentSize, addr32 );
- #endif
-
- // Leave the size as 0 for now, append the type and content.
-
- XMP_Uns8 * boxOrigin = newPtr; // Save origin to fill in the final size.
- PutUns32BE ( node.boxType, (newPtr + 4) );
- IncrNewPtr ( 8 );
-
- if ( node.contentSize != 0 ) {
- const XMP_Uns8 * content = PickContentPtr( node );
- memcpy ( newPtr, content, node.contentSize );
- IncrNewPtr ( node.contentSize );
- }
-
- // Append the nested boxes.
-
- if ( ! node.children.empty() ) {
-
- char suffix[6];
- suffix[0] = '/';
- PutUns32BE ( node.boxType, &suffix[1] );
- suffix[5] = 0;
- std::string nodePath = parentPath + suffix;
-
- for ( size_t i = 0, limit = node.children.size(); i < limit; ++i ) {
- newPtr = this->AppendNewSubtree ( node.children[i], nodePath, newPtr, newEnd );
- }
-
- }
-
- // Fill in the final size.
-
- PutUns32BE ( (XMP_Uns32)(newPtr - boxOrigin), boxOrigin );
-
- return newPtr;
-
-} // MOOV_Manager::AppendNewSubtree
-
-// =================================================================================================
-// MOOV_Manager::UpdateMemoryTree
-// ==============================
-
-void MOOV_Manager::UpdateMemoryTree()
-{
- if ( ! this->IsChanged() ) return;
-
- XMP_Uns32 newSize = this->NewSubtreeSize ( this->moovNode, "" );
- XMP_Enforce ( newSize < moovBoxSizeLimit );
-
- RawDataBlock newData;
- newData.assign ( newSize, 0 ); // Prefill with zeroes, can't append multiple items to a vector.
-
- XMP_Uns8 * newPtr = &newData[0];
- XMP_Uns8 * newEnd = newPtr + newSize;
-
- #if TraceUpdateMoovTree
- fprintf ( stderr, "Starting MOOV_Manager::UpdateMemoryTree\n" );
- newOrigin = newPtr;
- #endif
-
- XMP_Uns8 * trueEnd = this->AppendNewSubtree ( this->moovNode, "", newPtr, newEnd );
- XMP_Enforce ( trueEnd == newEnd );
-
- this->fullSubtree.swap ( newData );
- this->ParseMemoryTree ( this->fileMode );
-
-} // MOOV_Manager::UpdateMemoryTree
diff --git a/source/XMPFiles/FormatSupport/MOOV_Support.hpp b/source/XMPFiles/FormatSupport/MOOV_Support.hpp
deleted file mode 100644
index 3e19a9d..0000000
--- a/source/XMPFiles/FormatSupport/MOOV_Support.hpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef __MOOV_Support_hpp__
-#define __MOOV_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <vector>
-
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "EndianUtils.hpp"
-
-typedef vector<XMP_Uns8> RawDataBlock;
-
-#define moovBoxSizeLimit 100*1024*1024
-
-// =================================================================================================
-// MOOV_Manager
-// ============
-
-class MOOV_Manager {
-public:
-
- // ---------------------------------------------------------------------------------------------
- // Types and constants
-
- enum { // Values for fileMode.
- kFileIsNormalISO = 0, // A "normal" MPEG-4 file, no 'qt ' compatible brand.
- kFileIsModernQT = 1, // Has an 'ftyp' box and 'qt ' compatible brand.
- kFileIsTraditionalQT = 2 // Old QuickTime, no 'ftyp' box.
- };
-
- typedef const void * BoxRef; // Valid until a sibling or higher box is added or deleted.
-
- struct BoxInfo {
- XMP_Uns32 boxType; // In memory as native endian, compares work with ISOMedia::k_* constants.
- XMP_Uns32 childCount; // ! A 'meta' box has both content (version/flags) and children!
- XMP_Uns32 contentSize; // Does not include the size of nested boxes.
- const XMP_Uns8 * content; // Null if contentSize is zero.
- BoxInfo() : boxType(0), childCount(0), contentSize(0), content(0) {};
- };
-
- // ---------------------------------------------------------------------------------------------
- // GetBox - Pick a box given a '/' separated list of box types. Picks the 1st of each type.
- // GetNthChild - Pick the overall n-th child of the parent, zero based.
- // GetTypeChild - Pick the first child of the given type.
- // GetParsedOffset - Get the box's offset in the parsed tree, 0 if changed since parsing.
- // GetHeaderSize - Get the box's header size in the parsed tree, 0 if changed since parsing.
-
- BoxRef GetBox ( const char * boxPath, BoxInfo * info ) const;
-
- BoxRef GetNthChild ( BoxRef parentRef, size_t childIndex, BoxInfo * info ) const;
- BoxRef GetTypeChild ( BoxRef parentRef, XMP_Uns32 childType, BoxInfo * info ) const;
-
- XMP_Uns32 GetParsedOffset ( BoxRef ref ) const;
- XMP_Uns32 GetHeaderSize ( BoxRef ref ) const;
-
- // ---------------------------------------------------------------------------------------------
- // NoteChange - Note overall change, value was directly replaced.
- // SetBox(ref) - Replace the content with a copy of the given data.
- // SetBox(path) - Like above, but creating path to the box if necessary.
- // AddChildBox - Add a child of the given type, using a copy of the given data (may be null)
-
- void NoteChange();
-
- void SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size );
- void SetBox ( const char * boxPath, const void* dataPtr, XMP_Uns32 size );
-
- BoxRef AddChildBox ( BoxRef parentRef, XMP_Uns32 childType, const void * dataPtr, XMP_Uns32 size );
-
- // ---------------------------------------------------------------------------------------------
- // DeleteNthChild - Delete the overall n-th child, return true if there was one.
- // DeleteTypeChild - Delete the first child of the given type, return true if there was one.
-
- bool DeleteNthChild ( BoxRef parentRef, size_t childIndex );
- bool DeleteTypeChild ( BoxRef parentRef, XMP_Uns32 childType );
-
- // ---------------------------------------------------------------------------------------------
-
- bool IsChanged() const { return this->moovNode.changed; };
-
- // ---------------------------------------------------------------------------------------------
- // The client is expected to fill in fullSubtree before calling ParseMemoryTree, and directly
- // use fullSubtree after calling UpdateMemoryTree.
- //
- // IMPORTANT: We only support cases where the 'moov' subtree is significantly less than 4 GB, in
- // particular with a threshold of probably 100 MB. This has 2 big impacts: we can safely use
- // 32-bit offsets and sizes, and comfortably assume everything will fit in available heap space.
-
- RawDataBlock fullSubtree; // The entire 'moov' box, straight from the file or from UpdateMemoryTree.
-
- void ParseMemoryTree ( XMP_Uns8 fileMode );
- void UpdateMemoryTree();
-
- // ---------------------------------------------------------------------------------------------
-
- #pragma pack (1) // ! These must match the file layout!
-
- struct Content_mvhd_0 {
- XMP_Uns32 vFlags; // 0
- XMP_Uns32 creationTime; // 4
- XMP_Uns32 modificationTime; // 8
- XMP_Uns32 timescale; // 12
- XMP_Uns32 duration; // 16
- XMP_Int32 rate; // 20
- XMP_Int16 volume; // 24
- XMP_Uns16 pad_1; // 26
- XMP_Uns32 pad_2, pad_3; // 28
- XMP_Int32 matrix [9]; // 36
- XMP_Uns32 preDef [6]; // 72
- XMP_Uns32 nextTrackID; // 96
- }; // 100
-
- struct Content_mvhd_1 {
- XMP_Uns32 vFlags; // 0
- XMP_Uns64 creationTime; // 4
- XMP_Uns64 modificationTime; // 12
- XMP_Uns32 timescale; // 20
- XMP_Uns64 duration; // 24
- XMP_Int32 rate; // 32
- XMP_Int16 volume; // 36
- XMP_Uns16 pad_1; // 38
- XMP_Uns32 pad_2, pad_3; // 40
- XMP_Int32 matrix [9]; // 48
- XMP_Uns32 preDef [6]; // 84
- XMP_Uns32 nextTrackID; // 108
- }; // 112
-
- struct Content_hdlr { // An 'hdlr' box as defined by ISO 14496-12. Maps OK to the QuickTime box.
- XMP_Uns32 versionFlags; // 0
- XMP_Uns32 preDef; // 4
- XMP_Uns32 handlerType; // 8
- XMP_Uns32 reserved [3]; // 12
- // Plus optional component name string, null terminated UTF-8.
- }; // 24
-
- struct Content_stsd_entry {
- XMP_Uns32 entrySize; // 0
- XMP_Uns32 format; // 4
- XMP_Uns8 reserved_1 [6]; // 8
- XMP_Uns16 dataRefIndex; // 14
- XMP_Uns32 reserved_2; // 16
- XMP_Uns32 flags; // 20
- XMP_Uns32 timeScale; // 24
- XMP_Uns32 frameDuration; // 28
- XMP_Uns8 frameCount; // 32
- XMP_Uns8 reserved_3; // 33
- // Plus optional trailing ISO boxes.
- }; // 34
-
- struct Content_stsc_entry {
- XMP_Uns32 firstChunkNumber; // 0
- XMP_Uns32 samplesPerChunk; // 4
- XMP_Uns32 sampleDescrID; // 8
- }; // 12
-
- // ---------------------------------------------------------------------------------------------
-
- MOOV_Manager() : fileMode(0)
- {
- XMP_Assert ( sizeof ( Content_mvhd_0 ) == 100 ); // Make sure the structs really are packed.
- XMP_Assert ( sizeof ( Content_mvhd_1 ) == 112 );
- XMP_Assert ( sizeof ( Content_hdlr ) == 24 );
- XMP_Assert ( sizeof ( Content_stsd_entry ) == 34 );
- XMP_Assert ( sizeof ( Content_stsc_entry ) == 12 );
- };
-
- virtual ~MOOV_Manager() {};
-
-private:
-
- struct BoxNode;
- typedef std::vector<BoxNode> BoxList;
- typedef BoxList::iterator BoxListPos;
-
- struct BoxNode {
- // ! Don't have a parent link, it will get destroyed by vector growth!
-
- XMP_Uns32 offset; // The offset in the fullSubtree, 0 if not in the parse.
- XMP_Uns32 boxType;
- XMP_Uns32 headerSize; // The actual header size in the fullSubtree, 0 if not in the parse.
- XMP_Uns32 contentSize; // The current content size, does not include nested boxes.
- BoxList children;
- RawDataBlock changedContent; // Might be empty even if changed is true.
- bool changed; // If true, the content is in changedContent, else in fullSubtree.
-
- BoxNode() : offset(0), boxType(0), headerSize(0), contentSize(0), changed(false) {};
- BoxNode ( XMP_Uns32 _offset, XMP_Uns32 _boxType, XMP_Uns32 _headerSize, XMP_Uns32 _contentSize )
- : offset(_offset), boxType(_boxType), headerSize(_headerSize), contentSize(_contentSize), changed(false) {};
-
- };
-
- XMP_Uns8 fileMode;
- BoxNode moovNode;
-
- void ParseNestedBoxes ( BoxNode * parentNode, const std::string & parentPath, bool ignoreMetaBoxes );
-
- XMP_Uns8 * PickContentPtr ( const BoxNode & node ) const;
- void FillBoxInfo ( const BoxNode & node, BoxInfo * info ) const;
-
- XMP_Uns32 NewSubtreeSize ( const BoxNode & node, const std::string & parentPath );
- XMP_Uns8 * AppendNewSubtree ( const BoxNode & node, const std::string & parentPath,
- XMP_Uns8 * newPtr, XMP_Uns8 * newEnd );
-
-}; // MOOV_Manager
-
-#endif // __MOOV_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/MacScriptExtracts.h b/source/XMPFiles/FormatSupport/MacScriptExtracts.h
deleted file mode 100644
index 9856183..0000000
--- a/source/XMPFiles/FormatSupport/MacScriptExtracts.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#ifndef __MacScriptExtracts__
-#define __MacScriptExtracts__
-
-// Extracts of script (smXyz) and language (langXyz) enums from Apple's old Script.h.
-// These are used to support "traditional" QuickTime metadata processing.
-
-/*
- Script codes:
- These specify a Mac OS encoding that is related to a FOND ID range.
- Some of the encodings have several variants (e.g. for different localized systems)
- which all share the same script code.
- Not all of these script codes are currently supported by Apple software.
- Notes:
- - Script code 0 (smRoman) is also used (instead of smGreek) for the Greek encoding
- in the Greek localized system.
- - Script code 28 (smEthiopic) is also used for the Inuit encoding in the Inuktitut
- system.
-*/
-enum {
- smRoman = 0,
- smJapanese = 1,
- smTradChinese = 2, /* Traditional Chinese*/
- smKorean = 3,
- smArabic = 4,
- smHebrew = 5,
- smGreek = 6,
- smCyrillic = 7,
- smRSymbol = 8, /* Right-left symbol*/
- smDevanagari = 9,
- smGurmukhi = 10,
- smGujarati = 11,
- smOriya = 12,
- smBengali = 13,
- smTamil = 14,
- smTelugu = 15,
- smKannada = 16, /* Kannada/Kanarese*/
- smMalayalam = 17,
- smSinhalese = 18,
- smBurmese = 19,
- smKhmer = 20, /* Khmer/Cambodian*/
- smThai = 21,
- smLao = 22,
- smGeorgian = 23,
- smArmenian = 24,
- smSimpChinese = 25, /* Simplified Chinese*/
- smTibetan = 26,
- smMongolian = 27,
- smEthiopic = 28,
- smGeez = 28, /* Synonym for smEthiopic*/
- smCentralEuroRoman = 29, /* For Czech, Slovak, Polish, Hungarian, Baltic langs*/
- smVietnamese = 30,
- smExtArabic = 31, /* extended Arabic*/
- smUninterp = 32 /* uninterpreted symbols, e.g. palette symbols*/
-};
-
-/* Extended script code for full Unicode input*/
-enum {
- smUnicodeScript = 0x7E
-};
-
-/* Obsolete script code names (kept for backward compatibility):*/
-enum {
- smChinese = 2, /* (Use smTradChinese or smSimpChinese)*/
- smRussian = 7, /* Use smCyrillic*/
- /* smMaldivian = 25: deleted, no code for Maldivian*/
- smLaotian = 22, /* Use smLao */
- smAmharic = 28, /* Use smEthiopic or smGeez*/
- smSlavic = 29, /* Use smCentralEuroRoman*/
- smEastEurRoman = 29, /* Use smCentralEuroRoman*/
- smSindhi = 31, /* Use smExtArabic*/
- smKlingon = 32
-};
-
-/*
- Language codes:
- These specify a language implemented using a particular Mac OS encoding.
- Not all of these language codes are currently supported by Apple software.
-*/
-enum {
- langEnglish = 0, /* smRoman script*/
- langFrench = 1, /* smRoman script*/
- langGerman = 2, /* smRoman script*/
- langItalian = 3, /* smRoman script*/
- langDutch = 4, /* smRoman script*/
- langSwedish = 5, /* smRoman script*/
- langSpanish = 6, /* smRoman script*/
- langDanish = 7, /* smRoman script*/
- langPortuguese = 8, /* smRoman script*/
- langNorwegian = 9, /* (Bokmal) smRoman script*/
- langHebrew = 10, /* smHebrew script*/
- langJapanese = 11, /* smJapanese script*/
- langArabic = 12, /* smArabic script*/
- langFinnish = 13, /* smRoman script*/
- langGreek = 14, /* Greek script (monotonic) using smRoman script code*/
- langIcelandic = 15, /* modified smRoman/Icelandic script*/
- langMaltese = 16, /* Roman script*/
- langTurkish = 17, /* modified smRoman/Turkish script*/
- langCroatian = 18, /* modified smRoman/Croatian script*/
- langTradChinese = 19, /* Chinese (Mandarin) in traditional characters*/
- langUrdu = 20, /* smArabic script*/
- langHindi = 21, /* smDevanagari script*/
- langThai = 22, /* smThai script*/
- langKorean = 23 /* smKorean script*/
-};
-
-enum {
- langLithuanian = 24, /* smCentralEuroRoman script*/
- langPolish = 25, /* smCentralEuroRoman script*/
- langHungarian = 26, /* smCentralEuroRoman script*/
- langEstonian = 27, /* smCentralEuroRoman script*/
- langLatvian = 28, /* smCentralEuroRoman script*/
- langSami = 29, /* language of the Sami people of N. Scandinavia */
- langFaroese = 30, /* modified smRoman/Icelandic script */
- langFarsi = 31, /* modified smArabic/Farsi script*/
- langPersian = 31, /* Synonym for langFarsi*/
- langRussian = 32, /* smCyrillic script*/
- langSimpChinese = 33, /* Chinese (Mandarin) in simplified characters*/
- langFlemish = 34, /* smRoman script*/
- langIrishGaelic = 35, /* smRoman or modified smRoman/Celtic script (without dot above) */
- langAlbanian = 36, /* smRoman script*/
- langRomanian = 37, /* modified smRoman/Romanian script*/
- langCzech = 38, /* smCentralEuroRoman script*/
- langSlovak = 39, /* smCentralEuroRoman script*/
- langSlovenian = 40, /* modified smRoman/Croatian script*/
- langYiddish = 41, /* smHebrew script*/
- langSerbian = 42, /* smCyrillic script*/
- langMacedonian = 43, /* smCyrillic script*/
- langBulgarian = 44, /* smCyrillic script*/
- langUkrainian = 45, /* modified smCyrillic/Ukrainian script*/
- langByelorussian = 46, /* smCyrillic script*/
- langBelorussian = 46 /* Synonym for langByelorussian */
-};
-
-enum {
- langUzbek = 47, /* Cyrillic script*/
- langKazakh = 48, /* Cyrillic script*/
- langAzerbaijani = 49, /* Azerbaijani in Cyrillic script*/
- langAzerbaijanAr = 50, /* Azerbaijani in Arabic script*/
- langArmenian = 51, /* smArmenian script*/
- langGeorgian = 52, /* smGeorgian script*/
- langMoldavian = 53, /* smCyrillic script*/
- langKirghiz = 54, /* Cyrillic script*/
- langTajiki = 55, /* Cyrillic script*/
- langTurkmen = 56, /* Cyrillic script*/
- langMongolian = 57, /* Mongolian in smMongolian script*/
- langMongolianCyr = 58, /* Mongolian in Cyrillic script*/
- langPashto = 59, /* Arabic script*/
- langKurdish = 60, /* smArabic script*/
- langKashmiri = 61, /* Arabic script*/
- langSindhi = 62, /* Arabic script*/
- langTibetan = 63, /* smTibetan script*/
- langNepali = 64, /* smDevanagari script*/
- langSanskrit = 65, /* smDevanagari script*/
- langMarathi = 66, /* smDevanagari script*/
- langBengali = 67, /* smBengali script*/
- langAssamese = 68, /* smBengali script*/
- langGujarati = 69, /* smGujarati script*/
- langPunjabi = 70 /* smGurmukhi script*/
-};
-
-enum {
- langOriya = 71, /* smOriya script*/
- langMalayalam = 72, /* smMalayalam script*/
- langKannada = 73, /* smKannada script*/
- langTamil = 74, /* smTamil script*/
- langTelugu = 75, /* smTelugu script*/
- langSinhalese = 76, /* smSinhalese script*/
- langBurmese = 77, /* smBurmese script*/
- langKhmer = 78, /* smKhmer script*/
- langLao = 79, /* smLao script*/
- langVietnamese = 80, /* smVietnamese script*/
- langIndonesian = 81, /* smRoman script*/
- langTagalog = 82, /* Roman script*/
- langMalayRoman = 83, /* Malay in smRoman script*/
- langMalayArabic = 84, /* Malay in Arabic script*/
- langAmharic = 85, /* smEthiopic script*/
- langTigrinya = 86, /* smEthiopic script*/
- langOromo = 87, /* smEthiopic script*/
- langSomali = 88, /* smRoman script*/
- langSwahili = 89, /* smRoman script*/
- langKinyarwanda = 90, /* smRoman script*/
- langRuanda = 90, /* synonym for langKinyarwanda*/
- langRundi = 91, /* smRoman script*/
- langNyanja = 92, /* smRoman script*/
- langChewa = 92, /* synonym for langNyanja*/
- langMalagasy = 93, /* smRoman script*/
- langEsperanto = 94 /* Roman script*/
-};
-
-enum {
- langWelsh = 128, /* modified smRoman/Celtic script*/
- langBasque = 129, /* smRoman script*/
- langCatalan = 130, /* smRoman script*/
- langLatin = 131, /* smRoman script*/
- langQuechua = 132, /* smRoman script*/
- langGuarani = 133, /* smRoman script*/
- langAymara = 134, /* smRoman script*/
- langTatar = 135, /* Cyrillic script*/
- langUighur = 136, /* Arabic script*/
- langDzongkha = 137, /* (lang of Bhutan) smTibetan script*/
- langJavaneseRom = 138, /* Javanese in smRoman script*/
- langSundaneseRom = 139, /* Sundanese in smRoman script*/
- langGalician = 140, /* smRoman script*/
- langAfrikaans = 141 /* smRoman script */
-};
-
-enum {
- langBreton = 142, /* smRoman or modified smRoman/Celtic script */
- langInuktitut = 143, /* Inuit script using smEthiopic script code */
- langScottishGaelic = 144, /* smRoman or modified smRoman/Celtic script */
- langManxGaelic = 145, /* smRoman or modified smRoman/Celtic script */
- langIrishGaelicScript = 146, /* modified smRoman/Gaelic script (using dot above) */
- langTongan = 147, /* smRoman script */
- langGreekAncient = 148, /* Classical Greek, polytonic orthography */
- langGreenlandic = 149, /* smRoman script */
- langAzerbaijanRoman = 150, /* Azerbaijani in Roman script */
- langNynorsk = 151 /* Norwegian Nyorsk in smRoman*/
-};
-
-enum {
- langUnspecified = 32767 /* Special code for use in resources (such as 'itlm') */
-};
-
-/*
- Obsolete language code names (kept for backward compatibility):
- Misspelled, ambiguous, misleading, considered pejorative, archaic, etc.
-*/
-enum {
- langPortugese = 8, /* Use langPortuguese*/
- langMalta = 16, /* Use langMaltese*/
- langYugoslavian = 18, /* (use langCroatian, langSerbian, etc.)*/
- langChinese = 19, /* (use langTradChinese or langSimpChinese)*/
- langLettish = 28, /* Use langLatvian */
- langLapponian = 29, /* Use langSami*/
- langLappish = 29, /* Use langSami*/
- langSaamisk = 29, /* Use langSami */
- langFaeroese = 30, /* Use langFaroese */
- langIrish = 35, /* Use langIrishGaelic */
- langGalla = 87, /* Use langOromo */
- langAfricaans = 141, /* Use langAfrikaans */
- langGreekPoly = 148 /* Use langGreekAncient*/
-};
-
-#endif /* __MacScriptExtracts__ */
diff --git a/source/XMPFiles/FormatSupport/PNG_Support.cpp b/source/XMPFiles/FormatSupport/PNG_Support.cpp
deleted file mode 100644
index 988edda..0000000
--- a/source/XMPFiles/FormatSupport/PNG_Support.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-#include "PNG_Support.hpp"
-#include <string.h>
-
-typedef std::basic_string<unsigned char> filebuffer;
-
-namespace CRC
-{
- /* Table of CRCs of all 8-bit messages. */
- static unsigned long crc_table[256];
-
- /* Flag: has the table been computed? Initially false. */
- static int crc_table_computed = 0;
-
- /* Make the table for a fast CRC. */
- static void make_crc_table(void)
- {
- unsigned long c;
- int n, k;
-
- for (n = 0; n < 256; n++)
- {
- c = (unsigned long) n;
- for (k = 0; k < 8; k++)
- {
- if (c & 1)
- {
- c = 0xedb88320L ^ (c >> 1);
- }
- else
- {
- c = c >> 1;
- }
- }
- crc_table[n] = c;
- }
- crc_table_computed = 1;
- }
-
- /* Update a running CRC with the bytes buf[0..len-1]--the CRC
- should be initialized to all 1's, and the transmitted value
- is the 1's complement of the final running CRC (see the
- crc() routine below). */
-
- static unsigned long update_crc(unsigned long crc, unsigned char *buf, int len)
- {
- unsigned long c = crc;
- int n;
-
- if (!crc_table_computed)
- {
- make_crc_table();
- }
-
- for (n = 0; n < len; n++)
- {
- c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
- }
-
- return c;
- }
-
- /* Return the CRC of the bytes buf[0..len-1]. */
- static unsigned long crc(unsigned char *buf, int len)
- {
- return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
- }
-} // namespace CRC
-
-namespace PNG_Support
-{
- enum chunkType {
- // Critical chunks - (shall appear in this order, except PLTE is optional)
- IHDR = 'IHDR',
- PLTE = 'PLTE',
- IDAT = 'IDAT',
- IEND = 'IEND',
- // Ancillary chunks - (need not appear in this order)
- cHRM = 'cHRM',
- gAMA = 'gAMA',
- iCCP = 'iCCP',
- sBIT = 'sBIT',
- sRGB = 'sRGB',
- bKGD = 'bKGD',
- hIST = 'hIST',
- tRNS = 'tRNS',
- pHYs = 'pHYs',
- sPLT = 'sPLT',
- tIME = 'tIME',
- iTXt = 'iTXt',
- tEXt = 'tEXt',
- zTXt = 'zTXt'
-
- };
-
- // =============================================================================================
-
- long OpenPNG ( LFA_FileRef fileRef, ChunkState & inOutChunkState )
- {
- XMP_Uns64 pos = 0;
- long name;
- XMP_Uns32 len;
-
- pos = LFA_Seek ( fileRef, 8, SEEK_SET );
- if (pos != 8) return 0;
-
- // read first and following chunks
- while ( ReadChunk ( fileRef, inOutChunkState, &name, &len, pos) ) {}
-
- return (long)inOutChunkState.chunks.size();
-
- }
-
- // =============================================================================================
-
- bool ReadChunk ( LFA_FileRef fileRef, ChunkState & inOutChunkState, long * chunkType, XMP_Uns32 * chunkLength, XMP_Uns64 & inOutPosition )
- {
- try
- {
- XMP_Uns64 startPosition = inOutPosition;
- long bytesRead;
- char buffer[4];
-
- bytesRead = LFA_Read ( fileRef, buffer, 4 );
- if ( bytesRead != 4 ) return false;
- inOutPosition += 4;
- *chunkLength = GetUns32BE(buffer);
-
- bytesRead = LFA_Read ( fileRef, buffer, 4 );
- if ( bytesRead != 4 ) return false;
- inOutPosition += 4;
- *chunkType = GetUns32BE(buffer);
-
- inOutPosition += *chunkLength;
-
- bytesRead = LFA_Read ( fileRef, buffer, 4 );
- if ( bytesRead != 4 ) return false;
- inOutPosition += 4;
- long crc = GetUns32BE(buffer);
-
- ChunkData newChunk;
-
- newChunk.pos = startPosition;
- newChunk.len = *chunkLength;
- newChunk.type = *chunkType;
-
- // check for XMP in iTXt-chunk
- if (newChunk.type == iTXt)
- {
- CheckiTXtChunkHeader(fileRef, inOutChunkState, newChunk);
- }
-
- inOutChunkState.chunks.push_back ( newChunk );
-
- LFA_Seek ( fileRef, inOutPosition, SEEK_SET );
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return true;
-
- }
-
- // =============================================================================================
-
- bool WriteXMPChunk ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer )
- {
- bool ret = false;
- unsigned long datalen = (4 + ITXT_HEADER_LEN + len);
- unsigned char* buffer = new unsigned char[datalen];
-
- try
- {
- size_t pos = 0;
- memcpy(&buffer[pos], ITXT_CHUNK_TYPE, 4);
- pos += 4;
- memcpy(&buffer[pos], ITXT_HEADER_DATA, ITXT_HEADER_LEN);
- pos += ITXT_HEADER_LEN;
- memcpy(&buffer[pos], inBuffer, len);
-
- unsigned long crc_value = MakeUns32BE( CalculateCRC( buffer, datalen ));
- datalen -= 4;
- unsigned long len_value = MakeUns32BE( datalen );
- datalen += 4;
-
- LFA_Write(fileRef, &len_value, 4);
- LFA_Write(fileRef, buffer, datalen);
- LFA_Write(fileRef, &crc_value, 4);
-
- ret = true;
- }
- catch ( ... ) {}
-
- delete [] buffer;
-
- return ret;
- }
-
- // =============================================================================================
-
- bool CopyChunk ( LFA_FileRef sourceRef, LFA_FileRef destRef, ChunkData& chunk )
- {
- try
- {
- LFA_Seek (sourceRef, chunk.pos, SEEK_SET );
- LFA_Copy (sourceRef, destRef, (chunk.len + 12));
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return true;
- }
-
- // =============================================================================================
-
- unsigned long UpdateChunkCRC( LFA_FileRef fileRef, ChunkData& inOutChunkData )
- {
- unsigned long ret = 0;
- unsigned long datalen = (inOutChunkData.len + 4);
- unsigned char* buffer = new unsigned char[datalen];
-
- try
- {
- LFA_Seek(fileRef, (inOutChunkData.pos + 4), SEEK_SET);
-
- size_t pos = 0;
- long bytesRead = LFA_Read ( fileRef, &buffer[pos], (inOutChunkData.len + 4) );
-
- unsigned long crc = CalculateCRC( buffer, (inOutChunkData.len + 4) );
- unsigned long crc_value = MakeUns32BE( crc );
-
- LFA_Seek(fileRef, (inOutChunkData.pos + 4 + 4 + inOutChunkData.len), SEEK_SET);
- LFA_Write(fileRef, &crc_value, 4);
-
- ret = crc;
- }
- catch ( ... ) {}
-
- delete [] buffer;
-
- return ret;
- }
-
- // =============================================================================================
-
- bool CheckIHDRChunkHeader ( ChunkData& inOutChunkData )
- {
- return (inOutChunkData.type == IHDR);
- }
-
- // =============================================================================================
-
- unsigned long CheckiTXtChunkHeader ( LFA_FileRef fileRef, ChunkState& inOutChunkState, ChunkData& inOutChunkData )
- {
- try
- {
- LFA_Seek(fileRef, (inOutChunkData.pos + 8), SEEK_SET);
-
- char buffer[ITXT_HEADER_LEN];
- long bytesRead = LFA_Read ( fileRef, buffer, ITXT_HEADER_LEN );
-
- if (bytesRead == ITXT_HEADER_LEN)
- {
- if (memcmp(buffer, ITXT_HEADER_DATA, ITXT_HEADER_LEN) == 0)
- {
- // return length of XMP
- if (inOutChunkData.len > ITXT_HEADER_LEN)
- {
- inOutChunkState.xmpPos = inOutChunkData.pos + 8 + ITXT_HEADER_LEN;
- inOutChunkState.xmpLen = inOutChunkData.len - ITXT_HEADER_LEN;
- inOutChunkState.xmpChunk = inOutChunkData;
- inOutChunkData.xmp = true;
-
- return inOutChunkState.xmpLen;
- }
- }
- }
- }
- catch ( ... ) {}
-
- return 0;
- }
-
- bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, char * outBuffer )
- {
- try
- {
- if ( (fileRef == 0) || (outBuffer == 0) ) return false;
-
- LFA_Seek (fileRef, pos, SEEK_SET );
- long bytesRead = LFA_Read ( fileRef, outBuffer, len );
- if ( XMP_Uns32(bytesRead) != len ) return false;
-
- return true;
- }
- catch ( ... ) {}
-
- return false;
- }
-
- bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, const char * inBuffer )
- {
- try
- {
- if ( (fileRef == 0) || (inBuffer == 0) ) return false;
-
- LFA_Seek (fileRef, pos, SEEK_SET );
- LFA_Write( fileRef, inBuffer, len );
-
- return true;
- }
- catch ( ... ) {}
-
- return false;
- }
-
- unsigned long CalculateCRC( unsigned char* inBuffer, XMP_Uns32 len )
- {
- return CRC::update_crc(0xffffffffL, inBuffer, len) ^ 0xffffffffL;
- }
-
-} // namespace PNG_Support
diff --git a/source/XMPFiles/FormatSupport/PNG_Support.hpp b/source/XMPFiles/FormatSupport/PNG_Support.hpp
deleted file mode 100644
index b10f899..0000000
--- a/source/XMPFiles/FormatSupport/PNG_Support.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef __PNG_Support_hpp__
-#define __PNG_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#define PNG_SIGNATURE_LEN 8
-#define PNG_SIGNATURE_DATA "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
-
-#define ITXT_CHUNK_TYPE "iTXt"
-
-#define ITXT_HEADER_LEN 22
-#define ITXT_HEADER_DATA "XML:com.adobe.xmp\0\0\0\0\0"
-
-namespace PNG_Support
-{
- class ChunkData
- {
- public:
- ChunkData() : pos(0), len(0), type(0), xmp(false) {}
- virtual ~ChunkData() {}
-
- // | length | type | data | crc(type+data) |
- // | 4 | 4 | val(length) | 4 |
- //
- XMP_Uns64 pos; // file offset of chunk
- XMP_Uns32 len; // length of chunk data
- long type; // name/type of chunk
- bool xmp; // iTXt-chunk with XMP ?
- };
-
- typedef std::vector<ChunkData> ChunkVector;
- typedef ChunkVector::iterator ChunkIterator;
-
- class ChunkState
- {
- public:
- ChunkState() : xmpPos(0), xmpLen(0) {}
- virtual ~ChunkState() {}
-
- XMP_Uns64 xmpPos;
- XMP_Uns32 xmpLen;
- ChunkData xmpChunk;
- ChunkVector chunks; /* vector of chunks */
- };
-
- long OpenPNG ( LFA_FileRef fileRef, ChunkState& inOutChunkState );
-
- bool ReadChunk ( LFA_FileRef fileRef, ChunkState& inOutChunkState, long* chunkType, XMP_Uns32* chunkLength, XMP_Uns64& inOutPosition );
- bool WriteXMPChunk ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer );
- bool CopyChunk ( LFA_FileRef sourceRef, LFA_FileRef destRef, ChunkData& chunk );
- unsigned long UpdateChunkCRC( LFA_FileRef fileRef, ChunkData& inOutChunkData );
-
- bool CheckIHDRChunkHeader ( ChunkData& inOutChunkData );
- unsigned long CheckiTXtChunkHeader ( LFA_FileRef fileRef, ChunkState& inOutChunkState, ChunkData& inOutChunkData );
-
- bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, char* outBuffer );
- bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, const char* inBuffer );
-
- unsigned long CalculateCRC( unsigned char* inBuffer, XMP_Uns32 len );
-
-} // namespace PNG_Support
-
-#endif // __PNG_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp b/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp
deleted file mode 100644
index 0e57b49..0000000
--- a/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp
+++ /dev/null
@@ -1,568 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "PSIR_Support.hpp"
-#include "EndianUtils.hpp"
-
-#include <string.h>
-
-// =================================================================================================
-/// \file PSIR_FileWriter.cpp
-/// \brief Implementation of the file-based or read-write form of PSIR_Manager.
-// =================================================================================================
-
-// =================================================================================================
-// IsMetadataImgRsrc
-// =================
-
-static inline bool IsMetadataImgRsrc ( XMP_Uns16 id )
-{
- if ( id == 0 ) return false;
-
- int i;
- for ( i = 0; id < kPSIR_MetadataIDs[i]; ++i ) {}
- if ( id == kPSIR_MetadataIDs[i] ) return true;
- return false;
-
-} // IsMetadataImgRsrc
-
-// =================================================================================================
-// PSIR_FileWriter::DeleteExistingInfo
-// ===================================
-//
-// Delete all existing info about image resources.
-
-void PSIR_FileWriter::DeleteExistingInfo()
-{
- XMP_Assert ( ! (this->memParsed && this->fileParsed) );
-
- if ( this->memParsed ) {
- if ( this->ownedContent ) free ( this->memContent );
- } else {
- InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
- for ( ; irPos != irEnd; ++irPos ) irPos->second.changed = true; // Fool the InternalRsrcInfo destructor.
- }
-
- this->imgRsrcs.clear();
-
- this->memContent = 0;
- this->memLength = 0;
-
- this->changed = false;
- this->legacyDeleted = false;
- this->memParsed = false;
- this->fileParsed = false;
- this->ownedContent = false;
-
-} // PSIR_FileWriter::DeleteExistingInfo
-
-// =================================================================================================
-// PSIR_FileWriter::~PSIR_FileWriter
-// =================================
-
-PSIR_FileWriter::~PSIR_FileWriter()
-{
- XMP_Assert ( ! (this->memParsed && this->fileParsed) );
-
- if ( this->ownedContent ) {
- XMP_Assert ( this->memContent != 0 );
- free ( this->memContent );
- }
-
-} // PSIR_FileWriter::~PSIR_FileWriter
-
-// =================================================================================================
-// PSIR_FileWriter::GetImgRsrc
-// ===========================
-
-bool PSIR_FileWriter::GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const
-{
- InternalRsrcMap::const_iterator rsrcPos = this->imgRsrcs.find ( id );
- if ( rsrcPos == this->imgRsrcs.end() ) return false;
-
- const InternalRsrcInfo & rsrcInfo = rsrcPos->second;
-
- if ( info != 0 ) {
- info->id = rsrcInfo.id;
- info->dataLen = rsrcInfo.dataLen;
- info->dataPtr = rsrcInfo.dataPtr;
- info->origOffset = rsrcInfo.origOffset;
- }
-
- return true;
-
-} // PSIR_FileWriter::GetImgRsrc
-
-// =================================================================================================
-// PSIR_FileWriter::SetImgRsrc
-// ===========================
-
-void PSIR_FileWriter::SetImgRsrc ( XMP_Uns16 id, const void* clientPtr, XMP_Uns32 length )
-{
- InternalRsrcInfo* rsrcPtr = 0;
- InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
-
- if ( rsrcPos == this->imgRsrcs.end() ) {
-
- // This resource is not yet in the map, create the map entry.
- InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, length, this->fileParsed ) );
- rsrcPos = this->imgRsrcs.insert ( rsrcPos, mapValue );
- rsrcPtr = &rsrcPos->second;
-
- } else {
-
- rsrcPtr = &rsrcPos->second;
-
- // The resource already exists, make sure the value is actually changing.
- if ( (length == rsrcPtr->dataLen) &&
- (memcmp ( rsrcPtr->dataPtr, clientPtr, length ) == 0) ) {
- return;
- }
-
- rsrcPtr->FreeData(); // Release any existing data allocation.
- rsrcPtr->dataLen = length; // And this might be changing.
-
- }
-
- rsrcPtr->changed = true;
- rsrcPtr->dataPtr = malloc ( length );
- if ( rsrcPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( rsrcPtr->dataPtr, clientPtr, length ); // AUDIT: Safe, malloc'ed length bytes above.
-
- this->changed = true;
-
-} // PSIR_FileWriter::SetImgRsrc
-
-// =================================================================================================
-// PSIR_FileWriter::DeleteImgRsrc
-// ==============================
-
-void PSIR_FileWriter::DeleteImgRsrc ( XMP_Uns16 id )
-{
- InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
- if ( rsrcPos == this->imgRsrcs.end() ) return; // Nothing to delete.
-
- this->imgRsrcs.erase ( id );
- this->changed = true;
- if ( id != kPSIR_XMP ) this->legacyDeleted = true;
-
-} // PSIR_FileWriter::DeleteImgRsrc
-
-// =================================================================================================
-// PSIR_FileWriter::IsLegacyChanged
-// ================================
-
-bool PSIR_FileWriter::IsLegacyChanged()
-{
-
- if ( ! this->changed ) return false;
- if ( this->legacyDeleted ) return true;
-
- InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
-
- for ( ; irPos != irEnd; ++irPos ) {
- const InternalRsrcInfo & rsrcInfo = irPos->second;
- if ( rsrcInfo.changed && (rsrcInfo.id != kPSIR_XMP) ) return true;
- }
-
- return false; // Can get here if the XMP is the only thing changed.
-
-} // PSIR_FileWriter::IsLegacyChanged
-
-// =================================================================================================
-// PSIR_FileWriter::ParseMemoryResources
-// =====================================
-
-void PSIR_FileWriter::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
-{
- this->DeleteExistingInfo();
- this->memParsed = true;
- if ( length == 0 ) return;
-
- // Allocate space for the full in-memory data and copy it.
-
- if ( ! copyData ) {
- this->memContent = (XMP_Uns8*) data;
- XMP_Assert ( ! this->ownedContent );
- } else {
- if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
- this->memContent = (XMP_Uns8*) malloc ( length );
- if ( this->memContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( this->memContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
- this->ownedContent = true;
- }
- this->memLength = length;
-
- // Capture the info for all of the resources.
-
- XMP_Uns8* psirPtr = this->memContent;
- XMP_Uns8* psirEnd = psirPtr + length;
- XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;
-
- while ( psirPtr <= psirLimit ) {
-
- XMP_Uns8* origin = psirPtr; // The beginning of this resource.
- XMP_Uns32 type = GetUns32BE(psirPtr);
- XMP_Uns16 id = GetUns16BE(psirPtr+4);
- psirPtr += 6; // Advance to the resource name.
-
- XMP_Uns8* namePtr = psirPtr;
- XMP_Uns16 nameLen = namePtr[0]; // ! The length for the Pascal string, w/ room for "+2".
- psirPtr += ((nameLen + 2) & 0xFFFE); // ! Round up to an even offset. Yes, +2!
-
- if ( psirPtr > psirEnd-4 ) break; // Bad image resource. Throw instead?
-
- XMP_Uns32 dataLen = GetUns32BE(psirPtr);
- psirPtr += 4; // Advance to the resource data.
-
- XMP_Uns32 dataOffset = (XMP_Uns32) ( psirPtr - this->memContent );
- XMP_Uns8* nextRsrc = psirPtr + ((dataLen + 1) & 0xFFFFFFFEUL); // ! Round up to an even offset.
-
- if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break; // Bad image resource. Throw instead?
-
- if ( type == k8BIM ) {
- InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, dataLen, kIsMemoryBased ) );
- InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.insert ( this->imgRsrcs.end(), mapValue );
- InternalRsrcInfo* rsrcPtr = &rsrcPos->second;
- rsrcPtr->dataPtr = psirPtr;
- rsrcPtr->origOffset = dataOffset;
- if ( nameLen != 0 ) rsrcPtr->rsrcName = namePtr;
- } else {
- XMP_Uns32 rsrcOffset = XMP_Uns32( origin - this->memContent );
- XMP_Uns32 rsrcLength = XMP_Uns32( nextRsrc - origin ); // Includes trailing pad.
- XMP_Assert ( (rsrcLength & 1) == 0 );
- this->otherRsrcs.push_back ( OtherRsrcInfo ( rsrcOffset, rsrcLength ) );
- }
-
- psirPtr = nextRsrc;
-
- }
-
-} // PSIR_FileWriter::ParseMemoryResources
-
-// =================================================================================================
-// PSIR_FileWriter::ParseFileResources
-// ===================================
-
-void PSIR_FileWriter::ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length )
-{
- bool ok;
-
- this->DeleteExistingInfo();
- this->fileParsed = true;
- if ( length == 0 ) return;
-
- // Parse the image resource block.
-
- IOBuffer ioBuf;
- ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_CUR );
-
- XMP_Int64 psirOrigin = ioBuf.filePos; // Need this to determine the resource data offsets.
- XMP_Int64 fileEnd = ioBuf.filePos + length;
-
- std::string rsrcPName;
-
- while ( (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)) < fileEnd ) {
-
- ok = CheckFileSpace ( fileRef, &ioBuf, 12 ); // The minimal image resource takes 12 bytes.
- if ( ! ok ) break; // Bad image resource. Throw instead?
-
- XMP_Int64 thisRsrcPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);
-
- XMP_Uns32 type = GetUns32BE(ioBuf.ptr);
- XMP_Uns16 id = GetUns16BE(ioBuf.ptr+4);
- ioBuf.ptr += 6; // Advance to the resource name.
-
- XMP_Uns16 nameLen = ioBuf.ptr[0]; // ! The length for the Pascal string.
- XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE; // ! Round up to an even total. Yes, +2!
- ok = CheckFileSpace ( fileRef, &ioBuf, paddedLen+4 ); // Get the name text and the data length.
- if ( ! ok ) break; // Bad image resource. Throw instead?
-
- if ( nameLen > 0 ) rsrcPName.assign ( (char*)(ioBuf.ptr), paddedLen ); // ! Include the length byte and pad.
-
- ioBuf.ptr += paddedLen; // Move to the data length.
- XMP_Uns32 dataLen = GetUns32BE(ioBuf.ptr);
- XMP_Uns32 dataTotal = ((dataLen + 1) & 0xFFFFFFFEUL); // Round up to an even total.
- ioBuf.ptr += 4; // Advance to the resource data.
-
- XMP_Int64 thisDataPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);
- XMP_Int64 nextRsrcPos = thisDataPos + dataTotal;
-
- if ( type != k8BIM ) {
- XMP_Uns32 fullRsrcLen = (XMP_Uns32) (nextRsrcPos - thisRsrcPos);
- this->otherRsrcs.push_back ( OtherRsrcInfo ( (XMP_Uns32)thisRsrcPos, fullRsrcLen ) );
- MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
- continue;
- }
-
- InternalRsrcMap::value_type mapValue ( id, InternalRsrcInfo ( id, dataLen, kIsFileBased ) );
- InternalRsrcMap::iterator newRsrc = this->imgRsrcs.insert ( this->imgRsrcs.end(), mapValue );
- InternalRsrcInfo* rsrcPtr = &newRsrc->second;
-
- rsrcPtr->origOffset = (XMP_Uns32)thisDataPos;
-
- if ( nameLen > 0 ) {
- rsrcPtr->rsrcName = (XMP_Uns8*) malloc ( paddedLen );
- if ( rsrcPtr->rsrcName == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( (void*)rsrcPtr->rsrcName, rsrcPName.c_str(), paddedLen ); // AUDIT: Safe, allocated enough bytes above.
- }
-
- if ( ! IsMetadataImgRsrc ( id ) ) {
- MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
- continue;
- }
-
- rsrcPtr->dataPtr = malloc ( dataLen ); // ! Allocate after the IsMetadataImgRsrc check.
- if ( rsrcPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
-
- if ( dataTotal <= kIOBufferSize ) {
- // The image resource data fits within the I/O buffer.
- ok = CheckFileSpace ( fileRef, &ioBuf, dataTotal );
- if ( ! ok ) break; // Bad image resource. Throw instead?
- memcpy ( (void*)rsrcPtr->dataPtr, ioBuf.ptr, dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
- ioBuf.ptr += dataTotal; // ! Add the rounded length.
- } else {
- // The image resource data is bigger than the I/O buffer.
- LFA_Seek ( fileRef, (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)), SEEK_SET );
- LFA_Read ( fileRef, (void*)rsrcPtr->dataPtr, dataLen );
- FillBuffer ( fileRef, nextRsrcPos, &ioBuf );
- }
-
- }
-
- #if 0
- {
- printf ( "\nPSIR_FileWriter::ParseFileResources, count = %d\n", this->imgRsrcs.size() );
- InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
- for ( ; irPos != irEnd; ++irPos ) {
- InternalRsrcInfo& thisRsrc = irPos->second;
- printf ( " #%d, dataLen %d, origOffset %d (0x%X)%s\n",
- thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
- (thisRsrc.changed ? ", changed" : "") );
- }
- }
- #endif
-
-} // PSIR_FileWriter::ParseFileResources
-
-// =================================================================================================
-// PSIR_FileWriter::UpdateMemoryResources
-// ======================================
-
-XMP_Uns32 PSIR_FileWriter::UpdateMemoryResources ( void** dataPtr )
-{
- if ( this->fileParsed ) XMP_Throw ( "Not memory based", kXMPErr_EnforceFailure );
-
- // Compute the size and allocate the new image resource block.
-
- XMP_Uns32 newLength = 0;
-
- InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
-
- for ( ; irPos != irEnd; ++irPos ) { // Add in the lengths for the 8BIM resources.
- const InternalRsrcInfo & rsrcInfo = irPos->second;
- newLength += 10;
- newLength += ((rsrcInfo.dataLen + 1) & 0xFFFFFFFEUL);
- if ( rsrcInfo.rsrcName == 0 ) {
- newLength += 2;
- } else {
- XMP_Uns32 nameLen = rsrcInfo.rsrcName[0];
- newLength += ((nameLen + 2) & 0xFFFFFFFEUL); // ! Yes, +2.
- }
- }
-
- for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) { // Add in the non-8BIM resources.
- newLength += this->otherRsrcs[i].rsrcLength;
- }
-
- XMP_Uns8* newContent = (XMP_Uns8*) malloc ( newLength );
- if ( newContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
-
- // Fill in the new image resource block.
-
- XMP_Uns8* rsrcPtr = newContent;
-
- for ( irPos = this->imgRsrcs.begin(); irPos != irEnd; ++irPos ) { // Do the 8BIM resources.
-
- const InternalRsrcInfo & rsrcInfo = irPos->second;
-
- PutUns32BE ( k8BIM, rsrcPtr );
- rsrcPtr += 4;
- PutUns16BE ( rsrcInfo.id, rsrcPtr );
- rsrcPtr += 2;
-
- if ( rsrcInfo.rsrcName == 0 ) {
- PutUns16BE ( 0, rsrcPtr );
- rsrcPtr += 2;
- } else {
- XMP_Uns32 nameLen = rsrcInfo.rsrcName[0];
- if ( (nameLen+1) > (newLength - (rsrcPtr - newContent)) ) {
- XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
- }
- memcpy ( rsrcPtr, rsrcInfo.rsrcName, nameLen+1 ); // AUDIT: Protected by the above check.
- rsrcPtr += nameLen+1;
- if ( (nameLen & 1) == 0 ) {
- *rsrcPtr = 0;
- ++rsrcPtr;
- }
- }
-
- PutUns32BE ( rsrcInfo.dataLen, rsrcPtr );
- rsrcPtr += 4;
- if ( rsrcInfo.dataLen > (newLength - (rsrcPtr - newContent)) ) {
- XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
- }
- memcpy ( rsrcPtr, rsrcInfo.dataPtr, rsrcInfo.dataLen ); // AUDIT: Protected by the above check.
- rsrcPtr += rsrcInfo.dataLen;
- if ( (rsrcInfo.dataLen & 1) != 0 ) { // Pad to an even length if necessary.
- *rsrcPtr = 0;
- ++rsrcPtr;
- }
-
- }
-
- for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) { // Do the non-8BIM resources.
- XMP_Uns8* srcPtr = this->memContent + this->otherRsrcs[i].rsrcOffset;
- XMP_Uns32 srcLen = this->otherRsrcs[i].rsrcLength;
- if ( srcLen > (newLength - (rsrcPtr - newContent)) ) {
- XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
- }
- memcpy ( rsrcPtr, srcPtr, srcLen ); // AUDIT: Protected by the above check.
- rsrcPtr += srcLen; // No need to pad, included in the original resource length.
- }
-
- XMP_Assert ( rsrcPtr == (newContent + newLength) );
-
- // Parse the rebuilt image resource block. This is the easiest way to reconstruct the map.
-
- this->ParseMemoryResources ( newContent, newLength, false );
- this->ownedContent = (newLength > 0); // ! We really do own the new content, if not empty.
-
- if ( dataPtr != 0 ) *dataPtr = newContent;
- return newLength;
-
-} // PSIR_FileWriter::UpdateMemoryResources
-
-// =================================================================================================
-// PSIR_FileWriter::UpdateFileResources
-// ====================================
-
-XMP_Uns32 PSIR_FileWriter::UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
- IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg )
-{
- IgnoreParam(ioBuf);
- const XMP_Uns32 zero32 = 0;
-
- const bool checkAbort = (abortProc != 0);
-
- struct RsrcHeader {
- XMP_Uns32 type;
- XMP_Uns16 id;
- };
- XMP_Assert ( (offsetof(RsrcHeader,type) == 0) && (offsetof(RsrcHeader,id) == 4) );
-
- if ( this->memParsed ) XMP_Throw ( "Not file based", kXMPErr_EnforceFailure );
-
- XMP_Int64 destLenOffset = LFA_Seek ( destRef, 0, SEEK_CUR );
- XMP_Uns32 destLength = 0;
-
- LFA_Write ( destRef, &destLength, 4 ); // Write a placeholder for the new PSIR section length.
-
- #if 0
- {
- printf ( "\nPSIR_FileWriter::UpdateFileResources, count = %d\n", this->imgRsrcs.size() );
- InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
- for ( ; irPos != irEnd; ++irPos ) {
- InternalRsrcInfo& thisRsrc = irPos->second;
- printf ( " #%d, dataLen %d, origOffset %d (0x%X)%s\n",
- thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
- (thisRsrc.changed ? ", changed" : "") );
- }
- }
- #endif
-
- // First write all of the '8BIM' resources from the map. Use the internal data if present, else
- // copy the data from the file.
-
- RsrcHeader outHeader;
- outHeader.type = MakeUns32BE ( k8BIM );
-
- InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.begin();
- InternalRsrcMap::iterator rsrcEnd = this->imgRsrcs.end();
-
- // printf ( "\nPSIR_FileWriter::UpdateFileResources - 8BIM resources\n" );
- for ( ; rsrcPos != rsrcEnd; ++rsrcPos ) {
-
- InternalRsrcInfo& currRsrc = rsrcPos->second;
-
- outHeader.id = MakeUns16BE ( currRsrc.id );
- LFA_Write ( destRef, &outHeader, 6 );
- destLength += 6;
-
- if ( currRsrc.rsrcName == 0 ) {
- LFA_Write ( destRef, &zero32, 2 );
- destLength += 2;
- } else {
- XMP_Assert ( currRsrc.rsrcName[0] != 0 );
- XMP_Uns16 nameLen = currRsrc.rsrcName[0]; // ! Include room for +1.
- XMP_Uns16 paddedLen = (nameLen + 2) & 0xFFFE; // ! Round up to an even total. Yes, +2!
- LFA_Write ( destRef, currRsrc.rsrcName, paddedLen );
- destLength += paddedLen;
- }
-
- XMP_Uns32 dataLen = MakeUns32BE ( currRsrc.dataLen );
- LFA_Write ( destRef, &dataLen, 4 );
- // printf ( " #%d, offset %d (0x%X), dataLen %d\n", currRsrc.id, destLength, destLength, currRsrc.dataLen );
-
- if ( currRsrc.dataPtr != 0 ) {
- LFA_Write ( destRef, currRsrc.dataPtr, currRsrc.dataLen );
- } else {
- LFA_Seek ( sourceRef, currRsrc.origOffset, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, currRsrc.dataLen );
- }
-
- destLength += 4 + currRsrc.dataLen;
-
- if ( (currRsrc.dataLen & 1) != 0 ) {
- LFA_Write ( destRef, &zero32, 1 ); // ! Pad the data to an even length.
- ++destLength;
- }
-
- }
-
- // Now write all of the non-8BIM resources. Copy the entire resource chunk from the source file.
-
- // printf ( "\nPSIR_FileWriter::UpdateFileResources - other resources\n" );
- for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) {
- // printf ( " offset %d (0x%X), length %d",
- // this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcLength );
- LFA_Seek ( sourceRef, this->otherRsrcs[i].rsrcOffset, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, this->otherRsrcs[i].rsrcLength );
- destLength += this->otherRsrcs[i].rsrcLength; // Alignment padding is already included.
- }
-
- // Write the final PSIR section length, seek back to the end of the file, return the length.
-
- // printf ( "\nPSIR_FileWriter::UpdateFileResources - final length %d (0x%X)\n", destLength, destLength );
- LFA_Seek ( destRef, destLenOffset, SEEK_SET );
- XMP_Uns32 outLen = MakeUns32BE ( destLength );
- LFA_Write ( destRef, &outLen, 4 );
- LFA_Seek ( destRef, 0, SEEK_END );
-
- // *** Not rebuilding the internal map - turns out we never want it, why pay for the I/O.
- // *** Should probably add an option for all of these cases, memory and file based.
-
- return destLength;
-
-} // PSIR_FileWriter::UpdateFileResources
diff --git a/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp b/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp
deleted file mode 100644
index c372dce..0000000
--- a/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "PSIR_Support.hpp"
-#include "EndianUtils.hpp"
-
-#include <string.h>
-
-// =================================================================================================
-/// \file PSIR_MemoryReader.cpp
-/// \brief Implementation of the memory-based read-only form of PSIR_Manager.
-// =================================================================================================
-
-// =================================================================================================
-// PSIR_MemoryReader::GetImgRsrc
-// =============================
-
-bool PSIR_MemoryReader::GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const
-{
- ImgRsrcMap::const_iterator rsrcPos = this->imgRsrcs.find ( id );
- if ( rsrcPos == this->imgRsrcs.end() ) return false;
-
- if ( info != 0 ) *info = rsrcPos->second;
- return true;
-
-} // PSIR_MemoryReader::GetImgRsrc
-
-// =================================================================================================
-// PSIR_MemoryReader::ParseMemoryResources
-// =======================================
-
-void PSIR_MemoryReader::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
-{
- // Get rid of any existing image resources.
-
- if ( this->ownedContent ) free ( this->psirContent );
- this->ownedContent = false;
- this->psirContent = 0;
- this->psirLength = 0;
- this->imgRsrcs.clear();
-
- if ( length == 0 ) return;
-
- // Allocate space for the full in-memory data and copy it.
-
- if ( ! copyData ) {
- this->psirContent = (XMP_Uns8*) data;
- XMP_Assert ( ! this->ownedContent );
- } else {
- if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
- this->psirContent = (XMP_Uns8*) malloc(length);
- if ( this->psirContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( this->psirContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
- this->ownedContent = true;
- }
-
- this->psirLength = length;
-
- // Capture the info for all of the resources.
-
- XMP_Uns8* psirPtr = this->psirContent;
- XMP_Uns8* psirEnd = psirPtr + length;
- XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;
-
- while ( psirPtr <= psirLimit ) {
-
- XMP_Uns32 type = GetUns32BE(psirPtr);
- XMP_Uns16 id = GetUns16BE(psirPtr+4);
- psirPtr += 6; // Advance to the resource name.
-
- XMP_Uns16 nameLen = psirPtr[0]; // ! The length for the Pascal string, w/ room for "+2".
- psirPtr += ((nameLen + 2) & 0xFFFE); // ! Round up to an even offset. Yes, +2!
-
- if ( psirPtr > psirEnd-4 ) break; // Bad image resource. Throw instead?
-
- XMP_Uns32 dataLen = GetUns32BE(psirPtr);
- psirPtr += 4; // Advance to the resource data.
- XMP_Uns32 psirOffset = (XMP_Uns32) (psirPtr - this->psirContent);
-
- if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break; // Bad image resource. Throw instead?
-
- if ( type == k8BIM ) { // For read-only usage we ignore everything other than '8BIM' resources.
- ImgRsrcInfo info ( id, dataLen, psirPtr, psirOffset );
- this->imgRsrcs[id] = info;
- }
-
- psirPtr += ((dataLen + 1) & 0xFFFFFFFEUL); // ! Round up to an even offset.
-
- }
-
-} // PSIR_MemoryReader::ParseMemoryResources
diff --git a/source/XMPFiles/FormatSupport/PSIR_Support.hpp b/source/XMPFiles/FormatSupport/PSIR_Support.hpp
deleted file mode 100644
index 8b5c507..0000000
--- a/source/XMPFiles/FormatSupport/PSIR_Support.hpp
+++ /dev/null
@@ -1,318 +0,0 @@
-#ifndef __PSIR_Support_hpp__
-#define __PSIR_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <map>
-
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "EndianUtils.hpp"
-
-// =================================================================================================
-/// \file PSIR_Support.hpp
-/// \brief XMPFiles support for Photoshop image resources.
-///
-/// This header provides Photoshop image resource (PSIR) support specific to the needs of XMPFiles.
-/// This is not intended for general purpose PSIR processing. PSIR_Manager is an abstract base
-/// class with 2 concrete derived classes, PSIR_MemoryReader and PSIR_FileWriter.
-///
-/// PSIR_MemoryReader provides read-only support for PSIR streams that are small enough to be kept
-/// entirely in memory. This allows optimizations to reduce heap usage and processing code. It is
-/// sufficient for browsing access to the image resources (mainly the IPTC) in JPEG files. Think of
-/// PSIR_MemoryReader as "memory-based AND read-only".
-///
-/// PSIR_FileWriter is for cases where updates are needed or the PSIR stream is too large to be kept
-/// entirely in memory. Think of PSIR_FileWriter as "file-based OR read-write".
-///
-/// The needs of XMPFiles are well defined metadata access. Only a few image resources are handled.
-/// This is the case for all of the derived classes, even though the memory based ones happen to
-/// have all of the image resources in memory. Being "handled" means being in the image resource
-/// map used by GetImgRsrc. The handled image resources are:
-/// \li 1028 - IPTC
-/// \li 1034 - Copyrighted flag
-/// \li 1035 - Copyright information URL
-/// \li 1058 - Exif metadata
-/// \li 1060 - XMP
-/// \li 1061 - IPTC digest
-///
-/// \note These classes are for use only when directly compiled and linked. They should not be
-/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
-// =================================================================================================
-
-
-// These aren't inside PSIR_Manager because the static array can't be initialized there.
-
-enum {
- k8BIM = 0x3842494DUL, // The 4 ASCII characters '8BIM'.
- kMinImgRsrcSize = 4+2+2+4 // The minimum size for an image resource.
-};
-
-enum {
- kPSIR_IPTC = 1028,
- kPSIR_CopyrightFlag = 1034,
- kPSIR_CopyrightURL = 1035,
- kPSIR_Exif = 1058,
- kPSIR_XMP = 1060,
- kPSIR_IPTCDigest = 1061
-};
-
-enum { kPSIR_MetadataCount = 6 };
-static const XMP_Uns16 kPSIR_MetadataIDs[] = // ! Must be in descending order with 0 sentinel.
- { kPSIR_IPTCDigest, kPSIR_XMP, kPSIR_Exif, kPSIR_CopyrightURL, kPSIR_CopyrightFlag, kPSIR_IPTC, 0 };
-
-// =================================================================================================
-// =================================================================================================
-
-// NOTE: Although Photoshop image resources have a type and ID, for metadatya we only care about
-// those of type "8BIM". Resources of other types are preserved in files, but can't be individually
-// accessed through the PSIR_Manager API.
-
-// =================================================================================================
-// PSIR_Manager
-// ============
-
-class PSIR_Manager { // The abstract base class.
-public:
-
- // ---------------------------------------------------------------------------------------------
- // Types and constants
-
- struct ImgRsrcInfo {
- XMP_Uns16 id;
- XMP_Uns32 dataLen;
- const void* dataPtr; // ! The data is read-only!
- XMP_Uns32 origOffset; // The offset (at parse time) of the resource data.
- ImgRsrcInfo() : id(0), dataLen(0), dataPtr(0), origOffset(0) {};
- ImgRsrcInfo ( XMP_Uns16 _id, XMP_Uns32 _dataLen, void* _dataPtr, XMP_Uns32 _origOffset )
- : id(_id), dataLen(_dataLen), dataPtr(_dataPtr), origOffset(_origOffset) {};
- };
-
- // The origOffset is the absolute file offset for file parses, the memory block offset for
- // memory parses. It is the offset of the resource data portion, not the overall resource.
-
- // ---------------------------------------------------------------------------------------------
- // Get the information about a "handled" image resource. Returns false if the image resource is
- // not handled, even if it was present in the parsed input.
-
- virtual bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Set the value for an image resource. It can be any resource, even one not originally handled.
-
- virtual void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length ) = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Delete an image resource. Does nothing if the image resource does not exist.
-
- virtual void DeleteImgRsrc ( XMP_Uns16 id ) = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Determine if the image resources are changed.
-
- virtual bool IsChanged() = 0;
- virtual bool IsLegacyChanged() = 0;
-
- // ---------------------------------------------------------------------------------------------
-
- virtual void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true ) = 0;
- virtual void ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length ) = 0;
-
- // ---------------------------------------------------------------------------------------------
- // Update the image resources to reflect the changed values. Both \c UpdateMemoryResources and
- // \c UpdateFileResources return the new size of the image resource block. The dataPtr returned
- // by \c UpdateMemoryResources must be treated as read only. It exists until the PSIR_Manager
- // destructor is called. UpdateMemoryResources can be used on a read-only instance to get the
- // raw data block info.
-
- virtual XMP_Uns32 UpdateMemoryResources ( void** dataPtr ) = 0;
- virtual XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
- IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg ) = 0;
-
- // ---------------------------------------------------------------------------------------------
-
- virtual ~PSIR_Manager() {};
-
-protected:
-
- PSIR_Manager() {};
-
-}; // PSIR_Manager
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// PSIR_MemoryReader
-// =================
-
-class PSIR_MemoryReader : public PSIR_Manager { // The leaf class for memory-based read-only access.
-public:
-
- bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const;
-
- void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length ) { NotAppropriate(); };
-
- void DeleteImgRsrc ( XMP_Uns16 id ) { NotAppropriate(); };
-
- bool IsChanged() { return false; };
- bool IsLegacyChanged() { return false; };
-
- void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true );
- void ParseFileResources ( LFA_FileRef file, XMP_Uns32 length ) { NotAppropriate(); };
-
- XMP_Uns32 UpdateMemoryResources ( void** dataPtr ) { if ( dataPtr != 0 ) *dataPtr = psirContent; return psirLength; };
- XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
- IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg ) { NotAppropriate(); return 0; };
-
- PSIR_MemoryReader() : ownedContent(false), psirLength(0), psirContent(0) {};
-
- virtual ~PSIR_MemoryReader() { if ( this->ownedContent ) free ( this->psirContent ); };
-
-private:
-
- // Memory usage notes: PSIR_MemoryReader is for memory-based read-only usage (both apply). There
- // is no need to ever allocate separate blocks of memory, everything is used directly from the
- // PSIR stream.
-
- bool ownedContent;
-
- XMP_Uns32 psirLength;
- XMP_Uns8* psirContent;
-
- typedef std::map<XMP_Uns16,ImgRsrcInfo> ImgRsrcMap;
-
- ImgRsrcMap imgRsrcs;
-
- static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for PSIR_Reader", kXMPErr_InternalFailure ); };
-
-}; // PSIR_MemoryReader
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// PSIR_FileWriter
-// ===============
-
-class PSIR_FileWriter : public PSIR_Manager { // The leaf class for file-based read-write access.
-public:
-
- bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const;
-
- void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length );
-
- void DeleteImgRsrc ( XMP_Uns16 id );
-
- bool IsChanged() { return this->changed; };
-
- bool IsLegacyChanged();
-
- void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true );
- void ParseFileResources ( LFA_FileRef file, XMP_Uns32 length );
-
- XMP_Uns32 UpdateMemoryResources ( void** dataPtr );
- XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
- IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg );
-
- PSIR_FileWriter() : changed(false), legacyDeleted(false), memParsed(false), fileParsed(false),
- ownedContent(false), memLength(0), memContent(0) {};
-
- virtual ~PSIR_FileWriter();
-
- // Memory usage notes: PSIR_FileWriter is for file-based OR read/write usage. For memory-based
- // streams the dataPtr and rsrcName are initially into the stream, they become a separate
- // allocation if changed. For file-based streams they are always a separate allocation.
-
- // ! The working data values are always big endian, no matter where stored. It is the client's
- // ! responsibility to flip them as necessary.
-
- static const bool kIsFileBased = true; // For use in the InternalRsrcInfo constructor.
- static const bool kIsMemoryBased = false;
-
- struct InternalRsrcInfo {
- public:
-
- bool changed;
- bool fileBased;
- XMP_Uns16 id;
- XMP_Uns32 dataLen;
- void* dataPtr; // ! Null if the value is not captured!
- XMP_Uns32 origOffset; // The offset (at parse time) of the resource data.
- XMP_Uns8* rsrcName; // ! A Pascal string, leading length byte, no nul terminator!
-
- inline void FreeData() {
- if ( this->fileBased || this->changed ) {
- if ( this->dataPtr != 0 ) { free ( this->dataPtr ); this->dataPtr = 0; }
- }
- }
-
- inline void FreeName() {
- if ( this->fileBased || this->changed ) {
- if ( this->rsrcName != 0 ) { free ( this->rsrcName ); this->rsrcName = 0; }
- }
- }
-
- InternalRsrcInfo ( XMP_Uns16 _id, XMP_Uns32 _dataLen, bool _fileBased )
- : changed(false), fileBased(_fileBased), id(_id), dataLen(_dataLen), dataPtr(0),
- origOffset(0), rsrcName(0) {};
- ~InternalRsrcInfo() { this->FreeData(); this->FreeName(); };
-
- void operator= ( const InternalRsrcInfo & in )
- {
- // ! Gag! Transfer ownership of the dataPtr and rsrcName!
- this->FreeData();
- memcpy ( this, &in, sizeof(*this) ); // AUDIT: Use of sizeof(InternalRsrcInfo) is safe.
- *((void**)&in.dataPtr) = 0; // The pointer is now owned by "this".
- *((void**)&in.rsrcName) = 0; // The pointer is now owned by "this".
- };
-
- private:
-
- InternalRsrcInfo() // Hidden on purpose, fileBased must be properly set.
- : changed(false), fileBased(false), id(0), dataLen(0), dataPtr(0), origOffset(0), rsrcName(0) {};
-
- };
-
- // The origOffset is the absolute file offset for file parses, the memory block offset for
- // memory parses. It is the offset of the resource data portion, not the overall resource.
-
-private:
-
- bool changed, legacyDeleted;
- bool memParsed, fileParsed;
- bool ownedContent;
-
- XMP_Uns32 memLength;
- XMP_Uns8* memContent;
-
- typedef std::map<XMP_Uns16,InternalRsrcInfo> InternalRsrcMap;
- InternalRsrcMap imgRsrcs;
-
- struct OtherRsrcInfo { // For the resources of types other than "8BIM".
- XMP_Uns32 rsrcOffset; // The offset of the resource origin, the type field.
- XMP_Uns32 rsrcLength; // The full length of the resource, offset to the next resource.
- OtherRsrcInfo() : rsrcOffset(0), rsrcLength(0) {};
- OtherRsrcInfo ( XMP_Uns32 _rsrcOffset, XMP_Uns32 _rsrcLength )
- : rsrcOffset(_rsrcOffset), rsrcLength(_rsrcLength) {};
- };
- std::vector<OtherRsrcInfo> otherRsrcs;
-
- void DeleteExistingInfo();
-
-}; // PSIR_FileWriter
-
-#endif // __PSIR_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/QuickTime_Support.cpp b/source/XMPFiles/FormatSupport/QuickTime_Support.cpp
deleted file mode 100644
index 31091ea..0000000
--- a/source/XMPFiles/FormatSupport/QuickTime_Support.cpp
+++ /dev/null
@@ -1,1148 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h"
-
-#if XMP_MacBuild
- #include "Script.h"
-#else
- #include "MacScriptExtracts.h"
-#endif
-
-#include "QuickTime_Support.hpp"
-
-#include "UnicodeConversions.hpp"
-#include "UnicodeInlines.incl_cpp"
-#include "Reconcile_Impl.hpp"
-
-// =================================================================================================
-
-static const char * kMacRomanUTF8 [128] = { // UTF-8 mappings for MacRoman 80..FF.
- "\xC3\x84", "\xC3\x85", "\xC3\x87", "\xC3\x89", "\xC3\x91", "\xC3\x96", "\xC3\x9C", "\xC3\xA1",
- "\xC3\xA0", "\xC3\xA2", "\xC3\xA4", "\xC3\xA3", "\xC3\xA5", "\xC3\xA7", "\xC3\xA9", "\xC3\xA8",
- "\xC3\xAA", "\xC3\xAB", "\xC3\xAD", "\xC3\xAC", "\xC3\xAE", "\xC3\xAF", "\xC3\xB1", "\xC3\xB3",
- "\xC3\xB2", "\xC3\xB4", "\xC3\xB6", "\xC3\xB5", "\xC3\xBA", "\xC3\xB9", "\xC3\xBB", "\xC3\xBC",
- "\xE2\x80\xA0", "\xC2\xB0", "\xC2\xA2", "\xC2\xA3", "\xC2\xA7", "\xE2\x80\xA2", "\xC2\xB6", "\xC3\x9F",
- "\xC2\xAE", "\xC2\xA9", "\xE2\x84\xA2", "\xC2\xB4", "\xC2\xA8", "\xE2\x89\xA0", "\xC3\x86", "\xC3\x98",
- "\xE2\x88\x9E", "\xC2\xB1", "\xE2\x89\xA4", "\xE2\x89\xA5", "\xC2\xA5", "\xC2\xB5", "\xE2\x88\x82", "\xE2\x88\x91",
- "\xE2\x88\x8F", "\xCF\x80", "\xE2\x88\xAB", "\xC2\xAA", "\xC2\xBA", "\xCE\xA9", "\xC3\xA6", "\xC3\xB8",
- "\xC2\xBF", "\xC2\xA1", "\xC2\xAC", "\xE2\x88\x9A", "\xC6\x92", "\xE2\x89\x88", "\xE2\x88\x86", "\xC2\xAB",
- "\xC2\xBB", "\xE2\x80\xA6", "\xC2\xA0", "\xC3\x80", "\xC3\x83", "\xC3\x95", "\xC5\x92", "\xC5\x93",
- "\xE2\x80\x93", "\xE2\x80\x94", "\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x98", "\xE2\x80\x99", "\xC3\xB7", "\xE2\x97\x8A",
- "\xC3\xBF", "\xC5\xB8", "\xE2\x81\x84", "\xE2\x82\xAC", "\xE2\x80\xB9", "\xE2\x80\xBA", "\xEF\xAC\x81", "\xEF\xAC\x82",
- "\xE2\x80\xA1", "\xC2\xB7", "\xE2\x80\x9A", "\xE2\x80\x9E", "\xE2\x80\xB0", "\xC3\x82", "\xC3\x8A", "\xC3\x81",
- "\xC3\x8B", "\xC3\x88", "\xC3\x8D", "\xC3\x8E", "\xC3\x8F", "\xC3\x8C", "\xC3\x93", "\xC3\x94",
- "\xEF\xA3\xBF", "\xC3\x92", "\xC3\x9A", "\xC3\x9B", "\xC3\x99", "\xC4\xB1", "\xCB\x86", "\xCB\x9C",
- "\xC2\xAF", "\xCB\x98", "\xCB\x99", "\xCB\x9A", "\xC2\xB8", "\xCB\x9D", "\xCB\x9B", "\xCB\x87"
-};
-
-static const XMP_Uns32 kMacRomanCP [128] = { // Unicode codepoints for MacRoman 80..FF.
- 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
- 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
- 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
- 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
- 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
- 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
- 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
- 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
- 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
- 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
- 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
- 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
- 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
- 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
- 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, // ! U+F8FF is private use solid Apple icon.
- 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
-};
-
-// -------------------------------------------------------------------------------------------------
-
-static const XMP_Uns16 kMacLangToScript_0_94 [95] = {
-
- /* langEnglish (0) */ smRoman,
- /* langFrench (1) */ smRoman,
- /* langGerman (2) */ smRoman,
- /* langItalian (3) */ smRoman,
- /* langDutch (4) */ smRoman,
- /* langSwedish (5) */ smRoman,
- /* langSpanish (6) */ smRoman,
- /* langDanish (7) */ smRoman,
- /* langPortuguese (8) */ smRoman,
- /* langNorwegian (9) */ smRoman,
-
- /* langHebrew (10) */ smHebrew,
- /* langJapanese (11) */ smJapanese,
- /* langArabic (12) */ smArabic,
- /* langFinnish (13) */ smRoman,
- /* langGreek (14) */ smRoman,
- /* langIcelandic (15) */ smRoman,
- /* langMaltese (16) */ smRoman,
- /* langTurkish (17) */ smRoman,
- /* langCroatian (18) */ smRoman,
- /* langTradChinese (19) */ smTradChinese,
-
- /* langUrdu (20) */ smArabic,
- /* langHindi (21) */ smDevanagari,
- /* langThai (22) */ smThai,
- /* langKorean (23) */ smKorean,
- /* langLithuanian (24) */ smCentralEuroRoman,
- /* langPolish (25) */ smCentralEuroRoman,
- /* langHungarian (26) */ smCentralEuroRoman,
- /* langEstonian (27) */ smCentralEuroRoman,
- /* langLatvian (28) */ smCentralEuroRoman,
- /* langSami (29) */ kNoMacScript, // ! Not known, missing from Apple comments.
-
- /* langFaroese (30) */ smRoman,
- /* langFarsi (31) */ smArabic,
- /* langRussian (32) */ smCyrillic,
- /* langSimpChinese (33) */ smSimpChinese,
- /* langFlemish (34) */ smRoman,
- /* langIrishGaelic (35) */ smRoman,
- /* langAlbanian (36) */ smRoman,
- /* langRomanian (37) */ smRoman,
- /* langCzech (38) */ smCentralEuroRoman,
- /* langSlovak (39) */ smCentralEuroRoman,
-
- /* langSlovenian (40) */ smRoman,
- /* langYiddish (41) */ smHebrew,
- /* langSerbian (42) */ smCyrillic,
- /* langMacedonian (43) */ smCyrillic,
- /* langBulgarian (44) */ smCyrillic,
- /* langUkrainian (45) */ smCyrillic,
- /* langBelorussian (46) */ smCyrillic,
- /* langUzbek (47) */ smCyrillic,
- /* langKazakh (48) */ smCyrillic,
- /* langAzerbaijani (49) */ smCyrillic,
-
- /* langAzerbaijanAr (50) */ smArabic,
- /* langArmenian (51) */ smArmenian,
- /* langGeorgian (52) */ smGeorgian,
- /* langMoldavian (53) */ smCyrillic,
- /* langKirghiz (54) */ smCyrillic,
- /* langTajiki (55) */ smCyrillic,
- /* langTurkmen (56) */ smCyrillic,
- /* langMongolian (57) */ smMongolian,
- /* langMongolianCyr (58) */ smCyrillic,
- /* langPashto (59) */ smArabic,
-
- /* langKurdish (60) */ smArabic,
- /* langKashmiri (61) */ smArabic,
- /* langSindhi (62) */ smArabic,
- /* langTibetan (63) */ smTibetan,
- /* langNepali (64) */ smDevanagari,
- /* langSanskrit (65) */ smDevanagari,
- /* langMarathi (66) */ smDevanagari,
- /* langBengali (67) */ smBengali,
- /* langAssamese (68) */ smBengali,
- /* langGujarati (69) */ smGujarati,
-
- /* langPunjabi (70) */ smGurmukhi,
- /* langOriya (71) */ smOriya,
- /* langMalayalam (72) */ smMalayalam,
- /* langKannada (73) */ smKannada,
- /* langTamil (74) */ smTamil,
- /* langTelugu (75) */ smTelugu,
- /* langSinhalese (76) */ smSinhalese,
- /* langBurmese (77) */ smBurmese,
- /* langKhmer (78) */ smKhmer,
- /* langLao (79) */ smLao,
-
- /* langVietnamese (80) */ smVietnamese,
- /* langIndonesian (81) */ smRoman,
- /* langTagalog (82) */ smRoman,
- /* langMalayRoman (83) */ smRoman,
- /* langMalayArabic (84) */ smArabic,
- /* langAmharic (85) */ smEthiopic,
- /* langTigrinya (86) */ smEthiopic,
- /* langOromo (87) */ smEthiopic,
- /* langSomali (88) */ smRoman,
- /* langSwahili (89) */ smRoman,
-
- /* langKinyarwanda (90) */ smRoman,
- /* langRundi (91) */ smRoman,
- /* langNyanja (92) */ smRoman,
- /* langMalagasy (93) */ smRoman,
- /* langEsperanto (94) */ smRoman
-
-}; // kMacLangToScript_0_94
-
-static const XMP_Uns16 kMacLangToScript_128_151 [24] = {
-
- /* langWelsh (128) */ smRoman,
- /* langBasque (129) */ smRoman,
-
- /* langCatalan (130) */ smRoman,
- /* langLatin (131) */ smRoman,
- /* langQuechua (132) */ smRoman,
- /* langGuarani (133) */ smRoman,
- /* langAymara (134) */ smRoman,
- /* langTatar (135) */ smCyrillic,
- /* langUighur (136) */ smArabic,
- /* langDzongkha (137) */ smTibetan,
- /* langJavaneseRom (138) */ smRoman,
- /* langSundaneseRom (139) */ smRoman,
-
- /* langGalician (140) */ smRoman,
- /* langAfrikaans (141) */ smRoman,
- /* langBreton (142) */ smRoman,
- /* langInuktitut (143) */ smEthiopic,
- /* langScottishGaelic (144) */ smRoman,
- /* langManxGaelic (145) */ smRoman,
- /* langIrishGaelicScript (146) */ smRoman,
- /* langTongan (147) */ smRoman,
- /* langGreekAncient (148) */ smGreek,
- /* langGreenlandic (149) */ smRoman,
-
- /* langAzerbaijanRoman (150) */ smRoman,
- /* langNynorsk (151) */ smRoman
-
-}; // kMacLangToScript_128_151
-
-// -------------------------------------------------------------------------------------------------
-
-static const char * kMacToXMPLang_0_94 [95] = {
-
- /* langEnglish (0) */ "en",
- /* langFrench (1) */ "fr",
- /* langGerman (2) */ "de",
- /* langItalian (3) */ "it",
- /* langDutch (4) */ "nl",
- /* langSwedish (5) */ "sv",
- /* langSpanish (6) */ "es",
- /* langDanish (7) */ "da",
- /* langPortuguese (8) */ "pt",
- /* langNorwegian (9) */ "no",
-
- /* langHebrew (10) */ "he",
- /* langJapanese (11) */ "ja",
- /* langArabic (12) */ "ar",
- /* langFinnish (13) */ "fi",
- /* langGreek (14) */ "el",
- /* langIcelandic (15) */ "is",
- /* langMaltese (16) */ "mt",
- /* langTurkish (17) */ "tr",
- /* langCroatian (18) */ "hr",
- /* langTradChinese (19) */ "zh",
-
- /* langUrdu (20) */ "ur",
- /* langHindi (21) */ "hi",
- /* langThai (22) */ "th",
- /* langKorean (23) */ "ko",
- /* langLithuanian (24) */ "lt",
- /* langPolish (25) */ "pl",
- /* langHungarian (26) */ "hu",
- /* langEstonian (27) */ "et",
- /* langLatvian (28) */ "lv",
- /* langSami (29) */ "se",
-
- /* langFaroese (30) */ "fo",
- /* langFarsi (31) */ "fa",
- /* langRussian (32) */ "ru",
- /* langSimpChinese (33) */ "zh",
- /* langFlemish (34) */ "nl",
- /* langIrishGaelic (35) */ "ga",
- /* langAlbanian (36) */ "sq",
- /* langRomanian (37) */ "ro",
- /* langCzech (38) */ "cs",
- /* langSlovak (39) */ "sk",
-
- /* langSlovenian (40) */ "sl",
- /* langYiddish (41) */ "yi",
- /* langSerbian (42) */ "sr",
- /* langMacedonian (43) */ "mk",
- /* langBulgarian (44) */ "bg",
- /* langUkrainian (45) */ "uk",
- /* langBelorussian (46) */ "be",
- /* langUzbek (47) */ "uz",
- /* langKazakh (48) */ "kk",
- /* langAzerbaijani (49) */ "az",
-
- /* langAzerbaijanAr (50) */ "az",
- /* langArmenian (51) */ "hy",
- /* langGeorgian (52) */ "ka",
- /* langMoldavian (53) */ "ro",
- /* langKirghiz (54) */ "ky",
- /* langTajiki (55) */ "tg",
- /* langTurkmen (56) */ "tk",
- /* langMongolian (57) */ "mn",
- /* langMongolianCyr (58) */ "mn",
- /* langPashto (59) */ "ps",
-
- /* langKurdish (60) */ "ku",
- /* langKashmiri (61) */ "ks",
- /* langSindhi (62) */ "sd",
- /* langTibetan (63) */ "bo",
- /* langNepali (64) */ "ne",
- /* langSanskrit (65) */ "sa",
- /* langMarathi (66) */ "mr",
- /* langBengali (67) */ "bn",
- /* langAssamese (68) */ "as",
- /* langGujarati (69) */ "gu",
-
- /* langPunjabi (70) */ "pa",
- /* langOriya (71) */ "or",
- /* langMalayalam (72) */ "ml",
- /* langKannada (73) */ "kn",
- /* langTamil (74) */ "ta",
- /* langTelugu (75) */ "te",
- /* langSinhalese (76) */ "si",
- /* langBurmese (77) */ "my",
- /* langKhmer (78) */ "km",
- /* langLao (79) */ "lo",
-
- /* langVietnamese (80) */ "vi",
- /* langIndonesian (81) */ "id",
- /* langTagalog (82) */ "tl",
- /* langMalayRoman (83) */ "ms",
- /* langMalayArabic (84) */ "ms",
- /* langAmharic (85) */ "am",
- /* langTigrinya (86) */ "ti",
- /* langOromo (87) */ "om",
- /* langSomali (88) */ "so",
- /* langSwahili (89) */ "sw",
-
- /* langKinyarwanda (90) */ "rw",
- /* langRundi (91) */ "rn",
- /* langNyanja (92) */ "ny",
- /* langMalagasy (93) */ "mg",
- /* langEsperanto (94) */ "eo"
-
-}; // kMacToXMPLang_0_94
-
-static const char * kMacToXMPLang_128_151 [24] = {
-
- /* langWelsh (128) */ "cy",
- /* langBasque (129) */ "eu",
-
- /* langCatalan (130) */ "ca",
- /* langLatin (131) */ "la",
- /* langQuechua (132) */ "qu",
- /* langGuarani (133) */ "gn",
- /* langAymara (134) */ "ay",
- /* langTatar (135) */ "tt",
- /* langUighur (136) */ "ug",
- /* langDzongkha (137) */ "dz",
- /* langJavaneseRom (138) */ "jv",
- /* langSundaneseRom (139) */ "su",
-
- /* langGalician (140) */ "gl",
- /* langAfrikaans (141) */ "af",
- /* langBreton (142) */ "br",
- /* langInuktitut (143) */ "iu",
- /* langScottishGaelic (144) */ "gd",
- /* langManxGaelic (145) */ "gv",
- /* langIrishGaelicScript (146) */ "ga",
- /* langTongan (147) */ "to",
- /* langGreekAncient (148) */ "", // ! Has no ISO 639-1 2 letter code.
- /* langGreenlandic (149) */ "kl",
-
- /* langAzerbaijanRoman (150) */ "az",
- /* langNynorsk (151) */ "nn"
-
-}; // kMacToXMPLang_128_151
-
-// -------------------------------------------------------------------------------------------------
-
-#if XMP_WinBuild
-
-static UINT kMacScriptToWinCP[34] = {
- /* 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,
- /* smKorean (3) */ 10003,
- /* smArabic (4) */ 10004,
- /* smHebrew (5) */ 10005,
- /* smGreek (6) */ 10006,
- /* smCyrillic (7) */ 10007,
- /* smRSymbol (8) */ 0,
- /* smDevanagari (9) */ 0,
- /* smGurmukhi (10) */ 0,
- /* smGujarati (11) */ 0,
- /* smOriya (12) */ 0,
- /* smBengali (13) */ 0,
- /* smTamil (14) */ 0,
- /* smTelugu (15) */ 0,
- /* smKannada (16) */ 0,
- /* smMalayalam (17) */ 0,
- /* smSinhalese (18) */ 0,
- /* smBurmese (19) */ 0,
- /* smKhmer (20) */ 0,
- /* smThai (21) */ 10021,
- /* smLao (22) */ 0,
- /* smGeorgian (23) */ 0,
- /* smArmenian (24) */ 0,
- /* smSimpChinese (25) */ 10008,
- /* smTibetan (26) */ 0,
- /* smMongolian (27) */ 0,
- /* smEthiopic (28) */ 0,
- /* smGeez (28) */ 0,
- /* smCentralEuroRoman (29) */ 10029,
- /* smVietnamese (30) */ 0,
- /* smExtArabic (31) */ 0,
- /* smUninterp (32) */ 0
-}; // kMacScriptToWinCP
-
-static UINT kMacToWinCP_0_94 [95] = {
-
- /* langEnglish (0) */ 0,
- /* langFrench (1) */ 0,
- /* langGerman (2) */ 0,
- /* langItalian (3) */ 0,
- /* langDutch (4) */ 0,
- /* langSwedish (5) */ 0,
- /* langSpanish (6) */ 0,
- /* langDanish (7) */ 0,
- /* langPortuguese (8) */ 0,
- /* langNorwegian (9) */ 0,
-
- /* langHebrew (10) */ 10005,
- /* langJapanese (11) */ 10001,
- /* langArabic (12) */ 10004,
- /* langFinnish (13) */ 0,
- /* langGreek (14) */ 10006,
- /* langIcelandic (15) */ 10079,
- /* langMaltese (16) */ 0,
- /* langTurkish (17) */ 10081,
- /* langCroatian (18) */ 10082,
- /* langTradChinese (19) */ 10002,
-
- /* langUrdu (20) */ 0,
- /* langHindi (21) */ 0,
- /* langThai (22) */ 10021,
- /* langKorean (23) */ 10003,
- /* langLithuanian (24) */ 0,
- /* langPolish (25) */ 0,
- /* langHungarian (26) */ 0,
- /* langEstonian (27) */ 0,
- /* langLatvian (28) */ 0,
- /* langSami (29) */ 0,
-
- /* langFaroese (30) */ 0,
- /* langFarsi (31) */ 0,
- /* langRussian (32) */ 0,
- /* langSimpChinese (33) */ 10008,
- /* langFlemish (34) */ 0,
- /* langIrishGaelic (35) */ 0,
- /* langAlbanian (36) */ 0,
- /* langRomanian (37) */ 10010,
- /* langCzech (38) */ 0,
- /* langSlovak (39) */ 0,
-
- /* langSlovenian (40) */ 0,
- /* langYiddish (41) */ 0,
- /* langSerbian (42) */ 0,
- /* langMacedonian (43) */ 0,
- /* langBulgarian (44) */ 0,
- /* langUkrainian (45) */ 10017,
- /* langBelorussian (46) */ 0,
- /* langUzbek (47) */ 0,
- /* langKazakh (48) */ 0,
- /* langAzerbaijani (49) */ 0,
-
- /* langAzerbaijanAr (50) */ 0,
- /* langArmenian (51) */ 0,
- /* langGeorgian (52) */ 0,
- /* langMoldavian (53) */ 0,
- /* langKirghiz (54) */ 0,
- /* langTajiki (55) */ 0,
- /* langTurkmen (56) */ 0,
- /* langMongolian (57) */ 0,
- /* langMongolianCyr (58) */ 0,
- /* langPashto (59) */ 0,
-
- /* langKurdish (60) */ 0,
- /* langKashmiri (61) */ 0,
- /* langSindhi (62) */ 0,
- /* langTibetan (63) */ 0,
- /* langNepali (64) */ 0,
- /* langSanskrit (65) */ 0,
- /* langMarathi (66) */ 0,
- /* langBengali (67) */ 0,
- /* langAssamese (68) */ 0,
- /* langGujarati (69) */ 0,
-
- /* langPunjabi (70) */ 0,
- /* langOriya (71) */ 0,
- /* langMalayalam (72) */ 0,
- /* langKannada (73) */ 0,
- /* langTamil (74) */ 0,
- /* langTelugu (75) */ 0,
- /* langSinhalese (76) */ 0,
- /* langBurmese (77) */ 0,
- /* langKhmer (78) */ 0,
- /* langLao (79) */ 0,
-
- /* langVietnamese (80) */ 0,
- /* langIndonesian (81) */ 0,
- /* langTagalog (82) */ 0,
- /* langMalayRoman (83) */ 0,
- /* langMalayArabic (84) */ 0,
- /* langAmharic (85) */ 0,
- /* langTigrinya (86) */ 0,
- /* langOromo (87) */ 0,
- /* langSomali (88) */ 0,
- /* langSwahili (89) */ 0,
-
- /* langKinyarwanda (90) */ 0,
- /* langRundi (91) */ 0,
- /* langNyanja (92) */ 0,
- /* langMalagasy (93) */ 0,
- /* langEsperanto (94) */ 0
-
-}; // kMacToWinCP_0_94
-
-#endif
-
-// =================================================================================================
-// GetMacScript
-// ============
-
-static XMP_Uns16 GetMacScript ( XMP_Uns16 macLang )
-{
- XMP_Uns16 macScript = kNoMacScript;
-
- if ( macLang <= 94 ) {
- macScript = kMacLangToScript_0_94[macLang];
- } else if ( (128 <= macLang) && (macLang <= 151) ) {
- macScript = kMacLangToScript_0_94[macLang-128];
- }
-
- return macScript;
-
-} // GetMacScript
-
-// =================================================================================================
-// GetWinCP
-// ========
-
-#if XMP_WinBuild
-
-static UINT GetWinCP ( XMP_Uns16 macLang )
-{
- UINT winCP = 0;
-
- if ( macLang <= 94 ) winCP = kMacToWinCP_0_94[macLang];
-
- if ( winCP == 0 ) {
- XMP_Uns16 macScript = GetMacScript ( macLang );
- if ( macScript != kNoMacScript ) winCP = kMacScriptToWinCP[macScript];
- }
-
- return winCP;
-
-} // GetWinCP
-
-#endif
-
-// =================================================================================================
-// GetXMPLang
-// ==========
-
-static XMP_StringPtr GetXMPLang ( XMP_Uns16 macLang )
-{
- XMP_StringPtr xmpLang = "";
-
- if ( macLang <= 94 ) {
- xmpLang = kMacToXMPLang_0_94[macLang];
- } else if ( (128 <= macLang) && (macLang <= 151) ) {
- xmpLang = kMacToXMPLang_128_151[macLang-128];
- }
-
- return xmpLang;
-
-} // GetXMPLang
-
-// =================================================================================================
-// GetMacLang
-// ==========
-
-static XMP_Uns16 GetMacLang ( std::string * xmpLang )
-{
- if ( *xmpLang == "" ) return kNoMacLang;
-
- size_t hyphenPos = xmpLang->find ( '-' ); // Make sure the XMP language is "generic".
- if ( hyphenPos != std::string::npos ) xmpLang->erase ( hyphenPos );
-
- for ( XMP_Uns16 i = 0; i <= 94; ++i ) { // Using std::map would be faster.
- if ( *xmpLang == kMacToXMPLang_0_94[i] ) return i;
- }
-
- for ( XMP_Uns16 i = 128; i <= 151; ++i ) { // Using std::map would be faster.
- if ( *xmpLang == kMacToXMPLang_128_151[i-128] ) return i;
- }
-
- return kNoMacLang;
-
-} // GetMacLang
-
-// =================================================================================================
-// MacRomanToUTF8
-// ==============
-
-static void MacRomanToUTF8 ( const std::string & macRoman, std::string * utf8 )
-{
- utf8->erase();
-
- for ( XMP_Uns8* chPtr = (XMP_Uns8*)macRoman.c_str(); *chPtr != 0; ++chPtr ) { // ! Don't trust that char is unsigned.
- if ( *chPtr < 0x80 ) {
- (*utf8) += (char)*chPtr;
- } else {
- (*utf8) += kMacRomanUTF8[(*chPtr)-0x80];
- }
- }
-
-} // MacRomanToUTF8
-
-// =================================================================================================
-// UTF8ToMacRoman
-// ==============
-
-static void UTF8ToMacRoman ( const std::string & utf8, std::string * macRoman )
-{
- macRoman->erase();
- bool inNonMRSpan = false;
-
- for ( const XMP_Uns8 * chPtr = (XMP_Uns8*)utf8.c_str(); *chPtr != 0; ++chPtr ) { // ! Don't trust that char is unsigned.
- if ( *chPtr < 0x80 ) {
- (*macRoman) += (char)*chPtr;
- inNonMRSpan = false;
- } else {
- XMP_Uns32 cp = GetCodePoint ( &chPtr );
- --chPtr; // Make room for the loop increment.
- XMP_Uns8 mr;
- for ( mr = 0; (mr < 0x80) && (cp != kMacRomanCP[mr]); ++mr ) {}; // Using std::map would be faster.
- if ( mr < 0x80 ) {
- (*macRoman) += (char)(mr+0x80);
- inNonMRSpan = false;
- } else if ( ! inNonMRSpan ) {
- (*macRoman) += '?';
- inNonMRSpan = true;
- }
- }
- }
-
-} // UTF8ToMacRoman
-
-// =================================================================================================
-// IsMacLangKnown
-// ==============
-
-static inline bool IsMacLangKnown ( XMP_Uns16 macLang )
-{
- XMP_Uns16 macScript = GetMacScript ( macLang );
- if ( macScript == kNoMacScript ) return false;
-
- #if XMP_UNIXBuild
- if ( macScript != smRoman ) return false;
- #elif XMP_WinBuild
- if ( GetWinCP(macLang) == 0 ) return false;
- #endif
-
- return true;
-
-} // IsMacLangKnown
-
-// =================================================================================================
-// ConvertToMacLang
-// ================
-
-bool ConvertToMacLang ( const std::string & utf8Value, XMP_Uns16 macLang, std::string * macValue )
-{
- macValue->erase();
- if ( macLang == kNoMacLang ) macLang = 0; // *** Zero is English, ought to use the "active" OS lang.
- if ( ! IsMacLangKnown ( macLang ) ) return false;
-
- #if XMP_MacBuild
- XMP_Uns16 macScript = GetMacScript ( macLang );
- ReconcileUtils::UTF8ToMacEncoding ( macScript, macLang, (XMP_Uns8*)utf8Value.c_str(), utf8Value.size(), macValue );
- #elif XMP_UNIXBuild
- UTF8ToMacRoman ( utf8Value, macValue );
- #elif XMP_WinBuild
- UINT winCP = GetWinCP ( macLang );
- ReconcileUtils::UTF8ToWinEncoding ( winCP, (XMP_Uns8*)utf8Value.c_str(), utf8Value.size(), macValue );
- #endif
-
- return true;
-
-} // ConvertToMacLang
-
-// =================================================================================================
-// ConvertFromMacLang
-// ==================
-
-bool ConvertFromMacLang ( const std::string & macValue, XMP_Uns16 macLang, std::string * utf8Value )
-{
- utf8Value->erase();
- if ( ! IsMacLangKnown ( macLang ) ) return false;
-
- #if XMP_MacBuild
- XMP_Uns16 macScript = GetMacScript ( macLang );
- ReconcileUtils::MacEncodingToUTF8 ( macScript, macLang, (XMP_Uns8*)macValue.c_str(), macValue.size(), utf8Value );
- #elif XMP_UNIXBuild
- MacRomanToUTF8 ( macValue, utf8Value );
- #elif XMP_WinBuild
- UINT winCP = GetWinCP ( macLang );
- ReconcileUtils::WinEncodingToUTF8 ( winCP, (XMP_Uns8*)macValue.c_str(), macValue.size(), utf8Value );
- #endif
-
- return true;
-
-} // ConvertFromMacLang
-
-// =================================================================================================
-// =================================================================================================
-// TradQT_Manager
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// TradQT_Manager::ParseCachedBoxes
-// ================================
-//
-// Parse the cached '©...' children of the 'moov'/'udta' box. The contents of each cached box are
-// a sequence of "mini boxes" analogous to XMP AltText arrays. Each mini box has a 16-bit size,
-// 16-bit language code, and text. The size is only the text size. The language codes are Macintosh
-// Script Manager langXyz codes. The text encoding is implicit in the language, see comments in
-// Apple's Script.h header.
-
-bool TradQT_Manager::ParseCachedBoxes ( const MOOV_Manager & moovMgr )
-{
- MOOV_Manager::BoxInfo udtaInfo;
- MOOV_Manager::BoxRef udtaRef = moovMgr.GetBox ( "moov/udta", &udtaInfo );
- if ( udtaRef == 0 ) return false;
-
- for ( XMP_Uns32 i = 0; i < udtaInfo.childCount; ++i ) {
-
- MOOV_Manager::BoxInfo currInfo;
- MOOV_Manager::BoxRef currRef = moovMgr.GetNthChild ( udtaRef, i, &currInfo );
- if ( currRef == 0 ) break; // Sanity check, should not happen.
- if ( (currInfo.boxType >> 24) != 0xA9 ) continue;
- if ( currInfo.contentSize < 2+2+1 ) continue; // Want enough for a non-empty value.
-
- InfoMapPos newInfo = this->parsedBoxes.insert ( this->parsedBoxes.end(),
- InfoMap::value_type ( currInfo.boxType, ParsedBoxInfo ( currInfo.boxType ) ) );
- std::vector<ValueInfo> * newValues = &newInfo->second.values;
-
- XMP_Uns8 * boxPtr = (XMP_Uns8*) currInfo.content;
- XMP_Uns8 * boxEnd = boxPtr + currInfo.contentSize;
- XMP_Uns16 miniLen, macLang;
-
- for ( ; boxPtr < boxEnd-4; boxPtr += miniLen ) {
-
- miniLen = 4 + GetUns16BE ( boxPtr ); // ! Include header in local miniLen.
- macLang = GetUns16BE ( boxPtr+2);
- if ( (miniLen <= 4) || (miniLen > (boxEnd - boxPtr)) ) continue; // Ignore bad or empty values.
-
- XMP_StringPtr valuePtr = (char*)(boxPtr+4);
- size_t valueLen = miniLen - 4;
-
- newValues->push_back ( ValueInfo() );
- ValueInfo * newValue = &newValues->back();
-
- // Only set the XMP language if the Mac script is known, i.e. the value can be converted.
-
- newValue->macLang = macLang;
- if ( IsMacLangKnown ( macLang ) ) newValue->xmpLang = GetXMPLang ( macLang );
- newValue->macValue.assign ( valuePtr, valueLen );
-
- }
-
- }
-
- return (! this->parsedBoxes.empty());
-
-} // TradQT_Manager::ParseCachedBoxes
-
-// =================================================================================================
-// TradQT_Manager::ImportSimpleXMP
-// ===============================
-//
-// Update a simple XMP property if the QT value looks newer.
-
-bool TradQT_Manager::ImportSimpleXMP ( XMP_Uns32 id, SXMPMeta * xmp, XMP_StringPtr ns, XMP_StringPtr prop ) const
-{
-
- try {
-
- InfoMapCPos infoPos = this->parsedBoxes.find ( id );
- if ( infoPos == this->parsedBoxes.end() ) return false;
- if ( infoPos->second.values.empty() ) return false;
-
- std::string xmpValue, tempValue;
- XMP_OptionBits flags;
- bool xmpExists = xmp->GetProperty ( ns, prop, &xmpValue, &flags );
- if ( xmpExists && (! XMP_PropIsSimple ( flags )) ) {
- XMP_Throw ( "TradQT_Manager::ImportSimpleXMP - XMP property must be simple", kXMPErr_BadParam );
- }
-
- bool convertOK;
- const ValueInfo & qtItem = infoPos->second.values[0]; // ! Use the first QT entry.
-
- if ( xmpExists ) {
- convertOK = ConvertToMacLang ( xmpValue, qtItem.macLang, &tempValue );
- if ( ! convertOK ) return false; // throw?
- if ( tempValue == qtItem.macValue ) return false; // QT value matches back converted XMP value.
- }
-
- convertOK = ConvertFromMacLang ( qtItem.macValue, qtItem.macLang, &tempValue );
- if ( ! convertOK ) return false; // throw?
- xmp->SetProperty ( ns, prop, tempValue.c_str() );
- return true;
-
- } catch ( ... ) {
-
- return false; // Don't let one failure abort other imports.
-
- }
-
-} // TradQT_Manager::ImportSimpleXMP
-
-// =================================================================================================
-// TradQT_Manager::ImportLangItem
-// ==============================
-//
-// Update a specific XMP AltText item if the QuickTime value looks newer.
-
-bool TradQT_Manager::ImportLangItem ( const ValueInfo & qtItem, SXMPMeta * xmp,
- XMP_StringPtr ns, XMP_StringPtr langArray ) const
-{
-
- try {
-
- XMP_StringPtr genericLang, specificLang;
- if ( qtItem.xmpLang[0] != 0 ) {
- genericLang = qtItem.xmpLang;
- specificLang = qtItem.xmpLang;
- } else {
- genericLang = "";
- specificLang = "x-default";
- }
-
- bool convertOK;
- std::string xmpValue, tempValue, actualLang;
- bool xmpExists = xmp->GetLocalizedText ( ns, langArray, genericLang, specificLang, &actualLang, &xmpValue, 0 );
- if ( xmpExists ) {
- convertOK = ConvertToMacLang ( xmpValue, qtItem.macLang, &tempValue );
- if ( ! convertOK ) return false; // throw?
- if ( tempValue == qtItem.macValue ) return true; // QT value matches back converted XMP value.
- specificLang = actualLang.c_str();
- }
-
- convertOK = ConvertFromMacLang ( qtItem.macValue, qtItem.macLang, &tempValue );
- if ( ! convertOK ) return false; // throw?
- xmp->SetLocalizedText ( ns, langArray, "", specificLang, tempValue.c_str() );
- return true;
-
- } catch ( ... ) {
-
- return false; // Don't let one failure abort other imports.
-
- }
-
-} // TradQT_Manager::ImportLangItem
-
-// =================================================================================================
-// TradQT_Manager::ImportLangAltXMP
-// ================================
-//
-// Update items in the XMP array if the QT value looks newer.
-
-bool TradQT_Manager::ImportLangAltXMP ( XMP_Uns32 id, SXMPMeta * xmp, XMP_StringPtr ns, XMP_StringPtr langArray ) const
-{
-
- try {
-
- InfoMapCPos infoPos = this->parsedBoxes.find ( id );
- if ( infoPos == this->parsedBoxes.end() ) return false;
- if ( infoPos->second.values.empty() ) return false; // Quit now if there are no values.
-
- XMP_OptionBits flags;
- bool xmpExists = xmp->GetProperty ( ns, langArray, 0, &flags );
- if ( ! xmpExists ) {
- xmp->SetProperty ( ns, langArray, 0, kXMP_PropArrayIsAltText );
- } else if ( ! XMP_ArrayIsAltText ( flags ) ) {
- XMP_Throw ( "TradQT_Manager::ImportLangAltXMP - XMP array must be AltText", kXMPErr_BadParam );
- }
-
- // Process all of the QT values, looking up the appropriate XMP language for each.
-
- bool haveMappings = false;
- const ValueVector & qtValues = infoPos->second.values;
-
- for ( size_t i = 0, limit = qtValues.size(); i < limit; ++i ) {
- const ValueInfo & qtItem = qtValues[i];
- if ( *qtItem.xmpLang == 0 ) continue; // Only do known mappings in the loop.
- haveMappings |= this->ImportLangItem ( qtItem, xmp, ns, langArray );
- }
-
- if ( ! haveMappings ) {
- // If nothing mapped, process the first QT item to XMP's "x-default".
- haveMappings = this->ImportLangItem ( qtValues[0], xmp, ns, langArray ); // ! No xmpLang implies "x-default".
- }
-
- return haveMappings;
-
- } catch ( ... ) {
-
- return false; // Don't let one failure abort other imports.
-
- }
-
-} // TradQT_Manager::ImportLangAltXMP
-
-// =================================================================================================
-// TradQT_Manager::ExportSimpleXMP
-// ===============================
-//
-// Export a simple XMP value to the first existing QuickTime item. Delete all of the QT values if the
-// XMP value is empty or the XMP does not exist.
-
-// ! We don't create new QuickTime items since we don't know the language.
-
-void TradQT_Manager::ExportSimpleXMP ( XMP_Uns32 id, const SXMPMeta & xmp, XMP_StringPtr ns, XMP_StringPtr prop,
- bool createWithZeroLang /* = false */ )
-{
- std::string xmpValue, macValue;
-
- InfoMapPos infoPos = this->parsedBoxes.find ( id );
- bool qtFound = (infoPos != this->parsedBoxes.end()) && (! infoPos->second.values.empty());
-
- bool xmpFound = xmp.GetProperty ( ns, prop, &xmpValue, 0 );
- if ( (! xmpFound) || (xmpValue.empty()) ) {
- if ( qtFound ) {
- this->parsedBoxes.erase ( infoPos );
- this->changed = true;
- }
- return;
- }
-
- XMP_Assert ( xmpFound );
- if ( ! qtFound ) {
- if ( ! createWithZeroLang ) return;
- infoPos = this->parsedBoxes.insert ( this->parsedBoxes.end(),
- InfoMap::value_type ( id, ParsedBoxInfo ( id ) ) );
- ValueVector * newValues = &infoPos->second.values;
- newValues->push_back ( ValueInfo() );
- ValueInfo * newValue = &newValues->back();
- newValue->macLang = 0; // Happens to be langEnglish.
- newValue->xmpLang = kMacToXMPLang_0_94[0];
- this->changed = infoPos->second.changed = true;
- }
-
- ValueInfo * qtItem = &infoPos->second.values[0]; // ! Use the first QT entry.
- if ( ! IsMacLangKnown ( qtItem->macLang ) ) return;
-
- bool convertOK = ConvertToMacLang ( xmpValue, qtItem->macLang, &macValue );
- if ( convertOK && (macValue != qtItem->macValue) ) {
- qtItem->macValue = macValue;
- this->changed = infoPos->second.changed = true;
- }
-
-} // TradQT_Manager::ExportSimpleXMP
-
-// =================================================================================================
-// TradQT_Manager::ExportLangAltXMP
-// ================================
-//
-// Export XMP LangAlt array items to QuickTime, where the language and encoding mappings are known.
-// If there are no known language and encoding mappings, map the XMP default item to the first
-// existing QuickTime item.
-
-void TradQT_Manager::ExportLangAltXMP ( XMP_Uns32 id, const SXMPMeta & xmp, XMP_StringPtr ns, XMP_StringPtr langArray )
-{
- bool haveMappings = false;
- std::string xmpPath, xmpValue, xmpLang, macValue;
-
- InfoMapPos infoPos = this->parsedBoxes.find ( id );
- if ( infoPos == this->parsedBoxes.end() ) {
- infoPos = this->parsedBoxes.insert ( this->parsedBoxes.end(),
- InfoMap::value_type ( id, ParsedBoxInfo ( id ) ) );
- }
-
- ValueVector * qtValues = &infoPos->second.values;
- XMP_Index xmpCount = xmp.CountArrayItems ( ns, langArray );
- bool convertOK;
-
- if ( xmpCount == 0 ) {
- // Delete the "mappable" QuickTime items if there are no XMP values. Leave the others alone.
- for ( int i = (int)qtValues->size()-1; i > 0; --i ) { // ! Need a signed index.
- if ( (*qtValues)[i].xmpLang[0] != 0 ) {
- qtValues->erase ( qtValues->begin() + i );
- this->changed = infoPos->second.changed = true;
- }
- }
- return;
- }
-
- // Go through the XMP and look for a related macLang QuickTime item to update or create.
-
- 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 );
- xmp.GetQualifier ( ns, xmpPath.c_str(), kXMP_NS_XML, "lang", &xmpLang, 0 );
- if ( xmpLang == "x-default" ) continue;
-
- XMP_Uns16 macLang = GetMacLang ( &xmpLang );
- if ( macLang == kNoMacLang ) continue;
-
- size_t qtIndex, qtLimit;
- for ( qtIndex = 0, qtLimit = qtValues->size(); qtIndex < qtLimit; ++qtIndex ) {
- if ( (*qtValues)[qtIndex].macLang == macLang ) break;
- }
-
- if ( qtIndex == qtLimit ) {
- // No existing QuickTime item, try to create one.
- if ( ! IsMacLangKnown ( macLang ) ) continue;
- qtValues->push_back ( ValueInfo() );
- qtIndex = qtValues->size() - 1;
- ValueInfo * newItem = &((*qtValues)[qtIndex]);
- newItem->macLang = macLang;
- newItem->xmpLang = GetXMPLang ( macLang ); // ! Use the 2 character root language.
- }
-
- ValueInfo * qtItem = &((*qtValues)[qtIndex]);
- qtItem->marked = true; // Mark it whether updated or not, don't delete it in the next pass.
-
- convertOK = ConvertToMacLang ( xmpValue, qtItem->macLang, &macValue );
- if ( convertOK && (macValue != qtItem->macValue) ) {
- qtItem->macValue.swap ( macValue ); // No need to make a copy.
- haveMappings = true;
- }
-
- }
- this->changed |= haveMappings;
- infoPos->second.changed |= haveMappings;
-
- // Go through the QuickTime items that are unmarked and delete those that have an xmpLang
- // and known macScript. Clear all marks.
-
- for ( int i = (int)qtValues->size()-1; i > 0; --i ) { // ! Need a signed index.
- ValueInfo * qtItem = &((*qtValues)[i]);
- if ( qtItem->marked ) {
- qtItem->marked = false;
- } else if ( (qtItem->xmpLang[0] != 0) && IsMacLangKnown ( qtItem->macLang ) ) {
- qtValues->erase ( qtValues->begin() + i );
- this->changed = infoPos->second.changed = true;
- }
- }
-
- // If there were no mappings, export the XMP default item to the first QT item.
-
- if ( (! haveMappings) && (! qtValues->empty()) ) {
-
- bool ok = xmp.GetLocalizedText ( ns, langArray, "", "x-default", 0, &xmpValue, 0 );
- if ( ! ok ) return;
-
- ValueInfo * qtItem = &((*qtValues)[0]);
- if ( ! IsMacLangKnown ( qtItem->macLang ) ) return;
-
- convertOK = ConvertToMacLang ( xmpValue, qtItem->macLang, &macValue );
- if ( convertOK && (macValue != qtItem->macValue) ) {
- qtItem->macValue.swap ( macValue ); // No need to make a copy.
- this->changed = infoPos->second.changed = true;
- }
-
- }
-
-} // TradQT_Manager::ExportLangAltXMP
-
-// =================================================================================================
-// TradQT_Manager::UpdateChangedBoxes
-// ==================================
-
-void TradQT_Manager::UpdateChangedBoxes ( MOOV_Manager * moovMgr )
-{
- MOOV_Manager::BoxInfo udtaInfo;
- MOOV_Manager::BoxRef udtaRef = moovMgr->GetBox ( "moov/udta", &udtaInfo );
- XMP_Assert ( (udtaRef != 0) || (udtaInfo.childCount == 0) );
-
- if ( udtaRef != 0 ) { // Might not have been a moov/udta box in the parse.
-
- // First go through the moov/udta/©... children and delete those that are not in the map.
-
- for ( XMP_Uns32 ordinal = udtaInfo.childCount; ordinal > 0; --ordinal ) { // ! Go backwards because of deletions.
-
- MOOV_Manager::BoxInfo currInfo;
- MOOV_Manager::BoxRef currRef = moovMgr->GetNthChild ( udtaRef, (ordinal-1), &currInfo );
- if ( currRef == 0 ) break; // Sanity check, should not happen.
- if ( (currInfo.boxType >> 24) != 0xA9 ) continue;
- if ( currInfo.contentSize < 2+2+1 ) continue; // These were skipped by ParseCachedBoxes.
-
- InfoMapPos infoPos = this->parsedBoxes.find ( currInfo.boxType );
- if ( infoPos == this->parsedBoxes.end() ) moovMgr->DeleteNthChild ( udtaRef, (ordinal-1) );
-
- }
-
- }
-
- // Now go through the changed items in the map and update them in the moov/udta subtree.
-
- InfoMapCPos infoPos = this->parsedBoxes.begin();
- InfoMapCPos infoEnd = this->parsedBoxes.end();
-
- for ( ; infoPos != infoEnd; ++infoPos ) {
-
- ParsedBoxInfo * qtItem = (ParsedBoxInfo*) &infoPos->second;
- if ( ! qtItem->changed ) continue;
- qtItem->changed = false;
-
- XMP_Uns32 qtTotalSize = 0; // Total size of the QT values, ignoring empty values.
- for ( size_t i = 0, limit = qtItem->values.size(); i < limit; ++i ) {
- if ( ! qtItem->values[i].macValue.empty() ) {
- if ( qtItem->values[i].macValue.size() > 0xFFFF ) qtItem->values[i].macValue.erase ( 0xFFFF );
- qtTotalSize += (XMP_Uns32)(2+2 + qtItem->values[i].macValue.size());
- }
- }
-
- if ( udtaRef == 0 ) { // Might not have been a moov/udta box in the parse.
- moovMgr->SetBox ( "moov/udta", 0, 0 );
- udtaRef = moovMgr->GetBox ( "moov/udta", &udtaInfo );
- XMP_Assert ( udtaRef != 0 );
- }
-
- if ( qtTotalSize == 0 ) {
-
- moovMgr->DeleteTypeChild ( udtaRef, qtItem->id );
-
- } else {
-
- // Compose the complete box content.
-
- RawDataBlock fullValue;
- fullValue.assign ( qtTotalSize, 0 );
- XMP_Uns8 * valuePtr = &fullValue[0];
-
- for ( size_t i = 0, limit = qtItem->values.size(); i < limit; ++i ) {
- XMP_Assert ( qtItem->values[i].macValue.size() <= 0xFFFF );
- XMP_Uns16 textSize = (XMP_Uns16)qtItem->values[i].macValue.size();
- if ( textSize == 0 ) continue;
- PutUns16BE ( textSize, valuePtr ); valuePtr += 2;
- PutUns16BE ( qtItem->values[i].macLang, valuePtr ); valuePtr += 2;
- memcpy ( valuePtr, qtItem->values[i].macValue.c_str(), textSize ); valuePtr += textSize;
- }
-
- // Look for an existing box to update, else add a new one.
-
- MOOV_Manager::BoxInfo itemInfo;
- MOOV_Manager::BoxRef itemRef = moovMgr->GetTypeChild ( udtaRef, qtItem->id, &itemInfo );
-
- if ( itemRef != 0 ) {
- moovMgr->SetBox ( itemRef, &fullValue[0], qtTotalSize );
- } else {
- moovMgr->AddChildBox ( udtaRef, qtItem->id, &fullValue[0], qtTotalSize );
- }
-
- }
-
- }
-
-} // TradQT_Manager::UpdateChangedBoxes
-
-// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/QuickTime_Support.hpp b/source/XMPFiles/FormatSupport/QuickTime_Support.hpp
deleted file mode 100644
index 160dfc8..0000000
--- a/source/XMPFiles/FormatSupport/QuickTime_Support.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef __QuickTime_Support_hpp__
-#define __QuickTime_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "XMPFiles_Impl.hpp"
-#include "LargeFileAccess.hpp"
-#include "ISOBaseMedia_Support.hpp"
-#include "MOOV_Support.hpp"
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// TradQT_Manager
-// ==============
-
-// Support for selected traditional QuickTime metadata items. The supported items are the children
-// of the 'moov'/'udta' box whose type begins with 0xA9, a MacRoman copyright symbol. Each of these
-// is a box whose contents are a sequence of "mini boxes" analogous to XMP AltText arrays. Each mini
-// box has a 16-bit size, 16-bit language code, and text. The language code values are the old
-// Macintosh Script Manager langXyz codes, the text encoding is implicit, see Mac Script.h.
-
-enum { // List of recognized items from the QuickTime 'moov'/'udta' box.
- // These items are defined by Adobe.
- kQTilst_Reel = 0xA952454CUL, // '©REL'
- kQTilst_Timecode = 0xA954494DUL, // '©TIM'
- kQTilst_TimeScale = 0xA9545343UL, // '©TSC'
- kQTilst_TimeSize = 0xA954535AUL // '©TSZ'
-};
-
-enum {
- kNoMacLang = 0xFFFF,
- kNoMacScript = 0xFFFF
-};
-
-extern bool ConvertToMacLang ( const std::string & utf8Value, XMP_Uns16 macLang, std::string * macValue );
-extern bool ConvertFromMacLang ( const std::string & macValue, XMP_Uns16 macLang, std::string * utf8Value );
-
-class TradQT_Manager {
-public:
-
- TradQT_Manager() : changed(false) {};
-
- bool ParseCachedBoxes ( const MOOV_Manager & moovMgr );
-
- bool ImportSimpleXMP ( XMP_Uns32 id, SXMPMeta * xmp, XMP_StringPtr ns, XMP_StringPtr prop ) const;
- bool ImportLangAltXMP ( XMP_Uns32 id, SXMPMeta * xmp, XMP_StringPtr ns, XMP_StringPtr langArray ) const;
-
- void ExportSimpleXMP ( XMP_Uns32 id, const SXMPMeta & xmp, XMP_StringPtr ns, XMP_StringPtr prop,
- bool createWithZeroLang = false );
- void ExportLangAltXMP ( XMP_Uns32 id, const SXMPMeta & xmp, XMP_StringPtr ns, XMP_StringPtr langArray );
-
- bool IsChanged() const { return this->changed; };
-
- void UpdateChangedBoxes ( MOOV_Manager * moovMgr );
-
-private:
-
- struct ValueInfo {
- bool marked;
- XMP_Uns16 macLang;
- XMP_StringPtr xmpLang; // ! Only set if macLang is known, i.e. the value can be converted.
- std::string macValue;
- ValueInfo() : marked(false), macLang(kNoMacLang), xmpLang("") {};
- };
- typedef std::vector<ValueInfo> ValueVector;
- typedef ValueVector::iterator ValueInfoPos;
- typedef ValueVector::const_iterator ValueInfoCPos;
-
- struct ParsedBoxInfo {
- XMP_Uns32 id;
- ValueVector values;
- bool changed;
- ParsedBoxInfo() : id(0), changed(false) {};
- ParsedBoxInfo ( XMP_Uns32 _id ) : id(_id), changed(false) {};
- };
-
- typedef std::map < XMP_Uns32, ParsedBoxInfo > InfoMap; // Metadata item kind and content info.
- typedef InfoMap::iterator InfoMapPos;
- typedef InfoMap::const_iterator InfoMapCPos;
-
- InfoMap parsedBoxes;
- bool changed;
-
- bool ImportLangItem ( const ValueInfo & qtItem, SXMPMeta * xmp, XMP_StringPtr ns, XMP_StringPtr langArray ) const;
-
-}; // TradQT_Manager
-
-#endif // __QuickTime_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/RIFF.cpp b/source/XMPFiles/FormatSupport/RIFF.cpp
deleted file mode 100644
index 3992edd..0000000
--- a/source/XMPFiles/FormatSupport/RIFF.cpp
+++ /dev/null
@@ -1,879 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 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.
-// =================================================================================================
-
-// must have access to handler class fields...
-#include "RIFF.hpp"
-#include "RIFF_Support.hpp"
-#include "RIFF_Handler.hpp"
-
-using namespace RIFF;
-
-namespace RIFF {
-
-// GENERAL STATIC FUNCTIONS ////////////////////////////////////////
-
-Chunk* getChunk ( ContainerChunk* parent, RIFF_MetaHandler* handler )
-{
- LFA_FileRef file = handler->parent->fileRef;
- XMP_Uns8 level = handler->level;
- XMP_Uns32 peek = LFA_PeekUns32_LE( file );
-
- if ( level == 0 )
- {
- XMP_Validate( peek == kChunk_RIFF, "expected RIFF chunk not found", kXMPErr_BadFileFormat );
- XMP_Enforce( parent == NULL );
- }
- else
- {
- XMP_Validate( peek != kChunk_RIFF, "unexpected RIFF chunk below top-level", kXMPErr_BadFileFormat );
- XMP_Enforce( parent != NULL );
- }
-
- switch( peek )
- {
- case kChunk_RIFF:
- return new ContainerChunk( parent, handler );
- case kChunk_LIST:
- {
- if ( level != 1 ) break; // only care on this level
-
- // look further (beyond 4+4 = beyond id+size) to check on relevance
- LFA_Seek( file, 8, SEEK_CUR );
- XMP_Uns32 containerType = LFA_PeekUns32_LE( file );
- LFA_Seek( file, -8, SEEK_CUR );
-
- bool isRelevantList = ( containerType== kType_INFO || containerType == kType_Tdat );
- if ( !isRelevantList ) break;
-
- return new ContainerChunk( parent, handler );
- }
- case kChunk_XMP:
- if ( level != 1 ) break; // ignore on inappropriate levels (might be compound metadata?)
- return new XMPChunk( parent, handler );
- case kChunk_DISP:
- {
- if ( level != 1 ) break; // only care on this level
- // peek even further to see if type is 0x001 and size is reasonable
- LFA_Seek( file , 4, SEEK_CUR ); // jump DISP
- XMP_Uns32 dispSize = LFA_ReadUns32_LE( file );
- XMP_Uns32 dispType = LFA_ReadUns32_LE( file );
- LFA_Seek( file , -12, SEEK_CUR); // rewind, be in front of chunkID again
-
- // only take as a relevant disp if both criteria met,
- // otherwise treat as generic chunk!
- if ( (dispType == 0x0001) && ( dispSize < 256 * 1024 ) )
- {
- ValueChunk* r = new ValueChunk( parent, handler );
- handler->dispChunk = r;
- return r;
- }
- break; // treat as irrelevant (non-0x1) DISP chunks as generic chunk
- }
- case kChunk_bext:
- {
- if ( level != 1 ) break; // only care on this level
- // store for now in a value chunk
- ValueChunk* r = new ValueChunk( parent, handler );
- handler->bextChunk = r;
- return r;
- }
- case kChunk_PrmL:
- {
- if ( level != 1 ) break; // only care on this level
- ValueChunk* r = new ValueChunk( parent, handler );
- handler->prmlChunk = r;
- return r;
- }
- case kChunk_Cr8r:
- {
- if ( level != 1 ) break; // only care on this level
- ValueChunk* r = new ValueChunk( parent, handler );
- handler->cr8rChunk = r;
- return r;
- }
- case kChunk_JUNQ:
- case kChunk_JUNK:
- {
- JunkChunk* r = new JunkChunk( parent, handler );
- return r;
- }
- }
- // this "default:" section must be ouside switch bracket, to be
- // reachable by all those break statements above:
-
-
- // digest 'valuable' container chunks: LIST:INFO, LIST:Tdat
- bool insideRelevantList = ( level==2 && parent->id == kChunk_LIST
- && ( parent->containerType== kType_INFO || parent->containerType == kType_Tdat ));
-
- if ( insideRelevantList )
- {
- ValueChunk* r = new ValueChunk( parent, handler );
- return r;
- }
-
- // general chunk of no interest, treat as unknown blob
- return new Chunk( parent, handler, true, chunk_GENERAL );
-}
-
-// BASE CLASS CHUNK ///////////////////////////////////////////////
-// ad hoc creation
-Chunk::Chunk( ContainerChunk* parent, ChunkType c, XMP_Uns32 id )
-{
- this->chunkType = c; // base class assumption
- this->parent = parent;
- this->id = id;
- this->oldSize = 0;
- this->newSize = 8;
- this->oldPos = 0; // inevitable for ad-hoc
- this->needSizeFix = false;
-
- // good parenting for latter destruction
- if ( this->parent != NULL )
- {
- this->parent->children.push_back( this );
- if( this->chunkType == chunk_VALUE )
- this->parent->childmap.insert( make_pair( this->id, (ValueChunk*) this ) );
- }
-}
-
-// parsing creation
-Chunk::Chunk( ContainerChunk* parent, RIFF_MetaHandler* handler, bool skip, ChunkType c )
-{
- chunkType = c; // base class assumption
- this->parent = parent;
- this->oldSize = 0;
- this->hasChange = false; // [2414649] valid assumption at creation time
-
- LFA_FileRef file = handler->parent->fileRef;
-
- this->oldPos = LFA_Tell( file );
- this->id = LFA_ReadUns32_LE( file );
- this->oldSize = LFA_ReadUns32_LE( file ) + 8;
-
- // Make sure the size is within expected bounds.
- XMP_Int64 chunkEnd = this->oldPos + this->oldSize;
- XMP_Int64 chunkLimit = handler->oldFileSize;
- if ( parent != 0 ) chunkLimit = parent->oldPos + parent->oldSize;
- if ( chunkEnd > chunkLimit ) {
- bool isUpdate = XMP_OptionIsSet ( handler->parent->openFlags, kXMPFiles_OpenForUpdate );
- bool repairFile = XMP_OptionIsSet ( handler->parent->openFlags, kXMPFiles_OpenRepairFile );
- if ( (! isUpdate) || (repairFile && (parent == 0)) ) {
- this->oldSize = chunkLimit - this->oldPos;
- } else {
- XMP_Throw ( "Bad RIFF chunk size", kXMPErr_BadFileFormat );
- }
- }
-
- this->newSize = this->oldSize;
- this->needSizeFix = false;
-
- if ( skip )
- {
- bool ok;
- LFA_Seek( file, this->oldSize - 8 , SEEK_CUR, &ok );
- XMP_Validate( ok , "skipped beyond end of file (truncated file?)", kXMPErr_BadFileFormat );
- }
-
- // "good parenting", essential for latter destruction.
- if ( this->parent != NULL )
- {
- this->parent->children.push_back( this );
- if( this->chunkType == chunk_VALUE )
- this->parent->childmap.insert( make_pair( this->id, (ValueChunk*) this ) );
- }
-}
-
-void Chunk::changesAndSize( RIFF_MetaHandler* handler )
-{
- // only unknown chunks should reach this method,
- // all others must reach overloads, hence little to do here:
- hasChange = false; // unknown chunk ==> no change, naturally
- this->newSize = this->oldSize;
-}
-
-std::string Chunk::toString(XMP_Uns8 level )
-{
- char buffer[256];
- snprintf( buffer, 255, "%.4s -- "
- "oldSize: 0x%.8llX, "
- "newSize: 0x%.8llX, "
- "oldPos: 0x%.8llX\n",
- (char*)(&this->id), this->oldSize, this->newSize, this->oldPos );
- return std::string(buffer);
-}
-
-void Chunk::write( RIFF_MetaHandler* handler, LFA_FileRef file , bool isMainChunk )
-{
- throw new XMP_Error(kXMPErr_InternalFailure, "Chunk::write never to be called for unknown chunks.");
-}
-
-Chunk::~Chunk()
-{
- //nothing
-}
-
-// CONTAINER CHUNK /////////////////////////////////////////////////
-// a) creation
-// [2376832] expectedSize - minimum padding "parking size" to use, if not available append to end
-ContainerChunk::ContainerChunk( ContainerChunk* parent, XMP_Uns32 id, XMP_Uns32 containerType ) : Chunk( NULL /* !! */, chunk_CONTAINER, id )
-{
- // accept no unparented ConatinerChunks
- XMP_Enforce( parent != NULL );
-
- this->containerType = containerType;
- this->newSize = 12;
- this->parent = parent;
-
- chunkVect* siblings = &parent->children;
-
- // add at end. ( oldSize==0 will flag optimization later in the process)
- siblings->push_back( this );
-}
-
-// b) parsing
-ContainerChunk::ContainerChunk( ContainerChunk* parent, RIFF_MetaHandler* handler ) : Chunk( parent, handler, false, chunk_CONTAINER )
-{
- bool repairMode = ( 0 != ( handler->parent->openFlags & kXMPFiles_OpenRepairFile ));
-
- try
- {
- LFA_FileRef file = handler->parent->fileRef;
- XMP_Uns8 level = handler->level;
-
- // get type of container chunk
- this->containerType = LFA_ReadUns32_LE( file );
-
- // ensure legality of top-level chunks
- if ( level == 0 && handler->riffChunks.size() > 0 )
- {
- XMP_Validate( handler->parent->format == kXMP_AVIFile, "only AVI may have multiple top-level chunks", kXMPErr_BadFileFormat );
- XMP_Validate( this->containerType == kType_AVIX, "all chunks beyond main chunk must be type AVIX", kXMPErr_BadFileFormat );
- }
-
- // has *relevant* subChunks? (there might be e.g. non-INFO LIST chunks we don't care about)
- bool hasSubChunks = ( ( this->id == kChunk_RIFF ) ||
- ( this->id == kChunk_LIST && this->containerType == kType_INFO ) ||
- ( this->id == kChunk_LIST && this->containerType == kType_Tdat )
- );
- XMP_Int64 endOfChunk = this->oldPos + this->oldSize;
-
- // this statement catches beyond-EoF-offsets on any level
- // exception: level 0, tolerate if in repairMode
- if ( (level == 0) && repairMode && (endOfChunk > handler->oldFileSize) )
- {
- endOfChunk = handler->oldFileSize; // assign actual file size
- this->oldSize = endOfChunk - this->oldPos; //reversely calculate correct oldSize
- }
-
- XMP_Validate( endOfChunk <= handler->oldFileSize, "offset beyond EoF", kXMPErr_BadFileFormat );
-
- Chunk* curChild = 0;
- if ( hasSubChunks )
- {
- handler->level++;
- while ( LFA_Tell( file ) < endOfChunk )
- {
- curChild = RIFF::getChunk( this, handler );
-
- // digest pad byte - no value validation (0), since some 3rd party files have non-0-padding.
- if ( LFA_Tell(file) % 2 == 1 )
- {
- // [1521093] tolerate missing pad byte at very end of file:
- XMP_Uns8 pad;
- LFA_Read ( file, &pad, 1 ); // Read the pad, tolerate being at EOF.
-
- }
-
- // within relevant LISTs, relentlesly delete junk chunks (create a single one
- // at end as part of updateAndChanges()
- if ( (containerType== kType_INFO || containerType == kType_Tdat)
- && ( curChild->chunkType == chunk_JUNK ) )
- {
- this->children.pop_back();
- delete curChild;
- } // for other chunks: join neighouring Junk chunks into one
- else if ( (curChild->chunkType == chunk_JUNK) && ( this->children.size() >= 2 ) )
- {
- // nb: if there are e.g 2 chunks, then last one is at(1), prev one at(0) ==> '-2'
- Chunk* prevChunk = this->children.at( this->children.size() - 2 );
- if ( prevChunk->chunkType == chunk_JUNK )
- {
- // stack up size to prior chunk
- prevChunk->oldSize += curChild->oldSize;
- prevChunk->newSize += curChild->newSize;
- XMP_Enforce( prevChunk->oldSize == prevChunk->newSize );
- // destroy current chunk
- this->children.pop_back();
- delete curChild;
- }
- }
- }
- handler->level--;
- XMP_Validate( LFA_Tell( file ) == endOfChunk, "subchunks exceed outer chunk size", kXMPErr_BadFileFormat );
-
- // pointers for later legacy processing
- if ( level==1 && this->id==kChunk_LIST && this->containerType == kType_INFO )
- handler->listInfoChunk = this;
- if ( level==1 && this->id==kChunk_LIST && this->containerType == kType_Tdat )
- handler->listTdatChunk = this;
- }
- else // skip non-interest container chunk
- {
- bool ok;
- LFA_Seek( file, this->oldSize - 8 - 4, SEEK_CUR, &ok );
- XMP_Validate( ok , "skipped beyond end of file 2 (truncated file?)", kXMPErr_BadFileFormat );
- } // if - else
-
- } // try
- catch (XMP_Error& e) {
- this->release(); // free resources
- if ( this->parent != 0)
- this->parent->children.pop_back(); // hereby taken care of, so removing myself...
-
- throw e; // re-throw
- }
-}
-
-void ContainerChunk::changesAndSize( RIFF_MetaHandler* handler )
-{
-
- // Walk the container subtree adjusting the children that have size changes. The only containers
- // are RIFF and LIST chunks, they are treated differently.
- //
- // LISTs get recomposed as a whole. Existing JUNK children of a LIST are removed, existing real
- // children are left in order with their new size, new children have already been appended. The
- // LIST as a whole gets a new size that is the sum of the final children.
- //
- // Special rules apply to various children of a RIFF container. FIrst, adjacent JUNK children
- // are combined, this simplifies maximal reuse. The children are recursively adjusted in order
- // to get their final size.
- //
- // Try to determine the final placement of each RIFF child using general rules:
- // - if the size is unchanged: leave at current location
- // - if the chunk is at the end of the last RIFF chunk and grows: leave at current location
- // - if there is enough following JUNK: add part of the JUNK, adjust remaining JUNK size
- // - if it shrinks by 9 bytes or more: carve off trailing JUNK
- // - try to find adequate JUNK in the current parent
- //
- // Use child-specific rules as a last resort:
- // - if it is LIST:INFO: delete it, must be in first RIFF chunk
- // - for others: move to end of last RIFF chunk, make old space JUNK
-
- // ! Don't create any junk chunks of exactly 8 bytes, just a header and no content. That has a
- // ! size field of zero, which hits a crashing bug in some versions of Windows Media Player.
-
- bool isRIFFContainer = (this->id == kChunk_RIFF);
- bool isLISTContainer = (this->id == kChunk_LIST);
- XMP_Enforce ( isRIFFContainer | isLISTContainer );
-
- XMP_Index childIndex; // Could be local to the loops, this simplifies debuging. Need a signed type!
- Chunk * currChild;
-
- if ( this->children.empty() ) {
- if ( isRIFFContainer) {
- this->newSize = 12; // Keep a minimal size container.
- } else {
- this->newSize = 0; // Will get removed from parent in outer call.
- }
- this->hasChange = true;
- return; // Nothing more to do without children.
- }
-
- // Collapse adjacent RIFF junk children, remove all LIST junk children. Work back to front to
- // simplify the effect of .erase() on the loop. Purposely ignore the first chunk.
-
- for ( childIndex = (XMP_Index)this->children.size() - 1; childIndex > 0; --childIndex ) {
-
- currChild = this->children[childIndex];
- if ( currChild->chunkType != chunk_JUNK ) continue;
-
- if ( isRIFFContainer ) {
- Chunk * prevChild = this->children[childIndex-1];
- if ( prevChild->chunkType != chunk_JUNK ) continue;
- prevChild->oldSize += currChild->oldSize;
- prevChild->newSize += currChild->newSize;
- prevChild->hasChange = true;
- }
-
- this->children.erase ( this->children.begin() + childIndex );
- delete currChild;
- this->hasChange = true;
-
- }
-
- // Process the children of RIFF and LIST containers to get their final size. Remove empty
- // children. Work back to front to simplify the effect of .erase() on the loop. Do not ignore
- // the first chunk.
-
- for ( childIndex = (XMP_Index)this->children.size() - 1; childIndex >= 0; --childIndex ) {
-
- currChild = this->children[childIndex];
-
- ++handler->level;
- currChild->changesAndSize ( handler );
- --handler->level;
-
- if ( (currChild->newSize == 8) || (currChild->newSize == 0) ) { // ! The newSIze is supposed to include the header.
- this->children.erase ( this->children.begin() + childIndex );
- delete currChild;
- this->hasChange = true;
- } else {
- this->hasChange |= currChild->hasChange;
- currChild->needSizeFix = (currChild->newSize != currChild->oldSize);
- if ( currChild->needSizeFix && (currChild->newSize > currChild->oldSize) &&
- (this == handler->lastChunk) && (childIndex+1 == (XMP_Index)this->children.size()) ) {
- // Let an existing last-in-file chunk grow in-place. Shrinking is conceptually OK,
- // but complicates later sanity check that the main AVI chunk is not OK to append
- // other chunks later. Ignore new chunks, they might reuse junk space.
- if ( currChild->oldSize != 0 ) currChild->needSizeFix = false;
- }
- }
-
- }
-
- // Go through the children of a RIFF container, adjusting the placement as necessary. In brief,
- // things can only grow at the end of the last RIFF chunk, and non-junk chunks can't be shifted.
-
- if ( isRIFFContainer ) {
-
- for ( childIndex = 0; childIndex < (XMP_Index)this->children.size(); ++childIndex ) {
-
- currChild = this->children[childIndex];
- if ( ! currChild->needSizeFix ) continue;
- currChild->needSizeFix = false;
-
- XMP_Int64 sizeDiff = currChild->newSize - currChild->oldSize; // Positive for growth.
- XMP_Uns8 padSize = (currChild->newSize & 1); // Need a pad for odd size.
-
- // See if the following chunk is junk that can be utilized.
-
- Chunk * nextChild = 0;
- if ( childIndex+1 < (XMP_Index)this->children.size() ) nextChild = this->children[childIndex+1];
-
- if ( (nextChild != 0) && (nextChild->chunkType == chunk_JUNK) ) {
- if ( nextChild->newSize >= (9 + sizeDiff + padSize) ) {
-
- // Incorporate part of the trailing junk, or make the trailing junk grow.
- nextChild->newSize -= sizeDiff;
- nextChild->newSize -= padSize;
- nextChild->hasChange = true;
- continue;
-
- } else if ( nextChild->newSize == (sizeDiff + padSize) ) {
-
- // Incorporate all of the trailing junk.
- this->children.erase ( this->children.begin() + childIndex + 1 );
- delete nextChild;
- continue;
-
- }
- }
-
- // See if the chunk shrinks enough to turn the leftover space into junk.
-
- if ( (sizeDiff + padSize) <= -9 ) {
- this->children.insert ( (this->children.begin() + childIndex + 1), new JunkChunk ( NULL, ((-sizeDiff) - padSize) ) );
- continue;
- }
-
- // Look through the parent for a usable span of junk.
-
- XMP_Index junkIndex;
- Chunk * junkChunk = 0;
- for ( junkIndex = 0; junkIndex < (XMP_Index)this->children.size(); ++junkIndex ) {
- junkChunk = this->children[junkIndex];
- if ( junkChunk->chunkType != chunk_JUNK ) continue;
- if ( (junkChunk->newSize >= (9 + currChild->newSize + padSize)) ||
- (junkChunk->newSize == (currChild->newSize + padSize)) ) break;
- }
-
- if ( junkIndex < (XMP_Index)this->children.size() ) {
-
- // Use part or all of the junk for the relocated chunk, replace the old space with junk.
-
- if ( junkChunk->newSize == (currChild->newSize + padSize) ) {
-
- // The found junk is an exact fit.
- this->children[junkIndex] = currChild;
- delete junkChunk;
-
- } else {
-
- // The found junk has excess space. Insert the moving chunk and shrink the junk.
- XMP_Assert ( junkChunk->newSize >= (9 + currChild->newSize + padSize) );
- junkChunk->newSize -= (currChild->newSize + padSize);
- junkChunk->hasChange = true;
- this->children.insert ( (this->children.begin() + junkIndex), currChild );
- if ( junkIndex < childIndex ) ++childIndex; // The insertion moved the current child.
-
- }
-
- if ( currChild->oldSize != 0 ) {
- this->children[childIndex] = new JunkChunk ( 0, currChild->oldSize ); // Replace the old space with junk.
- } else {
- this->children.erase ( this->children.begin() + childIndex ); // Remove the newly created chunk's old location.
- --childIndex; // Make the next loop iteration not skip a chunk.
- }
-
- continue;
-
- }
-
- // If this is a LIST:INFO chunk not in the last of multiple RIFF chunks, then give up
- // and replace it with oldSize junk. Preserve the first RIFF chunk's original size.
-
- bool isListInfo = (currChild->id == kChunk_LIST) && (currChild->chunkType == chunk_CONTAINER) &&
- (((ContainerChunk*)currChild)->containerType == kType_INFO);
-
- if ( isListInfo && (handler->riffChunks.size() > 1) &&
- (this->id == kChunk_RIFF) && (this != handler->lastChunk) ) {
-
- if ( currChild->oldSize != 0 ) {
- this->children[childIndex] = new JunkChunk ( 0, currChild->oldSize );
- } else {
- this->children.erase ( this->children.begin() + childIndex );
- --childIndex; // Make the next loop iteration not skip a chunk.
- }
-
- delete currChild;
- continue;
-
- }
-
- // Move the chunk to the end of the last RIFF chunk and make the old space junk.
-
- if ( (this == handler->lastChunk) && (childIndex+1 == (XMP_Index)this->children.size()) ) continue; // Already last.
-
- handler->lastChunk->children.push_back( currChild );
- if ( currChild->oldSize != 0 ) {
- this->children[childIndex] = new JunkChunk ( 0, currChild->oldSize ); // Replace the old space with junk.
- } else {
- this->children.erase ( this->children.begin() + childIndex ); // Remove the newly created chunk's old location.
- --childIndex; // Make the next loop iteration not skip a chunk.
- }
-
- }
-
- }
-
- // Compute the finished container's new size (for both RIFF and LIST).
-
- this->newSize = 12; // Start with standard container header.
- for ( childIndex = 0; childIndex < (XMP_Index)this->children.size(); ++childIndex ) {
- currChild = this->children[childIndex];
- this->newSize += currChild->newSize;
- this->newSize += (this->newSize & 1); // Round up if odd.
- }
-
- XMP_Validate ( (this->newSize <= 0xFFFFFFFFLL), "No single chunk may be above 4 GB", kXMPErr_Unimplemented );
-
-}
-
-std::string ContainerChunk::toString(XMP_Uns8 level )
-{
- XMP_Int64 offset= 12; // compute offsets, just for informational purposes
- // (actually only correct for first chunk)
-
- char buffer[256];
- snprintf( buffer, 255, "%.4s:%.4s, "
- "oldSize: 0x%8llX, "
- "newSize: 0x%.8llX, "
- "oldPos: 0x%.8llX\n",
- (char*)(&this->id), (char*)(&this->containerType), this->oldSize, this->newSize, this->oldPos );
-
- std::string r(buffer);
- chunkVectIter iter;
- for( iter = this->children.begin(); iter != this->children.end(); iter++ )
- {
- char buffer[256];
- snprintf( buffer, 250, "offset 0x%.8llX", offset );
- r += std::string ( level*4, ' ' ) + std::string( buffer ) + ":" + (*iter)->toString( level + 1 );
- offset += (*iter)->newSize;
- if ( offset % 2 == 1 )
- offset++;
- }
- return std::string(r);
-}
-
-void ContainerChunk::write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk )
-{
- bool ok;
- if ( isMainChunk )
- LFA_Rewind( file );
-
- // enforce even position
- XMP_Int64 chunkStart = LFA_Tell(file);
- XMP_Int64 chunkEnd = chunkStart + this->newSize;
- XMP_Enforce( chunkStart % 2 == 0 );
- chunkVect *rc = &this->children;
-
- // [2473303] have to write back-to-front to avoid stomp-on-feet
- XMP_Int64 childStart = chunkEnd;
- for ( XMP_Int32 chunkNo = (XMP_Int32)(rc->size() -1); chunkNo >= 0; chunkNo-- )
- {
- Chunk* cur = rc->at(chunkNo);
-
- // pad byte first
- if ( cur->newSize % 2 == 1 )
- {
- childStart--;
- LFA_Seek( file, childStart, SEEK_SET );
- LFA_WriteUns8( file, 0 );
- }
-
- // then contents
- childStart-= cur->newSize;
- LFA_Seek( file, childStart, SEEK_SET );
- switch ( cur->chunkType )
- {
- case chunk_GENERAL: //COULDDO enfore no change, since not write-out-able
- if ( cur->oldPos != childStart )
- LFA_Move( file, cur->oldPos, file, childStart, cur->oldSize, 0, 0 );
- break;
- default:
- cur->write( handler, file, false );
- break;
- } // switch
-
- } // for
- XMP_Enforce ( chunkStart + 12 == childStart);
- LFA_Seek( file, chunkStart, SEEK_SET, &ok );
-
- LFA_WriteUns32_LE( file, this->id );
- LFA_WriteUns32_LE( file, (XMP_Uns32) this->newSize - 8 ); // validated in changesAndSize() above
- LFA_WriteUns32_LE( file, this->containerType );
-
-}
-
-void ContainerChunk::release()
-{
- // free subchunks
- Chunk* curChunk;
- while( ! this->children.empty() )
- {
- curChunk = this->children.back();
- delete curChunk;
- this->children.pop_back();
- }
-}
-
-ContainerChunk::~ContainerChunk()
-{
- this->release(); // free resources
-}
-
-// XMP CHUNK ///////////////////////////////////////////////
-// a) create
-
-// a) creation
-XMPChunk::XMPChunk( ContainerChunk* parent ) : Chunk( parent, chunk_XMP , kChunk_XMP )
-{
- // nothing
-}
-
-// b) parse
-XMPChunk::XMPChunk( ContainerChunk* parent, RIFF_MetaHandler* handler ) : Chunk( parent, handler, false, chunk_XMP )
-{
- chunkType = chunk_XMP;
- LFA_FileRef file = handler->parent->fileRef;
- XMP_Uns8 level = handler->level;
-
- handler->packetInfo.offset = this->oldPos + 8;
- handler->packetInfo.length = (XMP_Int32) this->oldSize - 8;
-
- handler->xmpPacket.reserve ( handler->packetInfo.length );
- handler->xmpPacket.assign ( handler->packetInfo.length, ' ' );
- LFA_Read ( file, (void*)handler->xmpPacket.data(), handler->packetInfo.length, kLFA_RequireAll );
-
- handler->containsXMP = true; // last, after all possible failure
-
- // pointer for later processing
- handler->xmpChunk = this;
-}
-
-void XMPChunk::changesAndSize( RIFF_MetaHandler* handler )
-{
- XMP_Enforce( &handler->xmpPacket != 0 );
- XMP_Enforce( handler->xmpPacket.size() > 0 );
- this->newSize = 8 + handler->xmpPacket.size();
-
- XMP_Validate( this->newSize <= 0xFFFFFFFFLL, "no single chunk may be above 4 GB", kXMPErr_InternalFailure );
-
- // a complete no-change would have been caught in XMPFiles common code anyway
- this->hasChange = true;
-}
-
-void XMPChunk::write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk )
-{
- LFA_WriteUns32_LE( file, kChunk_XMP );
- LFA_WriteUns32_LE( file, (XMP_Uns32) this->newSize - 8 ); // validated in changesAndSize() above
- LFA_Write( file, handler->xmpPacket.data(), (XMP_Int32)handler->xmpPacket.size() );
-}
-
-// Value CHUNK ///////////////////////////////////////////////
-// a) creation
-ValueChunk::ValueChunk( ContainerChunk* parent, std::string value, XMP_Uns32 id ) : Chunk( parent, chunk_VALUE, id )
-{
- this->oldValue = std::string();
- this->SetValue( value );
-}
-
-// b) parsing
-ValueChunk::ValueChunk( ContainerChunk* parent, RIFF_MetaHandler* handler ) : Chunk( parent, handler, false, chunk_VALUE )
-{
- // set value: -----------------
- LFA_FileRef file = handler->parent->fileRef;
- XMP_Uns8 level = handler->level;
-
- // unless changed through reconciliation, assume for now.
- // IMPORTANT to stay true to the original (no \0 cleanup or similar)
- // since unknown value chunks might not be fully understood,
- // hence must be precisely preserved !!!
-
- XMP_Int32 length = (XMP_Int32) this->oldSize - 8;
- this->oldValue.reserve( length );
- this->oldValue.assign( length + 1, '\0' );
- LFA_Read ( file, (void*)this->oldValue.data(), length, kLFA_RequireAll );
-
- this->newValue = this->oldValue;
- this->newSize = this->oldSize;
-}
-
-void ValueChunk::SetValue( std::string value, bool optionalNUL /* = false */ )
-{
- this->newValue.assign( value );
- if ( (! optionalNUL) || ((value.size() & 1) == 1) ) {
- // ! The NUL should be optional in WAV to avoid a parsing bug in Audition 3 - can't handle implicit pad byte.
- this->newValue.append( 1, '\0' ); // append zero termination as explicit part of string
- }
- this->newSize = this->newValue.size() + 8;
-}
-
-void ValueChunk::changesAndSize( RIFF_MetaHandler* handler )
-{
- // Don't simply assign to this->hasChange, it might already be true.
- if ( this->newValue.size() != this->oldValue.size() ) {
- this->hasChange = true;
- } else if ( strncmp ( this->oldValue.c_str(), this->newValue.c_str(), this->newValue.size() ) != 0 ) {
- this->hasChange = true;
- }
-}
-
-void ValueChunk::write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk )
-{
- LFA_WriteUns32_LE( file, this->id );
- LFA_WriteUns32_LE( file, (XMP_Uns32)this->newSize - 8 );
- LFA_Write( file, this->newValue.data() , (XMP_Int32)this->newSize - 8 );
-}
-
-/* remove value chunk if existing.
- return true if it was existing. */
-bool ContainerChunk::removeValue( XMP_Uns32 id )
-{
- valueMap* cm = &this->childmap;
- valueMapIter iter = cm->find( id );
-
- if( iter == cm->end() )
- return false; //not found
-
- ValueChunk* propChunk = iter->second;
-
- // remove from vector (difficult)
- chunkVect* cv = &this->children;
- chunkVectIter cvIter;
- for (cvIter = cv->begin(); cvIter != cv->end(); ++cvIter )
- {
- if ( (*cvIter)->id == id )
- break; // found!
- }
- XMP_Validate( cvIter != cv->end(), "property not found in children vector", kXMPErr_InternalFailure );
- cv->erase( cvIter );
-
- // remove from map (easy)
- cm->erase( iter );
-
- delete propChunk;
- return true; // found and removed
-}
-
-/* returns iterator to (first) occurence of this chunk.
- iterator to the end of the map if chunk pointer is not found */
-chunkVectIter ContainerChunk::getChild( Chunk* needle )
-{
- chunkVectIter iter;
- for( iter = this->children.begin(); iter != this->children.end(); iter++ )
- {
- Chunk* temp1 = *iter;
- Chunk* temp2 = needle;
- if ( (*iter) == needle ) return iter;
- }
- return this->children.end();
-}
-
-/* replaces a chunk by a JUNK chunk.
- Also frees memory of prior chunk. */
-void ContainerChunk::replaceChildWithJunk( Chunk* child, bool deleteChild )
-{
- chunkVectIter iter = getChild( child );
- if ( iter == this->children.end() ) {
- throw new XMP_Error(kXMPErr_InternalFailure, "replaceChildWithJunk: childChunk not found.");
- }
-
- *iter = new JunkChunk ( NULL, child->oldSize );
- if ( deleteChild ) delete child;
-
- this->hasChange = true;
-}
-
-// JunkChunk ///////////////////////////////////////////////////
-// a) creation
-JunkChunk::JunkChunk( ContainerChunk* parent, XMP_Int64 size ) : Chunk( parent, chunk_JUNK, kChunk_JUNK )
-{
- XMP_Assert( size >= 8 );
- this->oldSize = size;
- this->newSize = size;
- this->hasChange = true;
-}
-
-// b) parsing
-JunkChunk::JunkChunk( ContainerChunk* parent, RIFF_MetaHandler* handler ) : Chunk( parent, handler, true, chunk_JUNK )
-{
- chunkType = chunk_JUNK;
-}
-
-void JunkChunk::changesAndSize( RIFF_MetaHandler* handler )
-{
- this->newSize = this->oldSize; // optimization at a later stage
- XMP_Validate( this->newSize <= 0xFFFFFFFFLL, "no single chunk may be above 4 GB", kXMPErr_InternalFailure );
- if ( this->id == kChunk_JUNQ ) this->hasChange = true; // Force ID change to JUNK.
-}
-
-// zeroBuffer, etc to write out empty native padding
-const static XMP_Uns32 kZeroBufferSize64K = 64 * 1024;
-static XMP_Uns8 kZeroes64K [ kZeroBufferSize64K ]; // C semantics guarantee zero initialization.
-
-void JunkChunk::write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk )
-{
- LFA_WriteUns32_LE( file, kChunk_JUNK ); // write JUNK, never JUNQ
- XMP_Enforce( this->newSize < 0xFFFFFFFF );
- XMP_Enforce( this->newSize >= 8 ); // minimum size of any chunk
- XMP_Uns32 innerSize = (XMP_Uns32)this->newSize - 8;
- LFA_WriteUns32_LE( file, innerSize );
-
- // write out in 64K chunks
- while ( innerSize > kZeroBufferSize64K )
- {
- LFA_Write( file, kZeroes64K , kZeroBufferSize64K );
- innerSize -= kZeroBufferSize64K;
- }
- LFA_Write( file, kZeroes64K , innerSize );
-}
-
-} // namespace RIFF
diff --git a/source/XMPFiles/FormatSupport/RIFF.hpp b/source/XMPFiles/FormatSupport/RIFF.hpp
deleted file mode 100644
index 34b2100..0000000
--- a/source/XMPFiles/FormatSupport/RIFF.hpp
+++ /dev/null
@@ -1,316 +0,0 @@
-#ifndef __RIFF_hpp__
-#define __RIFF_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include <vector>
-#include <map>
-#include "XMPFiles_Impl.hpp"
-
-// ahead declaration:
-class RIFF_MetaHandler;
-
-namespace RIFF {
-
- enum ChunkType {
- chunk_GENERAL, //unknown or not relevant
- chunk_CONTAINER,
- chunk_XMP,
- chunk_VALUE,
- chunk_JUNK,
- NO_CHUNK // used as precessor to first chunk, etc.
- };
-
- // ahead declarations
- class Chunk;
- class ContainerChunk;
- class ValueChunk;
- class XMPChunk;
-
- // (scope: only used in RIFF_Support and RIFF_Handler.cpp
- // ==> no need to overspecify with lengthy names )
-
- typedef std::vector<Chunk*> chunkVect; // coulddo: narrow down toValueChunk (could give trouble with JUNK though)
- typedef chunkVect::iterator chunkVectIter; // or refactor ??
-
- typedef std::vector<ContainerChunk*> containerVect;
- typedef containerVect::iterator containerVectIter;
-
- typedef std::map<XMP_Uns32,ValueChunk*> valueMap;
- typedef valueMap::iterator valueMapIter;
-
-
- // format chunks+types
- const XMP_Uns32 kChunk_RIFF = 0x46464952;
- const XMP_Uns32 kType_AVI_ = 0x20495641;
- const XMP_Uns32 kType_AVIX = 0x58495641;
- const XMP_Uns32 kType_WAVE = 0x45564157;
-
- const XMP_Uns32 kChunk_JUNK = 0x4B4E554A;
- const XMP_Uns32 kChunk_JUNQ = 0x514E554A;
-
- // other container chunks
- const XMP_Uns32 kChunk_LIST = 0x5453494C;
- const XMP_Uns32 kType_INFO = 0x4F464E49;
- const XMP_Uns32 kType_Tdat = 0x74616454;
-
- // other relevant chunks
- const XMP_Uns32 kChunk_XMP = 0x584D505F; // "_PMX"
-
- // relevant for Index Correction
- // LIST:
- const XMP_Uns32 kType_hdrl = 0x6C726468;
- const XMP_Uns32 kType_strl = 0x6C727473;
- const XMP_Uns32 kChunk_indx = 0x78646E69;
- const XMP_Uns32 kChunk_ixXX = 0x58587869;
- const XMP_Uns32 kType_movi = 0x69766F6D;
-
- //should occur only in AVI
- const XMP_Uns32 kChunk_Cr8r = 0x72387243;
- const XMP_Uns32 kChunk_PrmL = 0x4C6D7250;
-
- //should occur only in WAV
- const XMP_Uns32 kChunk_DISP = 0x50534944;
- const XMP_Uns32 kChunk_bext = 0x74786562;
-
- // LIST/INFO constants
- const XMP_Uns32 kPropChunkIART = 0x54524149;
- const XMP_Uns32 kPropChunkICMT = 0x544D4349;
- const XMP_Uns32 kPropChunkICOP = 0x504F4349;
- const XMP_Uns32 kPropChunkICRD = 0x44524349;
- const XMP_Uns32 kPropChunkIENG = 0x474E4549;
- const XMP_Uns32 kPropChunkIGNR = 0x524E4749;
- const XMP_Uns32 kPropChunkINAM = 0x4D414E49;
- const XMP_Uns32 kPropChunkISFT = 0x54465349;
- const XMP_Uns32 kPropChunkIARL = 0x4C524149;
-
- const XMP_Uns32 kPropChunkIMED = 0x44454D49;
- const XMP_Uns32 kPropChunkISRF = 0x46525349;
- const XMP_Uns32 kPropChunkICMS = 0x4C524149;
- const XMP_Uns32 kPropChunkIPRD = 0x534D4349;
- const XMP_Uns32 kPropChunkISRC = 0x44525049;
- const XMP_Uns32 kPropChunkITCH = 0x43525349;
-
- const XMP_Uns32 kPropChunk_tc_O =0x4F5F6374;
- const XMP_Uns32 kPropChunk_tc_A =0x415F6374;
- const XMP_Uns32 kPropChunk_rn_O =0x4F5F6E72;
- const XMP_Uns32 kPropChunk_rn_A =0x415F6E72;
-
- ///////////////////////////////////////////////////////////////
-
- enum PropType { // from a simplified, opinionated legacy angle
- prop_SIMPLE,
- prop_TIMEVALUE,
- prop_LOCALIZED_TEXT,
- prop_ARRAYITEM, // ( here: a solitary one)
- };
-
- struct Mapping {
- XMP_Uns32 chunkID;
- const char* ns;
- const char* prop;
- PropType propType;
- };
-
- // bext Mappings, piece-by-piece:
- static Mapping bextDescription = { 0, kXMP_NS_BWF, "description", prop_SIMPLE };
- static Mapping bextOriginator = { 0, kXMP_NS_BWF, "originator", prop_SIMPLE };
- static Mapping bextOriginatorRef = { 0, kXMP_NS_BWF, "originatorReference", prop_SIMPLE };
- static Mapping bextOriginationDate = { 0, kXMP_NS_BWF, "originationDate", prop_SIMPLE };
- static Mapping bextOriginationTime = { 0, kXMP_NS_BWF, "originationTime", prop_SIMPLE };
- static Mapping bextTimeReference = { 0, kXMP_NS_BWF, "timeReference", prop_SIMPLE };
- static Mapping bextVersion = { 0, kXMP_NS_BWF, "version", prop_SIMPLE };
- static Mapping bextUMID = { 0, kXMP_NS_BWF, "umid", prop_SIMPLE };
- static Mapping bextCodingHistory = { 0, kXMP_NS_BWF, "codingHistory", prop_SIMPLE };
-
- // LIST:INFO properties
- static Mapping listInfoProps[] = {
- // reconciliations CS4 and before:
- { kPropChunkIART, kXMP_NS_DM, "artist" , prop_SIMPLE },
- { kPropChunkICMT, kXMP_NS_DM, "logComment" , prop_SIMPLE },
- { kPropChunkICOP, kXMP_NS_DC, "rights" , prop_LOCALIZED_TEXT },
- { kPropChunkICRD, kXMP_NS_XMP, "CreateDate" , prop_SIMPLE },
- { kPropChunkIENG, kXMP_NS_DM, "engineer" , prop_SIMPLE },
- { kPropChunkIGNR, kXMP_NS_DM, "genre" , prop_SIMPLE },
- { kPropChunkINAM, kXMP_NS_DC, "title" , prop_LOCALIZED_TEXT }, // ( was wrongly dc:album in pre-CS4)
- { kPropChunkISFT, kXMP_NS_XMP, "CreatorTool", prop_SIMPLE },
-
- // RIFF/*/LIST/INFO properties, new in CS5, both AVI and WAV
-
- { kPropChunkIMED, kXMP_NS_DC, "source" , prop_SIMPLE },
- { kPropChunkISRF, kXMP_NS_DC, "type" , prop_ARRAYITEM },
- // TO ENABLE { kPropChunkIARL, kXMP_NS_DC, "subject" , prop_SIMPLE }, // array !! (not x-default language alternative)
- //{ kPropChunkICMS, to be decided, "" , prop_SIMPLE },
- //{ kPropChunkIPRD, to be decided, "" , prop_SIMPLE },
- //{ kPropChunkISRC, to be decided, "" , prop_SIMPLE },
- //{ kPropChunkITCH, to be decided, "" , prop_SIMPLE },
-
- { 0, 0, 0 } // sentinel
- };
-
- static Mapping listTdatProps[] = {
- // reconciliations CS4 and before:
- { kPropChunk_tc_O, kXMP_NS_DM, "startTimecode" , prop_TIMEVALUE }, // special: must end up in dm:timeValue child
- { kPropChunk_tc_A, kXMP_NS_DM, "altTimecode" , prop_TIMEVALUE }, // special: must end up in dm:timeValue child
- { kPropChunk_rn_O, kXMP_NS_DM, "tapeName" , prop_SIMPLE },
- { kPropChunk_rn_A, kXMP_NS_DM, "altTapeName" , prop_SIMPLE },
- { 0, 0, 0 } // sentinel
- };
-
- // =================================================================================================
- // ImportCr8rItems
- // ===============
- #pragma pack ( push, 1 )
- struct PrmLBoxContent {
- XMP_Uns32 magic;
- XMP_Uns32 size;
- XMP_Uns16 verAPI;
- XMP_Uns16 verCode;
- XMP_Uns32 exportType;
- XMP_Uns16 MacVRefNum;
- XMP_Uns32 MacParID;
- char filePath[260];
- };
-
- enum { kExportTypeMovie = 0, kExportTypeStill = 1, kExportTypeAudio = 2, kExportTypeCustom = 3 };
-
- struct Cr8rBoxContent {
- XMP_Uns32 magic;
- XMP_Uns32 size;
- XMP_Uns16 majorVer;
- XMP_Uns16 minorVer;
- XMP_Uns32 creatorCode;
- XMP_Uns32 appleEvent;
- char fileExt[16];
- char appOptions[16];
- char appName[32];
- };
- #pragma pack ( pop )
-
- // static getter, determines appropriate chunkType (peeking)and returns
- // the respective constructor. It's the caller's responsibility to
- // delete obtained chunk.
- Chunk* getChunk ( ContainerChunk* parent, RIFF_MetaHandler* handler );
-
- class Chunk
- {
- public:
- ChunkType chunkType; // set by constructor
- ContainerChunk* parent; // 0 on top-level
-
- XMP_Uns32 id; // the first four bytes, first byte of highest value
- XMP_Int64 oldSize; // actual chunk size INCLUDING the 8/12 header bytes,
- XMP_Int64 oldPos; // file position of this chunk
-
- // both set as part of changesAndSize()
- XMP_Int64 newSize;
- bool hasChange;
- bool needSizeFix; // used in changesAndSize() only
-
- // Constructors ///////////////////////
- // parsing
- Chunk( ContainerChunk* parent, RIFF_MetaHandler* handler, bool skip, ChunkType c /*= chunk_GENERAL*/ );
- // ad-hoc creation
- Chunk( ContainerChunk* parent, ChunkType c, XMP_Uns32 id );
-
- /* returns true, if something has changed in chunk (which needs specific write-out,
- this->newSize is expected to be set by this routine */
- virtual void changesAndSize( RIFF_MetaHandler* handler );
- virtual std::string toString(XMP_Uns8 level = 0);
- virtual void write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk = false );
-
- virtual ~Chunk();
-
- }; // class Chunk
-
- class XMPChunk : public Chunk
- {
- public:
- XMPChunk( ContainerChunk* parent );
- XMPChunk( ContainerChunk* parent, RIFF_MetaHandler* handler );
-
- void changesAndSize( RIFF_MetaHandler* handler );
- void write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk = false );
-
- };
-
- // any chunk, whose value should be stored, e.g. LIST:INFO, LIST:Tdat
- class ValueChunk : public Chunk
- {
- public:
- std::string oldValue, newValue;
-
- // for ad-hoc creation (upon write)
- ValueChunk( ContainerChunk* parent, std::string value, XMP_Uns32 id );
-
- // for parsing
- ValueChunk( ContainerChunk* parent, RIFF_MetaHandler* handler );
-
- enum { kNULisOptional = true };
-
- void SetValue( std::string value, bool optionalNUL = false );
- void changesAndSize( RIFF_MetaHandler* handler );
- void write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk = false );
-
- // own destructor not needed.
- };
-
- // relevant (level 1) JUNQ and JUNK chunks...
- class JunkChunk : public Chunk
- {
- public:
- // construction
- JunkChunk( ContainerChunk* parent, XMP_Int64 size );
- // parsing
- JunkChunk( ContainerChunk* parent, RIFF_MetaHandler* handler );
-
- // own destructor not needed.
-
- void changesAndSize( RIFF_MetaHandler* handler );
- void write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk = false );
- };
-
-
- class ContainerChunk : public Chunk
- {
- public:
- XMP_Uns32 containerType; // e.g. kType_INFO as in "LIST:INFO"
-
- chunkVect children; // used for cleanup/destruction, ordering...
- valueMap childmap; // only for efficient *value* access (inside LIST), *not* used for other containers
-
- // construct
- ContainerChunk( ContainerChunk* parent, XMP_Uns32 id, XMP_Uns32 containerType );
- // parse
- ContainerChunk( ContainerChunk* parent, RIFF_MetaHandler* handler );
-
- bool removeValue( XMP_Uns32 id );
-
- /* returns iterator to (first) occurence of this chunk.
- iterator to the end of the map if chunk pointer is not found */
- chunkVectIter getChild( Chunk* needle );
-
- void replaceChildWithJunk( Chunk* child, bool deleteChild = true );
-
- void changesAndSize( RIFF_MetaHandler* handler );
- std::string toString(XMP_Uns8 level = 0);
- void write( RIFF_MetaHandler* handler, LFA_FileRef file, bool isMainChunk = false );
-
- // destroy
- void release(); // used by destructor and on error in constructor
- ~ContainerChunk();
-
- }; // class ContainerChunk
-
-} // namespace RIFF
-
-
-#endif // __RIFF_hpp__
diff --git a/source/XMPFiles/FormatSupport/RIFF_Support.cpp b/source/XMPFiles/FormatSupport/RIFF_Support.cpp
deleted file mode 100644
index fe7e568..0000000
--- a/source/XMPFiles/FormatSupport/RIFF_Support.cpp
+++ /dev/null
@@ -1,930 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-// must have access to handler class fields...
-#include "RIFF.hpp"
-#include "RIFF_Handler.hpp"
-#include "RIFF_Support.hpp"
-#include "Reconcile_Impl.hpp"
-
-using namespace RIFF;
-namespace RIFF {
-
-// The minimum BEXT chunk size should be 610 (incl. 8 byte header/size field)
-XMP_Int32 MIN_BEXT_SIZE = 610; // = > 8 + ( 256+32+32+10+8+4+4+2+64+190+0 )
-
-// An assumed secure max value of 100 MB.
-XMP_Int32 MAX_BEXT_SIZE = 100 * 1024 * 1024;
-
-// CR8R, PrmL have fixed sizes
-XMP_Int32 CR8R_SIZE = 0x5C;
-XMP_Int32 PRML_SIZE = 0x122;
-
-static const char* sHexChars = "0123456789ABCDEF";
-
-// Encode a string of raw data bytes into a HexString (w/o spaces, i.e. "DEADBEEF").
-// No insertation/acceptance of whitespace/linefeeds. No output/tolerance of lowercase.
-// returns true, if *all* characters returned are zero (or if 0 bytes are returned).
-static bool EncodeToHexString ( XMP_StringPtr rawStr,
- XMP_StringLen rawLen,
- std::string* encodedStr )
-{
- bool allZero = true; // assume for now
-
- if ( (rawStr == 0) && (rawLen != 0) )
- XMP_Throw ( "EncodeToHexString: null rawStr", kXMPErr_BadParam );
- if ( encodedStr == 0 )
- XMP_Throw ( "EncodeToHexString: null encodedStr", kXMPErr_BadParam );
-
- encodedStr->erase();
- if ( rawLen == 0 ) return allZero;
- encodedStr->reserve ( rawLen * 2 );
-
- for( XMP_Uns32 i = 0; i < rawLen; i++ )
- {
- // first, second nibble
- XMP_Uns8 first = rawStr[i] >> 4;
- XMP_Uns8 second = rawStr[i] & 0xF;
-
- if ( allZero && (( first != 0 ) || (second != 0)))
- allZero = false;
-
- encodedStr->append( 1, sHexChars[first] );
- encodedStr->append( 1, sHexChars[second] );
- }
-
- return allZero;
-} // EncodeToHexString
-
-// -------------------------------------------------------------------------------------------------
-// DecodeFromHexString
-// ----------------
-//
-// Decode a hex string to raw data bytes.
-// * Input must be all uppercase and w/o any whitespace, strictly (0-9A-Z)* (i.e. "DEADBEEF0099AABC")
-// * No insertation/acceptance of whitespace/linefeeds.
-// * bNo use/tolerance of lowercase.
-// * Number of bytes in the encoded String must be even.
-// * returns true if everything went well, false if illegal (non 0-9A-F) character encountered
-
-static bool DecodeFromHexString ( XMP_StringPtr encodedStr,
- XMP_StringLen encodedLen,
- std::string* rawStr )
-{
- if ( (encodedLen % 2) != 0 )
- return false;
- rawStr->erase();
- if ( encodedLen == 0 ) return true;
- rawStr->reserve ( encodedLen / 2 );
-
- for( XMP_Uns32 i = 0; i < encodedLen; )
- {
- XMP_Uns8 upperNibble = encodedStr[i];
- if ( (upperNibble < 48) || ( (upperNibble > 57 ) && ( upperNibble < 65 ) ) || (upperNibble > 70) )
- return false;
- if ( upperNibble >= 65 )
- upperNibble -= 7; // shift A-F area adjacent to 0-9
- upperNibble -= 48; // 'shift' to a value [0..15]
- upperNibble = ( upperNibble << 4 );
- i++;
-
- XMP_Uns8 lowerNibble = encodedStr[i];
- if ( (lowerNibble < 48) || ( (lowerNibble > 57 ) && ( lowerNibble < 65 ) ) || (lowerNibble > 70) )
- return false;
- if ( lowerNibble >= 65 )
- lowerNibble -= 7; // shift A-F area adjacent to 0-9
- lowerNibble -= 48; // 'shift' to a value [0..15]
- i++;
-
- rawStr->append ( 1, (upperNibble + lowerNibble) );
- }
- return true;
-} // DecodeFromHexString
-
-// Converts input string to an ascii output string
-// - terminates at first 0
-// - replaces all non ascii with 0x3F ('?')
-// - produces up to maxOut characters (note that several UTF-8 character bytes can 'melt' to one byte '?' in ascii.)
-static XMP_StringLen convertToASCII( XMP_StringPtr input, XMP_StringLen inputLen, std::string* output, XMP_StringLen maxOutputLen )
-{
- if ( (input == 0) && (inputLen != 0) )
- XMP_Throw ( "convertToASCII: null input string", kXMPErr_BadParam );
- if ( output == 0)
- XMP_Throw ( "convertToASCII: null output string", kXMPErr_BadParam );
- if ( maxOutputLen == 0)
- XMP_Throw ( "convertToASCII: zero maxOutputLen chars", kXMPErr_BadParam );
-
- output->reserve(inputLen);
- output->erase();
-
- bool isUTF8 = ReconcileUtils::IsUTF8( input, inputLen );
- XMP_StringLen outputLen = 0;
-
- for ( XMP_Uns32 i=0; i < inputLen; i++ )
- {
- XMP_Uns8 c = (XMP_Uns8) input[i];
- if ( c == 0 ) // early 0 termination, leave.
- break;
- if ( c > 127 ) // uft-8 multi-byte sequence.
- {
- if ( isUTF8 ) // skip all high bytes
- {
- // how many bytes in this ?
- if ( c >= 0xC2 && c <= 0xDF )
- i+=1; // 2-byte sequence
- else if ( c >= 0xE0 && c <= 0xEF )
- i+=2; // 3-byte sequence
- else if ( c >= 0xF0 && c <= 0xF4 )
- i+=3; // 4-byte sequence
- else
- continue; //invalid sequence, look for next 'low' byte ..
- } // thereafter and 'else': just append a question mark:
- output->append( 1, '?' );
- }
- else // regular valid ascii. 1 byte.
- {
- output->append( 1, input[i] );
- }
- outputLen++;
- if ( outputLen >= maxOutputLen )
- break; // (may be even or even greater due to UFT-8 multi-byte jumps)
- }
-
- return outputLen;
-}
-
-/**
- * ensures that native property gets returned as UTF-8 (may or mayn not already be UTF-8)
- * - also takes care of "moot padding" (pre-mature zero termination)
- * - propertyExists: it is important to know if there as an existing, non zero property
- * even (in the event of serverMode) it is not actually returned, but an empty string instead.
- */
-static std::string nativePropertyToUTF8 ( XMP_StringPtr cstring, XMP_StringLen maxSize, bool* propertyExists )
-{
- // the value might be properly 0-terminated, prematurely or not
- // at all, hence scan through to find actual size
- XMP_StringLen size = 0;
- for ( size = 0; size < maxSize; size++ )
- {
- if ( cstring[size] == 0 )
- break;
- }
-
- (*propertyExists) = ( size > 0 );
-
- std::string utf8("");
- if ( ReconcileUtils::IsUTF8( cstring, size ) )
- utf8 = std::string( cstring, size ); //use utf8 directly
- else
- {
- if ( ! ignoreLocalText )
- {
- #if ! UNIX_ENV // n/a anyway, since always ignoreLocalText on Unix
- ReconcileUtils::LocalToUTF8( cstring, size, &utf8 );
- #endif
- }
- }
- return utf8;
-}
-
-// reads maxSize bytes from file (not "up to", exactly fullSize)
-// puts it into a string, sets respective tree property
-static std::string getBextField ( const char* data, XMP_Uns32 offset, XMP_Uns32 maxSize )
-{
- if (data == 0)
- XMP_Throw ( "getBextField: null data pointer", kXMPErr_BadParam );
- if ( maxSize == 0)
- XMP_Throw ( "getBextField: maxSize must be greater than 0", kXMPErr_BadParam );
-
- std::string r;
- convertToASCII( data+offset, maxSize, &r, maxSize );
- return r;
-}
-
-static void importBextChunkToXMP( RIFF_MetaHandler* handler, ValueChunk* bextChunk )
-{
- // if there's a bext chunk, there is data...
- handler->containsXMP = true; // very important for treatment on caller level
-
- XMP_Enforce( bextChunk->oldSize >= MIN_BEXT_SIZE );
- XMP_Enforce( bextChunk->oldSize < MAX_BEXT_SIZE );
-
- const char* data = bextChunk->oldValue.data();
- std::string value;
-
- // register bext namespace:
- SXMPMeta::RegisterNamespace( kXMP_NS_BWF, "bext:", 0 );
-
- // bextDescription ------------------------------------------------
- value = getBextField( data, 0, 256 );
- if ( value.size() > 0 )
- handler->xmpObj.SetProperty( bextDescription.ns, bextDescription.prop, value.c_str() );
-
- // bextOriginator -------------------------------------------------
- value = getBextField( data, 256, 32 );
- if ( value.size() > 0 )
- handler->xmpObj.SetProperty( bextOriginator.ns , bextOriginator.prop, value.c_str() );
-
- // bextOriginatorRef ----------------------------------------------
- value = getBextField( data, 256+32, 32 );
- if ( value.size() > 0 )
- handler->xmpObj.SetProperty( bextOriginatorRef.ns , bextOriginatorRef.prop, value.c_str() );
-
- // bextOriginationDate --------------------------------------------
- value = getBextField( data, 256+32+32, 10 );
- if ( value.size() > 0 )
- handler->xmpObj.SetProperty( bextOriginationDate.ns , bextOriginationDate.prop, value.c_str() );
-
- // bextOriginationTime --------------------------------------------
- value = getBextField( data, 256+32+32+10, 8 );
- if ( value.size() > 0 )
- handler->xmpObj.SetProperty( bextOriginationTime.ns , bextOriginationTime.prop, value.c_str() );
-
- // bextTimeReference ----------------------------------------------
- // thanx to nice byte order, all 8 bytes can be read as one:
- XMP_Uns64 timeReferenceFull = GetUns64LE( &(data[256+32+32+10+8 ] ) );
- value.erase();
- SXMPUtils::ConvertFromInt64( timeReferenceFull, "%llu", &value );
- handler->xmpObj.SetProperty( bextTimeReference.ns, bextTimeReference.prop, value );
-
- // bextVersion ----------------------------------------------------
- XMP_Uns16 bwfVersion = GetUns16LE( &(data[256+32+32+10+8+8] ) );
- value.erase();
- SXMPUtils::ConvertFromInt( bwfVersion, "", &value );
- handler->xmpObj.SetProperty( bextVersion.ns, bextVersion.prop, value );
-
- // bextUMID -------------------------------------------------------
- // binary string is already in memory, must convert to hex string
- std::string umidString;
- bool allZero = EncodeToHexString( &(data[256+32+32+10+8+8+2]), 64, &umidString );
- if (! allZero )
- handler->xmpObj.SetProperty( bextUMID.ns, bextUMID.prop, umidString );
-
- // bextCodingHistory ----------------------------------------------
- bool hasCodingHistory = bextChunk->oldSize > MIN_BEXT_SIZE;
-
- if ( hasCodingHistory )
- {
- XMP_StringLen codingHistorySize = (XMP_StringLen) (bextChunk->oldSize - MIN_BEXT_SIZE);
- std::string codingHistory;
- convertToASCII( &data[MIN_BEXT_SIZE-8], codingHistorySize, &codingHistory, codingHistorySize );
- if (! codingHistory.empty() )
- handler->xmpObj.SetProperty( bextCodingHistory.ns, bextCodingHistory.prop, codingHistory );
- }
-} // importBextChunkToXMP
-
-static void importPrmLToXMP( RIFF_MetaHandler* handler, ValueChunk* prmlChunk )
-{
- bool haveXMP = false;
-
- XMP_Enforce( prmlChunk->oldSize == PRML_SIZE );
- PrmLBoxContent rawPrmL;
- XMP_Assert ( sizeof ( rawPrmL ) == PRML_SIZE - 8 ); // double check tight packing.
- XMP_Assert ( sizeof ( rawPrmL.filePath ) == 260 );
- memcpy ( &rawPrmL, prmlChunk->oldValue.data(), sizeof (rawPrmL) );
-
- if ( rawPrmL.magic != 0xBEEFCAFE ) {
- Flip4 ( &rawPrmL.exportType ); // The only numeric field that we care about.
- }
-
- rawPrmL.filePath[259] = 0; // Ensure a terminating nul.
- if ( rawPrmL.filePath[0] != 0 ) {
- if ( rawPrmL.filePath[0] == '/' ) {
- haveXMP = true;
- handler->xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom",
- kXMP_NS_CreatorAtom, "posixProjectPath", rawPrmL.filePath );
- } else if ( XMP_LitNMatch ( rawPrmL.filePath, "\\\\?\\", 4 ) ) {
- haveXMP = true;
- handler->xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom",
- kXMP_NS_CreatorAtom, "uncProjectPath", rawPrmL.filePath );
- }
- }
-
- const char * exportStr = 0;
- switch ( rawPrmL.exportType ) {
- case kExportTypeMovie : exportStr = "movie"; break;
- case kExportTypeStill : exportStr = "still"; break;
- case kExportTypeAudio : exportStr = "audio"; break;
- case kExportTypeCustom : exportStr = "custom"; break;
- }
- if ( exportStr != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetStructField ( kXMP_NS_DM, "projectRef", kXMP_NS_DM, "type", exportStr );
- }
-
- handler->containsXMP |= haveXMP; // mind the '|='
-} // importCr8rToXMP
-
-static void importCr8rToXMP( RIFF_MetaHandler* handler, ValueChunk* cr8rChunk )
-{
- bool haveXMP = false;
-
- XMP_Enforce( cr8rChunk->oldSize == CR8R_SIZE );
- Cr8rBoxContent rawCr8r;
- XMP_Assert ( sizeof ( rawCr8r ) == CR8R_SIZE - 8 ); // double check tight packing.
- memcpy ( &rawCr8r, cr8rChunk->oldValue.data(), sizeof (rawCr8r) );
-
- if ( rawCr8r.magic != 0xBEEFCAFE ) {
- Flip4 ( &rawCr8r.creatorCode ); // The only numeric fields that we care about.
- Flip4 ( &rawCr8r.appleEvent );
- }
-
- std::string fieldPath;
-
- SXMPUtils::ComposeStructFieldPath ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &fieldPath );
- if ( rawCr8r.creatorCode != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetProperty_Int64 ( kXMP_NS_CreatorAtom, fieldPath.c_str(), (XMP_Int64)rawCr8r.creatorCode ); // ! Unsigned trickery.
- }
-
- SXMPUtils::ComposeStructFieldPath ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &fieldPath );
- if ( rawCr8r.appleEvent != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetProperty_Int64 ( kXMP_NS_CreatorAtom, fieldPath.c_str(), (XMP_Int64)rawCr8r.appleEvent ); // ! Unsigned trickery.
- }
-
- rawCr8r.fileExt[15] = 0; // Ensure a terminating nul.
- if ( rawCr8r.fileExt[0] != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", rawCr8r.fileExt );
- }
-
- rawCr8r.appOptions[15] = 0; // Ensure a terminating nul.
- if ( rawCr8r.appOptions[0] != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", rawCr8r.appOptions );
- }
-
- rawCr8r.appName[31] = 0; // Ensure a terminating nul.
- if ( rawCr8r.appName[0] != 0 ) {
- haveXMP = true;
- handler->xmpObj.SetProperty ( kXMP_NS_XMP, "CreatorTool", rawCr8r.appName );
- }
-
- handler->containsXMP |= haveXMP; // mind the '|='
-} // importCr8rToXMP
-
-
-static void importListChunkToXMP( RIFF_MetaHandler* handler, ContainerChunk* listChunk, Mapping mapping[], bool xmpHasPriority )
-{
- valueMap* cm = &listChunk->childmap;
- for (int p=0; mapping[p].chunkID != 0; p++) // go through legacy chunks
- {
- valueMapIter result = cm->find(mapping[p].chunkID);
- if( result != cm->end() ) // if value found
- {
- ValueChunk* propChunk = result->second;
-
- bool propertyExists = false;
- std::string utf8 = nativePropertyToUTF8(
- propChunk->oldValue.c_str(),
- (XMP_StringLen)propChunk->oldValue.size(), &propertyExists );
-
- if ( utf8.size() > 0 ) // if property is not-empty, set Property
- {
- switch ( mapping[p].propType )
- {
- case prop_TIMEVALUE:
- if ( xmpHasPriority &&
- handler->xmpObj.DoesStructFieldExist( mapping[p].ns, mapping[p].prop, kXMP_NS_DM, "timeValue" ))
- break; // skip if XMP has precedence and exists
- handler->xmpObj.SetStructField( mapping[p].ns, mapping[p].prop,
- kXMP_NS_DM, "timeValue", utf8.c_str() );
- break;
- case prop_LOCALIZED_TEXT:
- if ( xmpHasPriority && handler->xmpObj.GetLocalizedText( mapping[p].ns ,
- mapping[p].prop, "" , "x-default", 0, 0, 0 ))
- break; // skip if XMP has precedence and exists
- handler->xmpObj.SetLocalizedText( mapping[p].ns , mapping[p].prop,
- "" , "x-default" , utf8.c_str() );
- if ( mapping[p].chunkID == kPropChunkINAM )
- handler->hasListInfoINAM = true; // needs to be known for special 3-way merge around dc:title
- break;
- case prop_ARRAYITEM:
- if ( xmpHasPriority &&
- handler->xmpObj.DoesArrayItemExist( mapping[p].ns, mapping[p].prop, 1 ))
- break; // skip if XMP has precedence and exists
- handler->xmpObj.DeleteProperty( mapping[p].ns, mapping[p].prop );
- handler->xmpObj.AppendArrayItem( mapping[p].ns, mapping[p].prop, kXMP_PropValueIsArray, utf8.c_str(), kXMP_NoOptions );
- break;
- case prop_SIMPLE:
- if ( xmpHasPriority &&
- handler->xmpObj.DoesPropertyExist( mapping[p].ns, mapping[p].prop ))
- break; // skip if XMP has precedence and exists
- handler->xmpObj.SetProperty( mapping[p].ns, mapping[p].prop, utf8.c_str() );
- break;
- default:
- XMP_Throw( "internal error" , kXMPErr_InternalFailure );
- }
-
- handler->containsXMP = true; // very important for treatment on caller level
- }
- else if ( ! propertyExists) // otherwise remove it.
- { // [2389942] don't, if legacy value is existing but non-retrievable (due to server mode)
- switch ( mapping[p].propType )
- {
- case prop_TIMEVALUE:
- if ( (!xmpHasPriority) && // forward deletion only if XMP has no priority
- handler->xmpObj.DoesPropertyExist( mapping[p].ns, mapping[p].prop ))
- handler->xmpObj.DeleteProperty( mapping[p].ns, mapping[p].prop );
- break;
- case prop_LOCALIZED_TEXT:
- if ( (!xmpHasPriority) && // forward deletion only if XMP has no priority
- handler->xmpObj.DoesPropertyExist( mapping[p].ns, mapping[p].prop ))
- handler->xmpObj.DeleteLocalizedText( mapping[p].ns, mapping[p].prop, "", "x-default" );
- break;
- case prop_ARRAYITEM:
- case prop_SIMPLE:
- if ( (!xmpHasPriority) && // forward deletion only if XMP has no priority
- handler->xmpObj.DoesPropertyExist( mapping[p].ns, mapping[p].prop ))
- handler->xmpObj.DeleteProperty( mapping[p].ns, mapping[p].prop );
- break;
- default:
- XMP_Throw( "internal error" , kXMPErr_InternalFailure );
- }
- }
- }
- } // for
-}
-void importProperties( RIFF_MetaHandler* handler )
-{
- bool hasDigest = handler->xmpObj.GetProperty( kXMP_NS_WAV, "NativeDigest", NULL , NULL );
- if ( hasDigest )
- {
- // remove! since it now becomse a 'new' handler file
- handler->xmpObj.DeleteProperty( kXMP_NS_WAV, "NativeDigest" );
- }
-
- // BWF Bext extension chunk -----------------------------------------------
- if ( handler->parent->format == kXMP_WAVFile && // applies only to WAV
- handler->bextChunk != 0 ) //skip if no BEXT chunk found.
- {
- importBextChunkToXMP( handler, handler->bextChunk );
- }
-
- // PrmL chunk --------------------------------------------------------------
- if ( handler->prmlChunk != 0 && handler->prmlChunk->oldSize == PRML_SIZE )
- {
- importPrmLToXMP( handler, handler->prmlChunk );
- }
-
- // Cr8r chunk --------------------------------------------------------------
- if ( handler->cr8rChunk != 0 && handler->cr8rChunk->oldSize == CR8R_SIZE )
- {
- importCr8rToXMP( handler, handler->cr8rChunk );
- }
-
- // LIST:INFO --------------------------------------------------------------
- if ( handler->listInfoChunk != 0) //skip if no LIST:INFO chunk found.
- importListChunkToXMP( handler, handler->listInfoChunk, listInfoProps, hasDigest );
-
- // LIST:Tdat --------------------------------------------------------------
- if ( handler->listTdatChunk != 0)
- importListChunkToXMP( handler, handler->listTdatChunk, listTdatProps, hasDigest );
-
- // DISP (do last, higher priority than INAM ) -----------------------------
- bool takeXMP = false; // assume for now
- if ( hasDigest )
- {
- std::string actualLang, value;
- bool r = handler->xmpObj.GetLocalizedText( kXMP_NS_DC, "title", "" , "x-default" , &actualLang, &value, NULL );
- if ( r && (actualLang == "x-default") ) takeXMP = true;
- }
-
- if ( (!takeXMP) && handler->dispChunk != 0) //skip if no LIST:INFO chunk found.
- {
- std::string* value = &handler->dispChunk->oldValue;
- if ( value->size() >= 4 ) // ignore contents if file too small
- {
- XMP_StringPtr cstring = value->c_str();
- XMP_StringLen size = (XMP_StringLen) value->size();
-
- size -= 4; // skip first four bytes known to contain constant
- cstring += 4;
-
- bool propertyExists = false;
- std::string utf8 = nativePropertyToUTF8( cstring, size, &propertyExists );
-
- if ( utf8.size() > 0 )
- {
- handler->xmpObj.SetLocalizedText( kXMP_NS_DC, "title", "" , "x-default" , utf8.c_str() );
- handler->containsXMP = true; // very important for treatment on caller level
- }
- else
- {
- // found as part of [2389942]
- // forward deletion may only happen if no LIST:INFO/INAM is present:
- if ( ! handler->hasListInfoINAM &&
- ! propertyExists ) // ..[2389942]part2: and if truly no legacy property
- { // (not just an unreadable one due to ServerMode).
- handler->xmpObj.DeleteProperty( kXMP_NS_DC, "title" );
- }
- }
- } // if size sufficient
- } // handler->dispChunk
-
-} // importProperties
-
-////////////////////////////////////////////////////////////////////////////////
-// EXPORT
-////////////////////////////////////////////////////////////////////////////////
-
-void relocateWronglyPlacedXMPChunk( RIFF_MetaHandler* handler )
-{
- LFA_FileRef file = handler->parent->fileRef;
- RIFF::containerVect *rc = &handler->riffChunks;
- RIFF::ContainerChunk* lastChunk = rc->at( rc->size()-1 );
-
- // 1) XMPPacket
- // needChunk exists but is not in lastChunk ?
- if (
- handler->xmpChunk != 0 && // XMP Chunk existing?
- (XMP_Uns32)rc->size() > 1 && // more than 1 top-level chunk (otherwise pointless)
- lastChunk->getChild( handler->xmpChunk ) == lastChunk->children.end() // not already in last chunk?
- )
- {
- RIFF::ContainerChunk* cur;
- chunkVectIter child;
- XMP_Int32 chunkNo;
-
- // find and relocate to last chunk:
- for ( chunkNo = (XMP_Int32)rc->size()-2 ; chunkNo >= 0; chunkNo-- ) // ==> start with second-last chunk
- {
- cur = rc->at(chunkNo);
- child = cur->getChild( handler->xmpChunk );
- if ( child != cur->children.end() ) // found?
- break;
- } // for
-
- if ( chunkNo < 0 ) // already in place? nothing left to do.
- return;
-
- lastChunk->children.push_back( *child ); // nb: order matters!
- cur->replaceChildWithJunk( *child, false );
- cur->hasChange = true; // [2414649] initialize early-on i.e: here
- } // if
-} // relocateWronglyPlacedXMPChunk
-
-// writes to buffer up to max size,
-// 0 termination only if shorter than maxSize
-// converts down to ascii
-static void setBextField ( std::string* value, XMP_Uns8* data, XMP_Uns32 offset, XMP_Uns32 maxSize )
-{
- XMP_Validate( value != 0, "setBextField: null value string pointer", kXMPErr_BadParam );
- XMP_Validate( data != 0, "setBextField: null data value", kXMPErr_BadParam );
- XMP_Validate( maxSize > 0, "setBextField: maxSize must be greater than 0", kXMPErr_BadParam );
-
- std::string ascii;
- XMP_StringLen actualSize = convertToASCII( value->data(), (XMP_StringLen) value->size() , &ascii , maxSize );
- strncpy( (char*)(data + offset), ascii.data(), actualSize );
-}
-
-// add bwf-bext related data to bext chunk, create if not existing yet.
-// * in fact, since bext is fully fixed and known, there can be no unknown subchunks worth keeping:
-// * prepare bext chunk in buffer
-// * value changed/created if needed only, otherways remove chunk
-// * remove bext-mapped properties from xmp (non-redundant storage)
-// note: ValueChunk**: adress of pointer to allow changing the pointer itself (i.e. chunk creation)
-static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextChunk )
-{
- // register bext namespace ( if there was no import, this is news, otherwise harmless moot)
- SXMPMeta::RegisterNamespace( kXMP_NS_BWF, "bext:", 0 );
-
- bool chunkUsed = false; // assume for now
- SXMPMeta* xmp = &handler->xmpObj;
-
- // prepare buffer, need to know CodingHistory size as the only variable
- XMP_Int32 bextBufferSize = MIN_BEXT_SIZE - 8; // -8 because of header
- std::string value;
- if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, kXMP_NoOptions ))
- {
- bextBufferSize += ((XMP_StringLen)value.size()) + 1 ; // add to size (and a trailing zero)
- }
-
- // create and clear buffer
- XMP_Uns8* buffer = new XMP_Uns8[bextBufferSize];
- for (XMP_Int32 i = 0; i < bextBufferSize; i++ )
- buffer[i] = 0;
-
- // grab props, write into buffer, remove from XMP ///////////////////////////
- // bextDescription ------------------------------------------------
- if ( xmp->GetProperty( bextDescription.ns, bextDescription.prop, &value, kXMP_NoOptions ) )
- {
- setBextField( &value, (XMP_Uns8*) buffer, 0, 256 );
- xmp->DeleteProperty( bextDescription.ns, bextDescription.prop) ;
- chunkUsed = true;
- }
- // bextOriginator -------------------------------------------------
- if ( xmp->GetProperty( bextOriginator.ns , bextOriginator.prop, &value, kXMP_NoOptions ) )
- {
- setBextField( &value, (XMP_Uns8*) buffer, 256, 32 );
- xmp->DeleteProperty( bextOriginator.ns , bextOriginator.prop );
- chunkUsed = true;
- }
- // bextOriginatorRef ----------------------------------------------
- if ( xmp->GetProperty( bextOriginatorRef.ns , bextOriginatorRef.prop, &value, kXMP_NoOptions ) )
- {
- setBextField( &value, (XMP_Uns8*) buffer, 256+32, 32 );
- xmp->DeleteProperty( bextOriginatorRef.ns , bextOriginatorRef.prop );
- chunkUsed = true;
- }
- // bextOriginationDate --------------------------------------------
- if ( xmp->GetProperty( bextOriginationDate.ns , bextOriginationDate.prop, &value, kXMP_NoOptions ) )
- {
- setBextField( &value, (XMP_Uns8*) buffer, 256+32+32, 10 );
- xmp->DeleteProperty( bextOriginationDate.ns , bextOriginationDate.prop );
- chunkUsed = true;
- }
- // bextOriginationTime --------------------------------------------
- if ( xmp->GetProperty( bextOriginationTime.ns , bextOriginationTime.prop, &value, kXMP_NoOptions ) )
- {
- setBextField( &value, (XMP_Uns8*) buffer, 256+32+32+10, 8 );
- xmp->DeleteProperty( bextOriginationTime.ns , bextOriginationTime.prop );
- chunkUsed = true;
- }
- // bextTimeReference ----------------------------------------------
- // thanx to friendly byte order, all 8 bytes can be written in one go:
- if ( xmp->GetProperty( bextTimeReference.ns, bextTimeReference.prop, &value, kXMP_NoOptions ) )
- {
- try
- {
- XMP_Int64 v = SXMPUtils::ConvertToInt64( value.c_str() );
- PutUns64LE( v, &(buffer[256+32+32+10+8] ));
- chunkUsed = true;
- }
- catch (XMP_Error& e)
- {
- if ( e.GetID() != kXMPErr_BadParam )
- throw e; // re-throw on any other error
- } // 'else' tolerate ( time reference remains 0x00000000 )
- // valid or not, do not store redundantly:
- xmp->DeleteProperty( bextTimeReference.ns, bextTimeReference.prop );
- }
-
- // bextVersion ----------------------------------------------------
- // set version=1, no matter what.
- PutUns16LE( 1, &(buffer[256+32+32+10+8+8]) );
- xmp->DeleteProperty( bextVersion.ns, bextVersion.prop );
-
- // bextUMID -------------------------------------------------------
- if ( xmp->GetProperty( bextUMID.ns, bextUMID.prop, &value, kXMP_NoOptions ) )
- {
- std::string rawStr;
-
- if ( !DecodeFromHexString( value.data(), (XMP_StringLen) value.size(), &rawStr ) )
- {
- delete [] buffer; // important.
- XMP_Throw ( "EncodeFromHexString: illegal umid string. Must contain an even number of 0-9 and uppercase A-F chars.", kXMPErr_BadParam );
- }
-
- // if UMID is smaller/longer than 64 byte for any reason,
- // truncate/do a partial write (just like for any other bext property)
-
- memcpy( (char*) &(buffer[256+32+32+10+8+8+2]), rawStr.data(), MIN( 64, rawStr.size() ) );
- xmp->DeleteProperty( bextUMID.ns, bextUMID.prop );
- chunkUsed = true;
- }
-
- // bextCodingHistory ----------------------------------------------
- if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, kXMP_NoOptions ) )
- {
- std::string ascii;
- convertToASCII( value.data(), (XMP_StringLen) value.size() , &ascii, (XMP_StringLen) value.size() );
- strncpy( (char*) &(buffer[MIN_BEXT_SIZE-8]), ascii.data(), ascii.size() );
- xmp->DeleteProperty( bextCodingHistory.ns, bextCodingHistory.prop );
- chunkUsed = true;
- }
-
- // always delete old, recreate if needed
- if ( *bextChunk != 0 )
- {
- (*bextChunk)->parent->replaceChildWithJunk( *bextChunk );
- (*bextChunk) = 0; // clear direct Chunk pointer
- }
-
- if ( chunkUsed)
- *bextChunk = new ValueChunk( handler->riffChunks.at(0), std::string( (char*)buffer, bextBufferSize ), kChunk_bext );
-
- delete [] buffer; // important.
-}
-
-static inline void SetBufferedString ( char * dest, const std::string source, size_t limit )
-{
- memset ( dest, 0, limit );
- size_t count = source.size();
- if ( count >= limit ) count = limit - 1; // Ensure a terminating nul.
- memcpy ( dest, source.c_str(), count );
-}
-
-static void exportXMPtoCr8rChunk ( RIFF_MetaHandler* handler, ValueChunk** cr8rChunk )
-{
- const SXMPMeta & xmp = handler->xmpObj;
-
- // Make sure an existing Cr8r chunk has the proper fixed length.
- bool haveOldCr8r = (*cr8rChunk != 0);
- if ( haveOldCr8r && ((*cr8rChunk)->oldSize != sizeof(Cr8rBoxContent)+8) ) {
- (*cr8rChunk)->parent->replaceChildWithJunk ( *cr8rChunk ); // Wrong length, the existing chunk must be bad.
- (*cr8rChunk) = 0;
- haveOldCr8r = false;
- }
-
- bool haveNewCr8r = false;
- std::string creatorCode, appleEvent, fileExt, appOptions, appName;
-
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &creatorCode, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &appleEvent, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", &fileExt, 0 );
- haveNewCr8r |= xmp.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", &appOptions, 0 );
- haveNewCr8r |= xmp.GetProperty ( kXMP_NS_XMP, "CreatorTool", &appName, 0 );
-
- if ( ! haveNewCr8r ) { // Get rid of an existing Cr8r chunk if there is no new XMP.
- if ( haveOldCr8r ) {
- (*cr8rChunk)->parent->replaceChildWithJunk ( *cr8rChunk );
- *cr8rChunk = 0;
- }
- return;
- }
-
- if ( ! haveOldCr8r ) {
- *cr8rChunk = new ValueChunk ( handler->lastChunk, std::string(), kChunk_Cr8r );
- }
-
- std::string strValue;
- strValue.assign ( (sizeof(Cr8rBoxContent) - 1), '\0' ); // ! Use size-1 because SetValue appends a trailing 0 byte.
- (*cr8rChunk)->SetValue ( strValue ); // ! Just get the space available.
- XMP_Assert ( (*cr8rChunk)->newValue.size() == sizeof(Cr8rBoxContent) );
- (*cr8rChunk)->hasChange = true;
-
- Cr8rBoxContent * newCr8r = (Cr8rBoxContent*) (*cr8rChunk)->newValue.data();
-
- if ( ! haveOldCr8r ) {
-
- newCr8r->magic = MakeUns32LE ( 0xBEEFCAFE );
- newCr8r->size = MakeUns32LE ( sizeof(Cr8rBoxContent) );
- newCr8r->majorVer = MakeUns16LE ( 1 );
-
- } else {
-
- const Cr8rBoxContent * oldCr8r = (Cr8rBoxContent*) (*cr8rChunk)->oldValue.data();
- memcpy ( newCr8r, oldCr8r, sizeof(Cr8rBoxContent) );
- if ( GetUns32LE ( &newCr8r->magic ) != 0xBEEFCAFE ) { // Make sure we write LE numbers.
- Flip4 ( &newCr8r->magic );
- Flip4 ( &newCr8r->size );
- Flip2 ( &newCr8r->majorVer );
- Flip2 ( &newCr8r->minorVer );
- Flip4 ( &newCr8r->creatorCode );
- Flip4 ( &newCr8r->appleEvent );
- }
-
- }
-
- if ( ! creatorCode.empty() ) {
- newCr8r->creatorCode = MakeUns32LE ( (XMP_Uns32) strtoul ( creatorCode.c_str(), 0, 0 ) );
- }
-
- if ( ! appleEvent.empty() ) {
- newCr8r->appleEvent = MakeUns32LE ( (XMP_Uns32) strtoul ( appleEvent.c_str(), 0, 0 ) );
- }
-
- if ( ! fileExt.empty() ) SetBufferedString ( newCr8r->fileExt, fileExt, sizeof ( newCr8r->fileExt ) );
- if ( ! appOptions.empty() ) SetBufferedString ( newCr8r->appOptions, appOptions, sizeof ( newCr8r->appOptions ) );
- if ( ! appName.empty() ) SetBufferedString ( newCr8r->appName, appName, sizeof ( newCr8r->appName ) );
-
-}
-
-static void exportXMPtoListChunk( XMP_Uns32 id, XMP_Uns32 containerType,
- RIFF_MetaHandler* handler, ContainerChunk** listChunk, Mapping mapping[])
-{
- // note: ContainerChunk**: adress of pointer to allow changing the pointer itself (i.e. chunk creation)
- SXMPMeta* xmp = &handler->xmpObj;
- bool listChunkIsNeeded = false; // assume for now
-
- // ! The NUL is optional in WAV to avoid a parsing bug in Audition 3 - can't handle implicit pad byte.
- bool optionalNUL = (handler->parent->format == kXMP_WAVFile);
-
- for ( int p=0; mapping[p].chunkID != 0; ++p ) { // go through all potential property mappings
-
- bool propExists = false;
- std::string value, actualLang;
-
- switch ( mapping[p].propType ) {
-
- // get property. if existing, remove from XMP (to avoid redundant storage)
- case prop_TIMEVALUE:
- propExists = xmp->GetStructField ( mapping[p].ns, mapping[p].prop, kXMP_NS_DM, "timeValue", &value, 0 );
- break;
-
- case prop_LOCALIZED_TEXT:
- propExists = xmp->GetLocalizedText ( mapping[p].ns, mapping[p].prop, "", "x-default", &actualLang, &value, 0);
- if ( actualLang != "x-default" ) propExists = false; // no "x-default" => nothing to reconcile !
- break;
-
- case prop_ARRAYITEM:
- propExists = xmp->GetArrayItem ( mapping[p].ns, mapping[p].prop, 1, &value, 0 );
- break;
-
- case prop_SIMPLE:
- propExists = xmp->GetProperty ( mapping[p].ns, mapping[p].prop, &value, 0 );
- break;
-
- default:
- XMP_Throw ( "internal error", kXMPErr_InternalFailure );
-
- }
-
- if ( ! propExists ) {
-
- if ( *listChunk != 0 ) (*listChunk)->removeValue ( mapping[p].chunkID );
-
- } else {
-
- listChunkIsNeeded = true;
- if ( *listChunk == 0 ) *listChunk = new ContainerChunk ( handler->riffChunks[0], id, containerType );
-
- valueMap* cm = &(*listChunk)->childmap;
- valueMapIter result = cm->find( mapping[p].chunkID );
- ValueChunk* propChunk = 0;
-
- if ( result != cm->end() ) {
- propChunk = result->second;
- } else {
- propChunk = new ValueChunk ( *listChunk, std::string(), mapping[p].chunkID );
- }
-
- propChunk->SetValue ( value.c_str(), optionalNUL );
-
- }
-
- } // for each property
-
- if ( (! listChunkIsNeeded) && (*listChunk != 0) && ((*listChunk)->children.size() == 0) ) {
- (*listChunk)->parent->replaceChildWithJunk ( *listChunk );
- (*listChunk) = 0; // reset direct Chunk pointer
- }
-
-}
-
-void exportAndRemoveProperties ( RIFF_MetaHandler* handler )
-{
- SXMPMeta xmpObj = handler->xmpObj;
-
- exportXMPtoCr8rChunk ( handler, &handler->cr8rChunk );
-
- // 1/4 BWF Bext extension chunk -----------------------------------------------
- if ( handler->parent->format == kXMP_WAVFile ) { // applies only to WAV
- exportXMPtoBextChunk ( handler, &handler->bextChunk );
- }
-
- // 2/4 DISP chunk
- if ( handler->parent->format == kXMP_WAVFile ) { // create for WAVE only
-
- std::string actualLang, xmpValue;
- bool r = xmpObj.GetLocalizedText ( kXMP_NS_DC, "title", "" , "x-default" , &actualLang, &xmpValue, 0 );
-
- if ( r && ( actualLang == "x-default" ) ) { // prop exists?
-
- // the 'right' DISP is lead by a 32 bit low endian 0x0001
- std::string dispValue = std::string( "\x1\0\0\0", 4 );
- dispValue.append ( xmpValue );
-
- if ( handler->dispChunk == 0 ) {
- handler->dispChunk = new RIFF::ValueChunk ( handler->riffChunks.at(0), std::string(), kChunk_DISP );
- }
-
- // ! The NUL is optional in WAV to avoid a parsing bug in Audition 3 - can't handle implicit pad byte.
- handler->dispChunk->SetValue ( dispValue, ValueChunk::kNULisOptional );
-
- } else { // remove Disp Chunk..
-
- if ( handler->dispChunk != 0 ) { // ..if existing
- ContainerChunk* mainChunk = handler->riffChunks.at(0);
- Chunk* needle = handler->dispChunk;
- chunkVectIter iter = mainChunk->getChild ( needle );
- if ( iter != mainChunk->children.end() ) {
- mainChunk->replaceChildWithJunk ( *iter );
- handler->dispChunk = 0;
- mainChunk->hasChange = true;
- }
- }
-
- }
-
- }
-
- // 3/4 LIST:INFO
- exportXMPtoListChunk ( kChunk_LIST, kType_INFO, handler, &handler->listInfoChunk, listInfoProps );
-
- // 4/4 LIST:Tdat
- exportXMPtoListChunk ( kChunk_LIST, kType_Tdat, handler, &handler->listTdatChunk, listTdatProps );
-
-}
-
-} // namespace RIFF
diff --git a/source/XMPFiles/FormatSupport/RIFF_Support.hpp b/source/XMPFiles/FormatSupport/RIFF_Support.hpp
deleted file mode 100644
index a0b972b..0000000
--- a/source/XMPFiles/FormatSupport/RIFF_Support.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __RIFF_Support_hpp__
-#define __RIFF_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2009 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include <vector>
-#include "XMPFiles_Impl.hpp"
-
-// ahead declaration:
-class RIFF_MetaHandler;
-
-namespace RIFF {
-
- // declare ahead
- class Chunk;
- class ContainerChunk;
- class ValueChunk;
- class XMPChunk;
-
- /* This rountines imports the properties found into the
- xmp packet. Use after parsing. */
- void importProperties( RIFF_MetaHandler* handler );
-
- /* This rountines exports XMP properties to the respective Chunks,
- creating those if needed. No writing to file here. */
- void exportAndRemoveProperties( RIFF_MetaHandler* handler );
-
- /* will relocated a wrongly placed chunk (one of XMP, LIST:Info, LIST:Tdat=
- from RIFF::avix back to main chunk. Chunk itself not touched. */
- void relocateWronglyPlacedXMPChunk( RIFF_MetaHandler* handler );
-
-} // namespace RIFF
-
-#endif // __RIFF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp b/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp
deleted file mode 100644
index bef1b11..0000000
--- a/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp
+++ /dev/null
@@ -1,855 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "Reconcile_Impl.hpp"
-
-#include <stdio.h>
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-// =================================================================================================
-/// \file ReconcileIPTC.cpp
-/// \brief Utilities to reconcile between XMP and legacy IPTC and PSIR metadata.
-///
-// =================================================================================================
-
-// =================================================================================================
-// NormalizeToCR
-// =============
-
-static inline void NormalizeToCR ( std::string * value )
-{
- char * strPtr = (char*) value->data();
- char * strEnd = strPtr + value->size();
-
- for ( ; strPtr < strEnd; ++strPtr ) {
- if ( *strPtr == kLF ) *strPtr = kCR;
- }
-
-} // NormalizeToCR
-
-// =================================================================================================
-// NormalizeToLF
-// =============
-
-static inline void NormalizeToLF ( std::string * value )
-{
- char * strPtr = (char*) value->data();
- char * strEnd = strPtr + value->size();
-
- for ( ; strPtr < strEnd; ++strPtr ) {
- if ( *strPtr == kCR ) *strPtr = kLF;
- }
-
-} // NormalizeToLF
-
-// =================================================================================================
-// ComputeIPTCDigest
-// =================
-//
-// Compute a 128 bit (16 byte) MD5 digest of the full IPTC block.
-
-static inline void ComputeIPTCDigest ( const void * iptcPtr, const XMP_Uns32 iptcLen, MD5_Digest * digest )
-{
- MD5_CTX context;
-
- MD5Init ( &context );
- MD5Update ( &context, (XMP_Uns8*)iptcPtr, iptcLen );
- MD5Final ( *digest, &context );
-
-} // ComputeIPTCDigest;
-
-// =================================================================================================
-// PhotoDataUtils::CheckIPTCDigest
-// ===============================
-
-int PhotoDataUtils::CheckIPTCDigest ( const void * newPtr, const XMP_Uns32 newLen, const void * oldDigest )
-{
- MD5_Digest newDigest;
- ComputeIPTCDigest ( newPtr, newLen, &newDigest );
- if ( memcmp ( &newDigest, oldDigest, 16 ) == 0 ) return kDigestMatches;
- return kDigestDiffers;
-
-} // PhotoDataUtils::CheckIPTCDigest
-
-// =================================================================================================
-// PhotoDataUtils::SetIPTCDigest
-// =============================
-
-void PhotoDataUtils::SetIPTCDigest ( void * iptcPtr, XMP_Uns32 iptcLen, PSIR_Manager * psir )
-{
- MD5_Digest newDigest;
-
- ComputeIPTCDigest ( iptcPtr, iptcLen, &newDigest );
- psir->SetImgRsrc ( kPSIR_IPTCDigest, &newDigest, sizeof(newDigest) );
-
-} // PhotoDataUtils::SetIPTCDigest
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// PhotoDataUtils::ImportIPTC_Simple
-// =================================
-
-void PhotoDataUtils::ImportIPTC_Simple ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
-{
- std::string utf8Str;
- size_t count = iptc.GetDataSet_UTF8 ( id, &utf8Str );
-
- if ( count != 0 ) {
- NormalizeToLF ( &utf8Str );
- xmp->SetProperty ( xmpNS, xmpProp, utf8Str.c_str() );
- }
-
-} // PhotoDataUtils::ImportIPTC_Simple
-
-// =================================================================================================
-// PhotoDataUtils::ImportIPTC_LangAlt
-// ==================================
-
-void PhotoDataUtils::ImportIPTC_LangAlt ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
-{
- std::string utf8Str;
- size_t count = iptc.GetDataSet_UTF8 ( id, &utf8Str );
-
- if ( count != 0 ) {
- NormalizeToLF ( &utf8Str );
- xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", utf8Str.c_str() );
- }
-
-} // PhotoDataUtils::ImportIPTC_LangAlt
-
-// =================================================================================================
-// PhotoDataUtils::ImportIPTC_Array
-// ================================
-
-void PhotoDataUtils::ImportIPTC_Array ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
-{
- std::string utf8Str;
- size_t count = iptc.GetDataSet ( id, 0 );
-
- xmp->DeleteProperty ( xmpNS, xmpProp );
-
- XMP_OptionBits arrayForm = kXMP_PropArrayIsUnordered;
- if ( XMP_LitMatch ( xmpNS, kXMP_NS_DC ) && XMP_LitMatch ( xmpProp, "creator" ) ) arrayForm = kXMP_PropArrayIsOrdered;
-
- for ( size_t ds = 0; ds < count; ++ds ) {
- (void) iptc.GetDataSet_UTF8 ( id, &utf8Str, ds );
- NormalizeToLF ( &utf8Str );
- xmp->AppendArrayItem ( xmpNS, xmpProp, arrayForm, utf8Str.c_str() );
- }
-
-} // PhotoDataUtils::ImportIPTC_Array
-
-// =================================================================================================
-// PhotoDataUtils::ImportIPTC_Date
-// ===============================
-//
-// An IPTC (IIM) date is 8 characters, YYYYMMDD. Include the time portion if it is present. The IPTC
-// time is HHMMSSxHHMM, where 'x' is '+' or '-'. Be tolerant of some ill-formed dates and times.
-// Apparently some non-Adobe apps put strings like "YYYY-MM-DD" or "HH:MM:SSxHH:MM" in the IPTC.
-// Allow a missing time zone portion.
-
-// *** The date/time handling differs from the MWG 1.0.1 policy, following a proposed tweak to MWG:
-// *** Exif DateTimeOriginal <-> XMP exif:DateTimeOriginal
-// *** IPTC DateCreated <-> XMP photoshop:DateCreated
-// *** Exif DateTimeDigitized <-> IPTC DigitalCreateDate <-> XMP xmp:CreateDate
-
-void PhotoDataUtils::ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & iptc, SXMPMeta * xmp )
-{
- XMP_Uns8 timeID;
- XMP_StringPtr xmpNS, xmpProp;
-
- if ( dateID == kIPTC_DateCreated ) {
- timeID = kIPTC_TimeCreated;
- xmpNS = kXMP_NS_Photoshop;
- xmpProp = "DateCreated";
- } else if ( dateID == kIPTC_DigitalCreateDate ) {
- timeID = kIPTC_DigitalCreateTime;
- xmpNS = kXMP_NS_XMP;
- xmpProp = "CreateDate";
- } else {
- XMP_Throw ( "Unrecognized dateID", kXMPErr_BadParam );
- }
-
- // First gather the date portion.
-
- IPTC_Manager::DataSetInfo dsInfo;
- size_t count = iptc.GetDataSet ( dateID, &dsInfo );
- if ( count == 0 ) return;
-
- size_t chPos, digits;
- XMP_DateTime xmpDate;
- memset ( &xmpDate, 0, sizeof(xmpDate) );
-
- chPos = 0;
- for ( digits = 0; digits < 4; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.year = (xmpDate.year * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
-
- if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.month = (xmpDate.month * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.month < 1 ) xmpDate.month = 1;
- if ( xmpDate.month > 12 ) xmpDate.month = 12;
-
- if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.day = (xmpDate.day * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.day < 1 ) xmpDate.day = 1;
- if ( xmpDate.day > 31 ) xmpDate.day = 28; // Close enough.
-
- if ( chPos != dsInfo.dataLen ) return; // The DataSet is ill-formed.
- xmpDate.hasDate = true;
-
- // Now add the time portion if present.
-
- count = iptc.GetDataSet ( timeID, &dsInfo );
- if ( count != 0 ) {
-
- chPos = 0;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.hour = (xmpDate.hour * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.hour < 0 ) xmpDate.hour = 0;
- if ( xmpDate.hour > 23 ) xmpDate.hour = 23;
-
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.minute = (xmpDate.minute * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.minute < 0 ) xmpDate.minute = 0;
- if ( xmpDate.minute > 59 ) xmpDate.minute = 59;
-
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.second = (xmpDate.second * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.second < 0 ) xmpDate.second = 0;
- if ( xmpDate.second > 59 ) xmpDate.second = 59;
-
- xmpDate.hasTime = true;
-
- if ( (dsInfo.dataPtr[chPos] != ' ') && (dsInfo.dataPtr[chPos] != 0) ) { // Tolerate a missing TZ.
-
- if ( dsInfo.dataPtr[chPos] == '+' ) {
- xmpDate.tzSign = kXMP_TimeEastOfUTC;
- } else if ( dsInfo.dataPtr[chPos] == '-' ) {
- xmpDate.tzSign = kXMP_TimeWestOfUTC;
- } else if ( chPos != dsInfo.dataLen ) {
- return; // The DataSet is ill-formed.
- }
-
- ++chPos; // Move past the time zone sign.
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.tzHour = (xmpDate.tzHour * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.tzHour < 0 ) xmpDate.tzHour = 0;
- if ( xmpDate.tzHour > 23 ) xmpDate.tzHour = 23;
-
- if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
- for ( digits = 0; digits < 2; ++digits, ++chPos ) {
- if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
- xmpDate.tzMinute = (xmpDate.tzMinute * 10) + (dsInfo.dataPtr[chPos] - '0');
- }
- if ( xmpDate.tzMinute < 0 ) xmpDate.tzMinute = 0;
- if ( xmpDate.tzMinute > 59 ) xmpDate.tzMinute = 59;
-
- if ( chPos != dsInfo.dataLen ) return; // The DataSet is ill-formed.
- xmpDate.hasTimeZone = true;
-
- }
-
- }
-
- // Finally, set the XMP property.
-
- xmp->SetProperty_Date ( xmpNS, xmpProp, xmpDate );
-
-} // PhotoDataUtils::ImportIPTC_Date
-
-// =================================================================================================
-// ImportIPTC_IntellectualGenre
-// ============================
-//
-// Import DataSet 2:04. In the IIM this is a 3 digit number, a colon, and an optional text name.
-// Even though the number is the more formal part, the IPTC4XMP rule is that the name is imported to
-// XMP and the number is dropped. Also, even though IIMv4.1 says that 2:04 is repeatable, the XMP
-// property to which it is mapped is simple.
-
-static void ImportIPTC_IntellectualGenre ( const IPTC_Manager & iptc, SXMPMeta * xmp )
-{
- std::string utf8Str;
- size_t count = iptc.GetDataSet_UTF8 ( kIPTC_IntellectualGenre, &utf8Str );
-
- if ( count == 0 ) return;
- NormalizeToLF ( &utf8Str );
-
- XMP_StringPtr namePtr = utf8Str.c_str() + 4;
-
- if ( utf8Str.size() <= 4 ) {
- // No name in the IIM. Look up the number in our list of known genres.
- int i;
- XMP_StringPtr numPtr = utf8Str.c_str();
- for ( i = 0; kIntellectualGenreMappings[i].refNum != 0; ++i ) {
- if ( strncmp ( numPtr, kIntellectualGenreMappings[i].refNum, 3 ) == 0 ) break;
- }
- if ( kIntellectualGenreMappings[i].refNum == 0 ) return;
- namePtr = kIntellectualGenreMappings[i].name;
- }
-
- xmp->SetProperty ( kXMP_NS_IPTCCore, "IntellectualGenre", namePtr );
-
-} // ImportIPTC_IntellectualGenre
-
-// =================================================================================================
-// ImportIPTC_SubjectCode
-// ======================
-//
-// Import all 2:12 DataSets into an unordered array. In the IIM each DataSet is composed of 5 colon
-// separated sections: a provider name, an 8 digit reference number, and 3 optional names for the
-// levels of the reference number hierarchy. The IPTC4XMP mapping rule is that only the reference
-// number is imported to XMP.
-
-static void ImportIPTC_SubjectCode ( const IPTC_Manager & iptc, SXMPMeta * xmp )
-{
- std::string utf8Str;
- size_t count = iptc.GetDataSet_UTF8 ( kIPTC_SubjectCode, 0 );
-
- for ( size_t ds = 0; ds < count; ++ds ) {
-
- (void) iptc.GetDataSet_UTF8 ( kIPTC_SubjectCode, &utf8Str, ds );
-
- char * refNumPtr = (char*) utf8Str.c_str();
- for ( ; (*refNumPtr != ':') && (*refNumPtr != 0); ++refNumPtr ) {}
- if ( *refNumPtr == 0 ) continue; // This DataSet is ill-formed.
-
- char * refNumEnd = refNumPtr + 1;
- for ( ; (*refNumEnd != ':') && (*refNumEnd != 0); ++refNumEnd ) {}
- if ( (refNumEnd - refNumPtr) != 8 ) continue; // This DataSet is ill-formed.
- *refNumEnd = 0; // Ensure a terminating nul for the reference number portion.
-
- xmp->AppendArrayItem ( kXMP_NS_IPTCCore, "SubjectCode", kXMP_PropArrayIsUnordered, refNumPtr );
-
- }
-
-} // ImportIPTC_SubjectCode
-
-// =================================================================================================
-// PhotoDataUtils::Import2WayIPTC
-// ==============================
-
-void PhotoDataUtils::Import2WayIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp, int iptcDigestState )
-{
- if ( iptcDigestState == kDigestMatches ) return; // Ignore the IPTC if the digest matches.
-
- std::string oldStr, newStr;
- IPTC_Writer oldIPTC;
-
- if ( iptcDigestState == kDigestDiffers ) {
- PhotoDataUtils::ExportIPTC ( *xmp, &oldIPTC ); // Predict old IPTC DataSets based on the existing XMP.
- }
-
- size_t newCount;
- IPTC_Manager::DataSetInfo newInfo, oldInfo;
-
- for ( size_t i = 0; kKnownDataSets[i].id != 255; ++i ) {
-
- const DataSetCharacteristics & thisDS = kKnownDataSets[i];
- if ( thisDS.mapForm >= kIPTC_Map3Way ) continue; // The mapping is handled elsewhere, or not at all.
-
- bool haveXMP = xmp->DoesPropertyExist ( thisDS.xmpNS, thisDS.xmpProp );
- newCount = PhotoDataUtils::GetNativeInfo ( iptc, thisDS.id, iptcDigestState, haveXMP, &newInfo );
- if ( newCount == 0 ) continue; // GetNativeInfo returns 0 for ignored local text.
-
- if ( iptcDigestState == kDigestMissing ) {
- if ( haveXMP ) continue; // Keep the existing XMP.
- } else if ( ! PhotoDataUtils::IsValueDifferent ( iptc, oldIPTC, thisDS.id ) ) {
- continue; // Don't import values that match the previous export.
- }
-
- // The IPTC wins. Delete any existing XMP and import the DataSet.
-
- xmp->DeleteProperty ( thisDS.xmpNS, thisDS.xmpProp );
-
- try { // Don't let errors with one stop the others.
-
- switch ( thisDS.mapForm ) {
-
- case kIPTC_MapSimple :
- ImportIPTC_Simple ( iptc, xmp, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
- break;
-
- case kIPTC_MapLangAlt :
- ImportIPTC_LangAlt ( iptc, xmp, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
- break;
-
- case kIPTC_MapArray :
- ImportIPTC_Array ( iptc, xmp, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
- break;
-
- case kIPTC_MapSpecial :
- if ( thisDS.id == kIPTC_DateCreated ) {
- PhotoDataUtils::ImportIPTC_Date ( thisDS.id, iptc, xmp );
- } else if ( thisDS.id == kIPTC_IntellectualGenre ) {
- ImportIPTC_IntellectualGenre ( iptc, xmp );
- } else if ( thisDS.id == kIPTC_SubjectCode ) {
- ImportIPTC_SubjectCode ( iptc, xmp );
- } else {
- XMP_Assert ( false ); // Catch mapping errors.
- }
- break;
-
- }
-
- } catch ( ... ) {
-
- // Do nothing, let other imports proceed.
- // ? Notify client?
-
- }
-
- }
-
-} // PhotoDataUtils::Import2WayIPTC
-
-// =================================================================================================
-// PhotoDataUtils::ImportPSIR
-// ==========================
-//
-// There are only 2 standalone Photoshop image resources for XMP properties:
-// 1034 - Copyright Flag - 0/1 Boolean mapped to xmpRights:Marked.
-// 1035 - Copyright URL - Local OS text mapped to xmpRights:WebStatement.
-
-// ! Photoshop does not use a true/false/missing model for PSIR 1034. Instead it essentially uses a
-// ! yes/don't-know model when importing. A missing or 0 value for PSIR 1034 cause xmpRights:Marked
-// ! to be deleted.
-
-void PhotoDataUtils::ImportPSIR ( const PSIR_Manager & psir, SXMPMeta * xmp, int iptcDigestState )
-{
- PSIR_Manager::ImgRsrcInfo rsrcInfo;
- bool import;
-
- if ( iptcDigestState == kDigestMatches ) return;
-
- try { // Don't let errors with one stop the others.
- import = psir.GetImgRsrc ( kPSIR_CopyrightFlag, &rsrcInfo );
- if ( import ) import = (! xmp->DoesPropertyExist ( kXMP_NS_XMP_Rights, "Marked" ));
- if ( import && (rsrcInfo.dataLen == 1) && (*((XMP_Uns8*)rsrcInfo.dataPtr) != 0) ) {
- xmp->SetProperty_Bool ( kXMP_NS_XMP_Rights, "Marked", true );
- }
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
- try { // Don't let errors with one stop the others.
- import = psir.GetImgRsrc ( kPSIR_CopyrightURL, &rsrcInfo );
- if ( import ) import = (! xmp->DoesPropertyExist ( kXMP_NS_XMP_Rights, "WebStatement" ));
- if ( import ) {
- std::string utf8;
- if ( ReconcileUtils::IsUTF8 ( rsrcInfo.dataPtr, rsrcInfo.dataLen ) ) {
- utf8.assign ( (char*)rsrcInfo.dataPtr, rsrcInfo.dataLen );
- } else if ( ! ignoreLocalText ) {
- ReconcileUtils::LocalToUTF8 ( rsrcInfo.dataPtr, rsrcInfo.dataLen, &utf8 );
- } else {
- import = false; // Inhibit the SetProperty call.
- }
- if ( import ) xmp->SetProperty ( kXMP_NS_XMP_Rights, "WebStatement", utf8.c_str() );
- }
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // PhotoDataUtils::ImportPSIR;
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// ExportIPTC_Simple
-// =================
-
-static void ExportIPTC_Simple ( const SXMPMeta & xmp, IPTC_Manager * iptc,
- const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
-{
- std::string value;
- XMP_OptionBits xmpFlags;
-
- bool found = xmp.GetProperty ( xmpNS, xmpProp, &value, &xmpFlags );
- if ( ! found ) {
- iptc->DeleteDataSet ( id );
- return;
- }
-
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
-
- NormalizeToCR ( &value );
-
- size_t iptcCount = iptc->GetDataSet ( id, 0 );
- if ( iptcCount > 1 ) iptc->DeleteDataSet ( id );
-
- iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), 0 ); // ! Don't append a 2nd DataSet!
-
-} // ExportIPTC_Simple
-
-// =================================================================================================
-// ExportIPTC_LangAlt
-// ==================
-
-static void ExportIPTC_LangAlt ( const SXMPMeta & xmp, IPTC_Manager * iptc,
- const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
-{
- std::string value;
- XMP_OptionBits xmpFlags;
-
- bool found = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
- if ( ! found ) {
- iptc->DeleteDataSet ( id );
- return;
- }
-
- if ( ! XMP_ArrayIsAltText ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
-
- found = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &value, 0 );
- if ( ! found ) {
- iptc->DeleteDataSet ( id );
- return;
- }
-
- NormalizeToCR ( &value );
-
- size_t iptcCount = iptc->GetDataSet ( id, 0 );
- if ( iptcCount > 1 ) iptc->DeleteDataSet ( id );
-
- iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), 0 ); // ! Don't append a 2nd DataSet!
-
-} // ExportIPTC_LangAlt
-
-// =================================================================================================
-// ExportIPTC_Array
-// ================
-//
-// Array exporting needs a bit of care to preserve the detection of XMP-only updates. If the current
-// XMP and IPTC array sizes differ, delete the entire IPTC and append all new values. If they match,
-// set the individual values in order - which lets SetDataSet apply its no-change optimization.
-
-static void ExportIPTC_Array ( const SXMPMeta & xmp, IPTC_Manager * iptc,
- const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
-{
- std::string value;
- XMP_OptionBits xmpFlags;
-
- bool found = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
- if ( ! found ) {
- iptc->DeleteDataSet ( id );
- return;
- }
-
- if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
-
- XMP_Index xmpCount = xmp.CountArrayItems ( xmpNS, xmpProp );
- XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( id, 0 );
-
- if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( id );
-
- for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0.
-
- (void) xmp.GetArrayItem ( xmpNS, xmpProp, ds+1, &value, &xmpFlags );
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
-
- NormalizeToCR ( &value );
-
- iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), ds ); // ! Appends if necessary.
-
- }
-
-} // ExportIPTC_Array
-
-// =================================================================================================
-// ExportIPTC_IntellectualGenre
-// ============================
-//
-// Export DataSet 2:04. In the IIM this is a 3 digit number, a colon, and a text name. Even though
-// the number is the more formal part, the IPTC4XMP rule is that the name is imported to XMP and the
-// number is dropped. Also, even though IIMv4.1 says that 2:04 is repeatable, the XMP property to
-// which it is mapped is simple. Look up the XMP value in a list of known genres to get the number.
-
-static void ExportIPTC_IntellectualGenre ( const SXMPMeta & xmp, IPTC_Manager * iptc )
-{
- std::string xmpValue;
- XMP_OptionBits xmpFlags;
-
- bool found = xmp.GetProperty ( kXMP_NS_IPTCCore, "IntellectualGenre", &xmpValue, &xmpFlags );
- if ( ! found ) {
- iptc->DeleteDataSet ( kIPTC_IntellectualGenre );
- return;
- }
-
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
-
- NormalizeToCR ( &xmpValue );
-
- int i;
- XMP_StringPtr namePtr = xmpValue.c_str();
- for ( i = 0; kIntellectualGenreMappings[i].name != 0; ++i ) {
- if ( strcmp ( namePtr, kIntellectualGenreMappings[i].name ) == 0 ) break;
- }
- if ( kIntellectualGenreMappings[i].name == 0 ) return; // Not a known genre, don't export it.
-
- std::string iimValue = kIntellectualGenreMappings[i].refNum;
- iimValue += ':';
- iimValue += xmpValue;
-
- size_t iptcCount = iptc->GetDataSet ( kIPTC_IntellectualGenre, 0 );
- if ( iptcCount > 1 ) iptc->DeleteDataSet ( kIPTC_IntellectualGenre );
-
- iptc->SetDataSet_UTF8 ( kIPTC_IntellectualGenre, iimValue.c_str(), (XMP_Uns32)iimValue.size(), 0 ); // ! Don't append a 2nd DataSet!
-
-} // ExportIPTC_IntellectualGenre
-
-// =================================================================================================
-// ExportIPTC_SubjectCode
-// ======================
-//
-// Export 2:12 DataSets from an unordered array. In the IIM each DataSet is composed of 5 colon
-// separated sections: a provider name, an 8 digit reference number, and 3 optional names for the
-// levels of the reference number hierarchy. The IPTC4XMP mapping rule is that only the reference
-// number is imported to XMP. We export with a fixed provider of "IPTC" and no optional names.
-
-static void ExportIPTC_SubjectCode ( const SXMPMeta & xmp, IPTC_Manager * iptc )
-{
- std::string xmpValue, iimValue;
- XMP_OptionBits xmpFlags;
-
- bool found = xmp.GetProperty ( kXMP_NS_IPTCCore, "SubjectCode", 0, &xmpFlags );
- if ( ! found ) {
- iptc->DeleteDataSet ( kIPTC_SubjectCode );
- return;
- }
-
- if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
-
- XMP_Index xmpCount = xmp.CountArrayItems ( kXMP_NS_IPTCCore, "SubjectCode" );
- XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( kIPTC_SubjectCode, 0 );
-
- if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( kIPTC_SubjectCode );
-
- for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0.
-
- (void) xmp.GetArrayItem ( kXMP_NS_IPTCCore, "SubjectCode", ds+1, &xmpValue, &xmpFlags );
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
- if ( xmpValue.size() != 8 ) continue; // ? Complain?
-
- iimValue = "IPTC:";
- iimValue += xmpValue;
- iimValue += ":::"; // Add the separating colons for the empty name portions.
-
- iptc->SetDataSet_UTF8 ( kIPTC_SubjectCode, iimValue.c_str(), (XMP_Uns32)iimValue.size(), ds ); // ! Appends if necessary.
-
- }
-
-} // ExportIPTC_SubjectCode
-
-// =================================================================================================
-// ExportIPTC_Date
-// ===============
-//
-// The IPTC date and time are "YYYYMMDD" and "HHMMSSxHHMM" where 'x' is '+' or '-'. Export the IPTC
-// time only if already present, or if the XMP has a time portion.
-
-// *** The date/time handling differs from the MWG 1.0 policy, following a proposed tweak to MWG:
-// *** Exif DateTimeOriginal <-> IPTC DateCreated <-> XMP photoshop:DateCreated
-// *** Exif DateTimeDigitized <-> IPTC DigitalCreateDate <-> XMP xmp:CreateDate
-
-static void ExportIPTC_Date ( XMP_Uns8 dateID, const SXMPMeta & xmp, IPTC_Manager * iptc )
-{
- XMP_Uns8 timeID;
- XMP_StringPtr xmpNS, xmpProp;
-
- if ( dateID == kIPTC_DateCreated ) {
- timeID = kIPTC_TimeCreated;
- xmpNS = kXMP_NS_Photoshop;
- xmpProp = "DateCreated";
- } else if ( dateID == kIPTC_DigitalCreateDate ) {
- timeID = kIPTC_DigitalCreateTime;
- xmpNS = kXMP_NS_XMP;
- xmpProp = "CreateDate";
- } else {
- XMP_Throw ( "Unrecognized dateID", kXMPErr_BadParam );
- }
-
- iptc->DeleteDataSet ( dateID ); // ! Either the XMP does not exist and we want to
- iptc->DeleteDataSet ( timeID ); // ! delete the IPTC, or we're replacing the IPTC.
-
- XMP_DateTime xmpValue;
- bool found = xmp.GetProperty_Date ( xmpNS, xmpProp, &xmpValue, 0 );
- if ( ! found ) return;
-
- char iimValue[16]; // AUDIT: Big enough for "YYYYMMDD" (8) and "HHMMSS+HHMM" (11).
-
- // Set the IIM date portion as YYYYMMDD with zeroes for unknown parts.
-
- snprintf ( iimValue, sizeof(iimValue), "%04d%02d%02d", // AUDIT: Use of sizeof(iimValue) is safe.
- xmpValue.year, xmpValue.month, xmpValue.day );
-
- iptc->SetDataSet_UTF8 ( dateID, iimValue, 8 );
-
- // Set the IIM time portion as HHMMSS+HHMM (or -HHMM). Allow a missing time zone.
-
- if ( xmpValue.hasTimeZone ) {
- snprintf ( iimValue, sizeof(iimValue), "%02d%02d%02d%c%02d%02d", // AUDIT: Use of sizeof(iimValue) is safe.
- xmpValue.hour, xmpValue.minute, xmpValue.second,
- ((xmpValue.tzSign == kXMP_TimeWestOfUTC) ? '-' : '+'), xmpValue.tzHour, xmpValue.tzMinute );
- iptc->SetDataSet_UTF8 ( timeID, iimValue, 11 );
- } else if ( xmpValue.hasTime ) {
- snprintf ( iimValue, sizeof(iimValue), "%02d%02d%02d", // AUDIT: Use of sizeof(iimValue) is safe.
- xmpValue.hour, xmpValue.minute, xmpValue.second );
- iptc->SetDataSet_UTF8 ( timeID, iimValue, 6 );
- } else {
- iptc->DeleteDataSet ( timeID );
- }
-
-} // ExportIPTC_Date
-
-// =================================================================================================
-// PhotoDataUtils::ExportIPTC
-// ==========================
-
-void PhotoDataUtils::ExportIPTC ( const SXMPMeta & xmp, IPTC_Manager * iptc )
-{
-
- for ( size_t i = 0; kKnownDataSets[i].id != 255; ++i ) {
-
- try { // Don't let errors with one stop the others.
-
- const DataSetCharacteristics & thisDS = kKnownDataSets[i];
- if ( thisDS.mapForm >= kIPTC_UnmappedText ) continue;
-
- switch ( thisDS.mapForm ) {
-
- case kIPTC_MapSimple :
- ExportIPTC_Simple ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
- break;
-
- case kIPTC_MapLangAlt :
- ExportIPTC_LangAlt ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
- break;
-
- case kIPTC_MapArray :
- ExportIPTC_Array ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
- break;
-
- case kIPTC_MapSpecial :
- if ( thisDS.id == kIPTC_DateCreated ) {
- ExportIPTC_Date ( thisDS.id, xmp, iptc );
- } else if ( thisDS.id == kIPTC_IntellectualGenre ) {
- ExportIPTC_IntellectualGenre ( xmp, iptc );
- } else if ( thisDS.id == kIPTC_SubjectCode ) {
- ExportIPTC_SubjectCode ( xmp, iptc );
- } else {
- XMP_Assert ( false ); // Catch mapping errors.
- }
- break;
-
- case kIPTC_Map3Way : // The 3 way case is special for import, not for export.
- if ( thisDS.id == kIPTC_DigitalCreateDate ) {
- // ! Special case: Don't create IIM DigitalCreateDate. This can avoid PSD
- // ! full rewrite due to new mapping from xmp:CreateDate.
- if ( iptc->GetDataSet ( thisDS.id, 0 ) > 0 ) ExportIPTC_Date ( thisDS.id, xmp, iptc );
- } else if ( thisDS.id == kIPTC_Creator ) {
- ExportIPTC_Array ( xmp, iptc, kXMP_NS_DC, "creator", kIPTC_Creator );
- } else if ( thisDS.id == kIPTC_CopyrightNotice ) {
- ExportIPTC_LangAlt ( xmp, iptc, kXMP_NS_DC, "rights", kIPTC_CopyrightNotice );
- } else if ( thisDS.id == kIPTC_Description ) {
- ExportIPTC_LangAlt ( xmp, iptc, kXMP_NS_DC, "description", kIPTC_Description );
- } else {
- XMP_Assert ( false ); // Catch mapping errors.
- }
-
- }
-
- } catch ( ... ) {
-
- // Do nothing, let other exports proceed.
- // ? Notify client?
-
- }
-
- }
-
-} // PhotoDataUtils::ExportIPTC;
-
-// =================================================================================================
-// PhotoDataUtils::ExportPSIR
-// ==========================
-//
-// There are only 2 standalone Photoshop image resources for XMP properties:
-// 1034 - Copyright Flag - 0/1 Boolean mapped to xmpRights:Marked.
-// 1035 - Copyright URL - Local OS text mapped to xmpRights:WebStatement.
-
-// ! Photoshop does not use a true/false/missing model for PSIR 1034. Instead it is always written,
-// ! a missing xmpRights:Marked results in 0 for PSIR 1034.
-
-// ! We don't bother with the CR<->LF normalization for xmpRights:WebStatement. Very little chance
-// ! of having a raw CR character in a URI.
-
-void PhotoDataUtils::ExportPSIR ( const SXMPMeta & xmp, PSIR_Manager * psir )
-{
- bool found;
- std::string utf8Value;
-
- try { // Don't let errors with one stop the others.
- bool copyrighted = false;
- found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "Marked", &utf8Value, 0 );
- if ( found ) copyrighted = SXMPUtils::ConvertToBool ( utf8Value );
- psir->SetImgRsrc ( kPSIR_CopyrightFlag, &copyrighted, 1 );
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
- try { // Don't let errors with one stop the others.
- found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "WebStatement", &utf8Value, 0 );
- if ( ! found ) {
- psir->DeleteImgRsrc ( kPSIR_CopyrightURL );
- } else if ( ! ignoreLocalText ) {
- std::string localValue;
- ReconcileUtils::UTF8ToLocal ( utf8Value.c_str(), utf8Value.size(), &localValue );
- psir->SetImgRsrc ( kPSIR_CopyrightURL, localValue.c_str(), (XMP_Uns32)localValue.size() );
- } else if ( ReconcileUtils::IsASCII ( utf8Value.c_str(), utf8Value.size() ) ) {
- psir->SetImgRsrc ( kPSIR_CopyrightURL, utf8Value.c_str(), (XMP_Uns32)utf8Value.size() );
- } else {
- psir->DeleteImgRsrc ( kPSIR_CopyrightURL );
- }
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // PhotoDataUtils::ExportPSIR;
diff --git a/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp b/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp
deleted file mode 100644
index 78eeaa4..0000000
--- a/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "ReconcileLegacy.hpp"
-#include "Reconcile_Impl.hpp"
-
-// =================================================================================================
-/// \file ReconcileLegacy.cpp
-/// \brief Top level parts of utilities to reconcile between XMP and legacy metadata forms such as
-/// TIFF/Exif and IPTC.
-///
-// =================================================================================================
-
-// =================================================================================================
-// ImportPhotoData
-// ===============
-//
-// Import legacy metadata for JPEG, TIFF, and Photoshop files into the XMP. The caller must have
-// already done the file specific processing to select the appropriate sources of the TIFF stream,
-// the Photoshop image resources, and the IPTC.
-
-#define SaveExifTag(ns,prop) \
- if ( xmp->DoesPropertyExist ( ns, prop ) ) SXMPUtils::DuplicateSubtree ( *xmp, &savedExif, ns, prop )
-#define RestoreExifTag(ns,prop) \
- if ( savedExif.DoesPropertyExist ( ns, prop ) ) SXMPUtils::DuplicateSubtree ( savedExif, xmp, ns, prop )
-
-void ImportPhotoData ( const TIFF_Manager & exif,
- const IPTC_Manager & iptc,
- const PSIR_Manager & psir,
- int iptcDigestState,
- SXMPMeta * xmp,
- XMP_OptionBits options /* = 0 */ )
-{
- bool haveXMP = XMP_OptionIsSet ( options, k2XMP_FileHadXMP );
- bool haveExif = XMP_OptionIsSet ( options, k2XMP_FileHadExif );
- bool haveIPTC = XMP_OptionIsSet ( options, k2XMP_FileHadIPTC );
-
- // Save some new Exif writebacks that can be XMP-only from older versions, delete all of the
- // XMP's tiff: and exif: namespaces (they should only reflect native Exif), then put back the
- // saved writebacks (which might get replaced by the native Exif values in the Import calls).
- // The value of exif:ISOSpeedRatings is saved for special case handling of ISO over 65535.
-
- SXMPMeta savedExif;
-
- SaveExifTag ( kXMP_NS_EXIF, "DateTimeOriginal" );
- SaveExifTag ( kXMP_NS_EXIF, "GPSLatitude" );
- SaveExifTag ( kXMP_NS_EXIF, "GPSLongitude" );
- SaveExifTag ( kXMP_NS_EXIF, "GPSTimeStamp" );
- SaveExifTag ( kXMP_NS_EXIF, "GPSAltitude" );
- SaveExifTag ( kXMP_NS_EXIF, "GPSAltitudeRef" );
- SaveExifTag ( kXMP_NS_EXIF, "ISOSpeedRatings" );
-
- SXMPUtils::RemoveProperties ( xmp, kXMP_NS_TIFF, 0, kXMPUtil_DoAllProperties );
- SXMPUtils::RemoveProperties ( xmp, kXMP_NS_EXIF, 0, kXMPUtil_DoAllProperties );
-
- RestoreExifTag ( kXMP_NS_EXIF, "DateTimeOriginal" );
- RestoreExifTag ( kXMP_NS_EXIF, "GPSLatitude" );
- RestoreExifTag ( kXMP_NS_EXIF, "GPSLongitude" );
- RestoreExifTag ( kXMP_NS_EXIF, "GPSTimeStamp" );
- RestoreExifTag ( kXMP_NS_EXIF, "GPSAltitude" );
- RestoreExifTag ( kXMP_NS_EXIF, "GPSAltitudeRef" );
- RestoreExifTag ( kXMP_NS_EXIF, "ISOSpeedRatings" );
-
- // Not obvious here, but the logic in PhotoDataUtils follows the MWG reader guidelines.
-
- PhotoDataUtils::ImportPSIR ( psir, xmp, iptcDigestState );
-
- if ( haveIPTC ) PhotoDataUtils::Import2WayIPTC ( iptc, xmp, iptcDigestState );
- if ( haveExif ) PhotoDataUtils::Import2WayExif ( exif, xmp, iptcDigestState );
-
- if ( haveExif | haveIPTC ) PhotoDataUtils::Import3WayItems ( exif, iptc, xmp, iptcDigestState );
-
- // If photoshop:DateCreated does not exist try to create it from exif:DateTimeOriginal.
-
- if ( ! xmp->DoesPropertyExist ( kXMP_NS_Photoshop, "DateCreated" ) ) {
- std::string exifValue;
- bool haveExifDTO = xmp->GetProperty ( kXMP_NS_EXIF, "DateTimeOriginal", &exifValue, 0 );
- if ( haveExifDTO ) xmp->SetProperty ( kXMP_NS_Photoshop, "DateCreated", exifValue.c_str() );
- }
-
-} // ImportPhotoData
-
-// =================================================================================================
-// ExportPhotoData
-// ===============
-
-void ExportPhotoData ( XMP_FileFormat destFormat,
- SXMPMeta * xmp,
- TIFF_Manager * exif, // Pass 0 if not wanted.
- IPTC_Manager * iptc, // Pass 0 if not wanted.
- PSIR_Manager * psir, // Pass 0 if not wanted.
- XMP_OptionBits options /* = 0 */ )
-{
- XMP_Assert ( (destFormat == kXMP_JPEGFile) || (destFormat == kXMP_TIFFFile) || (destFormat == kXMP_PhotoshopFile) );
-
- // Do not write IPTC-IIM or PSIR in DNG files (which are a variant of TIFF).
-
- if ( (destFormat == kXMP_TIFFFile) && (exif != 0) &&
- exif->GetTag ( kTIFF_PrimaryIFD, kTIFF_DNGVersion, 0 ) ) {
-
- iptc = 0; // These prevent calls to ExportIPTC and ExportPSIR.
- psir = 0;
-
- exif->DeleteTag ( kTIFF_PrimaryIFD, kTIFF_IPTC ); // These remove any existing IPTC and PSIR.
- exif->DeleteTag ( kTIFF_PrimaryIFD, kTIFF_PSIR );
-
- }
-
- // Export the individual metadata items to the non-XMP forms. Set the IPTC digest whether or not
- // it changed, it might not have been present or correct before.
-
- bool iptcChanged = false; // Save explicitly, internal flag is reset by UpdateMemoryDataSets.
-
- void * iptcPtr = 0;
- XMP_Uns32 iptcLen = 0;
-
- if ( iptc != 0 ) {
- PhotoDataUtils::ExportIPTC ( *xmp, iptc );
- iptcChanged = iptc->IsChanged();
- if ( iptcChanged ) iptc->UpdateMemoryDataSets();
- iptcLen = iptc->GetBlockInfo ( &iptcPtr );
- if ( psir != 0 ) PhotoDataUtils::SetIPTCDigest ( iptcPtr, iptcLen, psir );
- }
-
- if ( exif != 0 ) PhotoDataUtils::ExportExif ( xmp, exif );
- if ( psir != 0 ) PhotoDataUtils::ExportPSIR ( *xmp, psir );
-
- // Now update the non-XMP collections of metadata according to the file format. Do not update
- // the XMP here, that is done in the file handlers after deciding if an XMP-only in-place
- // update should be done.
- // - JPEG has the IPTC in PSIR 1028, the Exif and PSIR are marker segments.
- // - TIFF has the IPTC and PSIR in primary IFD tags.
- // - PSD has everything in PSIRs.
-
- if ( destFormat == kXMP_JPEGFile ) {
-
- if ( iptcChanged && (psir != 0) ) psir->SetImgRsrc ( kPSIR_IPTC, iptcPtr, iptcLen );
-
- } else if ( destFormat == kXMP_TIFFFile ) {
-
- XMP_Assert ( exif != 0 );
-
- if ( iptcChanged ) exif->SetTag ( kTIFF_PrimaryIFD, kTIFF_IPTC, kTIFF_UndefinedType, iptcLen, iptcPtr );
-
- if ( (psir != 0) && psir->IsChanged() ) {
- void* psirPtr;
- XMP_Uns32 psirLen = psir->UpdateMemoryResources ( &psirPtr );
- exif->SetTag ( kTIFF_PrimaryIFD, kTIFF_PSIR, kTIFF_UndefinedType, psirLen, psirPtr );
- }
-
- } else if ( destFormat == kXMP_PhotoshopFile ) {
-
- XMP_Assert ( psir != 0 );
-
- if ( iptcChanged ) psir->SetImgRsrc ( kPSIR_IPTC, iptcPtr, iptcLen );
-
- if ( (exif != 0) && exif->IsChanged() ) {
- void* exifPtr;
- XMP_Uns32 exifLen = exif->UpdateMemoryStream ( &exifPtr );
- psir->SetImgRsrc ( kPSIR_Exif, exifPtr, exifLen );
- }
-
- }
-
- // Strip the tiff: and exif: namespaces from the XMP, we're done with them. Save the Exif
- // ISOSpeedRatings if any of the values are over 0xFFFF, the native tag is SHORT. Lower level
- // code already kept or stripped the XMP form.
-
- SXMPMeta savedExif;
- SaveExifTag ( kXMP_NS_EXIF, "ISOSpeedRatings" );
-
- SXMPUtils::RemoveProperties ( xmp, kXMP_NS_TIFF, 0, kXMPUtil_DoAllProperties );
- SXMPUtils::RemoveProperties ( xmp, kXMP_NS_EXIF, 0, kXMPUtil_DoAllProperties );
-
- RestoreExifTag ( kXMP_NS_EXIF, "ISOSpeedRatings" );
-
-} // ExportPhotoData
diff --git a/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp b/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp
deleted file mode 100644
index 59918cf..0000000
--- a/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp
+++ /dev/null
@@ -1,272 +0,0 @@
-#ifndef __ReconcileLegacy_hpp__
-#define __ReconcileLegacy_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "TIFF_Support.hpp"
-#include "PSIR_Support.hpp"
-#include "IPTC_Support.hpp"
-
-// =================================================================================================
-/// \file ReconcileLegacy.hpp
-/// \brief Utilities to reconcile between XMP and photo metadata forms such as TIFF/Exif and IPTC.
-///
-// =================================================================================================
-
-// ImportPhotoData imports TIFF/Exif and IPTC metadata from JPEG, TIFF, and Photoshop files into
-// XMP. The caller must have already done the file specific processing to select the appropriate
-// sources of the TIFF stream, the Photoshop image resources, and the IPTC.
-//
-// The reconciliation logic used here is based on the Metadata Working Group guidelines. This is a
-// simpler approach than used previously - which was modeled after historical Photoshop behavior.
-
-enum { // Bits for the options to ImportJTPtoXMP.
- k2XMP_FileHadXMP = 0x0001, // Set if the file had an XMP packet.
- k2XMP_FileHadIPTC = 0x0002, // Set if the file had legacy IPTC.
- k2XMP_FileHadExif = 0x0004 // Set if the file had legacy Exif.
-};
-
-extern void ImportPhotoData ( const TIFF_Manager & exif,
- const IPTC_Manager & iptc,
- const PSIR_Manager & psir,
- int iptcDigestState,
- SXMPMeta * xmp,
- XMP_OptionBits options = 0 );
-
-// ExportPhotoData exports XMP into TIFF/Exif and IPTC metadata for JPEG, TIFF, and Photoshop files.
-
-extern void ExportPhotoData ( XMP_FileFormat destFormat,
- SXMPMeta * xmp,
- TIFF_Manager * exif, // Pass 0 if not wanted.
- IPTC_Manager * iptc, // Pass 0 if not wanted.
- PSIR_Manager * psir, // Pass 0 if not wanted.
- XMP_OptionBits options = 0 );
-
-// *** Mapping notes need revision for MWG related changes.
-
-// =================================================================================================
-// Summary of TIFF/Exif mappings to XMP
-// ====================================
-//
-// The mapping for each tag is driven mainly by the tag ID, and secondarily by the type. E.g. there
-// is no blanket rule that all ASCII tags are mapped to simple strings in XMP. Some, such as
-// SubSecTime or GPSLatitudeRef, are combined with other tags; others, like Flash, are reformated.
-// However, most tags are in fact mapped in an obvious manner based on their type and count.
-//
-// Photoshop practice has been to truncate ASCII tags at the first NUL, not supporting the TIFF
-// specification's notion of multi-part ASCII values.
-//
-// Rational values are mapped to XMP as "num/denom".
-//
-// The tags of UNDEFINED type that are mapped to XMP text are either special cases like ExifVersion
-// or the strings with an explicit encoding like UserComment.
-//
-// Latitude and logitude are mapped to XMP as "DDD,MM,SSk" or "DDD,MM.mmk"; k is N, S, E, or W.
-//
-// Flash struct in XMP separates the Fired, Return, Mode, Function, and RedEyeMode portions of the
-// Exif value. Fired, Function, and RedEyeMode are Boolean; Return and Mode are integers.
-//
-// The OECF/SFR, CFA, and DeviceSettings tables are described in the XMP spec.
-//
-// Instead of iterating through all tags in the various IFDs, it is probably more efficient to have
-// explicit processing for the tags that get special treatment, and a static table listing those
-// that get mapped by type and count. The type and count processing will verify that the actual
-// type and count are as expected, if not the tag is ignored.
-//
-// Here are the primary (0th) IFD tags that get special treatment:
-//
-// 270, 33432 - ASCII mapped to alt-text['x-default']
-// 306 - DateTime master
-// 315 - ASCII mapped to text seq[1]
-//
-// Here are the primary (0th) IFD tags that get mapped by type and count:
-//
-// 256, 257, 258, 259, 262, 271, 272, 274, 277, 282, 283, 284, 296, 301, 305, 318, 319,
-// 529, 530, 531, 532
-//
-// Here are the Exif IFD tags that get special treatment:
-//
-// 34856, 41484 - OECF/SFR table
-// 36864, 40960 - 4 ASCII chars to text
-// 36867, 36868 - DateTime master
-// 37121 - 4 UInt8 to integer seq
-// 37385 - Flash struct
-// 37510 - explicitly encoded text to alt-text['x-default']
-// 41728, 41729 - UInt8 to integer
-// 41730 - CFA table
-// 41995 - DeviceSettings table
-//
-// Here are the Exif IFD tags that get mapped by type and count:
-//
-// 33434, 33437, 34850, 34852, 34855, 37122, 37377, 37378, 37379, 37380, 37381, 37382, 37383, 37384,
-// 37386, 37396, 40961, 40962, 40963, 40964, 41483, 41486, 41487, 41488, 41492, 41493, 41495, 41985,
-// 41986, 41987, 41988, 41989, 41990, 41991, 41992, 41993, 41994, 41996, 42016
-//
-// Here are the GPS IFD tags that get special treatment:
-//
-// 0 - 4 UInt8 to text "n.n.n.n"
-// 2, 4, 20, 22 - Latitude or longitude master
-// 7 - special DateTime master, the time part
-// 27, 28 - explicitly encoded text
-//
-// Here are the GPS IFD tags that get mapped by type and count:
-//
-// 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25, 26, 30
-// =================================================================================================
-
-// *** What about the Camera Raw tags that MDKit maps:
-// *** 0xFDE8, 0xFDE9, 0xFDEA, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, 0xFE50, 0xFE51, 0xFE52, 0xFE53,
-// *** 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58
-
-// =================================================================================================
-// Summary of TIFF/Exif mappings from XMP
-// ======================================
-//
-// Only a small number of properties are written back from XMP to TIFF/Exif. Most of the TIFF/Exif
-// tags mapped into XMP are information about the image or capture process, not things that users
-// should be editing. The tags that can be edited and written back to TIFF/Exif are:
-//
-// 270, 274, 282, 283, 296, 305, 306, 315, 33432; 36867, 36868, 37510, 40964
-// =================================================================================================
-
-// =================================================================================================
-// Details of TIFF/Exif mappings
-// =============================
-//
-// General (primary and thumbnail, 0th and 1st) IFD tags
-// tag TIFF type count Name XMP mapping
-//
-// 256 SHORTorLONG 1 ImageWidth integer
-// 257 SHORTorLONG 1 ImageLength integer
-// 258 SHORT 3 BitsPerSample integer seq
-// 259 SHORT 1 Compression integer
-// 262 SHORT 1 PhotometricInterpretation integer
-// 270 ASCII Any ImageDescription text, dc:description['x-default']
-// 271 ASCII Any Make text
-// 272 ASCII Any Model text
-// 274 SHORT 1 Orientation integer
-// 277 SHORT 1 SamplesPerPixel integer
-// 282 RATIONAL 1 XResolution rational
-// 283 RATIONAL 1 YResolution rational
-// 284 SHORT 1 PlanarConfiguration integer
-// 296 SHORT 1 ResolutionUnit integer
-// 301 SHORT 3*256 TransferFunction integer seq
-// 305 ASCII Any Software text, xmp:CreatorTool
-// 306 ASCII 20 DateTime date, master of 37520, xmp:DateTime
-// 315 ASCII Any Artist text, dc:creator[1]
-// 318 RATIONAL 2 WhitePoint rational seq
-// 319 RATIONAL 6 PrimaryChromaticities rational seq
-// 529 RATIONAL 3 YCbCrCoefficients rational seq
-// 530 SHORT 2 YCbCrSubSampling integer seq
-// 531 SHORT 1 YCbCrPositioning integer
-// 532 RATIONAL 6 ReferenceBlackWhite rational seq
-// 33432 ASCII Any Copyright text, dc:rights['x-default']
-//
-// Exif IFD tags
-// tag TIFF type count Name XMP mapping
-//
-// 33434 RATIONAL 1 ExposureTime rational
-// 33437 RATIONAL 1 FNumber rational
-// 34850 SHORT 1 ExposureProgram integer
-// 34852 ASCII Any SpectralSensitivity text
-// 34855 SHORT Any ISOSpeedRatings integer seq
-// 34856 UNDEFINED Any OECF OECF/SFR table
-// 36864 UNDEFINED 4 ExifVersion text, Exif has 4 ASCII chars
-// 36867 ASCII 20 DateTimeOriginal date, master of 37521
-// 36868 ASCII 20 DateTimeDigitized date, master of 37522
-// 37121 UNDEFINED 4 ComponentsConfiguration integer seq, Exif has 4 UInt8
-// 37122 RATIONAL 1 CompressedBitsPerPixel rational
-// 37377 SRATIONAL 1 ShutterSpeedValue rational
-// 37378 RATIONAL 1 ApertureValue rational
-// 37379 SRATIONAL 1 BrightnessValue rational
-// 37380 SRATIONAL 1 ExposureBiasValue rational
-// 37381 RATIONAL 1 MaxApertureValue rational
-// 37382 RATIONAL 1 SubjectDistance rational
-// 37383 SHORT 1 MeteringMode integer
-// 37384 SHORT 1 LightSource integer
-// 37385 SHORT 1 Flash Flash struct
-// 37386 RATIONAL 1 FocalLength rational
-// 37396 SHORT 2..4 SubjectArea integer seq
-// 37510 UNDEFINED Any UserComment text, explicit encoding, exif:UserComment['x-default]
-// 37520 ASCII Any SubSecTime date, with 306
-// 37521 ASCII Any SubSecTimeOriginal date, with 36867
-// 37522 ASCII Any SubSecTimeDigitized date, with 36868
-// 40960 UNDEFINED 4 FlashpixVersion text, Exif has 4 ASCII chars
-// 40961 SHORT 1 ColorSpace integer
-// 40962 SHORTorLONG 1 PixelXDimension integer
-// 40963 SHORTorLONG 1 PixelYDimension integer
-// 40964 ASCII 13 RelatedSoundFile text
-// 41483 RATIONAL 1 FlashEnergy rational
-// 41484 UNDEFINED Any SpatialFrequencyResponse OECF/SFR table
-// 41486 RATIONAL 1 FocalPlaneXResolution rational
-// 41487 RATIONAL 1 FocalPlaneYResolution rational
-// 41488 SHORT 1 FocalPlaneResolutionUnit integer
-// 41492 SHORT 2 SubjectLocation integer seq
-// 41493 RATIONAL 1 ExposureIndex rational
-// 41495 SHORT 1 SensingMethod integer
-// 41728 UNDEFINED 1 FileSource integer, Exif has UInt8
-// 41729 UNDEFINED 1 SceneType integer, Exif has UInt8
-// 41730 UNDEFINED Any CFAPattern CFA table
-// 41985 SHORT 1 CustomRendered integer
-// 41986 SHORT 1 ExposureMode integer
-// 41987 SHORT 1 WhiteBalance integer
-// 41988 RATIONAL 1 DigitalZoomRatio rational
-// 41989 SHORT 1 FocalLengthIn35mmFilm integer
-// 41990 SHORT 1 SceneCaptureType integer
-// 41991 SHORT 1 GainControl integer
-// 41992 SHORT 1 Contrast integer
-// 41993 SHORT 1 Saturation integer
-// 41994 SHORT 1 Sharpness integer
-// 41995 UNDEFINED Any DeviceSettingDescription DeviceSettings table
-// 41996 SHORT 1 SubjectDistanceRange integer
-// 42016 ASCII 33 ImageUniqueID text
-//
-// GPS IFD tags
-// tag TIFF type count Name XMP mapping
-//
-// 0 BYTE 4 GPSVersionID text, "n.n.n.n", Exif has 4 UInt8
-// 1 ASCII 2 GPSLatitudeRef latitude, with 2
-// 2 RATIONAL 3 GPSLatitude latitude, master of 2
-// 3 ASCII 2 GPSLongitudeRef longitude, with 4
-// 4 RATIONAL 3 GPSLongitude longitude, master of 3
-// 5 BYTE 1 GPSAltitudeRef integer
-// 6 RATIONAL 1 GPSAltitude rational
-// 7 RATIONAL 3 GPSTimeStamp date, master of 29
-// 8 ASCII Any GPSSatellites text
-// 9 ASCII 2 GPSStatus text
-// 10 ASCII 2 GPSMeasureMode text
-// 11 RATIONAL 1 GPSDOP rational
-// 12 ASCII 2 GPSSpeedRef text
-// 13 RATIONAL 1 GPSSpeed rational
-// 14 ASCII 2 GPSTrackRef text
-// 15 RATIONAL 1 GPSTrack rational
-// 16 ASCII 2 GPSImgDirectionRef text
-// 17 RATIONAL 1 GPSImgDirection rational
-// 18 ASCII Any GPSMapDatum text
-// 19 ASCII 2 GPSDestLatitudeRef latitude, with 20
-// 20 RATIONAL 3 GPSDestLatitude latitude, master of 19
-// 21 ASCII 2 GPSDestLongitudeRef longitude, with 22
-// 22 RATIONAL 3 GPSDestLongitude logitude, master of 21
-// 23 ASCII 2 GPSDestBearingRef text
-// 24 RATIONAL 1 GPSDestBearing rational
-// 25 ASCII 2 GPSDestDistanceRef text
-// 26 RATIONAL 1 GPSDestDistance rational
-// 27 UNDEFINED Any GPSProcessingMethod text, explicit encoding
-// 28 UNDEFINED Any GPSAreaInformation text, explicit encoding
-// 29 ASCII 11 GPSDateStamp date, with 29
-// 30 SHORT 1 GPSDifferential integer
-//
-// =================================================================================================
-
-// =================================================================================================
-
-#endif // #ifndef __ReconcileLegacy_hpp__
diff --git a/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp b/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp
deleted file mode 100644
index 892c683..0000000
--- a/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp
+++ /dev/null
@@ -1,2934 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "Reconcile_Impl.hpp"
-
-#include "UnicodeConversions.hpp"
-
-#include <stdio.h>
-#if XMP_WinBuild
- #define snprintf _snprintf
-#endif
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4146 ) // unary minus operator applied to unsigned type
- #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false'
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-// =================================================================================================
-/// \file ReconcileTIFF.cpp
-/// \brief Utilities to reconcile between XMP and legacy TIFF/Exif metadata.
-///
-// =================================================================================================
-
-// =================================================================================================
-
-// =================================================================================================
-// Tables of the TIFF/Exif tags that are mapped into XMP. For the most part, the tags have obvious
-// mappings based on their IFD, tag number, type and count. These tables do not list tags that are
-// mapped as subsidiary parts of others, e.g. TIFF SubSecTime or GPS Info GPSDateStamp. Tags that
-// have special mappings are marked by having an empty string for the XMP property name.
-
-// ! These tables have the tags listed in the order of tables 3, 4, 5, and 12 of Exif 2.2, with the
-// ! exception of ImageUniqueID (which is listed at the end of the Exif mappings). This order is
-// ! very important to consistent checking of the legacy status. The NativeDigest properties list
-// ! all possible mapped tags in this order. The NativeDigest strings are compared as a whole, so
-// ! the same tags listed in a different order would compare as different.
-
-// ! The sentinel tag value can't be 0, that is a valid GPS Info tag, 0xFFFF is unused so far.
-
-enum {
- kExport_Never = 0, // Never export.
- kExport_Always = 1, // Add, modify, or delete.
- kExport_NoDelete = 2, // Add or modify, do not delete if no XMP.
- kExport_InjectOnly = 3 // Add tag if new, never modify or delete existing values.
-};
-
-struct TIFF_MappingToXMP {
- XMP_Uns16 id;
- XMP_Uns16 type;
- XMP_Uns32 count; // Zero means any.
- XMP_Uns8 exportMode;
- const char * name; // The name of the mapped XMP property. The namespace is implicit.
-};
-
-enum { kAnyCount = 0 };
-
-static const TIFF_MappingToXMP sPrimaryIFDMappings[] = { // A blank name indicates a special mapping.
- { /* 256 */ kTIFF_ImageWidth, kTIFF_ShortOrLongType, 1, kExport_Never, "ImageWidth" },
- { /* 257 */ kTIFF_ImageLength, kTIFF_ShortOrLongType, 1, kExport_Never, "ImageLength" },
- { /* 258 */ kTIFF_BitsPerSample, kTIFF_ShortType, 3, kExport_Never, "BitsPerSample" },
- { /* 259 */ kTIFF_Compression, kTIFF_ShortType, 1, kExport_Never, "Compression" },
- { /* 262 */ kTIFF_PhotometricInterpretation, kTIFF_ShortType, 1, kExport_Never, "PhotometricInterpretation" },
- { /* 274 */ kTIFF_Orientation, kTIFF_ShortType, 1, kExport_NoDelete, "Orientation" },
- { /* 277 */ kTIFF_SamplesPerPixel, kTIFF_ShortType, 1, kExport_Never, "SamplesPerPixel" },
- { /* 284 */ kTIFF_PlanarConfiguration, kTIFF_ShortType, 1, kExport_Never, "PlanarConfiguration" },
- { /* 530 */ kTIFF_YCbCrSubSampling, kTIFF_ShortType, 2, kExport_Never, "YCbCrSubSampling" },
- { /* 531 */ kTIFF_YCbCrPositioning, kTIFF_ShortType, 1, kExport_Never, "YCbCrPositioning" },
- { /* 282 */ kTIFF_XResolution, kTIFF_RationalType, 1, kExport_NoDelete, "XResolution" },
- { /* 283 */ kTIFF_YResolution, kTIFF_RationalType, 1, kExport_NoDelete, "YResolution" },
- { /* 296 */ kTIFF_ResolutionUnit, kTIFF_ShortType, 1, kExport_NoDelete, "ResolutionUnit" },
- { /* 301 */ kTIFF_TransferFunction, kTIFF_ShortType, 3*256, kExport_Never, "TransferFunction" },
- { /* 318 */ kTIFF_WhitePoint, kTIFF_RationalType, 2, kExport_Never, "WhitePoint" },
- { /* 319 */ kTIFF_PrimaryChromaticities, kTIFF_RationalType, 6, kExport_Never, "PrimaryChromaticities" },
- { /* 529 */ kTIFF_YCbCrCoefficients, kTIFF_RationalType, 3, kExport_Never, "YCbCrCoefficients" },
- { /* 532 */ kTIFF_ReferenceBlackWhite, kTIFF_RationalType, 6, kExport_Never, "ReferenceBlackWhite" },
- { /* 306 */ kTIFF_DateTime, kTIFF_ASCIIType, 20, kExport_Always, "" }, // ! Has a special mapping.
- { /* 270 */ kTIFF_ImageDescription, kTIFF_ASCIIType, kAnyCount, kExport_Always, "" }, // ! Has a special mapping.
- { /* 271 */ kTIFF_Make, kTIFF_ASCIIType, kAnyCount, kExport_InjectOnly, "Make" },
- { /* 272 */ kTIFF_Model, kTIFF_ASCIIType, kAnyCount, kExport_InjectOnly, "Model" },
- { /* 305 */ kTIFF_Software, kTIFF_ASCIIType, kAnyCount, kExport_Always, "Software" }, // Has alias to xmp:CreatorTool.
- { /* 315 */ kTIFF_Artist, kTIFF_ASCIIType, kAnyCount, kExport_Always, "" }, // ! Has a special mapping.
- { /* 33432 */ kTIFF_Copyright, kTIFF_ASCIIType, kAnyCount, kExport_Always, "" }, // ! Has a special mapping.
- { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
-};
-
-// ! A special need, easier than looking up the entry in sExifIFDMappings:
-static const TIFF_MappingToXMP kISOSpeedMapping = { kTIFF_ISOSpeedRatings, kTIFF_ShortType, kAnyCount, kExport_InjectOnly, "ISOSpeedRatings" };
-
-static const TIFF_MappingToXMP sExifIFDMappings[] = {
- { /* 36864 */ kTIFF_ExifVersion, kTIFF_UndefinedType, 4, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 40960 */ kTIFF_FlashpixVersion, kTIFF_UndefinedType, 4, kExport_Never, "" }, // ! Has a special mapping.
- { /* 40961 */ kTIFF_ColorSpace, kTIFF_ShortType, 1, kExport_InjectOnly, "ColorSpace" },
- { /* 37121 */ kTIFF_ComponentsConfiguration, kTIFF_UndefinedType, 4, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 37122 */ kTIFF_CompressedBitsPerPixel, kTIFF_RationalType, 1, kExport_InjectOnly, "CompressedBitsPerPixel" },
- { /* 40962 */ kTIFF_PixelXDimension, kTIFF_ShortOrLongType, 1, kExport_InjectOnly, "PixelXDimension" },
- { /* 40963 */ kTIFF_PixelYDimension, kTIFF_ShortOrLongType, 1, kExport_InjectOnly, "PixelYDimension" },
- { /* 37510 */ kTIFF_UserComment, kTIFF_UndefinedType, kAnyCount, kExport_Always, "" }, // ! Has a special mapping.
- { /* 40964 */ kTIFF_RelatedSoundFile, kTIFF_ASCIIType, kAnyCount, kExport_Always, "RelatedSoundFile" }, // ! Exif spec says count of 13.
- { /* 36867 */ kTIFF_DateTimeOriginal, kTIFF_ASCIIType, 20, kExport_Always, "" }, // ! Has a special mapping.
- { /* 36868 */ kTIFF_DateTimeDigitized, kTIFF_ASCIIType, 20, kExport_Always, "" }, // ! Has a special mapping.
- { /* 33434 */ kTIFF_ExposureTime, kTIFF_RationalType, 1, kExport_InjectOnly, "ExposureTime" },
- { /* 33437 */ kTIFF_FNumber, kTIFF_RationalType, 1, kExport_InjectOnly, "FNumber" },
- { /* 34850 */ kTIFF_ExposureProgram, kTIFF_ShortType, 1, kExport_InjectOnly, "ExposureProgram" },
- { /* 34852 */ kTIFF_SpectralSensitivity, kTIFF_ASCIIType, kAnyCount, kExport_InjectOnly, "SpectralSensitivity" },
- { /* 34855 */ kTIFF_ISOSpeedRatings, kTIFF_ShortType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 34856 */ kTIFF_OECF, kTIFF_UndefinedType, kAnyCount, kExport_Never, "" }, // ! Has a special mapping.
- { /* 37377 */ kTIFF_ShutterSpeedValue, kTIFF_SRationalType, 1, kExport_InjectOnly, "ShutterSpeedValue" },
- { /* 37378 */ kTIFF_ApertureValue, kTIFF_RationalType, 1, kExport_InjectOnly, "ApertureValue" },
- { /* 37379 */ kTIFF_BrightnessValue, kTIFF_SRationalType, 1, kExport_InjectOnly, "BrightnessValue" },
- { /* 37380 */ kTIFF_ExposureBiasValue, kTIFF_SRationalType, 1, kExport_InjectOnly, "ExposureBiasValue" },
- { /* 37381 */ kTIFF_MaxApertureValue, kTIFF_RationalType, 1, kExport_InjectOnly, "MaxApertureValue" },
- { /* 37382 */ kTIFF_SubjectDistance, kTIFF_RationalType, 1, kExport_InjectOnly, "SubjectDistance" },
- { /* 37383 */ kTIFF_MeteringMode, kTIFF_ShortType, 1, kExport_InjectOnly, "MeteringMode" },
- { /* 37384 */ kTIFF_LightSource, kTIFF_ShortType, 1, kExport_InjectOnly, "LightSource" },
- { /* 37385 */ kTIFF_Flash, kTIFF_ShortType, 1, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 37386 */ kTIFF_FocalLength, kTIFF_RationalType, 1, kExport_InjectOnly, "FocalLength" },
- { /* 37396 */ kTIFF_SubjectArea, kTIFF_ShortType, kAnyCount, kExport_Never, "SubjectArea" }, // ! Actually 2..4.
- { /* 41483 */ kTIFF_FlashEnergy, kTIFF_RationalType, 1, kExport_InjectOnly, "FlashEnergy" },
- { /* 41484 */ kTIFF_SpatialFrequencyResponse, kTIFF_UndefinedType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 41486 */ kTIFF_FocalPlaneXResolution, kTIFF_RationalType, 1, kExport_InjectOnly, "FocalPlaneXResolution" },
- { /* 41487 */ kTIFF_FocalPlaneYResolution, kTIFF_RationalType, 1, kExport_InjectOnly, "FocalPlaneYResolution" },
- { /* 41488 */ kTIFF_FocalPlaneResolutionUnit, kTIFF_ShortType, 1, kExport_InjectOnly, "FocalPlaneResolutionUnit" },
- { /* 41492 */ kTIFF_SubjectLocation, kTIFF_ShortType, 2, kExport_Never, "SubjectLocation" },
- { /* 41493 */ kTIFF_ExposureIndex, kTIFF_RationalType, 1, kExport_InjectOnly, "ExposureIndex" },
- { /* 41495 */ kTIFF_SensingMethod, kTIFF_ShortType, 1, kExport_InjectOnly, "SensingMethod" },
- { /* 41728 */ kTIFF_FileSource, kTIFF_UndefinedType, 1, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 41729 */ kTIFF_SceneType, kTIFF_UndefinedType, 1, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 41730 */ kTIFF_CFAPattern, kTIFF_UndefinedType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 41985 */ kTIFF_CustomRendered, kTIFF_ShortType, 1, kExport_Never, "CustomRendered" },
- { /* 41986 */ kTIFF_ExposureMode, kTIFF_ShortType, 1, kExport_InjectOnly, "ExposureMode" },
- { /* 41987 */ kTIFF_WhiteBalance, kTIFF_ShortType, 1, kExport_InjectOnly, "WhiteBalance" },
- { /* 41988 */ kTIFF_DigitalZoomRatio, kTIFF_RationalType, 1, kExport_InjectOnly, "DigitalZoomRatio" },
- { /* 41989 */ kTIFF_FocalLengthIn35mmFilm, kTIFF_ShortType, 1, kExport_InjectOnly, "FocalLengthIn35mmFilm" },
- { /* 41990 */ kTIFF_SceneCaptureType, kTIFF_ShortType, 1, kExport_InjectOnly, "SceneCaptureType" },
- { /* 41991 */ kTIFF_GainControl, kTIFF_ShortType, 1, kExport_InjectOnly, "GainControl" },
- { /* 41992 */ kTIFF_Contrast, kTIFF_ShortType, 1, kExport_InjectOnly, "Contrast" },
- { /* 41993 */ kTIFF_Saturation, kTIFF_ShortType, 1, kExport_InjectOnly, "Saturation" },
- { /* 41994 */ kTIFF_Sharpness, kTIFF_ShortType, 1, kExport_InjectOnly, "Sharpness" },
- { /* 41995 */ kTIFF_DeviceSettingDescription, kTIFF_UndefinedType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 41996 */ kTIFF_SubjectDistanceRange, kTIFF_ShortType, 1, kExport_InjectOnly, "SubjectDistanceRange" },
- { /* 42016 */ kTIFF_ImageUniqueID, kTIFF_ASCIIType, 33, kExport_InjectOnly, "ImageUniqueID" },
- { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
-};
-
-static const TIFF_MappingToXMP sGPSInfoIFDMappings[] = {
- { /* 0 */ kTIFF_GPSVersionID, kTIFF_ByteType, 4, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 2 */ kTIFF_GPSLatitude, kTIFF_RationalType, 3, kExport_Always, "" }, // ! Has a special mapping.
- { /* 4 */ kTIFF_GPSLongitude, kTIFF_RationalType, 3, kExport_Always, "" }, // ! Has a special mapping.
- { /* 5 */ kTIFF_GPSAltitudeRef, kTIFF_ByteType, 1, kExport_Always, "GPSAltitudeRef" },
- { /* 6 */ kTIFF_GPSAltitude, kTIFF_RationalType, 1, kExport_Always, "GPSAltitude" },
- { /* 7 */ kTIFF_GPSTimeStamp, kTIFF_RationalType, 3, kExport_Always, "" }, // ! Has a special mapping.
- { /* 8 */ kTIFF_GPSSatellites, kTIFF_ASCIIType, kAnyCount, kExport_InjectOnly, "GPSSatellites" },
- { /* 9 */ kTIFF_GPSStatus, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSStatus" },
- { /* 10 */ kTIFF_GPSMeasureMode, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSMeasureMode" },
- { /* 11 */ kTIFF_GPSDOP, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSDOP" },
- { /* 12 */ kTIFF_GPSSpeedRef, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSSpeedRef" },
- { /* 13 */ kTIFF_GPSSpeed, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSSpeed" },
- { /* 14 */ kTIFF_GPSTrackRef, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSTrackRef" },
- { /* 15 */ kTIFF_GPSTrack, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSTrack" },
- { /* 16 */ kTIFF_GPSImgDirectionRef, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSImgDirectionRef" },
- { /* 17 */ kTIFF_GPSImgDirection, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSImgDirection" },
- { /* 18 */ kTIFF_GPSMapDatum, kTIFF_ASCIIType, kAnyCount, kExport_InjectOnly, "GPSMapDatum" },
- { /* 20 */ kTIFF_GPSDestLatitude, kTIFF_RationalType, 3, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 22 */ kTIFF_GPSDestLongitude, kTIFF_RationalType, 3, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 23 */ kTIFF_GPSDestBearingRef, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSDestBearingRef" },
- { /* 24 */ kTIFF_GPSDestBearing, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSDestBearing" },
- { /* 25 */ kTIFF_GPSDestDistanceRef, kTIFF_ASCIIType, 2, kExport_InjectOnly, "GPSDestDistanceRef" },
- { /* 26 */ kTIFF_GPSDestDistance, kTIFF_RationalType, 1, kExport_InjectOnly, "GPSDestDistance" },
- { /* 27 */ kTIFF_GPSProcessingMethod, kTIFF_UndefinedType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 28 */ kTIFF_GPSAreaInformation, kTIFF_UndefinedType, kAnyCount, kExport_InjectOnly, "" }, // ! Has a special mapping.
- { /* 30 */ kTIFF_GPSDifferential, kTIFF_ShortType, 1, kExport_InjectOnly, "GPSDifferential" },
- { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
-};
-
-// =================================================================================================
-
-static void // ! Needed by Import2WayExif
-ExportTIFF_Date ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp, TIFF_Manager * tiff, XMP_Uns16 mainID );
-
-// =================================================================================================
-
-static XMP_Uns32 GatherInt ( const char * strPtr, size_t count )
-{
- XMP_Uns32 value = 0;
- const char * strEnd = strPtr + count;
-
- while ( strPtr < strEnd ) {
- char ch = *strPtr;
- if ( (ch < '0') || (ch > '9') ) break;
- value = value*10 + (ch - '0');
- ++strPtr;
- }
-
- return value;
-
-} // GatherInt
-
-// =================================================================================================
-
-static void TrimTrailingSpaces ( TIFF_Manager::TagInfo * info )
-{
- if ( info->dataLen == 0 ) return;
- XMP_Assert ( info->dataPtr != 0 );
-
- char * firstChar = (char*)info->dataPtr;
- char * lastChar = firstChar + info->dataLen - 1;
-
- if ( (*lastChar != ' ') && (*lastChar != 0) ) return; // Nothing to do.
-
- while ( (firstChar <= lastChar) && ((*lastChar == ' ') || (*lastChar == 0)) ) --lastChar;
-
- XMP_Assert ( (lastChar == firstChar-1) ||
- ((lastChar >= firstChar) && (*lastChar != ' ') && (*lastChar != 0)) );
-
- ++lastChar;
- XMP_Uns32 newLen = (XMP_Uns32)(lastChar - firstChar) + 1;
- XMP_Assert ( newLen <= info->dataLen );
-
- *lastChar = 0;
- info->dataLen = newLen;
-
-} // TrimTrailingSpaces
-
-// =================================================================================================
-
-bool PhotoDataUtils::GetNativeInfo ( const TIFF_Manager & exif, XMP_Uns8 ifd, XMP_Uns16 id, TIFF_Manager::TagInfo * info )
-{
- bool haveExif = exif.GetTag ( ifd, id, info );
-
- if ( haveExif ) {
-
- XMP_Uns32 i;
- char * chPtr;
-
- XMP_Assert ( (info->dataPtr != 0) || (info->dataLen == 0) ); // Null pointer requires zero length.
-
- bool isDate = ((id == kTIFF_DateTime) || (id == kTIFF_DateTimeOriginal) || (id == kTIFF_DateTimeOriginal));
-
- for ( i = 0, chPtr = (char*)info->dataPtr; i < info->dataLen; ++i, ++chPtr ) {
- if ( isDate && (*chPtr == ':') ) continue; // Ignore colons, empty dates have spaces and colons.
- if ( (*chPtr != ' ') && (*chPtr != 0) ) break; // Break if the Exif value is non-empty.
- }
-
- if ( i == info->dataLen ) {
- haveExif = false; // Ignore empty Exif.
- } else {
- TrimTrailingSpaces ( info );
- if ( info->dataLen == 0 ) haveExif = false;
- }
-
- }
-
- return haveExif;
-
-} // PhotoDataUtils::GetNativeInfo
-
-// =================================================================================================
-
-size_t PhotoDataUtils::GetNativeInfo ( const IPTC_Manager & iptc, XMP_Uns8 id, int digestState, bool haveXMP, IPTC_Manager::DataSetInfo * info )
-{
- size_t iptcCount = 0;
-
- if ( (digestState == kDigestDiffers) || ((digestState == kDigestMissing) && (! haveXMP)) ) {
- iptcCount = iptc.GetDataSet ( id, info );
- }
-
- if ( ignoreLocalText && (iptcCount > 0) && (! iptc.UsingUTF8()) ) {
- // Check to see if the new value(s) should be ignored.
- size_t i;
- IPTC_Manager::DataSetInfo tmpInfo;
- for ( i = 0; i < iptcCount; ++i ) {
- (void) iptc.GetDataSet ( id, &tmpInfo, i );
- if ( ReconcileUtils::IsASCII ( tmpInfo.dataPtr, tmpInfo.dataLen ) ) break;
- }
- if ( i == iptcCount ) iptcCount = 0; // Return 0 if value(s) should be ignored.
- }
-
- return iptcCount;
-
-} // PhotoDataUtils::GetNativeInfo
-
-// =================================================================================================
-
-bool PhotoDataUtils::IsValueDifferent ( const TIFF_Manager::TagInfo & exifInfo, const std::string & xmpValue, std::string * exifValue )
-{
- if ( exifInfo.dataLen == 0 ) return false; // Ignore empty Exif values.
-
- if ( ReconcileUtils::IsUTF8 ( exifInfo.dataPtr, exifInfo.dataLen ) ) { // ! Note that ASCII is UTF-8.
- exifValue->assign ( (char*)exifInfo.dataPtr, exifInfo.dataLen );
- } else {
- if ( ignoreLocalText ) return false;
- ReconcileUtils::LocalToUTF8 ( exifInfo.dataPtr, exifInfo.dataLen, exifValue );
- }
-
- return (*exifValue != xmpValue);
-
-} // PhotoDataUtils::IsValueDifferent
-
-// =================================================================================================
-
-bool PhotoDataUtils::IsValueDifferent ( const IPTC_Manager & newIPTC, const IPTC_Manager & oldIPTC, XMP_Uns8 id )
-{
- IPTC_Manager::DataSetInfo newInfo;
- size_t newCount = newIPTC.GetDataSet ( id, &newInfo );
- if ( newCount == 0 ) return false; // Ignore missing new IPTC values.
-
- IPTC_Manager::DataSetInfo oldInfo;
- size_t oldCount = oldIPTC.GetDataSet ( id, &oldInfo );
- if ( oldCount == 0 ) return true; // Missing old IPTC values differ.
-
- if ( newCount != oldCount ) return true;
-
- std::string oldStr, newStr;
-
- for ( newCount = 0; newCount < oldCount; ++newCount ) {
-
- if ( ignoreLocalText & (! newIPTC.UsingUTF8()) ) { // Check to see if the new value should be ignored.
- (void) newIPTC.GetDataSet ( id, &newInfo, newCount );
- if ( ! ReconcileUtils::IsASCII ( newInfo.dataPtr, newInfo.dataLen ) ) continue;
- }
-
- (void) newIPTC.GetDataSet_UTF8 ( id, &newStr, newCount );
- (void) oldIPTC.GetDataSet_UTF8 ( id, &oldStr, newCount );
- if ( newStr.size() == 0 ) continue; // Ignore empty new IPTC.
- if ( newStr != oldStr ) break;
-
- }
-
- return ( newCount != oldCount ); // Not different if all values matched.
-
-} // PhotoDataUtils::IsValueDifferent
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// ImportSingleTIFF_Short
-// ======================
-
-static void
-ImportSingleTIFF_Short ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns16 binValue = *((XMP_Uns16*)tagInfo.dataPtr);
- if ( ! nativeEndian ) binValue = Flip2 ( binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Short
-
-// =================================================================================================
-// ImportSingleTIFF_Long
-// =====================
-
-static void
-ImportSingleTIFF_Long ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns32 binValue = *((XMP_Uns32*)tagInfo.dataPtr);
- if ( ! nativeEndian ) binValue = Flip4 ( binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%lu", (unsigned long)binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Long
-
-// =================================================================================================
-// ImportSingleTIFF_Rational
-// =========================
-
-static void
-ImportSingleTIFF_Rational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
- XMP_Uns32 binNum = binPtr[0];
- XMP_Uns32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- binNum = Flip4 ( binNum );
- binDenom = Flip4 ( binDenom );
- }
-
- char strValue[40];
- snprintf ( strValue, sizeof(strValue), "%lu/%lu", (unsigned long)binNum, (unsigned long)binDenom ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Rational
-
-// =================================================================================================
-// ImportSingleTIFF_SRational
-// ==========================
-
-static void
-ImportSingleTIFF_SRational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
- XMP_Int32 binNum = binPtr[0];
- XMP_Int32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- Flip4 ( &binNum );
- Flip4 ( &binDenom );
- }
-
- char strValue[40];
- snprintf ( strValue, sizeof(strValue), "%ld/%ld", (unsigned long)binNum, (unsigned long)binDenom ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_SRational
-
-// =================================================================================================
-// ImportSingleTIFF_ASCII
-// ======================
-
-static void
-ImportSingleTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- TrimTrailingSpaces ( (TIFF_Manager::TagInfo*) &tagInfo );
- if ( tagInfo.dataLen == 0 ) return; // Ignore empty tags.
-
- const char * chPtr = (const char *)tagInfo.dataPtr;
- const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
- const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
-
- if ( isUTF8 && hasNul ) {
- xmp->SetProperty ( xmpNS, xmpProp, chPtr );
- } else {
- std::string strValue;
- if ( isUTF8 ) {
- strValue.assign ( chPtr, tagInfo.dataLen );
- } else {
- if ( ignoreLocalText ) return;
- ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
- }
- xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() );
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_ASCII
-
-// =================================================================================================
-// ImportSingleTIFF_Byte
-// =====================
-
-static void
-ImportSingleTIFF_Byte ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns8 binValue = *((XMP_Uns8*)tagInfo.dataPtr);
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Byte
-
-// =================================================================================================
-// ImportSingleTIFF_SByte
-// ======================
-
-static void
-ImportSingleTIFF_SByte ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int8 binValue = *((XMP_Int8*)tagInfo.dataPtr);
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_SByte
-
-// =================================================================================================
-// ImportSingleTIFF_SShort
-// =======================
-
-static void
-ImportSingleTIFF_SShort ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int16 binValue = *((XMP_Int16*)tagInfo.dataPtr);
- if ( ! nativeEndian ) Flip2 ( &binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_SShort
-
-// =================================================================================================
-// ImportSingleTIFF_SLong
-// ======================
-
-static void
-ImportSingleTIFF_SLong ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int32 binValue = *((XMP_Int32*)tagInfo.dataPtr);
- if ( ! nativeEndian ) Flip4 ( &binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%ld", (long)binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->SetProperty ( xmpNS, xmpProp, strValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_SLong
-
-// =================================================================================================
-// ImportSingleTIFF_Float
-// ======================
-
-static void
-ImportSingleTIFF_Float ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- float binValue = *((float*)tagInfo.dataPtr);
- if ( ! nativeEndian ) Flip4 ( &binValue );
-
- xmp->SetProperty_Float ( xmpNS, xmpProp, binValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Float
-
-// =================================================================================================
-// ImportSingleTIFF_Double
-// =======================
-
-static void
-ImportSingleTIFF_Double ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- double binValue = *((double*)tagInfo.dataPtr);
- if ( ! nativeEndian ) Flip8 ( &binValue );
-
- xmp->SetProperty_Float ( xmpNS, xmpProp, binValue ); // ! Yes, SetProperty_Float.
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportSingleTIFF_Double
-
-// =================================================================================================
-// ImportSingleTIFF
-// ================
-
-static void
-ImportSingleTIFF ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
-
- // We've got a tag to map to XMP, decide how based on actual type and the expected count. Using
- // the actual type eliminates a ShortOrLong case. Using the expected count is needed to know
- // whether to create an XMP array. The actual count for an array could be 1. Put the most
- // common cases first for better iCache utilization.
-
- switch ( tagInfo.type ) {
-
- case kTIFF_ShortType :
- ImportSingleTIFF_Short ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_LongType :
- ImportSingleTIFF_Long ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_RationalType :
- ImportSingleTIFF_Rational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SRationalType :
- ImportSingleTIFF_SRational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_ASCIIType :
- ImportSingleTIFF_ASCII ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_ByteType :
- ImportSingleTIFF_Byte ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SByteType :
- ImportSingleTIFF_SByte ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SShortType :
- ImportSingleTIFF_SShort ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SLongType :
- ImportSingleTIFF_SLong ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_FloatType :
- ImportSingleTIFF_Float ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_DoubleType :
- ImportSingleTIFF_Double ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- }
-
-} // ImportSingleTIFF
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// ImportArrayTIFF_Short
-// =====================
-
-static void
-ImportArrayTIFF_Short ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns16 * binPtr = (XMP_Uns16*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Uns16 binValue = *binPtr;
- if ( ! nativeEndian ) binValue = Flip2 ( binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Short
-
-// =================================================================================================
-// ImportArrayTIFF_Long
-// ====================
-
-static void
-ImportArrayTIFF_Long ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Uns32 binValue = *binPtr;
- if ( ! nativeEndian ) binValue = Flip4 ( binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%lu", (unsigned long)binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Long
-
-// =================================================================================================
-// ImportArrayTIFF_Rational
-// ========================
-
-static void
-ImportArrayTIFF_Rational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, binPtr += 2 ) {
-
- XMP_Uns32 binNum = binPtr[0];
- XMP_Uns32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- binNum = Flip4 ( binNum );
- binDenom = Flip4 ( binDenom );
- }
-
- char strValue[40];
- snprintf ( strValue, sizeof(strValue), "%lu/%lu", (unsigned long)binNum, (unsigned long)binDenom ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Rational
-
-// =================================================================================================
-// ImportArrayTIFF_SRational
-// =========================
-
-static void
-ImportArrayTIFF_SRational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, binPtr += 2 ) {
-
- XMP_Int32 binNum = binPtr[0];
- XMP_Int32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- Flip4 ( &binNum );
- Flip4 ( &binDenom );
- }
-
- char strValue[40];
- snprintf ( strValue, sizeof(strValue), "%ld/%ld", (long)binNum, (long)binDenom ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_SRational
-
-// =================================================================================================
-// ImportArrayTIFF_ASCII
-// =====================
-
-static void
-ImportArrayTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- TrimTrailingSpaces ( (TIFF_Manager::TagInfo*) &tagInfo );
- if ( tagInfo.dataLen == 0 ) return; // Ignore empty tags.
-
- const char * chPtr = (const char *)tagInfo.dataPtr;
- const char * chEnd = chPtr + tagInfo.dataLen;
- const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
- const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
-
- std::string strValue;
-
- if ( (! isUTF8) || (! hasNul) ) {
- if ( isUTF8 ) {
- strValue.assign ( chPtr, tagInfo.dataLen );
- } else {
- if ( ignoreLocalText ) return;
- ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
- }
- chPtr = strValue.c_str();
- chEnd = chPtr + strValue.size();
- }
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( ; chPtr < chEnd; chPtr += (strlen(chPtr) + 1) ) {
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, chPtr );
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_ASCII
-
-// =================================================================================================
-// ImportArrayTIFF_Byte
-// ====================
-
-static void
-ImportArrayTIFF_Byte ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns8 * binPtr = (XMP_Uns8*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Uns8 binValue = *binPtr;
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Byte
-
-// =================================================================================================
-// ImportArrayTIFF_SByte
-// =====================
-
-static void
-ImportArrayTIFF_SByte ( const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int8 * binPtr = (XMP_Int8*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Int8 binValue = *binPtr;
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_SByte
-
-// =================================================================================================
-// ImportArrayTIFF_SShort
-// ======================
-
-static void
-ImportArrayTIFF_SShort ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int16 * binPtr = (XMP_Int16*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Int16 binValue = *binPtr;
- if ( ! nativeEndian ) Flip2 ( &binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_SShort
-
-// =================================================================================================
-// ImportArrayTIFF_SLong
-// =====================
-
-static void
-ImportArrayTIFF_SLong ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- XMP_Int32 binValue = *binPtr;
- if ( ! nativeEndian ) Flip4 ( &binValue );
-
- char strValue[20];
- snprintf ( strValue, sizeof(strValue), "%ld", (long)binValue ); // AUDIT: Using sizeof(strValue) is safe.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_SLong
-
-// =================================================================================================
-// ImportArrayTIFF_Float
-// =====================
-
-static void
-ImportArrayTIFF_Float ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- float * binPtr = (float*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- float binValue = *binPtr;
- if ( ! nativeEndian ) Flip4 ( &binValue );
-
- std::string strValue;
- SXMPUtils::ConvertFromFloat ( binValue, "", &strValue );
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue.c_str() );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Float
-
-// =================================================================================================
-// ImportArrayTIFF_Double
-// ======================
-
-static void
-ImportArrayTIFF_Double ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- double * binPtr = (double*)tagInfo.dataPtr;
-
- xmp->DeleteProperty ( xmpNS, xmpProp ); // ! Don't keep appending, create a new array.
-
- for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
-
- double binValue = *binPtr;
- if ( ! nativeEndian ) Flip8 ( &binValue );
-
- std::string strValue;
- SXMPUtils::ConvertFromFloat ( binValue, "", &strValue ); // ! Yes, ConvertFromFloat.
-
- xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue.c_str() );
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportArrayTIFF_Double
-
-// =================================================================================================
-// ImportArrayTIFF
-// ===============
-
-static void
-ImportArrayTIFF ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
-
- // We've got a tag to map to XMP, decide how based on actual type and the expected count. Using
- // the actual type eliminates a ShortOrLong case. Using the expected count is needed to know
- // whether to create an XMP array. The actual count for an array could be 1. Put the most
- // common cases first for better iCache utilization.
-
- switch ( tagInfo.type ) {
-
- case kTIFF_ShortType :
- ImportArrayTIFF_Short ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_LongType :
- ImportArrayTIFF_Long ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_RationalType :
- ImportArrayTIFF_Rational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SRationalType :
- ImportArrayTIFF_SRational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_ASCIIType :
- ImportArrayTIFF_ASCII ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_ByteType :
- ImportArrayTIFF_Byte ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SByteType :
- ImportArrayTIFF_SByte ( tagInfo, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SShortType :
- ImportArrayTIFF_SShort ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_SLongType :
- ImportArrayTIFF_SLong ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_FloatType :
- ImportArrayTIFF_Float ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- case kTIFF_DoubleType :
- ImportArrayTIFF_Double ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
- break;
-
- }
-
-} // ImportArrayTIFF
-
-// =================================================================================================
-// ImportTIFF_CheckStandardMapping
-// ===============================
-
-static bool
-ImportTIFF_CheckStandardMapping ( const TIFF_Manager::TagInfo & tagInfo, const TIFF_MappingToXMP & mapInfo )
-{
- XMP_Assert ( (kTIFF_ByteType <= tagInfo.type) && (tagInfo.type <= kTIFF_LastType) );
- XMP_Assert ( mapInfo.type <= kTIFF_LastType );
-
- if ( (tagInfo.type < kTIFF_ByteType) || (tagInfo.type > kTIFF_LastType) ) return false;
-
- if ( tagInfo.type != mapInfo.type ) {
- if ( mapInfo.type != kTIFF_ShortOrLongType ) return false;
- if ( (tagInfo.type != kTIFF_ShortType) && (tagInfo.type != kTIFF_LongType) ) return false;
- }
-
- if ( (tagInfo.count != mapInfo.count) && // Maybe there is a problem because the counts don't match.
- // (mapInfo.count != kAnyCount) && ... don't need this because of the new check below ...
- (mapInfo.count == 1) ) return false; // Be tolerant of mismatch in expected array size.
-
- return true;
-
-} // ImportTIFF_CheckStandardMapping
-
-// =================================================================================================
-// ImportTIFF_StandardMappings
-// ===========================
-
-static void
-ImportTIFF_StandardMappings ( XMP_Uns8 ifd, const TIFF_Manager & tiff, SXMPMeta * xmp )
-{
- const bool nativeEndian = tiff.IsNativeEndian();
- TIFF_Manager::TagInfo tagInfo;
-
- const TIFF_MappingToXMP * mappings = 0;
- const char * xmpNS = 0;
-
- if ( ifd == kTIFF_PrimaryIFD ) {
- mappings = sPrimaryIFDMappings;
- xmpNS = kXMP_NS_TIFF;
- } else if ( ifd == kTIFF_ExifIFD ) {
- mappings = sExifIFDMappings;
- xmpNS = kXMP_NS_EXIF;
- } else if ( ifd == kTIFF_GPSInfoIFD ) {
- mappings = sGPSInfoIFDMappings;
- xmpNS = kXMP_NS_EXIF; // ! Yes, the GPS Info tags go into the exif: namespace.
- } else {
- XMP_Throw ( "Invalid IFD for standard mappings", kXMPErr_InternalFailure );
- }
-
- for ( size_t i = 0; mappings[i].id != 0xFFFF; ++i ) {
-
- try { // Don't let errors with one stop the others.
-
- const TIFF_MappingToXMP & mapInfo = mappings[i];
- const bool mapSingle = ((mapInfo.count == 1) || (mapInfo.type == kTIFF_ASCIIType));
-
- if ( mapInfo.name[0] == 0 ) continue; // Skip special mappings, handled higher up.
-
- bool found = tiff.GetTag ( ifd, mapInfo.id, &tagInfo );
- if ( ! found ) continue;
-
- XMP_Assert ( tagInfo.type != kTIFF_UndefinedType ); // These must have a special mapping.
- if ( tagInfo.type == kTIFF_UndefinedType ) continue;
- if ( ! ImportTIFF_CheckStandardMapping ( tagInfo, mapInfo ) ) continue;
-
- if ( mapSingle ) {
- ImportSingleTIFF ( tagInfo, nativeEndian, xmp, xmpNS, mapInfo.name );
- } else {
- ImportArrayTIFF ( tagInfo, nativeEndian, xmp, xmpNS, mapInfo.name );
- }
-
- } catch ( ... ) {
-
- // Do nothing, let other imports proceed.
- // ? Notify client?
-
- }
-
- }
-
-} // ImportTIFF_StandardMappings
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// ImportTIFF_Date
-// ===============
-//
-// Convert an Exif 2.2 master date/time tag plus associated fractional seconds to an XMP date/time.
-// The Exif date/time part is a 20 byte ASCII value formatted as "YYYY:MM:DD HH:MM:SS" with a
-// terminating nul. Any of the numeric portions can be blanks if unknown. The fractional seconds
-// are a nul terminated ASCII string with possible space padding. They are literally the fractional
-// part, the digits that would be to the right of the decimal point.
-
-static void
-ImportTIFF_Date ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & dateInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- XMP_Uns16 secID;
- switch ( dateInfo.id ) {
- case kTIFF_DateTime : secID = kTIFF_SubSecTime; break;
- case kTIFF_DateTimeOriginal : secID = kTIFF_SubSecTimeOriginal; break;
- case kTIFF_DateTimeDigitized : secID = kTIFF_SubSecTimeDigitized; break;
- }
-
- try { // Don't let errors with one stop the others.
-
- if ( (dateInfo.type != kTIFF_ASCIIType) || (dateInfo.count != 20) ) return;
-
- const char * dateStr = (const char *) dateInfo.dataPtr;
- if ( (dateStr[4] != ':') || (dateStr[7] != ':') ||
- (dateStr[10] != ' ') || (dateStr[13] != ':') || (dateStr[16] != ':') ) return;
-
- XMP_DateTime binValue;
-
- binValue.year = GatherInt ( &dateStr[0], 4 );
- binValue.month = GatherInt ( &dateStr[5], 2 );
- binValue.day = GatherInt ( &dateStr[8], 2 );
- if ( (binValue.year != 0) | (binValue.month != 0) | (binValue.day != 0) ) binValue.hasDate = true;
-
- binValue.hour = GatherInt ( &dateStr[11], 2 );
- binValue.minute = GatherInt ( &dateStr[14], 2 );
- binValue.second = GatherInt ( &dateStr[17], 2 );
- binValue.nanoSecond = 0; // Get the fractional seconds later.
- if ( (binValue.hour != 0) | (binValue.minute != 0) | (binValue.second != 0) ) binValue.hasTime = true;
-
- binValue.tzSign = 0; // ! Separate assignment, avoid VS integer truncation warning.
- binValue.tzHour = binValue.tzMinute = 0;
- binValue.hasTimeZone = false; // Exif times have no zone.
-
- // *** Consider looking at the TIFF/EP TimeZoneOffset tag?
-
- TIFF_Manager::TagInfo secInfo;
- bool found = tiff.GetTag ( kTIFF_ExifIFD, secID, &secInfo ); // ! Subseconds are all in the Exif IFD.
-
- if ( found && (secInfo.type == kTIFF_ASCIIType) ) {
- const char * fracPtr = (const char *) secInfo.dataPtr;
- binValue.nanoSecond = GatherInt ( fracPtr, secInfo.dataLen );
- size_t digits = 0;
- for ( ; (('0' <= *fracPtr) && (*fracPtr <= '9')); ++fracPtr ) ++digits;
- for ( ; digits < 9; ++digits ) binValue.nanoSecond *= 10;
- if ( binValue.nanoSecond != 0 ) binValue.hasTime = true;
- }
-
- xmp->SetProperty_Date ( xmpNS, xmpProp, binValue );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_Date
-
-// =================================================================================================
-// ImportTIFF_LocTextASCII
-// =======================
-
-static void
-ImportTIFF_LocTextASCII ( const TIFF_Manager & tiff, XMP_Uns8 ifd, XMP_Uns16 tagID,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- TIFF_Manager::TagInfo tagInfo;
-
- bool found = tiff.GetTag ( ifd, tagID, &tagInfo );
- if ( (! found) || (tagInfo.type != kTIFF_ASCIIType) ) return;
-
- const char * chPtr = (const char *)tagInfo.dataPtr;
- const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
- const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
-
- if ( isUTF8 && hasNul ) {
- xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", chPtr );
- } else {
- std::string strValue;
- if ( isUTF8 ) {
- strValue.assign ( chPtr, tagInfo.dataLen );
- } else {
- if ( ignoreLocalText ) return;
- ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
- }
- xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", strValue.c_str() );
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_LocTextASCII
-
-// =================================================================================================
-// ImportTIFF_EncodedString
-// ========================
-
-static void
-ImportTIFF_EncodedString ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp, bool isLangAlt = false )
-{
- try { // Don't let errors with one stop the others.
-
- std::string strValue;
-
- bool ok = tiff.DecodeString ( tagInfo.dataPtr, tagInfo.dataLen, &strValue );
- if ( ! ok ) return;
-
- if ( ! isLangAlt ) {
- xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() );
- } else {
- xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", strValue.c_str() );
- }
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_EncodedString
-
-// =================================================================================================
-// ImportTIFF_Flash
-// ================
-
-static void
-ImportTIFF_Flash ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- XMP_Uns16 binValue = *((XMP_Uns16*)tagInfo.dataPtr);
- if ( ! nativeEndian ) binValue = Flip2 ( binValue );
-
- bool fired = (bool)(binValue & 1); // Avoid implicit 0/1 conversion.
- int rtrn = (binValue >> 1) & 3;
- int mode = (binValue >> 3) & 3;
- bool function = (bool)((binValue >> 5) & 1);
- bool redEye = (bool)((binValue >> 6) & 1);
-
- static const char * sTwoBits[] = { "0", "1", "2", "3" };
-
- xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Fired", (fired ? kXMP_TrueStr : kXMP_FalseStr) );
- xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Return", sTwoBits[rtrn] );
- xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Mode", sTwoBits[mode] );
- xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Function", (function ? kXMP_TrueStr : kXMP_FalseStr) );
- xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "RedEyeMode", (redEye ? kXMP_TrueStr : kXMP_FalseStr) );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_Flash
-
-// =================================================================================================
-// ImportTIFF_OECFTable
-// ====================
-//
-// Although the XMP for the OECF and SFR tables is the same, the Exif is not. The OECF table has
-// signed rational values and the SFR table has unsigned.
-
-static void
-ImportTIFF_OECFTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
- const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
-
- XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
- XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
- if ( ! nativeEndian ) {
- columns = Flip2 ( columns );
- rows = Flip2 ( rows );
- }
-
- char buffer[40];
-
- snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
- snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
-
- std::string arrayPath;
-
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Names", &arrayPath );
-
- bytePtr += 4; // Move to the list of names.
- for ( size_t i = columns; i > 0; --i ) {
- size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul.
- if ( (bytePtr + nameLen) > byteEnd ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; };
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr );
- bytePtr += nameLen;
- }
-
- if ( (byteEnd - bytePtr) != (8 * columns * rows) ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; // Make sure the values are present.
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
-
- XMP_Int32 * binPtr = (XMP_Int32*)bytePtr;
- for ( size_t i = (columns * rows); i > 0; --i, binPtr += 2 ) {
-
- XMP_Int32 binNum = binPtr[0];
- XMP_Int32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- Flip4 ( &binNum );
- Flip4 ( &binDenom );
- }
-
- snprintf ( buffer, sizeof(buffer), "%ld/%ld", (long)binNum, (long)binDenom ); // AUDIT: Use of sizeof(buffer) is safe.
-
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
-
- }
-
- return;
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_OECFTable
-
-// =================================================================================================
-// ImportTIFF_SFRTable
-// ===================
-//
-// Although the XMP for the OECF and SFR tables is the same, the Exif is not. The OECF table has
-// signed rational values and the SFR table has unsigned.
-
-static void
-ImportTIFF_SFRTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
- const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
-
- XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
- XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
- if ( ! nativeEndian ) {
- columns = Flip2 ( columns );
- rows = Flip2 ( rows );
- }
-
- char buffer[40];
-
- snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
- snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
-
- std::string arrayPath;
-
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Names", &arrayPath );
-
- bytePtr += 4; // Move to the list of names.
- for ( size_t i = columns; i > 0; --i ) {
- size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul.
- if ( (bytePtr + nameLen) > byteEnd ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; };
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr );
- bytePtr += nameLen;
- }
-
- if ( (byteEnd - bytePtr) != (8 * columns * rows) ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; // Make sure the values are present.
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)bytePtr;
- for ( size_t i = (columns * rows); i > 0; --i, binPtr += 2 ) {
-
- XMP_Uns32 binNum = binPtr[0];
- XMP_Uns32 binDenom = binPtr[1];
- if ( ! nativeEndian ) {
- binNum = Flip4 ( binNum );
- binDenom = Flip4 ( binDenom );
- }
-
- snprintf ( buffer, sizeof(buffer), "%lu/%lu", (unsigned long)binNum, (unsigned long)binDenom ); // AUDIT: Use of sizeof(buffer) is safe.
-
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
-
- }
-
- return;
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_SFRTable
-
-// =================================================================================================
-// ImportTIFF_CFATable
-// ===================
-
-static void
-ImportTIFF_CFATable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
- const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
-
- XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
- XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
- if ( ! nativeEndian ) {
- columns = Flip2 ( columns );
- rows = Flip2 ( rows );
- }
-
- char buffer[20];
- std::string arrayPath;
-
- snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
- snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
-
- bytePtr += 4; // Move to the matrix of values.
- if ( (byteEnd - bytePtr) != (columns * rows) ) goto BadExif; // Make sure the values are present.
-
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
-
- for ( size_t i = (columns * rows); i > 0; --i, ++bytePtr ) {
- snprintf ( buffer, sizeof(buffer), "%hu", *bytePtr ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
- }
-
- return;
-
- BadExif: // Ignore the tag if the table is ill-formed.
- xmp->DeleteProperty ( xmpNS, xmpProp );
- return;
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_CFATable
-
-// =================================================================================================
-// ImportTIFF_DSDTable
-// ===================
-
-static void
-ImportTIFF_DSDTable ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & tagInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
- const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
-
- XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
- XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
- if ( ! tiff.IsNativeEndian() ) {
- columns = Flip2 ( columns );
- rows = Flip2 ( rows );
- }
-
- char buffer[20];
-
- snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
- snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
- xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
-
- std::string arrayPath;
- SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Settings", &arrayPath );
-
- bytePtr += 4; // Move to the list of settings.
- UTF16Unit * utf16Ptr = (UTF16Unit*)bytePtr;
- UTF16Unit * utf16End = (UTF16Unit*)byteEnd;
-
- std::string utf8;
-
- // Figure 17 in the Exif 2.2 spec is unclear. It has counts for rows and columns, but the
- // settings are listed as 1..n, not as a rectangular matrix. So, ignore the counts and copy
- // strings until the end of the Exif value.
-
- while ( utf16Ptr < utf16End ) {
-
- size_t nameLen = 0;
- while ( utf16Ptr[nameLen] != 0 ) ++nameLen;
- ++nameLen; // ! Include the terminating nul.
- if ( (utf16Ptr + nameLen) > utf16End ) goto BadExif;
-
- try {
- FromUTF16 ( utf16Ptr, nameLen, &utf8, tiff.IsBigEndian() );
- } catch ( ... ) {
- goto BadExif; // Ignore the tag if there are conversion errors.
- }
-
- xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, utf8.c_str() );
-
- utf16Ptr += nameLen;
-
- }
-
- return;
-
- BadExif: // Ignore the tag if the table is ill-formed.
- xmp->DeleteProperty ( xmpNS, xmpProp );
- return;
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_DSDTable
-
-// =================================================================================================
-// ImportTIFF_GPSCoordinate
-// ========================
-
-static void
-ImportTIFF_GPSCoordinate ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & posInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const bool nativeEndian = tiff.IsNativeEndian();
-
- XMP_Uns16 refID = posInfo.id - 1; // ! The GPS refs and coordinates are all tag n and n+1.
- TIFF_Manager::TagInfo refInfo;
- bool found = tiff.GetTag ( kTIFF_GPSInfoIFD, refID, &refInfo );
- if ( (! found) || (refInfo.type != kTIFF_ASCIIType) || (refInfo.count != 2) ) return;
- char ref = *((char*)refInfo.dataPtr);
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)posInfo.dataPtr;
- XMP_Uns32 degNum = binPtr[0];
- XMP_Uns32 degDenom = binPtr[1];
- XMP_Uns32 minNum = binPtr[2];
- XMP_Uns32 minDenom = binPtr[3];
- XMP_Uns32 secNum = binPtr[4];
- XMP_Uns32 secDenom = binPtr[5];
- if ( ! nativeEndian ) {
- degNum = Flip4 ( degNum );
- degDenom = Flip4 ( degDenom );
- minNum = Flip4 ( minNum );
- minDenom = Flip4 ( minDenom );
- secNum = Flip4 ( secNum );
- secDenom = Flip4 ( secDenom );
- }
-
- char buffer[40];
-
- if ( (degDenom == 1) && (minDenom == 1) && (secDenom == 1) ) {
-
- snprintf ( buffer, sizeof(buffer), "%lu,%lu,%lu%c", (unsigned long)degNum, (unsigned long)minNum, (unsigned long)secNum, ref ); // AUDIT: Using sizeof(buffer is safe.
-
- } else {
-
- XMP_Uns32 maxDenom = degDenom;
- if ( minDenom > degDenom ) maxDenom = minDenom;
- if ( secDenom > degDenom ) maxDenom = secDenom;
-
- int fracDigits = 1;
- while ( maxDenom > 10 ) { ++fracDigits; maxDenom = maxDenom/10; }
-
- double temp = (double)degNum / (double)degDenom;
- double degrees = (double)((XMP_Uns32)temp); // Just the integral number of degrees.
- double minutes = ((temp - degrees) * 60.0) +
- ((double)minNum / (double)minDenom) +
- (((double)secNum / (double)secDenom) / 60.0);
-
- snprintf ( buffer, sizeof(buffer), "%.0f,%.*f%c", degrees, fracDigits, minutes, ref ); // AUDIT: Using sizeof(buffer is safe.
-
- }
-
- xmp->SetProperty ( xmpNS, xmpProp, buffer );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_GPSCoordinate
-
-// =================================================================================================
-// ImportTIFF_GPSTimeStamp
-// =======================
-
-static void
-ImportTIFF_GPSTimeStamp ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & timeInfo,
- SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
-{
- try { // Don't let errors with one stop the others.
-
- const bool nativeEndian = tiff.IsNativeEndian();
-
- bool haveDate;
- TIFF_Manager::TagInfo dateInfo;
- haveDate = tiff.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDateStamp, &dateInfo );
- if ( ! haveDate ) haveDate = tiff.GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeOriginal, &dateInfo );
- if ( ! haveDate ) haveDate = tiff.GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeDigitized, &dateInfo );
- if ( ! haveDate ) return;
-
- const char * dateStr = (const char *) dateInfo.dataPtr;
- if ( (dateStr[4] != ':') || (dateStr[7] != ':') ) return;
- if ( (dateStr[10] != 0) && (dateStr[10] != ' ') ) return;
-
- XMP_Uns32 * binPtr = (XMP_Uns32*)timeInfo.dataPtr;
- XMP_Uns32 hourNum = binPtr[0];
- XMP_Uns32 hourDenom = binPtr[1];
- XMP_Uns32 minNum = binPtr[2];
- XMP_Uns32 minDenom = binPtr[3];
- XMP_Uns32 secNum = binPtr[4];
- XMP_Uns32 secDenom = binPtr[5];
- if ( ! nativeEndian ) {
- hourNum = Flip4 ( hourNum );
- hourDenom = Flip4 ( hourDenom );
- minNum = Flip4 ( minNum );
- minDenom = Flip4 ( minDenom );
- secNum = Flip4 ( secNum );
- secDenom = Flip4 ( secDenom );
- }
-
- double fHour, fMin, fSec, fNano, temp;
- fSec = (double)secNum / (double)secDenom;
- temp = (double)minNum / (double)minDenom;
- fMin = (double)((XMP_Uns32)temp);
- fSec += (temp - fMin) * 60.0;
- temp = (double)hourNum / (double)hourDenom;
- fHour = (double)((XMP_Uns32)temp);
- fSec += (temp - fHour) * 3600.0;
- temp = (double)((XMP_Uns32)fSec);
- fNano = ((fSec - temp) * (1000.0*1000.0*1000.0)) + 0.5; // Try to avoid n999... problems.
- fSec = temp;
-
- XMP_DateTime binStamp;
- binStamp.year = GatherInt ( dateStr, 4 );
- binStamp.month = GatherInt ( dateStr+5, 2 );
- binStamp.day = GatherInt ( dateStr+8, 2 );
- binStamp.hour = (XMP_Int32)fHour;
- binStamp.minute = (XMP_Int32)fMin;
- binStamp.second = (XMP_Int32)fSec;
- binStamp.nanoSecond = (XMP_Int32)fNano;
- binStamp.hasTimeZone = true; // Exif GPS TimeStamp is implicitly UTC.
- binStamp.tzSign = kXMP_TimeIsUTC;
- binStamp.tzHour = binStamp.tzMinute = 0;
-
- xmp->SetProperty_Date ( xmpNS, xmpProp, binStamp );
-
- } catch ( ... ) {
- // Do nothing, let other imports proceed.
- // ? Notify client?
- }
-
-} // ImportTIFF_GPSTimeStamp
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// PhotoDataUtils::Import2WayExif
-// ==============================
-//
-// Import the TIFF/Exif tags that have 2 way mappings to XMP, i.e. no correspondence to IPTC.
-// These are always imported for the tiff: and exif: namespaces, but not for others.
-
-void
-PhotoDataUtils::Import2WayExif ( const TIFF_Manager & exif, SXMPMeta * xmp, int iptcDigestState )
-{
- const bool nativeEndian = exif.IsNativeEndian();
-
- bool found, foundFromXMP;
- TIFF_Manager::TagInfo tagInfo;
-
- ImportTIFF_StandardMappings ( kTIFF_PrimaryIFD, exif, xmp );
- ImportTIFF_StandardMappings ( kTIFF_ExifIFD, exif, xmp );
- ImportTIFF_StandardMappings ( kTIFF_GPSInfoIFD, exif, xmp );
-
- // -----------------------------------------------------------------
- // Fixup erroneous files that have a negative value for GPSAltitude.
-
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSAltitude, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_RationalType) && (tagInfo.count == 1) ) {
-
- XMP_Uns32 num = exif.GetUns32 ( tagInfo.dataPtr );
- XMP_Uns32 denom = exif.GetUns32 ( (XMP_Uns8*)tagInfo.dataPtr + 4 );
- bool numNeg = num >> 31;
- bool denomNeg = denom >> 31;
-
- if ( (numNeg != denomNeg) || numNeg ) { // Does the GPSAltitude look negative?
- if ( denomNeg ) {
- denom = -denom;
- num = -num;
- numNeg = num >> 31;
- }
- if ( numNeg ) {
- char buffer [32];
- num = -num;
- snprintf ( buffer, sizeof(buffer), "%lu/%lu", (unsigned long) num, (unsigned long) denom ); // AUDIT: Using sizeof(buffer) is safe.
- xmp->SetProperty ( kXMP_NS_EXIF, "GPSAltitude", buffer );
- xmp->SetProperty ( kXMP_NS_EXIF, "GPSAltitudeRef", "1" );
- }
- }
-
- }
-
- // ---------------------------------------------------------------
- // Import DateTimeOriginal and DateTime if the XMP doss not exist.
-
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeOriginal, &tagInfo );
- foundFromXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "DateTimeOriginal" );
-
- if ( found && (! foundFromXMP) && (tagInfo.type == kTIFF_ASCIIType) ) {
- ImportTIFF_Date ( exif, tagInfo, xmp, kXMP_NS_EXIF, "DateTimeOriginal" );
- }
-
- found = exif.GetTag ( kTIFF_PrimaryIFD, kTIFF_DateTime, &tagInfo );
- foundFromXMP = xmp->DoesPropertyExist ( kXMP_NS_XMP, "ModifyDate" );
-
- if ( found && (! foundFromXMP) && (tagInfo.type == kTIFF_ASCIIType) ) {
- ImportTIFF_Date ( exif, tagInfo, xmp, kXMP_NS_XMP, "ModifyDate" );
- }
-
- // ----------------------------------------------------
- // Import the Exif IFD tags that have special mappings.
-
- // 34855 ISOSpeedRatings has special cases for ISO over 65535. The tag is SHORT, some cameras
- // omit the tag and some write 65535, all put the real ISO in MakerNote - which ACR might
- // extract and leave in the XMP. There are 3 import cases:
- // 1. No native tag: Leave existing XMP.
- // 2. All of the native values are under 65535: Clear any XMP and import.
- // 3. One or more of the native values are 65535: Leave existing XMP, else import.
-
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_ISOSpeedRatings, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_ShortType) && (tagInfo.count > 0) ) {
-
- bool keepXMP = false;
- XMP_Uns16 * itemPtr = (XMP_Uns16*) tagInfo.dataPtr;
- for ( XMP_Uns32 i = 0; i < tagInfo.count; ++i, ++itemPtr ) {
- if ( *itemPtr == 0xFFFF ) { keepXMP = true; break; } // ! Don't care about BE or LF, same either way.
- }
-
- if ( ! keepXMP ) xmp->DeleteProperty ( kXMP_NS_EXIF, "ISOSpeedRatings" );
-
- if ( ! xmp->DoesPropertyExist ( kXMP_NS_EXIF, "ISOSpeedRatings" ) ) {
- ImportArrayTIFF ( tagInfo, exif.IsNativeEndian(), xmp, kXMP_NS_EXIF, "ISOSpeedRatings" );
- }
-
- }
-
- // 36864 ExifVersion is 4 "undefined" ASCII characters.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_ExifVersion, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
- char str[5];
- *((XMP_Uns32*)str) = *((XMP_Uns32*)tagInfo.dataPtr);
- str[4] = 0;
- xmp->SetProperty ( kXMP_NS_EXIF, "ExifVersion", str );
- }
-
- // 40960 FlashpixVersion is 4 "undefined" ASCII characters.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_FlashpixVersion, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
- char str[5];
- *((XMP_Uns32*)str) = *((XMP_Uns32*)tagInfo.dataPtr);
- str[4] = 0;
- xmp->SetProperty ( kXMP_NS_EXIF, "FlashpixVersion", str );
- }
-
- // 37121 ComponentsConfiguration is an array of 4 "undefined" UInt8 bytes.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_ComponentsConfiguration, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
- ImportArrayTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "ComponentsConfiguration" );
- }
-
- // 37510 UserComment is a string with explicit encoding.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_UserComment, &tagInfo );
- if ( found ) {
- ImportTIFF_EncodedString ( exif, tagInfo, xmp, kXMP_NS_EXIF, "UserComment", true /* isLangAlt */ );
- }
-
- // 34856 OECF is an OECF/SFR table.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_OECF, &tagInfo );
- if ( found ) {
- ImportTIFF_OECFTable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "OECF" );
- }
-
- // 37385 Flash is a UInt16 collection of bit fields and is mapped to a struct in XMP.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_Flash, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_ShortType) && (tagInfo.count == 1) ) {
- ImportTIFF_Flash ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "Flash" );
- }
-
- // 41484 SpatialFrequencyResponse is an OECF/SFR table.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_SpatialFrequencyResponse, &tagInfo );
- if ( found ) {
- ImportTIFF_SFRTable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "SpatialFrequencyResponse" );
- }
-
- // 41728 FileSource is an "undefined" UInt8.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_FileSource, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 1) ) {
- ImportSingleTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "FileSource" );
- }
-
- // 41729 SceneType is an "undefined" UInt8.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_SceneType, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 1) ) {
- ImportSingleTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "SceneType" );
- }
-
- // 41730 CFAPattern is a custom table.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_CFAPattern, &tagInfo );
- if ( found ) {
- ImportTIFF_CFATable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "CFAPattern" );
- }
-
- // 41995 DeviceSettingDescription is a custom table.
- found = exif.GetTag ( kTIFF_ExifIFD, kTIFF_DeviceSettingDescription, &tagInfo );
- if ( found ) {
- ImportTIFF_DSDTable ( exif, tagInfo, xmp, kXMP_NS_EXIF, "DeviceSettingDescription" );
- }
-
- // --------------------------------------------------------
- // Import the GPS Info IFD tags that have special mappings.
-
- // 0 GPSVersionID is 4 UInt8 bytes and mapped as "n.n.n.n".
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSVersionID, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_ByteType) && (tagInfo.count == 4) ) {
- const char * strIn = (const char *) tagInfo.dataPtr;
- char strOut[8];
- strOut[0] = strIn[0];
- strOut[2] = strIn[1];
- strOut[4] = strIn[2];
- strOut[6] = strIn[3];
- strOut[1] = strOut[3] = strOut[5] = '.';
- strOut[7] = 0;
- xmp->SetProperty ( kXMP_NS_EXIF, "GPSVersionID", strOut );
- }
-
- // 2 GPSLatitude is a GPS coordinate master.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSLatitude, &tagInfo );
- if ( found ) {
- ImportTIFF_GPSCoordinate ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSLatitude" );
- }
-
- // 4 GPSLongitude is a GPS coordinate master.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSLongitude, &tagInfo );
- if ( found ) {
- ImportTIFF_GPSCoordinate ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSLongitude" );
- }
-
- // 7 GPSTimeStamp is a UTC time as 3 rationals, mated with the optional GPSDateStamp.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSTimeStamp, &tagInfo );
- if ( found && (tagInfo.type == kTIFF_RationalType) && (tagInfo.count == 3) ) {
- ImportTIFF_GPSTimeStamp ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSTimeStamp" );
- }
-
- // 20 GPSDestLatitude is a GPS coordinate master.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDestLatitude, &tagInfo );
- if ( found ) {
- ImportTIFF_GPSCoordinate ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSDestLatitude" );
- }
-
- // 22 GPSDestLongitude is a GPS coordinate master.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDestLongitude, &tagInfo );
- if ( found ) {
- ImportTIFF_GPSCoordinate ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSDestLongitude" );
- }
-
- // 27 GPSProcessingMethod is a string with explicit encoding.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSProcessingMethod, &tagInfo );
- if ( found ) {
- ImportTIFF_EncodedString ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSProcessingMethod" );
- }
-
- // 28 GPSAreaInformation is a string with explicit encoding.
- found = exif.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSAreaInformation, &tagInfo );
- if ( found ) {
- ImportTIFF_EncodedString ( exif, tagInfo, xmp, kXMP_NS_EXIF, "GPSAreaInformation" );
- }
-
-} // PhotoDataUtils::Import2WayExif
-
-// =================================================================================================
-// Import3WayDateTime
-// ==================
-
-static void Import3WayDateTime ( XMP_Uns16 exifTag, const TIFF_Manager & exif, const IPTC_Manager & iptc,
- SXMPMeta * xmp, int iptcDigestState, const IPTC_Manager & oldIPTC )
-{
- XMP_Uns8 iptcDS;
- XMP_StringPtr xmpNS, xmpProp;
-
- if ( exifTag == kTIFF_DateTimeOriginal ) {
- iptcDS = kIPTC_DateCreated;
- xmpNS = kXMP_NS_Photoshop;
- xmpProp = "DateCreated";
- } else if ( exifTag == kTIFF_DateTimeDigitized ) {
- iptcDS = kIPTC_DigitalCreateDate;
- xmpNS = kXMP_NS_XMP;
- xmpProp = "CreateDate";
- } else {
- XMP_Throw ( "Unrecognized dateID", kXMPErr_BadParam );
- }
-
- size_t iptcCount;
- bool haveXMP, haveExif, haveIPTC; // ! These are manipulated to simplify MWG-compliant logic.
- std::string xmpValue, exifValue, iptcValue;
- TIFF_Manager::TagInfo exifInfo;
- IPTC_Manager::DataSetInfo iptcInfo;
-
- // Get the basic info about available values.
- haveXMP = xmp->GetProperty ( xmpNS, xmpProp, &xmpValue, 0 );
- iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, iptcDS, iptcDigestState, haveXMP, &iptcInfo );
- haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
- haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_ExifIFD, exifTag, &exifInfo );
- XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
-
- if ( haveIPTC ) {
-
- PhotoDataUtils::ImportIPTC_Date ( iptcDS, iptc, xmp );
-
- } else if ( haveExif && (exifInfo.type == kTIFF_ASCIIType) ) {
-
- // Only import the Exif form if the non-TZ information differs from the XMP.
-
- TIFF_FileWriter exifFromXMP;
- TIFF_Manager::TagInfo infoFromXMP;
-
- ExportTIFF_Date ( *xmp, xmpNS, xmpProp, &exifFromXMP, exifTag );
- bool foundFromXMP = exifFromXMP.GetTag ( kTIFF_ExifIFD, exifTag, &infoFromXMP );
-
- if ( (! foundFromXMP) || (exifInfo.dataLen != infoFromXMP.dataLen) ||
- (! XMP_LitNMatch ( (char*)exifInfo.dataPtr, (char*)infoFromXMP.dataPtr, exifInfo.dataLen )) ) {
- ImportTIFF_Date ( exif, exifInfo, xmp, xmpNS, xmpProp );
- }
-
- }
-
-} // Import3WayDateTime
-
-// =================================================================================================
-// PhotoDataUtils::Import3WayItems
-// ===============================
-//
-// Handle the imports that involve all 3 of Exif, IPTC, and XMP. There are only 4 properties with
-// 3-way mappings, copyright, description, creator, and date/time. Following the MWG guidelines,
-// this general policy is applied separately to each:
-//
-// If the new IPTC digest differs from the stored digest (favor IPTC over Exif and XMP)
-// If the IPTC value differs from the predicted old IPTC value
-// Import the IPTC value, including deleting the XMP
-// Else if the Exif is non-empty and differs from the XMP
-// Import the Exif value (does not delete existing XMP)
-// Else if the stored IPTC digest is missing (favor Exif over IPTC, or IPTC over missing XMP)
-// If the Exif is non-empty and differs from the XMP
-// Import the Exif value (does not delete existing XMP)
-// Else if the XMP is missing and the Exif is missing or empty
-// Import the IPTC value
-// Else (the new IPTC digest matches the stored digest - ignore the IPTC)
-// If the Exif is non-empty and differs from the XMP
-// Import the Exif value (does not delete existing XMP)
-//
-// Note that missing or empty Exif will never cause existing XMP to be deleted. This is a pragmatic
-// choice to improve compatibility with pre-MWG software. There are few Exif-only editors for these
-// 3-way properties, there are important existing IPTC-only editors.
-
-// -------------------------------------------------------------------------------------------------
-
-void PhotoDataUtils::Import3WayItems ( const TIFF_Manager & exif, const IPTC_Manager & iptc, SXMPMeta * xmp, int iptcDigestState )
-{
- size_t iptcCount;
-
- bool haveXMP, haveExif, haveIPTC; // ! These are manipulated to simplify MWG-compliant logic.
- std::string xmpValue, exifValue, iptcValue;
-
- TIFF_Manager::TagInfo exifInfo;
- IPTC_Manager::DataSetInfo iptcInfo;
-
- IPTC_Writer oldIPTC;
- if ( iptcDigestState == kDigestDiffers ) {
- PhotoDataUtils::ExportIPTC ( *xmp, &oldIPTC ); // Predict old IPTC DataSets based on the existing XMP.
- }
-
- // ---------------------------------------------------------------------------------
- // Process the copyright. Replace internal nuls in the Exif to "merge" the portions.
-
- // Get the basic info about available values.
- haveXMP = xmp->GetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", 0, &xmpValue, 0 );
- iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_CopyrightNotice, iptcDigestState, haveXMP, &iptcInfo );
- haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
- haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Copyright, &exifInfo );
- XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
-
- if ( haveExif && (exifInfo.dataLen > 1) ) { // Replace internal nul characters with linefeed.
- for ( XMP_Uns32 i = 0; i < exifInfo.dataLen-1; ++i ) {
- if ( ((char*)exifInfo.dataPtr)[i] == 0 ) ((char*)exifInfo.dataPtr)[i] = 0x0A;
- }
- }
-
- if ( haveIPTC ) {
- PhotoDataUtils::ImportIPTC_LangAlt ( iptc, xmp, kIPTC_CopyrightNotice, kXMP_NS_DC, "rights" );
- } else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
- xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", exifValue.c_str() );
- }
-
- // ------------------------
- // Process the description.
-
- // Get the basic info about available values.
- haveXMP = xmp->GetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", 0, &xmpValue, 0 );
- iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_Description, iptcDigestState, haveXMP, &iptcInfo );
- haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
- haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_ImageDescription, &exifInfo );
- XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
-
- if ( haveIPTC ) {
- PhotoDataUtils::ImportIPTC_LangAlt ( iptc, xmp, kIPTC_Description, kXMP_NS_DC, "description" );
- } else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
- xmp->SetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", exifValue.c_str() );
- }
-
- // -------------------------------------------------------------------------------------------
- // Process the creator. The XMP and IPTC are arrays, the Exif is a semicolon separated string.
-
- // Get the basic info about available values.
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_DC, "creator" );
- haveExif = PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Artist, &exifInfo );
- iptcCount = PhotoDataUtils::GetNativeInfo ( iptc, kIPTC_Creator, iptcDigestState, haveXMP, &iptcInfo );
- haveIPTC = (iptcCount > 0);
- XMP_Assert ( (iptcDigestState == kDigestMatches) ? (! haveIPTC) : true );
- haveExif = (! haveXMP) && (! haveIPTC) && PhotoDataUtils::GetNativeInfo ( exif, kTIFF_PrimaryIFD, kTIFF_Artist, &exifInfo );
- XMP_Assert ( (! (haveExif & haveXMP)) & (! (haveExif & haveIPTC)) );
-
- if ( haveIPTC ) {
- PhotoDataUtils::ImportIPTC_Array ( iptc, xmp, kIPTC_Creator, kXMP_NS_DC, "creator" );
- } else if ( haveExif && PhotoDataUtils::IsValueDifferent ( exifInfo, xmpValue, &exifValue ) ) {
- SXMPUtils::SeparateArrayItems ( xmp, kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, exifValue );
- }
-
- // ------------------------------------------------------------------------------
- // Process DateTimeDigitized; DateTimeOriginal and DateTime are 2-way.
- // *** Exif DateTimeOriginal <-> XMP exif:DateTimeOriginal
- // *** IPTC DateCreated <-> XMP photoshop:DateCreated
- // *** Exif DateTimeDigitized <-> IPTC DigitalCreateDate <-> XMP xmp:CreateDate
- // *** TIFF DateTime <-> XMP xmp:ModifyDate
-
- Import3WayDateTime ( kTIFF_DateTimeDigitized, exif, iptc, xmp, iptcDigestState, oldIPTC );
-
-} // PhotoDataUtils::Import3WayItems
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// ExportSingleTIFF
-// ================
-//
-// This is only called when the XMP exists and will be exported. And only for standard mappings.
-
-// ! Only implemented for the types known to be needed.
-
-static void
-ExportSingleTIFF ( TIFF_Manager * tiff, XMP_Uns8 ifd, const TIFF_MappingToXMP & mapInfo,
- bool nativeEndian, const std::string & xmpValue )
-{
- XMP_Assert ( (mapInfo.count == 1) || (mapInfo.type == kTIFF_ASCIIType) );
- XMP_Assert ( mapInfo.name[0] != 0 ); // Must be a standard mapping.
-
- char nextChar; // Used to make sure sscanf consumes all of the string.
-
- switch ( mapInfo.type ) {
-
- case kTIFF_ByteType : {
- unsigned short binValue;
- int items = sscanf ( xmpValue.c_str(), "%hu%c", &binValue, &nextChar ); // AUDIT: Using xmpValue.c_str() is safe.
- if ( items != 1 ) return; // ? complain? notify client?
- tiff->SetTag_Byte ( ifd, mapInfo.id, (XMP_Uns8)binValue );
- break;
- }
-
- case kTIFF_ShortType : {
- unsigned long binValue;
- int items = sscanf ( xmpValue.c_str(), "%lu%c", &binValue, &nextChar ); // AUDIT: Using xmpValue.c_str() is safe.
- if ( items != 1 ) return; // ? complain? notify client?
- tiff->SetTag_Short ( ifd, mapInfo.id, (XMP_Uns16)binValue );
- break;
- }
-
- case kTIFF_ShortOrLongType : {
- unsigned long binValue;
- int items = sscanf ( xmpValue.c_str(), "%lu%c", &binValue, &nextChar ); // AUDIT: Using xmpValue.c_str() is safe.
- if ( items != 1 ) return; // ? complain? notify client?
- if ( binValue <= 0xFFFF ) {
- tiff->SetTag_Short ( ifd, mapInfo.id, (XMP_Uns16)binValue );
- } else {
- tiff->SetTag_Long ( ifd, mapInfo.id, (XMP_Uns32)binValue );
- }
- break;
- }
-
- case kTIFF_RationalType : { // The XMP is formatted as "num/denom".
- unsigned long num, denom;
- int items = sscanf ( xmpValue.c_str(), "%lu/%lu%c", &num, &denom, &nextChar ); // AUDIT: Using xmpValue.c_str() is safe.
- if ( items != 2 ) {
- if ( items != 1 ) return; // ? complain? notify client?
- denom = 1; // The XMP was just an integer, assume a denominator of 1.
- }
- tiff->SetTag_Rational ( ifd, mapInfo.id, (XMP_Uns32)num, (XMP_Uns32)denom );
- break;
- }
-
- case kTIFF_SRationalType : { // The XMP is formatted as "num/denom".
- signed long num, denom;
- int items = sscanf ( xmpValue.c_str(), "%ld/%ld%c", &num, &denom, &nextChar ); // AUDIT: Using xmpValue.c_str() is safe.
- if ( items != 2 ) {
- if ( items != 1 ) return; // ? complain? notify client?
- denom = 1; // The XMP was just an integer, assume a denominator of 1.
- }
- tiff->SetTag_SRational ( ifd, mapInfo.id, (XMP_Int32)num, (XMP_Int32)denom );
- break;
- }
-
- case kTIFF_ASCIIType :
- tiff->SetTag ( ifd, mapInfo.id, kTIFF_ASCIIType, (XMP_Uns32)(xmpValue.size()+1), xmpValue.c_str() );
- break;
-
- default:
- XMP_Assert ( false ); // Force a debug assert for unexpected types.
-
- }
-
-} // ExportSingleTIFF
-
-// =================================================================================================
-// ExportArrayTIFF
-// ================
-//
-// This is only called when the XMP exists and will be exported. And only for standard mappings.
-
-// ! Only implemented for the types known to be needed.
-
-static void
-ExportArrayTIFF ( TIFF_Manager * tiff, XMP_Uns8 ifd, const TIFF_MappingToXMP & mapInfo, bool nativeEndian,
- const SXMPMeta & xmp, const char * xmpNS, const char * xmpArray )
-{
- XMP_Assert ( (mapInfo.count != 1) && (mapInfo.type != kTIFF_ASCIIType) );
- XMP_Assert ( mapInfo.name[0] != 0 ); // Must be a standard mapping.
- XMP_Assert ( mapInfo.type == kTIFF_ShortType ); // ! So far ISOSpeedRatings is the only standard array export.
- XMP_Assert ( xmp.DoesPropertyExist ( xmpNS, xmpArray ) );
-
- if ( mapInfo.type != kTIFF_ShortType ) return; // ! So far ISOSpeedRatings is the only standard array export.
-
- size_t arraySize = xmp.CountArrayItems ( xmpNS, xmpArray );
- if ( arraySize == 0 ) {
- tiff->DeleteTag ( ifd, mapInfo.id );
- return;
- }
-
- std::vector<XMP_Uns16> vecValue;
- vecValue.assign ( arraySize, 0 );
- XMP_Uns16 * binPtr = (XMP_Uns16*) &vecValue[0];
-
- std::string itemPath;
- XMP_Int32 int32;
- XMP_Uns16 uns16;
- for ( size_t i = 1; i <= arraySize; ++i, ++binPtr ) {
- SXMPUtils::ComposeArrayItemPath ( xmpNS, xmpArray, (XMP_Index)i, &itemPath );
- xmp.GetProperty_Int ( xmpNS, itemPath.c_str(), &int32, 0 );
- uns16 = (XMP_Uns16)int32;
- if ( ! nativeEndian ) uns16 = Flip2 ( uns16 );
- *binPtr = uns16;
- }
-
- tiff->SetTag ( ifd, mapInfo.id, kTIFF_ShortType, (XMP_Uns32)arraySize, &vecValue[0] );
-
-} // ExportArrayTIFF
-
-// =================================================================================================
-// ExportTIFF_StandardMappings
-// ===========================
-
-static void
-ExportTIFF_StandardMappings ( XMP_Uns8 ifd, TIFF_Manager * tiff, const SXMPMeta & xmp )
-{
- const bool nativeEndian = tiff->IsNativeEndian();
- TIFF_Manager::TagInfo tagInfo;
- std::string xmpValue;
- XMP_OptionBits xmpForm;
-
- const TIFF_MappingToXMP * mappings = 0;
- const char * xmpNS = 0;
-
- if ( ifd == kTIFF_PrimaryIFD ) {
- mappings = sPrimaryIFDMappings;
- xmpNS = kXMP_NS_TIFF;
- } else if ( ifd == kTIFF_ExifIFD ) {
- mappings = sExifIFDMappings;
- xmpNS = kXMP_NS_EXIF;
- } else if ( ifd == kTIFF_GPSInfoIFD ) {
- mappings = sGPSInfoIFDMappings;
- xmpNS = kXMP_NS_EXIF; // ! Yes, the GPS Info tags are in the exif: namespace.
- } else {
- XMP_Throw ( "Invalid IFD for standard mappings", kXMPErr_InternalFailure );
- }
-
- for ( size_t i = 0; mappings[i].id != 0xFFFF; ++i ) {
-
- try { // Don't let errors with one stop the others.
-
- const TIFF_MappingToXMP & mapInfo = mappings[i];
-
- if ( mapInfo.exportMode == kExport_Never ) continue;
- if ( mapInfo.name[0] == 0 ) continue; // Skip special mappings, handled higher up.
-
- bool haveTIFF = tiff->GetTag ( ifd, mapInfo.id, &tagInfo );
- if ( haveTIFF && (mapInfo.exportMode == kExport_InjectOnly) ) continue;
-
- bool haveXMP = xmp.GetProperty ( xmpNS, mapInfo.name, &xmpValue, &xmpForm );
- if ( ! haveXMP ) {
-
- if ( haveTIFF && (mapInfo.exportMode == kExport_Always) ) tiff->DeleteTag ( ifd, mapInfo.id );
-
- } else {
-
- XMP_Assert ( tagInfo.type != kTIFF_UndefinedType ); // These must have a special mapping.
- if ( tagInfo.type == kTIFF_UndefinedType ) continue;
-
- const bool mapSingle = ((mapInfo.count == 1) || (mapInfo.type == kTIFF_ASCIIType));
- if ( mapSingle ) {
- if ( ! XMP_PropIsSimple ( xmpForm ) ) continue; // ? Notify client?
- ExportSingleTIFF ( tiff, ifd, mapInfo, nativeEndian, xmpValue );
- } else {
- if ( ! XMP_PropIsArray ( xmpForm ) ) continue; // ? Notify client?
- ExportArrayTIFF ( tiff, ifd, mapInfo, nativeEndian, xmp, xmpNS, mapInfo.name );
- }
-
- }
-
- } catch ( ... ) {
-
- // Do nothing, let other imports proceed.
- // ? Notify client?
-
- }
-
- }
-
-} // ExportTIFF_StandardMappings
-
-// =================================================================================================
-// ExportTIFF_Date
-// ===============
-//
-// Convert an XMP date/time to an Exif 2.2 master date/time tag plus associated fractional seconds.
-// The Exif date/time part is a 20 byte ASCII value formatted as "YYYY:MM:DD HH:MM:SS" with a
-// terminating nul. The fractional seconds are a nul terminated ASCII string with possible space
-// padding. They are literally the fractional part, the digits that would be to the right of the
-// decimal point.
-
-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;
- switch ( mainID ) {
- case kTIFF_DateTime : mainIFD = kTIFF_PrimaryIFD; fracID = kTIFF_SubSecTime; break;
- case kTIFF_DateTimeOriginal : fracID = kTIFF_SubSecTimeOriginal; break;
- case kTIFF_DateTimeDigitized : fracID = kTIFF_SubSecTimeDigitized; break;
- }
-
- try { // Don't let errors with one stop the others.
-
- std::string xmpStr;
- bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpStr, 0 );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( mainIFD, mainID );
- tiff->DeleteTag ( kTIFF_ExifIFD, fracID ); // ! The subseconds are always in the Exif IFD.
- return;
- }
-
- // Format using all of the numbers. Then overwrite blanks for missing fields. The fields
- // missing from the XMP are detected with length checks: YYYY-MM-DDThh:mm:ss
- // < 18 - no seconds
- // < 15 - no minutes
- // < 12 - no hours
- // < 9 - no day
- // < 6 - no month
- // < 1 - no year
-
- XMP_DateTime xmpBin;
- SXMPUtils::ConvertToDate ( xmpStr.c_str(), &xmpBin );
-
- char buffer[24];
- snprintf ( buffer, sizeof(buffer), "%04d:%02d:%02d %02d:%02d:%02d", // AUDIT: Use of sizeof(buffer) is safe.
- xmpBin.year, xmpBin.month, xmpBin.day, xmpBin.hour, xmpBin.minute, xmpBin.second );
-
- size_t xmpLen = xmpStr.size();
- if ( xmpLen < 18 ) {
- buffer[17] = buffer[18] = ' ';
- if ( xmpLen < 15 ) {
- buffer[14] = buffer[15] = ' ';
- if ( xmpLen < 12 ) {
- buffer[11] = buffer[12] = ' ';
- if ( xmpLen < 9 ) {
- buffer[8] = buffer[9] = ' ';
- if ( xmpLen < 6 ) {
- buffer[5] = buffer[6] = ' ';
- if ( xmpLen < 1 ) {
- buffer[0] = buffer[1] = buffer[2] = buffer[3] = ' ';
- }
- }
- }
- }
- }
- }
-
- tiff->SetTag_ASCII ( mainIFD, mainID, buffer );
-
- if ( xmpBin.nanoSecond == 0 ) {
-
- tiff->DeleteTag ( kTIFF_ExifIFD, fracID );
-
- } else {
-
- snprintf ( buffer, sizeof(buffer), "%09d", xmpBin.nanoSecond ); // AUDIT: Use of sizeof(buffer) is safe.
- for ( size_t i = strlen(buffer)-1; i > 0; --i ) {
- if ( buffer[i] != '0' ) break;
- buffer[i] = 0; // Strip trailing zero digits.
- }
-
- tiff->SetTag_ASCII ( kTIFF_ExifIFD, fracID, buffer ); // ! The subseconds are always in the Exif IFD.
-
- }
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_Date
-
-// =================================================================================================
-// ExportTIFF_ArrayASCII
-// =====================
-//
-// Catenate all of the XMP array values into a string. Use a "; " separator for Artist, nul for others.
-
-static void
-ExportTIFF_ArrayASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
- TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
-{
- try { // Don't let errors with one stop the others.
-
- std::string itemValue, fullValue;
- XMP_OptionBits xmpFlags;
-
- bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( ifd, id );
- return;
- }
-
- if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the tag?
-
- if ( id == kTIFF_Artist ) {
- SXMPUtils::CatenateArrayItems ( xmp, xmpNS, xmpProp, 0, 0, kXMP_PropArrayIsOrdered, &fullValue );
- fullValue += '\x0'; // ! Need explicit final nul for SetTag below.
- } else {
- size_t count = xmp.CountArrayItems ( xmpNS, xmpProp );
- for ( size_t i = 1; i <= count; ++i ) { // ! XMP arrays are indexed from 1.
- (void) xmp.GetArrayItem ( xmpNS, xmpProp, (XMP_Index)i, &itemValue, &xmpFlags );
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
- fullValue.append ( itemValue );
- fullValue.append ( 1, '\x0' );
- }
- }
-
- tiff->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)fullValue.size(), fullValue.c_str() ); // ! Already have trailing nul.
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_ArrayASCII
-
-// =================================================================================================
-// ExportTIFF_LocTextASCII
-// ======================
-
-static void
-ExportTIFF_LocTextASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
- TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
-{
- try { // Don't let errors with one stop the others.
-
- std::string xmpValue;
-
- bool foundXMP = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &xmpValue, 0 );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( ifd, id );
- return;
- }
-
- tiff->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)( xmpValue.size()+1 ), xmpValue.c_str() );
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_LocTextASCII
-
-// =================================================================================================
-// ExportTIFF_EncodedString
-// ========================
-
-static void
-ExportTIFF_EncodedString ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
- TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id, bool isLangAlt = false )
-{
- try { // Don't let errors with one stop the others.
-
- std::string xmpValue;
- XMP_OptionBits xmpFlags;
-
- bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( ifd, id );
- return;
- }
-
- if ( ! isLangAlt ) {
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag?
- } else {
- if ( ! XMP_ArrayIsAltText ( xmpFlags ) ) return; // ? Complain? Delete the tag?
- bool ok = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &xmpValue, 0 );
- if ( ! ok ) return; // ? Complain? Delete the tag?
- }
-
- XMP_Uns8 encoding = kTIFF_EncodeASCII;
- for ( size_t i = 0; i < xmpValue.size(); ++i ) {
- if ( (XMP_Uns8)xmpValue[i] >= 0x80 ) {
- encoding = kTIFF_EncodeUnicode;
- break;
- }
- }
-
- tiff->SetTag_EncodedString ( ifd, id, xmpValue.c_str(), encoding );
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_EncodedString
-
-// =================================================================================================
-// ExportTIFF_GPSCoordinate
-// ========================
-//
-// The XMP format is either "deg,min,secR" or "deg,min.fracR", where 'R' is the reference direction,
-// 'N', 'S', 'E', or 'W'. The location gets output as ( deg/1, min/1, sec/1 ) for the first form,
-// and ( deg/1, minFrac/denom, 0/1 ) for the second form.
-
-// ! We arbitrarily limit the number of fractional minute digits to 6 to avoid overflow in the
-// ! combined numerator. But we don't otherwise check for overflow or range errors.
-
-static void
-ExportTIFF_GPSCoordinate ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
- TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 _id )
-{
- XMP_Uns16 refID = _id-1; // ! The GPS refs and locations are all tag N-1 and N pairs.
- XMP_Uns16 locID = _id;
-
- XMP_Assert ( (locID & 1) == 0 );
-
- try { // Don't let errors with one stop the others.
-
- std::string xmpValue;
- XMP_OptionBits xmpFlags;
-
- bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( ifd, refID );
- tiff->DeleteTag ( ifd, locID );
- return;
- }
-
- if ( ! XMP_PropIsSimple ( xmpFlags ) ) return;
-
- const char * chPtr = xmpValue.c_str();
-
- XMP_Uns32 deg=0, minNum=0, minDenom=1, sec=0;
-
- for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) deg = deg*10 + (*chPtr - '0');
- if ( *chPtr != ',' ) return; // Bad XMP string.
- ++chPtr; // Skip the comma.
-
- for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) minNum = minNum*10 + (*chPtr - '0');
- if ( (*chPtr != ',') && (*chPtr != '.') ) return; // Bad XMP string.
-
- if ( *chPtr == ',' ) {
-
- ++chPtr; // Skip the comma.
- for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) sec = sec*10 + (*chPtr - '0');
-
- } else {
-
- XMP_Assert ( *chPtr == '.' );
- ++chPtr; // Skip the period.
- for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) {
- if ( minDenom > 100*1000 ) continue; // Don't accumulate any more digits.
- minDenom *= 10;
- minNum = minNum*10 + (*chPtr - '0');
- }
-
- }
-
- if ( *(chPtr+1) != 0 ) return; // Bad XMP string.
-
- char ref[2];
- ref[0] = *chPtr;
- ref[1] = 0;
-
- tiff->SetTag ( ifd, refID, kTIFF_ASCIIType, 2, &ref[0] );
-
- XMP_Uns32 loc[6];
- tiff->PutUns32 ( deg, &loc[0] );
- tiff->PutUns32 ( 1, &loc[1] );
- tiff->PutUns32 ( minNum, &loc[2] );
- tiff->PutUns32 ( minDenom, &loc[3] );
- tiff->PutUns32 ( sec, &loc[4] );
- tiff->PutUns32 ( 1, &loc[5] );
-
- tiff->SetTag ( ifd, locID, kTIFF_RationalType, 3, &loc[0] );
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_GPSCoordinate
-
-// =================================================================================================
-// ExportTIFF_GPSTimeStamp
-// =======================
-//
-// The Exif is in 2 tags, GPSTimeStamp and GPSDateStamp. The time is 3 rationals for the hour, minute,
-// and second in UTC. The date is a nul terminated string "YYYY:MM:DD".
-
-static const double kBillion = 1000.0*1000.0*1000.0;
-static const double mMaxSec = 4.0*kBillion - 1.0;
-
-static void
-ExportTIFF_GPSTimeStamp ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp, TIFF_Manager * tiff )
-{
-
- try { // Don't let errors with one stop the others.
-
- XMP_DateTime binXMP;
- bool foundXMP = xmp.GetProperty_Date ( xmpNS, xmpProp, &binXMP, 0 );
- if ( ! foundXMP ) {
- tiff->DeleteTag ( kTIFF_GPSInfoIFD, kTIFF_GPSTimeStamp );
- tiff->DeleteTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDateStamp );
- return;
- }
-
- SXMPUtils::ConvertToUTCTime ( &binXMP );
-
- XMP_Uns32 exifTime[6];
- tiff->PutUns32 ( binXMP.hour, &exifTime[0] );
- tiff->PutUns32 ( 1, &exifTime[1] );
- tiff->PutUns32 ( binXMP.minute, &exifTime[2] );
- tiff->PutUns32 ( 1, &exifTime[3] );
- if ( binXMP.nanoSecond == 0 ) {
- tiff->PutUns32 ( binXMP.second, &exifTime[4] );
- tiff->PutUns32 ( 1, &exifTime[5] );
- } else {
- double fSec = (double)binXMP.second + ((double)binXMP.nanoSecond / kBillion );
- XMP_Uns32 denom = 1000*1000; // Choose microsecond resolution by default.
- TIFF_Manager::TagInfo oldInfo;
- bool hadExif = tiff->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSTimeStamp, &oldInfo );
- if ( hadExif && (oldInfo.type == kTIFF_RationalType) && (oldInfo.count == 3) ) {
- XMP_Uns32 oldDenom = tiff->GetUns32 ( &(((XMP_Uns32*)oldInfo.dataPtr)[5]) );
- if ( oldDenom != 1 ) denom = oldDenom;
- }
- fSec *= denom;
- while ( fSec > mMaxSec ) { fSec /= 10; denom /= 10; }
- tiff->PutUns32 ( (XMP_Uns32)fSec, &exifTime[4] );
- tiff->PutUns32 ( denom, &exifTime[5] );
- }
- tiff->SetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSTimeStamp, kTIFF_RationalType, 3, &exifTime[0] );
-
- char exifDate[16]; // AUDIT: Long enough, only need 11.
- snprintf ( exifDate, 12, "%04d:%02d:%02d", binXMP.year, binXMP.month, binXMP.day );
- if ( exifDate[10] == 0 ) { // Make sure there is no value overflow.
- tiff->SetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDateStamp, kTIFF_ASCIIType, 11, exifDate );
- }
-
- } catch ( ... ) {
- // Do nothing, let other exports proceed.
- // ? Notify client?
- }
-
-} // ExportTIFF_GPSTimeStamp
-
-// =================================================================================================
-// =================================================================================================
-
-// =================================================================================================
-// PhotoDataUtils::ExportExif
-// ==========================
-
-void
-PhotoDataUtils::ExportExif ( SXMPMeta * xmp, TIFF_Manager * exif )
-{
- bool haveXMP, haveExif;
- std::string xmpValue;
- XMP_Int32 int32;
- XMP_Uns8 uns8;
-
- // Do all of the table driven standard exports.
-
- ExportTIFF_StandardMappings ( kTIFF_PrimaryIFD, exif, *xmp );
- ExportTIFF_StandardMappings ( kTIFF_ExifIFD, exif, *xmp );
- ExportTIFF_StandardMappings ( kTIFF_GPSInfoIFD, exif, *xmp );
-
- // Export dc:description to TIFF ImageDescription, and exif:UserComment to EXIF UserComment.
-
- // *** This is not following the MWG guidelines. The policy here tries to be more backward compatible.
-
- ExportTIFF_LocTextASCII ( *xmp, kXMP_NS_DC, "description",
- exif, kTIFF_PrimaryIFD, kTIFF_ImageDescription );
-
- ExportTIFF_EncodedString ( *xmp, kXMP_NS_EXIF, "UserComment",
- exif, kTIFF_ExifIFD, kTIFF_UserComment, true /* isLangAlt */ );
-
- // Export all of the date/time tags.
- // ! Special case: Don't create Exif DateTimeDigitized. This can avoid PSD full rewrite due to
- // ! new mapping from xmp:CreateDate.
-
- if ( exif->GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeDigitized, 0 ) ) {
- ExportTIFF_Date ( *xmp, kXMP_NS_XMP, "CreateDate", exif, kTIFF_DateTimeDigitized );
- }
-
- ExportTIFF_Date ( *xmp, kXMP_NS_EXIF, "DateTimeOriginal", exif, kTIFF_DateTimeOriginal );
- ExportTIFF_Date ( *xmp, kXMP_NS_XMP, "ModifyDate", exif, kTIFF_DateTime );
-
- // 34855 ISOSpeedRatings has special cases for ISO over 65535. The tag is SHORT, some cameras
- // omit the tag and some write 65535, all put the real ISO in MakerNote - which ACR might
- // extract and leave in the XMP. There are 2 export cases:
- // 1. No XMP property, or one or more of the XMP values are over 65535:
- // Leave both the XMP and native tag alone.
- // 1. Have XMP property and all of the XMP values are under 65535:
- // Leave existing native tag, else export; strip the XMP either way.
-
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "ISOSpeedRatings" );
- if ( haveXMP ) {
-
- XMP_Index i, count;
- std::string isoValue;
- bool haveHighISO = false;
-
- for ( i = 1, count = xmp->CountArrayItems ( kXMP_NS_EXIF, "ISOSpeedRatings" ); i <= count; ++i ) {
- xmp->GetArrayItem ( kXMP_NS_EXIF, "ISOSpeedRatings", i, &isoValue, 0 );
- if ( SXMPUtils::ConvertToInt ( isoValue.c_str() ) > 0xFFFF ) { haveHighISO = true; break; }
- }
-
- if ( ! haveHighISO ) {
- haveExif = exif->GetTag ( kTIFF_ExifIFD, kTIFF_ISOSpeedRatings, 0 );
- if ( ! haveExif ) { // ISOSpeedRatings has an inject-only mapping.
- ExportArrayTIFF ( exif, kTIFF_ExifIFD, kISOSpeedMapping, exif->IsNativeEndian(), *xmp, kXMP_NS_EXIF, "ISOSpeedRatings" );
- }
- xmp->DeleteProperty ( kXMP_NS_EXIF, "ISOSpeedRatings");
- }
-
- }
-
- // Export the remaining TIFF, Exif, and GPS IFD tags.
-
- ExportTIFF_ArrayASCII ( *xmp, kXMP_NS_DC, "creator", exif, kTIFF_PrimaryIFD, kTIFF_Artist );
-
- ExportTIFF_LocTextASCII ( *xmp, kXMP_NS_DC, "rights", exif, kTIFF_PrimaryIFD, kTIFF_Copyright );
-
- haveXMP = xmp->GetProperty ( kXMP_NS_EXIF, "ExifVersion", &xmpValue, 0 );
- if ( haveXMP && (xmpValue.size() == 4) && (! exif->GetTag ( kTIFF_ExifIFD, kTIFF_ExifVersion, 0 )) ) {
- // 36864 ExifVersion is 4 "undefined" ASCII characters.
- exif->SetTag ( kTIFF_ExifIFD, kTIFF_ExifVersion, kTIFF_UndefinedType, 4, xmpValue.data() );
- }
-
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "ComponentsConfiguration" );
- if ( haveXMP && (xmp->CountArrayItems ( kXMP_NS_EXIF, "ComponentsConfiguration" ) == 4) &&
- (! exif->GetTag ( kTIFF_ExifIFD, kTIFF_ComponentsConfiguration, 0 )) ) {
- // 37121 ComponentsConfiguration is an array of 4 "undefined" UInt8 bytes.
- XMP_Uns8 compConfig[4];
- xmp->GetProperty_Int ( kXMP_NS_EXIF, "ComponentsConfiguration[1]", &int32, 0 );
- compConfig[0] = (XMP_Uns8)int32;
- xmp->GetProperty_Int ( kXMP_NS_EXIF, "ComponentsConfiguration[2]", &int32, 0 );
- compConfig[1] = (XMP_Uns8)int32;
- xmp->GetProperty_Int ( kXMP_NS_EXIF, "ComponentsConfiguration[3]", &int32, 0 );
- compConfig[2] = (XMP_Uns8)int32;
- xmp->GetProperty_Int ( kXMP_NS_EXIF, "ComponentsConfiguration[4]", &int32, 0 );
- compConfig[3] = (XMP_Uns8)int32;
- exif->SetTag ( kTIFF_ExifIFD, kTIFF_ComponentsConfiguration, kTIFF_UndefinedType, 4, &compConfig[0] );
- }
-
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "Flash" );
- if ( haveXMP && (! exif->GetTag ( kTIFF_ExifIFD, kTIFF_Flash, 0 )) ) {
- // 37385 Flash is a UInt16 collection of bit fields and is mapped to a struct in XMP.
- XMP_Uns16 binFlash = 0;
- bool field;
- haveXMP = xmp->GetProperty_Bool ( kXMP_NS_EXIF, "Flash/exif:Fired", &field, 0 );
- if ( haveXMP & field ) binFlash |= 0x0001;
- haveXMP = xmp->GetProperty_Int ( kXMP_NS_EXIF, "Flash/exif:Return", &int32, 0 );
- if ( haveXMP ) binFlash |= (int32 & 3) << 1;
- haveXMP = xmp->GetProperty_Int ( kXMP_NS_EXIF, "Flash/exif:Mode", &int32, 0 );
- if ( haveXMP ) binFlash |= (int32 & 3) << 3;
- haveXMP = xmp->GetProperty_Bool ( kXMP_NS_EXIF, "Flash/exif:Function", &field, 0 );
- if ( haveXMP & field ) binFlash |= 0x0020;
- haveXMP = xmp->GetProperty_Bool ( kXMP_NS_EXIF, "Flash/exif:RedEyeMode", &field, 0 );
- if ( haveXMP & field ) binFlash |= 0x0040;
- exif->SetTag_Short ( kTIFF_ExifIFD, kTIFF_Flash, binFlash );
- }
-
- haveXMP = xmp->GetProperty_Int ( kXMP_NS_EXIF, "FileSource", &int32, 0 );
- if ( haveXMP && (! exif->GetTag ( kTIFF_ExifIFD, kTIFF_FileSource, 0 )) ) {
- // 41728 FileSource is an "undefined" UInt8.
- uns8 = (XMP_Uns8)int32;
- exif->SetTag ( kTIFF_ExifIFD, kTIFF_FileSource, kTIFF_UndefinedType, 1, &uns8 );
- }
-
- haveXMP = xmp->GetProperty_Int ( kXMP_NS_EXIF, "SceneType", &int32, 0 );
- if ( haveXMP && (! exif->GetTag ( kTIFF_ExifIFD, kTIFF_SceneType, 0 )) ) {
- // 41729 SceneType is an "undefined" UInt8.
- uns8 = (XMP_Uns8)int32;
- exif->SetTag ( kTIFF_ExifIFD, kTIFF_SceneType, kTIFF_UndefinedType, 1, &uns8 );
- }
-
- // *** Deferred inject-only tags: SpatialFrequencyResponse, DeviceSettingDescription, CFAPattern
-
- haveXMP = xmp->GetProperty ( kXMP_NS_EXIF, "GPSVersionID", &xmpValue, 0 ); // This is inject-only.
- if ( haveXMP && (xmpValue.size() == 7) && (! exif->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSVersionID, 0 )) ) {
- char gpsID[4]; // 0 GPSVersionID is 4 UInt8 bytes and mapped in XMP as "n.n.n.n".
- gpsID[0] = xmpValue[0];
- gpsID[1] = xmpValue[2];
- gpsID[2] = xmpValue[4];
- gpsID[3] = xmpValue[6];
- exif->SetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSVersionID, kTIFF_ByteType, 4, &gpsID[0] );
- }
-
- ExportTIFF_GPSCoordinate ( *xmp, kXMP_NS_EXIF, "GPSLatitude", exif, kTIFF_GPSInfoIFD, kTIFF_GPSLatitude );
-
- ExportTIFF_GPSCoordinate ( *xmp, kXMP_NS_EXIF, "GPSLongitude", exif, kTIFF_GPSInfoIFD, kTIFF_GPSLongitude );
-
- ExportTIFF_GPSTimeStamp ( *xmp, kXMP_NS_EXIF, "GPSTimeStamp", exif );
-
- // The following GPS tags are inject-only.
-
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "GPSDestLatitude" );
- if ( haveXMP && (! exif->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDestLatitude, 0 )) ) {
- ExportTIFF_GPSCoordinate ( *xmp, kXMP_NS_EXIF, "GPSDestLatitude", exif, kTIFF_GPSInfoIFD, kTIFF_GPSDestLatitude );
- }
-
- haveXMP = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "GPSDestLongitude" );
- if ( haveXMP && (! exif->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDestLongitude, 0 )) ) {
- ExportTIFF_GPSCoordinate ( *xmp, kXMP_NS_EXIF, "GPSDestLongitude", exif, kTIFF_GPSInfoIFD, kTIFF_GPSDestLongitude );
- }
-
- haveXMP = xmp->GetProperty ( kXMP_NS_EXIF, "GPSProcessingMethod", &xmpValue, 0 );
- if ( haveXMP && (! xmpValue.empty()) && (! exif->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSProcessingMethod, 0 )) ) {
- // 27 GPSProcessingMethod is a string with explicit encoding.
- ExportTIFF_EncodedString ( *xmp, kXMP_NS_EXIF, "GPSProcessingMethod", exif, kTIFF_GPSInfoIFD, kTIFF_GPSProcessingMethod );
- }
-
- haveXMP = xmp->GetProperty ( kXMP_NS_EXIF, "GPSAreaInformation", &xmpValue, 0 );
- if ( haveXMP && (! xmpValue.empty()) && (! exif->GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSAreaInformation, 0 )) ) {
- // 28 GPSAreaInformation is a string with explicit encoding.
- ExportTIFF_EncodedString ( *xmp, kXMP_NS_EXIF, "GPSAreaInformation", exif, kTIFF_GPSInfoIFD, kTIFF_GPSAreaInformation );
- }
-
-} // PhotoDataUtils::ExportExif
diff --git a/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp b/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp
deleted file mode 100644
index 7d27769..0000000
--- a/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "Reconcile_Impl.hpp"
-
-#include "UnicodeConversions.hpp"
-
-#if XMP_WinBuild
-#elif XMP_MacBuild
- #include "UnicodeConverter.h"
-#endif
-
-// =================================================================================================
-/// \file Reconcile_Impl.cpp
-/// \brief Implementation utilities for the photo metadata reconciliation support.
-///
-// =================================================================================================
-
-// =================================================================================================
-// ReconcileUtils::IsASCII
-// =======================
-//
-// See if a string is 7 bit ASCII.
-
-bool ReconcileUtils::IsASCII ( const void * textPtr, size_t textLen )
-{
-
- for ( const XMP_Uns8 * textPos = (XMP_Uns8*)textPtr; textLen > 0; --textLen, ++textPos ) {
- if ( *textPos >= 0x80 ) return false;
- }
-
- return true;
-
-} // ReconcileUtils::IsASCII
-
-// =================================================================================================
-// ReconcileUtils::IsUTF8
-// ======================
-//
-// See if a string contains valid UTF-8. Allow nul bytes, they can appear inside of multi-part Exif
-// strings. We don't use CodePoint_from_UTF8_Multi in UnicodeConversions because it throws an
-// exception for non-Unicode and we don't need to actually compute the code points.
-
-bool ReconcileUtils::IsUTF8 ( const void * textPtr, size_t textLen )
-{
- const XMP_Uns8 * textPos = (XMP_Uns8*)textPtr;
- const XMP_Uns8 * textEnd = textPos + textLen;
-
- while ( textPos < textEnd ) {
-
- if ( *textPos < 0x80 ) {
-
- ++textPos; // ASCII is UTF-8, tolerate nuls.
-
- } else {
-
- // -------------------------------------------------------------------------------------
- // We've got a multibyte UTF-8 character. The first byte has the number of bytes as the
- // number of high order 1 bits. The remaining bytes must have 1 and 0 as the top 2 bits.
-
- #if 0 // *** This might be a more effcient way to count the bytes.
- static XMP_Uns8 kByteCounts[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 };
- size_t bytesNeeded = kByteCounts [ *textPos >> 4 ];
- if ( (bytesNeeded < 2) || ((bytesNeeded == 4) && ((*textPos & 0x08) != 0)) ) return false;
- if ( (textPos + bytesNeeded) > textEnd ) return false;
- #endif
-
- size_t bytesNeeded = 0; // Count the high order 1 bits in the first byte.
- for ( XMP_Uns8 temp = *textPos; temp > 0x7F; temp = temp << 1 ) ++bytesNeeded;
- // *** Consider CPU-specific assembly inline, e.g. cntlzw on PowerPC.
-
- if ( (bytesNeeded < 2) || (bytesNeeded > 4) || ((textPos+bytesNeeded) > textEnd) ) return false;
-
- for ( --bytesNeeded, ++textPos; bytesNeeded > 0; --bytesNeeded, ++textPos ) {
- if ( (*textPos >> 6) != 2 ) return false;
- }
-
- }
-
- }
-
- return true; // ! Returns true for empty strings.
-
-} // ReconcileUtils::IsUTF8
-
-// =================================================================================================
-// UTF8ToHostEncoding
-// ==================
-
-#if XMP_WinBuild
-
- void ReconcileUtils::UTF8ToWinEncoding ( UINT codePage, const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host )
- {
-
- std::string utf16; // WideCharToMultiByte wants native UTF-16.
- ToUTF16Native ( (UTF8Unit*)utf8Ptr, utf8Len, &utf16 );
-
- LPCWSTR utf16Ptr = (LPCWSTR) utf16.c_str();
- size_t utf16Len = utf16.size() / 2;
-
- int hostLen = WideCharToMultiByte ( codePage, 0, utf16Ptr, (int)utf16Len, 0, 0, 0, 0 );
- host->assign ( hostLen, ' ' ); // Allocate space for the results.
-
- (void) WideCharToMultiByte ( codePage, 0, utf16Ptr, (int)utf16Len, (LPSTR)host->data(), hostLen, 0, 0 );
- XMP_Assert ( hostLen == host->size() );
-
- } // UTF8ToWinEncoding
-
-#elif XMP_MacBuild
-
- void ReconcileUtils::UTF8ToMacEncoding ( XMP_Uns16 macScript, XMP_Uns16 macLang, const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host )
- {
- OSStatus err;
-
- TextEncoding destEncoding;
- if ( macLang == langUnspecified ) macLang = kTextLanguageDontCare;
- err = UpgradeScriptInfoToTextEncoding ( macScript, macLang, kTextRegionDontCare, 0, &destEncoding );
- if ( err != noErr ) XMP_Throw ( "UpgradeScriptInfoToTextEncoding failed", kXMPErr_ExternalFailure );
-
- UnicodeMapping mappingInfo;
- mappingInfo.mappingVersion = kUnicodeUseLatestMapping;
- mappingInfo.otherEncoding = GetTextEncodingBase ( destEncoding );
- mappingInfo.unicodeEncoding = CreateTextEncoding ( kTextEncodingUnicodeDefault,
- kUnicodeNoSubset, kUnicodeUTF8Format );
-
- UnicodeToTextInfo converterInfo;
- err = CreateUnicodeToTextInfo ( &mappingInfo, &converterInfo );
- if ( err != noErr ) XMP_Throw ( "CreateUnicodeToTextInfo failed", kXMPErr_ExternalFailure );
-
- try { // ! Need to call DisposeUnicodeToTextInfo before exiting.
-
- OptionBits convFlags = kUnicodeUseFallbacksMask |
- kUnicodeLooseMappingsMask | kUnicodeDefaultDirectionMask;
- ByteCount bytesRead, bytesWritten;
-
- enum { kBufferLen = 1000 }; // Ought to be enough in practice, without using too much stack.
- char buffer [kBufferLen];
-
- host->reserve ( utf8Len ); // As good a guess as any.
-
- while ( utf8Len > 0 ) {
- // Ignore all errors from ConvertFromUnicodeToText. It returns info like "output
- // buffer full" or "use substitution" as errors.
- err = ConvertFromUnicodeToText ( converterInfo, utf8Len, (UniChar*)utf8Ptr, convFlags,
- 0, 0, 0, 0, kBufferLen, &bytesRead, &bytesWritten, buffer );
- if ( bytesRead == 0 ) break; // Make sure forward progress happens.
- host->append ( &buffer[0], bytesWritten );
- utf8Ptr += bytesRead;
- utf8Len -= bytesRead;
- }
-
- DisposeUnicodeToTextInfo ( &converterInfo );
-
- } catch ( ... ) {
-
- DisposeUnicodeToTextInfo ( &converterInfo );
- throw;
-
- }
-
- } // UTF8ToMacEncoding
-
-#elif XMP_UNIXBuild
-
- // ! Does not exist, must not be called, for Generic UNIX builds.
-
-#endif
-
-// =================================================================================================
-// ReconcileUtils::UTF8ToLocal
-// ===========================
-
-void ReconcileUtils::UTF8ToLocal ( const void * _utf8Ptr, size_t utf8Len, std::string * local )
-{
- const XMP_Uns8* utf8Ptr = (XMP_Uns8*)_utf8Ptr;
-
- local->erase();
-
- if ( ReconcileUtils::IsASCII ( utf8Ptr, utf8Len ) ) {
- local->assign ( (const char *)utf8Ptr, utf8Len );
- return;
- }
-
- #if XMP_WinBuild
-
- UTF8ToWinEncoding ( CP_ACP, utf8Ptr, utf8Len, local );
-
- #elif XMP_MacBuild
-
- UTF8ToMacEncoding ( smSystemScript, kTextLanguageDontCare, utf8Ptr, utf8Len, local );
-
- #elif XMP_UNIXBuild
-
- XMP_Throw ( "Generic UNIX does not have conversions between local and Unicode", kXMPErr_Unavailable );
-
- #endif
-
-} // ReconcileUtils::UTF8ToLocal
-
-// =================================================================================================
-// ReconcileUtils::UTF8ToLatin1
-// ============================
-
-void ReconcileUtils::UTF8ToLatin1 ( const void * _utf8Ptr, size_t utf8Len, std::string * latin1 )
-{
- const XMP_Uns8* utf8Ptr = (XMP_Uns8*)_utf8Ptr;
- const XMP_Uns8* utf8End = utf8Ptr + utf8Len;
-
- latin1->erase();
- latin1->reserve ( utf8Len ); // As good a guess as any, at least enough, exact for ASCII.
-
- bool inBadRun = false;
-
- while ( utf8Ptr < utf8End ) {
-
- if ( *utf8Ptr <= 0x7F ) {
-
- (*latin1) += (char)*utf8Ptr; // Have an ASCII character.
- inBadRun = false;
- ++utf8Ptr;
-
- } else if ( utf8Ptr == (utf8End - 1) ) {
-
- inBadRun = false;
- ++utf8Ptr; // Ignore a bad end to the UTF-8.
-
- } else {
-
- XMP_Assert ( (utf8End - utf8Ptr) >= 2 );
- XMP_Uns16 ch16 = GetUns16BE ( utf8Ptr ); // A Latin-1 80..FF is 2 UTF-8 bytes.
-
- if ( (0xC280 <= ch16) && (ch16 <= 0xC2BF) ) {
-
- (*latin1) += (char)(ch16 & 0xFF); // UTF-8 C280..C2BF are Latin-1 80..BF.
- inBadRun = false;
- utf8Ptr += 2;
-
- } else if ( (0xC380 <= ch16) && (ch16 <= 0xC3BF) ) {
-
- (*latin1) += (char)((ch16 & 0xFF) + 0x40); // UTF-8 C380..C3BF are Latin-1 C0..FF.
- inBadRun = false;
- utf8Ptr += 2;
-
- } else {
-
- if ( ! inBadRun ) {
- inBadRun = true;
- (*latin1) += "(?)"; // Mark the run of out of scope UTF-8.
- }
-
- ++utf8Ptr; // Skip the presumably well-formed UTF-8 character.
- while ( (utf8Ptr < utf8End) && ((*utf8Ptr & 0xC0) == 0x80) ) ++utf8Ptr;
-
- }
-
- }
-
- }
-
- XMP_Assert ( utf8Ptr == utf8End );
-
-} // ReconcileUtils::UTF8ToLatin1
-
-// =================================================================================================
-// HostEncodingToUTF8
-// ==================
-
-#if XMP_WinBuild
-
- void ReconcileUtils::WinEncodingToUTF8 ( UINT codePage, const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 )
- {
-
- int utf16Len = MultiByteToWideChar ( codePage, 0, (LPCSTR)hostPtr, (int)hostLen, 0, 0 );
- std::vector<UTF16Unit> utf16 ( utf16Len, 0 ); // MultiByteToWideChar returns native UTF-16.
-
- (void) MultiByteToWideChar ( codePage, 0, (LPCSTR)hostPtr, (int)hostLen, (LPWSTR)&utf16[0], utf16Len );
- FromUTF16Native ( &utf16[0], (int)utf16Len, utf8 );
-
- } // WinEncodingToUTF8
-
-#elif XMP_MacBuild
-
- void ReconcileUtils::MacEncodingToUTF8 ( XMP_Uns16 macScript, XMP_Uns16 macLang, const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 )
- {
- OSStatus err;
-
- TextEncoding srcEncoding;
- if ( macLang == langUnspecified ) macLang = kTextLanguageDontCare;
- err = UpgradeScriptInfoToTextEncoding ( macScript, macLang, kTextRegionDontCare, 0, &srcEncoding );
- if ( err != noErr ) XMP_Throw ( "UpgradeScriptInfoToTextEncoding failed", kXMPErr_ExternalFailure );
-
- UnicodeMapping mappingInfo;
- mappingInfo.mappingVersion = kUnicodeUseLatestMapping;
- mappingInfo.otherEncoding = GetTextEncodingBase ( srcEncoding );
- mappingInfo.unicodeEncoding = CreateTextEncoding ( kTextEncodingUnicodeDefault,
- kUnicodeNoSubset, kUnicodeUTF8Format );
-
- TextToUnicodeInfo converterInfo;
- err = CreateTextToUnicodeInfo ( &mappingInfo, &converterInfo );
- if ( err != noErr ) XMP_Throw ( "CreateTextToUnicodeInfo failed", kXMPErr_ExternalFailure );
-
- try { // ! Need to call DisposeTextToUnicodeInfo before exiting.
-
- ByteCount bytesRead, bytesWritten;
-
- enum { kBufferLen = 1000 }; // Ought to be enough in practice, without using too much stack.
- char buffer [kBufferLen];
-
- utf8->reserve ( hostLen ); // As good a guess as any.
-
- while ( hostLen > 0 ) {
- // Ignore all errors from ConvertFromTextToUnicode. It returns info like "output
- // buffer full" or "use substitution" as errors.
- err = ConvertFromTextToUnicode ( converterInfo, hostLen, hostPtr, kNilOptions,
- 0, 0, 0, 0, kBufferLen, &bytesRead, &bytesWritten, (UniChar*)buffer );
- if ( bytesRead == 0 ) break; // Make sure forward progress happens.
- utf8->append ( &buffer[0], bytesWritten );
- hostPtr += bytesRead;
- hostLen -= bytesRead;
- }
-
- DisposeTextToUnicodeInfo ( &converterInfo );
-
- } catch ( ... ) {
-
- DisposeTextToUnicodeInfo ( &converterInfo );
- throw;
-
- }
-
- } // MacEncodingToUTF8
-
-#elif XMP_UNIXBuild
-
- // ! Does not exist, must not be called, for Generic UNIX builds.
-
-#endif
-
-// =================================================================================================
-// ReconcileUtils::LocalToUTF8
-// ===========================
-
-void ReconcileUtils::LocalToUTF8 ( const void * _localPtr, size_t localLen, std::string * utf8 )
-{
- const XMP_Uns8* localPtr = (XMP_Uns8*)_localPtr;
-
- utf8->erase();
-
- if ( ReconcileUtils::IsASCII ( localPtr, localLen ) ) {
- utf8->assign ( (const char *)localPtr, localLen );
- return;
- }
-
- #if XMP_WinBuild
-
- WinEncodingToUTF8 ( CP_ACP, localPtr, localLen, utf8 );
-
- #elif XMP_MacBuild
-
- MacEncodingToUTF8 ( smSystemScript, kTextLanguageDontCare, localPtr, localLen, utf8 );
-
- #elif XMP_UNIXBuild
-
- XMP_Throw ( "Generic UNIX does not have conversions between local and Unicode", kXMPErr_Unavailable );
-
- #endif
-
-} // ReconcileUtils::LocalToUTF8
-
-// =================================================================================================
-// ReconcileUtils::Latin1ToUTF8
-// ============================
-
-void ReconcileUtils::Latin1ToUTF8 ( const void * _latin1Ptr, size_t latin1Len, std::string * utf8 )
-{
- const XMP_Uns8* latin1Ptr = (XMP_Uns8*)_latin1Ptr;
- const XMP_Uns8* latin1End = latin1Ptr + latin1Len;
-
- utf8->erase();
- utf8->reserve ( latin1Len ); // As good a guess as any, exact for ASCII.
-
- for ( ; latin1Ptr < latin1End; ++latin1Ptr ) {
-
- XMP_Uns8 ch8 = *latin1Ptr;
-
- if ( ch8 <= 0x7F ) {
- (*utf8) += (char)ch8; // Have an ASCII character.
- } else if ( ch8 <= 0xBF ) {
- (*utf8) += 0xC2; // Latin-1 80..BF are UTF-8 C280..C2BF.
- (*utf8) += (char)ch8;
- } else {
- (*utf8) += 0xC3; // Latin-1 C0..FF are UTF-8 C380..C3BF.
- (*utf8) += (char)(ch8 - 0x40);
- }
-
- }
-
-} // ReconcileUtils::Latin1ToUTF8
diff --git a/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp b/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp
deleted file mode 100644
index 19ea865..0000000
--- a/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef __Reconcile_Impl_hpp__
-#define __Reconcile_Impl_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "ReconcileLegacy.hpp"
-#include "MD5.h"
-
-// =================================================================================================
-/// \file Reconcile_Impl.hpp
-/// \brief Implementation utilities for the legacy metadata reconciliation support.
-///
-// =================================================================================================
-
-typedef XMP_Uns8 MD5_Digest[16]; // ! Should be in MD5.h.
-
-enum {
- kDigestMissing = -1, // A partial import is done, existing XMP is left alone.
- kDigestDiffers = 0, // A full import is done, existing XMP is deleted or replaced.
- kDigestMatches = +1 // No importing is done.
-};
-
-namespace ReconcileUtils {
-
- // *** These ought to be with the Unicode conversions.
-
- static const char * kHexDigits = "0123456789ABCDEF";
-
- bool IsASCII ( const void * _textPtr, size_t textLen );
- bool IsUTF8 ( const void * _textPtr, size_t textLen );
-
- void UTF8ToLocal ( const void * _utf8Ptr, size_t utf8Len, std::string * local );
- void UTF8ToLatin1 ( const void * _utf8Ptr, size_t utf8Len, std::string * latin1 );
- void LocalToUTF8 ( const void * _localPtr, size_t localLen, std::string * utf8 );
- void Latin1ToUTF8 ( const void * _latin1Ptr, size_t latin1Len, std::string * utf8 );
-
- #if XMP_WinBuild
- void UTF8ToWinEncoding ( UINT codePage, const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host );
- void WinEncodingToUTF8 ( UINT codePage, const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 );
- #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 );
- #endif
-
-}; // ReconcileUtils
-
-namespace PhotoDataUtils {
-
- int CheckIPTCDigest ( const void * newPtr, const XMP_Uns32 newLen, const void * oldDigest );
- void SetIPTCDigest ( void * iptcPtr, XMP_Uns32 iptcLen, PSIR_Manager * psir );
-
- bool GetNativeInfo ( const TIFF_Manager & exif, XMP_Uns8 ifd, XMP_Uns16 id, TIFF_Manager::TagInfo * info );
- size_t GetNativeInfo ( const IPTC_Manager & iptc, XMP_Uns8 id, int digestState,
- bool haveXMP, IPTC_Manager::DataSetInfo * info );
-
- bool IsValueDifferent ( const TIFF_Manager::TagInfo & exifInfo,
- const std::string & xmpValue, std::string * exifValue );
- bool IsValueDifferent ( const IPTC_Manager & newIPTC, const IPTC_Manager & oldIPTC, XMP_Uns8 id );
-
- void ImportPSIR ( const PSIR_Manager & psir, SXMPMeta * xmp, int iptcDigestState );
-
- void Import2WayIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp, int iptcDigestState );
- void Import2WayExif ( const TIFF_Manager & exif, SXMPMeta * xmp, int iptcDigestState );
-
- void Import3WayItems ( const TIFF_Manager & exif, const IPTC_Manager & iptc, SXMPMeta * xmp, int iptcDigestState );
-
- void ExportPSIR ( const SXMPMeta & xmp, PSIR_Manager * psir );
- void ExportIPTC ( const SXMPMeta & xmp, IPTC_Manager * iptc );
- void ExportExif ( SXMPMeta * xmp, TIFF_Manager * exif );
-
- // These need to be exposed for use in Import3WayItem:
-
- void ImportIPTC_Simple ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp );
-
- void ImportIPTC_LangAlt ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp );
-
- void ImportIPTC_Array ( const IPTC_Manager & iptc, SXMPMeta * xmp,
- XMP_Uns8 id, const char * xmpNS, const char * xmpProp );
-
- void ImportIPTC_Date ( XMP_Uns8 dateID, const IPTC_Manager & iptc, SXMPMeta * xmp );
-
-}; // PhotoDataUtils
-
-#endif // __Reconcile_Impl_hpp__
diff --git a/source/XMPFiles/FormatSupport/SWF_Support.cpp b/source/XMPFiles/FormatSupport/SWF_Support.cpp
deleted file mode 100644
index d9b8115..0000000
--- a/source/XMPFiles/FormatSupport/SWF_Support.cpp
+++ /dev/null
@@ -1,844 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2007 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "SWF_Support.hpp"
-#include "zlib.h"
-
-
-namespace SWF_Support
-{
-
- // =============================================================================================
-
- static int CalcHeaderSize ( IO::InputStream* inputStream )
- {
- int size = 0;
-
- try {
-
- XMP_Uns8 buffer[1];
- long bytesRead = inputStream->Read ( buffer, 1 );
- if ( bytesRead != 1 ) return 0;
-
- // The RECT datatype has a variable size depending on the packed bit-values -> rectDatatypeSize = size in bytes
- int bits = int(buffer[0] >> 3);
- int bytes = ((5 + (4 * bits)) / 8) + 1;
-
- size = 12 + bytes;
-
- } catch ( ... ) {
-
- return 0;
- }
-
- inputStream->Skip ( size - inputStream->GetCurrentPos() );
- return size;
-
- } // CalcHeaderSize
-
- // =============================================================================================
-
- static unsigned long CheckTag ( IO::InputStream* inputStream, TagState& inOutTagState, TagData& inOutTagData )
- {
- unsigned long ret = 0;
- XMP_Uns8 * buffer = 0;
-
- try {
-
- if ( inOutTagData.id == SWF_TAG_ID_METADATA ) {
-
- buffer = new XMP_Uns8[inOutTagData.len];
- XMP_Uns32 bytes = inputStream->Read ( buffer, inOutTagData.len );
-
- XMP_Assert ( bytes == inOutTagData.len );
-
- inOutTagState.xmpPos = inOutTagData.pos + inOutTagData.offset;
- inOutTagState.xmpLen = inOutTagData.len;
- inOutTagData.xmp = true;
-
- inOutTagState.xmpPacket.assign ( (char*)buffer, inOutTagData.len );
-
- delete[] buffer;
- buffer = 0;
- ret = inOutTagState.xmpLen;
-
- }
-
- } catch ( ... ) {
-
- if ( buffer != 0 ) {
- delete[] buffer;
- buffer = 0;
- }
-
- }
-
- if ( buffer != 0 ) {
- delete[] buffer;
- buffer = 0;
- }
-
- return ret;
-
- } // CheckTag
-
- // =============================================================================================
-
- bool HasMetadata ( IO::InputStream* inputStream, TagState& tagState )
- {
-
- XMP_Uns32 flags = ReadFileAttrFlags ( inputStream );
- tagState.fileAttrFlags = flags;
- return ((flags & SWF_METADATA_FLAG) == SWF_METADATA_FLAG);
-
- } // HasMetadata
-
- // =============================================================================================
-
- XMP_Uns32 ReadFileAttrFlags ( IO::InputStream* inputStream )
- {
- XMP_Uns8 buffer[4];
-
- XMP_Uns32 bytes = inputStream->Read ( buffer, 4 );
- XMP_Assert ( bytes == 4 );
-
- return GetUns32LE ( buffer );
-
- } // ReadFileAttrFlags
-
- // =============================================================================================
-
- long OpenSWF ( IO::InputStream *inputStream, TagState & inOutTagState )
- {
- XMP_Uns64 pos = 0;
- long name;
- XMP_Uns32 len;
-
- inOutTagState.headerSize = CalcHeaderSize ( inputStream );
- pos = inOutTagState.headerSize;
-
- // read first and following chunks
- bool running = true;
- while ( running ) {
- running = ReadTag ( inputStream, inOutTagState, &name, &len, pos );
- if ( inOutTagState.cachingFile ) {
- if ( (! inOutTagState.hasXMP) || (inOutTagState.xmpLen > 0) ) running = false;
- }
- }
-
- return (long) inOutTagState.tags.size();
-
- } // OpenSWF
-
- // =============================================================================================
-
- bool ReadTag ( IO::InputStream* inputStream, TagState & inOutTagState,
- long* tagType, XMP_Uns32* tagLength, XMP_Uns64& inOutPosition )
- {
-
- try {
-
- XMP_Uns64 startPosition = inOutPosition;
- long bytesRead;
- XMP_Uns8 buffer[4];
-
- bytesRead = inputStream->Read ( buffer, 2 );
- if ( bytesRead != 2 ) return false;
-
- inOutPosition += 2;
- XMP_Uns16 code = GetUns16LE ( buffer );
- *tagType = code >> 6;
- *tagLength = code & 0x3f;
-
- bool longTag = false;
-
- if ( *tagLength == 0x3f ) {
- longTag = true;
- bytesRead = inputStream->Read ( buffer, 4 );
- if ( bytesRead != 4 ) return false;
- inOutPosition += 4;
- *tagLength = GetUns32LE ( buffer );
- }
-
- inOutPosition += *tagLength;
-
- TagData newTag;
-
- newTag.pos = startPosition;
- newTag.len = *tagLength;
- newTag.id = *tagType;
- newTag.offset = ( (! longTag) ? 2 : 6 );
-
- // we cannot check valid XMP within the handler
- // provide validating XMP by invoking XMPCore
- // check tag for XMP
- if ( newTag.id == SWF_TAG_ID_METADATA ) {
- newTag.xmp = true;
- inOutTagState.xmpTag = newTag;
- CheckTag ( inputStream, inOutTagState, newTag );
- if ( ! inOutTagState.hasFileAttrTag ) inOutTagState.hasXMP = true;
- }
-
- //store FileAttribute Tag
- if ( newTag.id == SWF_TAG_ID_FILEATTRIBUTES ) {
- inOutTagState.hasFileAttrTag = true;
- inOutTagState.fileAttrTag = newTag;
- inOutTagState.hasXMP = HasMetadata ( inputStream, inOutTagState );
- //decreasing since stream moved on within HasMetadata function
- *tagLength -= 4;
- }
-
- //store tag in vector to process later
- inOutTagState.tags.push_back ( newTag );
-
- //seek to next tag
- if ( ! newTag.xmp ) inputStream->Skip ( *tagLength );
- if ( inputStream->IsEOF() ) return false;
-
- } catch ( ... ) {
-
- return false;
-
- }
-
- return true;
-
- } // ReadTag
-
- // =============================================================================================
-
- bool WriteXMPTag ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer )
- {
- bool ret = false;
-
- XMP_Uns16 code = MakeUns16LE ( (SWF_TAG_ID_METADATA << 6) | 0x3F );
- XMP_Uns32 length = MakeUns32LE ( len );
-
- try {
- LFA_Write (fileRef, &code, 2 );
- LFA_Write (fileRef, &length, 4 );
- LFA_Write (fileRef, inBuffer, len );
- ret = true;
- } catch ( ... ) {}
-
- return ret;
-
- } // WriteXMPTag
-
- // =============================================================================================
-
- bool CopyHeader ( LFA_FileRef sourceRef, LFA_FileRef destRef, const TagState& tagState )
- {
- try {
- int headerSize = tagState.headerSize;
- LFA_Seek ( sourceRef, 0, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, headerSize );
- return true;
- } catch ( ... ) {}
-
- return false;
-
- } // CopyHeader
-
- // =============================================================================================
-
- bool UpdateHeader ( LFA_FileRef fileRef )
- {
-
- try {
-
- XMP_Int64 length64 = LFA_Measure ( fileRef );
- if ( (length64 < 8) || (length64 > (XMP_Int64)0xFFFFFFFFULL) ) return false;
-
- XMP_Uns32 length32 = MakeUns32LE ( (XMP_Uns32)length64 );
-
- LFA_Seek ( fileRef, 4, SEEK_SET );
- LFA_Write ( fileRef, &length32, 4 );
-
- return true;
-
- } catch ( ... ) {}
-
- return false;
-
- } // UpdateHeader
-
- // =============================================================================================
-
- bool CopyTag ( LFA_FileRef sourceRef, LFA_FileRef destRef, TagData& tag )
- {
-
- try {
- LFA_Seek ( sourceRef, tag.pos, SEEK_SET );
- LFA_Copy ( sourceRef, destRef, (tag.len + tag.offset) );
- return true;
- } catch ( ... ) {}
-
- return false;
-
- } // CopyTag
-
- // =============================================================================================
-
- bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, XMP_Uns8* outBuffer )
- {
-
- try {
- if ( (fileRef == 0) || (outBuffer == 0) ) return false;
- LFA_Seek ( fileRef, pos, SEEK_SET );
- long bytesRead = LFA_Read ( fileRef, outBuffer, len );
- return ( (XMP_Uns32)bytesRead == len );
- } catch ( ... ) {}
-
- return false;
-
- } // ReadBuffer
-
- // =============================================================================================
-
- bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, const char* inBuffer )
- {
-
- try {
- if ( (fileRef == 0) || (inBuffer == 0) ) return false;
- LFA_Seek ( fileRef, pos, SEEK_SET );
- LFA_Write ( fileRef, inBuffer, len );
- return true;
- }
- catch ( ... ) {}
-
- return false;
-
- } // WriteBuffer
-
- // =============================================================================================
-
- bool UpdateFileAttrTag ( LFA_FileRef fileRef, const TagData& fileAttrTag, const TagState& tagState )
- {
-
- try {
- XMP_Uns32 flags = tagState.fileAttrFlags;
- flags |= SWF_METADATA_FLAG;
- return WriteFileAttrFlags ( fileRef, fileAttrTag, flags );
- } catch ( ... ) {}
-
- return false;
-
- } // UpdateFileAttrTag
-
- // =============================================================================================
-
-
- bool WriteFileAttrFlags ( LFA_FileRef fileRef, const TagData& fileAttrTag, XMP_Uns32 flags )
- {
-
- try {
- XMP_Uns32 bitMask = MakeUns32LE ( flags );
- LFA_Seek ( fileRef, fileAttrTag.pos + fileAttrTag.offset, SEEK_SET );
- LFA_Write ( fileRef, &bitMask, 4 );
- return true;
- } catch ( ... ) {}
-
- return false;
-
- } // WriteFileAttrFlags
-
- // =============================================================================================
- // =============================================================================================
-
- FileInfo::FileInfo ( LFA_FileRef fileRef, const std::string& origPath )
- {
-
- this->compressedFile = false;
- this->iSize = 0;
- this->CheckFormat ( fileRef );
- this->origFilePath.assign ( origPath );
- this->fileRef = fileRef;
-
- } // FileInfo::FileInfo
-
- // =============================================================================================
-
- void FileInfo::CheckFormat ( LFA_FileRef fileRef )
- {
- IOBuffer ioBuf;
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
-
- if ( CheckFileSpace ( fileRef, &ioBuf, SWF_SIGNATURE_LEN ) ) {
-
- if ( CheckBytes ( ioBuf.ptr, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) {
- this->compressedFile = false;
- } else if ( CheckBytes ( ioBuf.ptr, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN ) ) {
- this->compressedFile = true;
- }
-
- LFA_Seek ( fileRef, 4, SEEK_SET );
- XMP_Uns8 buffer[4];
- LFA_Read ( fileRef, buffer, 4 );
- iSize = GetUns32LE ( buffer );
-
- }
-
- LFA_Seek ( fileRef, 0, SEEK_SET );
-
- } // FileInfo::CheckFormat
-
- // =============================================================================================
-
- bool FileInfo::IsCompressed()
- {
-
- return this->compressedFile;
-
- } // FileInfo::IsCompressed
-
- // =============================================================================================
-
- LFA_FileRef FileInfo::Decompress()
- {
-
- if ( ! this->IsCompressed() ) return this->fileRef;
-
- LFA_FileRef updateRef = 0;
- std::string updatePath;
-
- try {
-
- CreateTempFile ( this->origFilePath, &updatePath, kCopyMacRsrc );
- updateRef = LFA_Open ( updatePath.c_str(), 'w' );
- this->tmpFilePath.assign ( updatePath );
-
- int ret = this->Encode ( this->fileRef, updateRef, FWS, Inf );
- this->tmpFileRef = updateRef;
- if ( ret != Z_OK ) XMP_Throw ( "zstream error occured", kXMPErr_ExternalFailure );
-
- return this->tmpFileRef;
-
- } catch ( ... ) {
-
- LFA_Close ( updateRef );
- LFA_Delete ( updatePath.c_str() );
- return this->fileRef;
-
- }
-
- } // FileInfo::Decompress
-
- // =============================================================================================
-
- void FileInfo::Compress ( LFA_FileRef sourceRef, LFA_FileRef destRef )
- {
-
- if ( this->IsCompressed() ) this->Encode ( sourceRef, destRef, CWS, Def );
-
- } // FileInfo::Compress
-
- // =============================================================================================
-
- void FileInfo::Clean()
- {
-
- if ( this->tmpFileRef != 0 ) LFA_Close ( this->tmpFileRef );
- this->tmpFileRef = 0;
- this->CleanTempFiles();
-
- } // FileInfo::Clean
-
- // =============================================================================================
-
- void FileInfo::CleanTempFiles()
- {
-
- if ( ! this->tmpFilePath.empty() ) {
- LFA_Delete ( this->tmpFilePath.c_str() );
- this->tmpFilePath.erase();
- }
-
- } // FileInfo::CleanTempFiles
-
- // =============================================================================================
-
- int FileInfo::Encode ( LFA_FileRef fileRef, LFA_FileRef updateRef, SWF_MODE swfMode, CompressionFnc cmpFnc )
- {
-
- LFA_Seek ( updateRef, 0, SEEK_SET );
-
- if ( swfMode == CWS ) {
- LFA_Write ( updateRef, SWF_C_SIGNATURE_DATA, SWF_SIGNATURE_LEN );
- } else {
- XMP_Assert ( swfMode == FWS );
- LFA_Write ( updateRef, SWF_F_SIGNATURE_DATA, SWF_SIGNATURE_LEN );
- }
-
- LFA_Seek ( fileRef, SWF_SIGNATURE_LEN, SEEK_SET );
- LFA_Seek ( updateRef, SWF_SIGNATURE_LEN, SEEK_SET );
- LFA_Copy ( fileRef, updateRef, 5 );
-
- int ret = cmpFnc ( fileRef, updateRef );
- LFA_Flush ( updateRef );
-
- return ret;
-
- } // FileInfo::Encode
-
- // =============================================================================================
-
- int FileInfo::Inf ( LFA_FileRef source, LFA_FileRef dest )
- {
- int ret;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
-
- XMP_Uns64 allBytes = 0;
-
- // allocate inflate state
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
-
- ret = inflateInit ( &strm );
-
- if ( ret != Z_OK ) return ret;
-
- // decompress until deflate stream ends or end of file
-
- LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET );
- XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN;
-
- try {
-
- do {
-
- strm.avail_in = LFA_Read ( source, in, CHUNK );
- if ( strm.avail_in == 0 ) {
- ret = Z_STREAM_END;
- break;
- }
-
- strm.next_in = in;
-
- // run inflate() on input until output buffer not full
- do {
-
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = inflate ( &strm, Z_NO_FLUSH );
- XMP_Assert ( ret != Z_STREAM_ERROR ); // state not clobbered
-
- switch ( ret ) {
- case Z_NEED_DICT: ret = Z_DATA_ERROR; // and fall through
- case Z_DATA_ERROR:
- case Z_MEM_ERROR: inflateEnd ( &strm );
- return ret;
- }
-
- have = CHUNK - strm.avail_out;
- LFA_Seek ( dest, outPos, SEEK_SET );
- LFA_Write ( dest, out, have );
-
- outPos += have;
-
- } while ( strm.avail_out == 0 );
-
- // done when inflate() says it's done
-
- } while ( ret != Z_STREAM_END );
-
- } catch ( ... ) {
-
- inflateEnd ( &strm );
- return Z_ERRNO;
-
- }
-
- // clean up and return
- inflateEnd ( &strm );
- return ( (ret == Z_STREAM_END) ? Z_OK : Z_DATA_ERROR );
-
- } // FileInfo::Inf
-
- // =============================================================================================
-
- int FileInfo::Def ( LFA_FileRef source, LFA_FileRef dest )
- {
- int ret, flush;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
-
- // allocate deflate state
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = deflateInit ( &strm, SWF_DEFAULT_COMPRESSION_LEVEL );
- if ( ret != Z_OK ) return ret;
-
- // compress until end of file
-
- LFA_Seek ( source, SWF_COMPRESSION_BEGIN, SEEK_SET );
- XMP_Uns64 outPos = SWF_COMPRESSION_BEGIN;
-
- try {
-
- do {
-
- strm.avail_in = LFA_Read ( source, in, CHUNK );
-
- flush = ( (strm.avail_in < CHUNK) ? Z_FINISH : Z_NO_FLUSH );
-
- strm.next_in = in;
-
- // run deflate() on input until output buffer not full, finish
- // compression if all of source has been read in
- do {
-
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = deflate ( &strm, flush ); // no bad return value
- XMP_Assert ( ret != Z_STREAM_ERROR ); // state not clobbered
- have = CHUNK - strm.avail_out;
-
- LFA_Seek ( dest, outPos, SEEK_SET );
- LFA_Write ( dest, out, have );
- outPos += have;
-
- } while ( strm.avail_out == 0 );
- XMP_Assert ( strm.avail_in == 0 ); // all input will be used
-
- // done when last data in file processed
-
- } while ( flush != Z_FINISH );
- XMP_Assert ( ret == Z_STREAM_END ); // stream will be complete
-
- } catch ( ... ) {
-
- deflateEnd ( &strm );
- return Z_ERRNO;
-
- }
-
- /* clean up and return */
- deflateEnd ( &strm );
- return Z_OK;
-
- } // FileInfo::Def
-
- // =============================================================================================
-
-} // namespace SWF_Support
-
-// =================================================================================================
-// =================================================================================================
-
-namespace IO
-{
-
- // =============================================================================================
-
- void FileInputStream::InitStream()
- {
-
- iEndPos = LFA_Seek ( iFile, 0, SEEK_END );
- iPos = LFA_Seek ( iFile, 0, SEEK_SET );
-
- } // FileInputStream::InitStream
-
- // =============================================================================================
-
- XMP_Int32 FileInputStream::Read ( XMP_Uns8* ioBuf, XMP_Int32 len )
- {
- if ( IsEOF() ) throw new IOException ( IO::STATUS_EOF );
-
- XMP_Int32 bytes = LFA_Read ( iFile, ioBuf, len );
- iPos += bytes;
-
- return bytes;
-
- } // FileInputStream::Read
-
- // =============================================================================================
-
- XMP_Int64 FileInputStream::Skip ( XMP_Int64 len )
- {
-
- if ( IsEOF() ) return 0;
-
- iPos += len;
- XMP_Int64 bytes = LFA_Seek ( iFile, iPos, SEEK_SET );
- return bytes;
-
- } // FileInputStream::Skip
-
- // =============================================================================================
-
- void FileInputStream::Reset()
- {
-
- iPos = LFA_Seek ( iFile, 0, SEEK_SET );
-
- } // FileInputStream::Reset
-
- // =============================================================================================
-
- bool FileInputStream::IsEOF()
- {
-
- return (iPos >= iEndPos);
-
- } // FileInputStream::IsEOF
-
- // =============================================================================================
- // =============================================================================================
-
- namespace ZIP
- {
-
- // =========================================================================================
-
- DeflateInputStream::DeflateInputStream ( LFA_FileRef file, XMP_Int32 bufferLength )
- : FileInputStream(file), iStatus(0), iBufferLength(bufferLength)
- {
-
- InitStream();
- iBuffer = new XMP_Uns8[bufferLength];
-
- } // DeflateInputStream::DeflateInputStream
-
- // =========================================================================================
-
- DeflateInputStream::~DeflateInputStream()
- {
-
- inflateEnd ( &iStream );
- delete[] iBuffer;
- iBuffer = NULL;
-
- } // DeflateInputStream::~DeflateInputStream
-
- // =========================================================================================
-
- void DeflateInputStream::InitStream()
- {
-
- iStream.zalloc = Z_NULL;
- iStream.zfree = Z_NULL;
- iStream.opaque = Z_NULL;
- iStream.avail_in = 0;
- iStream.next_in = Z_NULL;
- iStream.avail_out = 1;
-
- iStatus = inflateInit ( &iStream );
- if ( iStatus != Z_OK ) throw new ZIPException ( iStatus );
-
- } // DeflateInputStream::InitStream
-
- // =========================================================================================
-
- XMP_Int32 DeflateInputStream::Read ( XMP_Uns8* ioBuf, XMP_Int32 len )
- {
-
- // *** if ( len > iBufferLength ) throw new IOException ( STATUS_BUFFER_OVERFLOW );
-
- if( iStream.avail_out != 0 ) {
- XMP_Int64 pos = GetCurrentPos();
- iStream.avail_in = FileInputStream::Read ( iBuffer, iBufferLength );
- iPos = pos + len;
- iStream.next_in = iBuffer;
- }
-
- iStream.avail_out = len;
- iStream.next_out = ioBuf;
-
- iStatus = inflate ( &iStream, Z_NO_FLUSH );
-
- if ( iStatus == Z_MEM_ERROR ) {
- inflateEnd ( &iStream );
- throw new ZIPException ( Z_MEM_ERROR );
- }
-
- return (len - iStream.avail_out);
-
- } // DeflateInputStream::Read
-
- // =========================================================================================
-
- XMP_Int32 DeflateInputStream::Read ( XMP_Uns8* ioBuf )
- {
-
- return Read ( ioBuf, iBufferLength );
-
- } // DeflateInputStream::Read
-
- // =========================================================================================
-
- void DeflateInputStream::Close()
- {
-
- inflateEnd ( &iStream );
- iPos = 0;
-
- } // DeflateInputStream::Close
-
- // =========================================================================================
-
- bool DeflateInputStream::IsEOF()
- {
-
- return (iStatus == Z_STREAM_END);
-
- } // DeflateInputStream::IsEOF
-
- // =========================================================================================
-
- XMP_Int64 DeflateInputStream::Skip ( XMP_Int64 len )
- {
-
- return Skip ( len, DEFLATE );
-
- } // DeflateInputStream::Skip
-
- // =========================================================================================
-
- XMP_Int64 DeflateInputStream::Skip ( XMP_Int64 len, EDeflate deflate )
- {
-
- switch ( deflate ) {
-
- case DEFLATE:
- {
- XMP_Uns8 * buffer = new XMP_Uns8 [ (XMP_Uns32)len ];
- XMP_Int64 bytes = Read ( buffer, (XMP_Uns32)len );
- delete[] buffer;
- return bytes;
- }
- break;
-
- case DEFLATE_NO:
- return FileInputStream::Skip ( len );
-
- default:
- throw new IOException ( STATUS_SKIP );
-
- }
-
- } // DeflateInputStream::Skip
-
- // =========================================================================================
-
- } // namespace ZIP
-
- // =============================================================================================
-
-} // namespace IO
diff --git a/source/XMPFiles/FormatSupport/SWF_Support.hpp b/source/XMPFiles/FormatSupport/SWF_Support.hpp
deleted file mode 100644
index db20ab2..0000000
--- a/source/XMPFiles/FormatSupport/SWF_Support.hpp
+++ /dev/null
@@ -1,254 +0,0 @@
-#ifndef __SWF_Support_hpp__
-#define __SWF_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-//#include "XMP_Environment.h" // ! This must be the first include.
-
-#include "XMPFiles_Impl.hpp"
-
-#define SWF_SIGNATURE_LEN 3
-#define SWF_C_SIGNATURE_DATA "\x43\x57\x53"
-#define SWF_F_SIGNATURE_DATA "\x46\x57\x53"
-
-#define SWF_TAG_ID_FILEATTRIBUTES 69
-#define SWF_TAG_ID_METADATA 77
-#define SWF_TAG_ID_ENDTAG 0
-
-#define SWF_METADATA_FLAG 0x10
-#define SWF_DEFAULT_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION
-
-#define SWF_COMPRESSION_BEGIN 8
-
-#define CHUNK 16384
-
-#include "zlib.h"
-
-namespace IO
-{
- //------------------------------------------------------------------
- //input/output stream declaration
- typedef enum {FLUSH, FLUSH_NO} EFlush;
-
- class InputStream
- {
- public:
- virtual ~InputStream() {};
- virtual XMP_Int32 Read(XMP_Uns8 * ioBuf, XMP_Int32 len) = 0;
- virtual XMP_Int64 Skip(XMP_Int64 len) = 0;
- virtual void Reset(void) = 0;
- virtual void Close(void) = 0;
- virtual bool IsEOF(void) = 0;
- virtual XMP_Int64 GetCurrentPos(void) = 0;
- };
-
-
- class FileInputStream : public InputStream
- {
- public:
- FileInputStream(LFA_FileRef file) : iFile(file), iPos(0), iEndPos(0) { InitStream(); };
- virtual ~FileInputStream() {};
-
- virtual XMP_Int32 Read(XMP_Uns8 * ioBuf, XMP_Int32 len);
- virtual XMP_Int64 Skip(XMP_Int64 len);
- virtual void Reset(void);
- virtual void Close(void) {};
- virtual bool IsEOF(void);
- virtual XMP_Int64 GetCurrentPos(void) { return iPos; };
-
- protected:
- void InitStream(void);
-
- LFA_FileRef iFile;
- XMP_Int64 iPos;
- XMP_Int64 iEndPos;
- };
-
- typedef enum {
- STATUS_WRITE,
- STATUS_READ,
- STATUS_EOF,
- STATUS_BUFFER_OVERFLOW,
- STATUS_SKIP
- } EStatus;
-
- class IOException
- {
- public:
- IOException(EStatus status) : iStatus(status) {};
- ~IOException(void) {};
- EStatus GetErrorCode(void) { return iStatus; };
- protected:
- EStatus iStatus;
-
- };
-
- namespace ZIP
- {
- typedef enum {DEFLATE, DEFLATE_NO} EDeflate;
-
- class DeflateInputStream : public FileInputStream
- {
- public:
- DeflateInputStream(LFA_FileRef file, XMP_Int32 bufferLength);
- virtual ~DeflateInputStream();
-
- virtual XMP_Int32 Read(XMP_Uns8 * ioBuf, XMP_Int32 len);
- virtual XMP_Int32 Read(XMP_Uns8 * ioBuf);
- virtual void Close(void);
- virtual bool IsEOF(void);
- virtual XMP_Int64 Skip(XMP_Int64 len);
- virtual XMP_Int64 Skip(XMP_Int64 len, EDeflate deflate);
- virtual XMP_Int64 GetCurrentPos(void) { return iPos; };
-
-
- protected:
- void InitStream(void);
- z_stream iStream;
- XMP_Int32 iStatus;
- XMP_Uns8 * iBuffer;
- XMP_Int32 iBufferLength;
-
- };
-
- class ZIPException
- {
- public:
- ZIPException(XMP_Int32 err) : iErrorCode(err) {};
- ~ZIPException(void) {};
-
- XMP_Int32 GetErrorCode(void) { return iErrorCode; };
-
- protected:
- XMP_Int32 iErrorCode;
-
- };
-
-
- } // namespace zip
-
-} // namespace IO
-
-namespace SWF_Support
-{
- class TagData
- {
- public:
- TagData() : pos(0), len(0), id(0), offset(0), xmp(false) {}
- virtual ~TagData() {}
-
- // Short tag:
- // | code/length | data |
- // | 2 | val(length) |
- // Long tag (data > 63):
- // | code/length | length | data |
- // | 2 | 4 | val(length) |
- XMP_Uns64 pos; // file offset of tag
- XMP_Uns32 len; // length of tag data
- long id; // tag ID
- long offset; // offset of data in tag (short vs. long tag)
- bool xmp; // tag with XMP ?
- };
-
- typedef std::vector<TagData> TagVector;
- typedef TagVector::iterator TagIterator;
-
- class TagState
- {
- public:
- TagState() : xmpPos(0), xmpLen(0), headerSize(0),hasFileAttrTag(false), cachingFile(false),
- hasXMP(false), xmpPacket(""), fileAttrFlags(0) {}
- virtual ~TagState() {}
-
- XMP_Uns64 xmpPos;
- XMP_Uns32 xmpLen;
- TagData xmpTag;
- TagVector tags;
- XMP_Uns32 headerSize;
- TagData fileAttrTag;
- XMP_Uns32 fileAttrFlags;
- bool hasFileAttrTag;
- bool cachingFile;
- bool hasXMP;
- std::string xmpPacket;
- };
-
- //compression related data types
-
- typedef enum swf_mode { CWS, FWS } SWF_MODE;
- typedef int (*CompressionFnc)(LFA_FileRef source, LFA_FileRef dest);
-
- class FileInfo
- {
- public:
- FileInfo(LFA_FileRef fileRef, const std::string & origPath);
- virtual ~FileInfo() {}
-
- bool IsCompressed();
- LFA_FileRef Decompress();
- void Compress(LFA_FileRef sourceRef, LFA_FileRef destRef);
- void Clean();
- inline XMP_Uns32 GetSize() { return iSize; }
-
- private:
- std::string tmpFilePath;
- std::string origFilePath;
- LFA_FileRef fileRef;
- bool compressedFile;
- XMP_Uns32 iSize;
-
- //tmp Data
- LFA_FileRef tmpFileRef;
-
-
- void CheckFormat(LFA_FileRef fileRef);
- void CleanTempFiles();
-
- int Encode ( LFA_FileRef fileRef, LFA_FileRef updateRef, SWF_MODE swfMode, CompressionFnc cmpFnc );
-
- static int Inf ( LFA_FileRef source, LFA_FileRef dest );
- static int Def ( LFA_FileRef source, LFA_FileRef dest );
-
- };
-
- long OpenSWF ( IO::InputStream *inputStream, TagState & inOutTagState );
- bool ReadTag ( IO::InputStream * inputStream, TagState & inOutTagState, long * tagType,
- XMP_Uns32 * tagLength, XMP_Uns64 & inOutPosition );
- unsigned long CheckTag ( IO::InputStream * inputStream, const TagState& inOutTagState, const TagData& inOutTagData );
- bool HasMetadata(IO::InputStream * inputStream, TagState& tagState);
- XMP_Uns32 ReadFileAttrFlags(IO::InputStream * inputStream);
-
- bool WriteXMPTag ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer );
- bool CopyHeader ( LFA_FileRef sourceRef, LFA_FileRef destRef, const TagState & tagState );
- bool UpdateHeader ( LFA_FileRef fileRef );
- bool CopyTag ( LFA_FileRef sourceRef, LFA_FileRef destRef, TagData& tag );
-
- bool UpdateFileAttrTag(LFA_FileRef fileRef, const TagData& fileAttrTag, const TagState& tagState);
- bool WriteFileAttrFlags(LFA_FileRef fileRef, const TagData& fileAttrTag, XMP_Uns32 flags);
-
- bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, XMP_Uns8* outBuffer );
- bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, const char* inBuffer );
-
-
- typedef struct TailBufferDef
- {
- XMP_Uns64 tailStartPosition;
- XMP_Uns64 writePosition;
- XMP_Uns64 tailEndPosition;
-
- TailBufferDef() : tailStartPosition(0), writePosition(0), tailEndPosition(0) {};
- XMP_Uns32 GetTailSize(void) { return static_cast<XMP_Uns32>(tailEndPosition - tailStartPosition); }
- } TailBufferDef;
-
-
-
-} // namespace SWF_Support
-
-#endif // __SWF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp b/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp
deleted file mode 100644
index 3eb6eb2..0000000
--- a/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp
+++ /dev/null
@@ -1,1901 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Support.hpp"
-
-// =================================================================================================
-/// \file TIFF_FileWriter.cpp
-/// \brief TIFF_FileWriter is used for memory-based read-write access and all file-based access.
-///
-/// \c TIFF_FileWriter is used for memory-based read-write access and all file-based access. The
-/// main internal data structure is the InternalTagMap, a std::map that uses the tag number as the
-/// key and InternalTagInfo as the value. There are 5 of these maps, one for each of the recognized
-/// IFDs. The maps contain an entry for each tag in the IFD, whether we capture the data or not. The
-/// dataPtr and dataLen fields in the InternalTagInfo are zero if the tag is not captured.
-// =================================================================================================
-
-// =================================================================================================
-// TIFF_FileWriter::TIFF_FileWriter
-// ================================
-//
-// Set big endian Get/Put routines so that routines are in place for creating TIFF without a parse.
-// Parsing will reset them to the proper endianness for the stream. Big endian is a good default
-// since JPEG and PSD files are big endian overall.
-
-TIFF_FileWriter::TIFF_FileWriter() : changed(false), legacyDeleted(false), memParsed(false),
- fileParsed(false), ownedStream(false), memStream(0), tiffLength(0)
-{
-
- XMP_Uns8 bogusTIFF [kEmptyTIFFLength];
-
- bogusTIFF[0] = 0x4D;
- bogusTIFF[1] = 0x4D;
- bogusTIFF[2] = 0x00;
- bogusTIFF[3] = 0x2A;
- bogusTIFF[4] = bogusTIFF[5] = bogusTIFF[6] = bogusTIFF[7] = 0x00;
-
- (void) this->CheckTIFFHeader ( bogusTIFF, sizeof ( bogusTIFF ) );
-
-} // TIFF_FileWriter::TIFF_FileWriter
-
-// =================================================================================================
-// TIFF_FileWriter::~TIFF_FileWriter
-// =================================
-
-TIFF_FileWriter::~TIFF_FileWriter()
-{
- XMP_Assert ( ! (this->memParsed && this->fileParsed) );
-
- if ( this->ownedStream ) {
- XMP_Assert ( this->memStream != 0 );
- free ( this->memStream );
- }
-
-} // TIFF_FileWriter::~TIFF_FileWriter
-
-// =================================================================================================
-// TIFF_FileWriter::DeleteExistingInfo
-// ===================================
-
-void TIFF_FileWriter::DeleteExistingInfo()
-{
- XMP_Assert ( ! (this->memParsed && this->fileParsed) );
-
- if ( this->ownedStream ) free ( this->memStream ); // ! Current TIFF might be memory-parsed.
- this->memStream = 0;
- this->tiffLength = 0;
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) this->containedIFDs[ifd].clear();
-
- this->changed = false;
- this->legacyDeleted = false;
- this->memParsed = false;
- this->fileParsed = false;
- this->ownedStream = false;
-
-} // TIFF_FileWriter::DeleteExistingInfo
-
-// =================================================================================================
-// TIFF_FileWriter::PickIFD
-// ========================
-
-XMP_Uns8 TIFF_FileWriter::PickIFD ( XMP_Uns8 ifd, XMP_Uns16 id )
-{
- if ( ifd > kTIFF_LastRealIFD ) {
- if ( ifd != kTIFF_KnownIFD ) XMP_Throw ( "Invalid IFD number", kXMPErr_BadParam );
- XMP_Throw ( "kTIFF_KnownIFD not yet implemented", kXMPErr_Unimplemented );
- // *** Likely to stay unimplemented until there is a client need.
- }
-
- return ifd;
-
-} // TIFF_FileWriter::PickIFD
-
-// =================================================================================================
-// TIFF_FileWriter::FindTagInIFD
-// =============================
-
-const TIFF_FileWriter::InternalTagInfo* TIFF_FileWriter::FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const
-{
- ifd = PickIFD ( ifd, id );
- const InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
-
- InternalTagMap::const_iterator tagPos = currIFD.find ( id );
- if ( tagPos == currIFD.end() ) return 0;
- return &tagPos->second;
-
-} // TIFF_FileWriter::FindTagInIFD
-
-// =================================================================================================
-// TIFF_FileWriter::GetIFD
-// =======================
-
-bool TIFF_FileWriter::GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const
-{
- if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD number", kXMPErr_BadParam );
- const InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
-
- InternalTagMap::const_iterator tagPos = currIFD.begin();
- InternalTagMap::const_iterator tagEnd = currIFD.end();
-
- if ( ifdMap != 0 ) ifdMap->clear();
- if ( tagPos == tagEnd ) return false; // Empty IFD.
-
- if ( ifdMap != 0 ) {
- for ( ; tagPos != tagEnd; ++tagPos ) {
- const InternalTagInfo& intInfo = tagPos->second;
- TagInfo extInfo ( intInfo.id, intInfo.type, intInfo.count, intInfo.dataPtr, intInfo.dataLen );
- (*ifdMap)[intInfo.id] = extInfo;
- }
- }
-
- return true;
-
-} // TIFF_FileWriter::GetIFD
-
-// =================================================================================================
-// TIFF_FileWriter::GetValueOffset
-// ===============================
-
-XMP_Uns32 TIFF_FileWriter::GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( (thisTag == 0) || (thisTag->origDataLen == 0) ) return 0;
-
- return thisTag->origDataOffset;
-
-} // TIFF_FileWriter::GetValueOffset
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag
-// =======================
-
-bool TIFF_FileWriter::GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
-
- if ( info != 0 ) {
-
- info->id = thisTag->id;
- info->type = thisTag->type;
- info->count = thisTag->dataLen / (XMP_Uns32)kTIFF_TypeSizes[thisTag->type];
- info->dataLen = thisTag->dataLen;
- info->dataPtr = (const void*)(thisTag->dataPtr);
-
- }
-
- return true;
-
-} // TIFF_FileWriter::GetTag
-
-// =================================================================================================
-// TIFF_FileWriter::SetTag
-// =======================
-
-void TIFF_FileWriter::SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* clientPtr )
-{
- if ( (type < kTIFF_ByteType) || (type > kTIFF_LastType) ) XMP_Throw ( "Invalid TIFF tag type", kXMPErr_BadParam );
- size_t typeSize = kTIFF_TypeSizes[type];
- size_t fullSize = count * typeSize;
-
- ifd = PickIFD ( ifd, id );
- InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
-
- InternalTagInfo* tagPtr = 0;
- InternalTagMap::iterator tagPos = currIFD.find ( id );
-
- if ( tagPos == currIFD.end() ) {
-
- // The tag does not yet exist, add it.
- InternalTagMap::value_type mapValue ( id, InternalTagInfo ( id, type, count, this->fileParsed ) );
- tagPos = currIFD.insert ( tagPos, mapValue );
- tagPtr = &tagPos->second;
-
- } else {
-
- tagPtr = &tagPos->second;
-
- // The tag already exists, make sure the value is actually changing.
- if ( (type == tagPtr->type) && (count == tagPtr->count) &&
- (memcmp ( clientPtr, tagPtr->dataPtr, tagPtr->dataLen ) == 0) ) {
- return; // ! The value is unchanged, exit.
- }
-
- tagPtr->FreeData(); // Release any existing data allocation.
-
- tagPtr->type = type; // These might be changing also.
- tagPtr->count = count;
-
- }
-
- tagPtr->changed = true;
- tagPtr->dataLen = (XMP_Uns32)fullSize;
-
- if ( fullSize <= 4 ) {
- // The data is less than 4 bytes, store it in the smallValue field using native endianness.
- tagPtr->dataPtr = (XMP_Uns8*) &tagPtr->smallValue;
- } else {
- // The data is more than 4 bytes, make a copy.
- tagPtr->dataPtr = (XMP_Uns8*) malloc ( fullSize );
- if ( tagPtr->dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- }
- memcpy ( tagPtr->dataPtr, clientPtr, fullSize ); // AUDIT: Safe, space guaranteed to be fullSize.
-
- if ( ! this->nativeEndian ) {
- if ( typeSize == 2 ) {
- XMP_Uns16* flipPtr = (XMP_Uns16*) tagPtr->dataPtr;
- for ( XMP_Uns32 i = 0; i < count; ++i ) Flip2 ( flipPtr[i] );
- } else if ( typeSize == 4 ) {
- XMP_Uns32* flipPtr = (XMP_Uns32*) tagPtr->dataPtr;
- for ( XMP_Uns32 i = 0; i < count; ++i ) Flip4 ( flipPtr[i] );
- } else if ( typeSize == 8 ) {
- XMP_Uns64* flipPtr = (XMP_Uns64*) tagPtr->dataPtr;
- for ( XMP_Uns32 i = 0; i < count; ++i ) Flip8 ( flipPtr[i] );
- }
- }
-
- this->containedIFDs[ifd].changed = true;
- this->changed = true;
-
-} // TIFF_FileWriter::SetTag
-
-// =================================================================================================
-// TIFF_FileWriter::DeleteTag
-// ==========================
-
-void TIFF_FileWriter::DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id )
-{
- ifd = PickIFD ( ifd, id );
- InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
-
- InternalTagMap::iterator tagPos = currIFD.find ( id );
- if ( tagPos == currIFD.end() ) return; // ! Don't set the changed flags if the tag didn't exist.
-
- currIFD.erase ( tagPos );
- this->containedIFDs[ifd].changed = true;
- this->changed = true;
- if ( (ifd != kTIFF_PrimaryIFD) || (id != kTIFF_XMP) ) this->legacyDeleted = true;
-
-} // TIFF_FileWriter::DeleteTag
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Integer
-// ===============================
-
-bool TIFF_FileWriter::GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( thisTag->count != 1 ) return false;
-
- static XMP_Uns32 voidValue;
- if ( data == 0 ) data = &voidValue;
-
- if ( thisTag->type == kTIFF_ShortType ) {
- *data = this->GetUns16 ( thisTag->dataPtr );
- } else if ( thisTag->type == kTIFF_LongType ) {
- *data = this->GetUns32 ( thisTag->dataPtr );
- } else {
- return false;
- }
-
- return true;
-
-} // TIFF_FileWriter::GetTag_Integer
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Byte
-// ============================
-
-bool TIFF_FileWriter::GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_ByteType) || (thisTag->dataLen != 1) ) return false;
-
- if ( data != 0 ) *data = *thisTag->dataPtr;
- return true;
-
-} // TIFF_FileWriter::GetTag_Byte
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_SByte
-// =============================
-
-bool TIFF_FileWriter::GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SByteType) || (thisTag->dataLen != 1) ) return false;
-
- if ( data != 0 ) *data = *thisTag->dataPtr;
- return true;
-
-} // TIFF_FileWriter::GetTag_SByte
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Short
-// =============================
-
-bool TIFF_FileWriter::GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_ShortType) || (thisTag->dataLen != 2) ) return false;
-
- if ( data != 0 ) *data = this->GetUns16 ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_Short
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_SShort
-// ==============================
-
-bool TIFF_FileWriter::GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SShortType) || (thisTag->dataLen != 2) ) return false;
-
- if ( data != 0 ) *data = (XMP_Int16) this->GetUns16 ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_SShort
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Long
-// ============================
-
-bool TIFF_FileWriter::GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_LongType) || (thisTag->dataLen != 4) ) return false;
-
- if ( data != 0 ) *data = this->GetUns32 ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_Long
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_SLong
-// =============================
-
-bool TIFF_FileWriter::GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SLongType) || (thisTag->dataLen != 4) ) return false;
-
- if ( data != 0 ) *data = (XMP_Int32) this->GetUns32 ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_SLong
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Rational
-// ================================
-
-bool TIFF_FileWriter::GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
- if ( (thisTag->type != kTIFF_RationalType) || (thisTag->dataLen != 8) ) return false;
-
- if ( data != 0 ) {
- XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataPtr;
- data->num = this->GetUns32 ( dataPtr );
- data->denom = this->GetUns32 ( dataPtr+1 );
- }
-
- return true;
-
-} // TIFF_FileWriter::GetTag_Rational
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_SRational
-// =================================
-
-bool TIFF_FileWriter::GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
- if ( (thisTag->type != kTIFF_SRationalType) || (thisTag->dataLen != 8) ) return false;
-
- if ( data != 0 ) {
- XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataPtr;
- data->num = (XMP_Int32) this->GetUns32 ( dataPtr );
- data->denom = (XMP_Int32) this->GetUns32 ( dataPtr+1 );
- }
-
- return true;
-
-} // TIFF_FileWriter::GetTag_SRational
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Float
-// =============================
-
-bool TIFF_FileWriter::GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_FloatType) || (thisTag->dataLen != 4) ) return false;
-
- if ( data != 0 ) *data = this->GetFloat ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_Float
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_Double
-// ==============================
-
-bool TIFF_FileWriter::GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
- if ( (thisTag->type != kTIFF_DoubleType) || (thisTag->dataLen != 8) ) return false;
-
- if ( data != 0 ) *data = this->GetDouble ( thisTag->dataPtr );
- return true;
-
-} // TIFF_FileWriter::GetTag_Double
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_ASCII
-// =============================
-
-bool TIFF_FileWriter::GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->dataLen > 4) && (thisTag->dataPtr == 0) ) return false;
- if ( thisTag->type != kTIFF_ASCIIType ) return false;
-
- if ( dataPtr != 0 ) *dataPtr = (XMP_StringPtr)thisTag->dataPtr;
- if ( dataLen != 0 ) *dataLen = thisTag->dataLen;
-
- return true;
-
-} // TIFF_FileWriter::GetTag_ASCII
-
-// =================================================================================================
-// TIFF_FileWriter::GetTag_EncodedString
-// =====================================
-
-bool TIFF_FileWriter::GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const
-{
- const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( thisTag->type != kTIFF_UndefinedType ) return false;
-
- if ( utf8Str == 0 ) return true; // Return true if the converted string is not wanted.
-
- bool ok = this->DecodeString ( thisTag->dataPtr, thisTag->dataLen, utf8Str );
- return ok;
-
-} // TIFF_FileWriter::GetTag_EncodedString
-
-// =================================================================================================
-// TIFF_FileWriter::SetTag_EncodedString
-// =====================================
-
-void TIFF_FileWriter::SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding )
-{
- std::string encodedStr;
-
- this->EncodeString ( utf8Str, encoding, &encodedStr );
- this->SetTag ( ifd, id, kTIFF_UndefinedType, (XMP_Uns32)encodedStr.size(), encodedStr.c_str() );
-
-} // TIFF_FileWriter::SetTag_EncodedString
-
-// =================================================================================================
-// TIFF_FileWriter::IsLegacyChanged
-// ================================
-
-bool TIFF_FileWriter::IsLegacyChanged()
-{
-
- if ( ! this->changed ) return false;
- if ( this->legacyDeleted ) return true;
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- if ( ! thisIFD.changed ) continue;
-
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
-
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- if ( thisTag.changed && (thisTag.id != kTIFF_XMP) ) return true;
- }
-
- }
-
- return false; // Can get here if the XMP tag is the only one changed.
-
-} // TIFF_FileWriter::IsLegacyChanged
-
-// =================================================================================================
-// TIFF_FileWriter::ParseMemoryStream
-// ==================================
-
-void TIFF_FileWriter::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
-{
- this->DeleteExistingInfo();
- this->memParsed = true;
- if ( length == 0 ) return;
-
- // Allocate space for the full in-memory stream and copy it.
-
- if ( ! copyData ) {
- XMP_Assert ( ! this->ownedStream );
- this->memStream = (XMP_Uns8*) data;
- } else {
- if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based TIFF", kXMPErr_BadTIFF );
- this->memStream = (XMP_Uns8*) malloc(length);
- if ( this->memStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( this->memStream, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
- this->ownedStream = true;
- }
- this->tiffLength = length;
-
- // Find and process the primary, Exif, GPS, and Interoperability IFDs.
-
- XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->memStream, length );
-
- if ( primaryIFDOffset != 0 ) (void) this->ProcessMemoryIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
-
- const InternalTagInfo* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
- if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->dataLen == 4) ) {
- XMP_Uns32 exifOffset = this->GetUns32 ( exifIFDTag->dataPtr );
- (void) this->ProcessMemoryIFD ( exifOffset, kTIFF_ExifIFD );
- }
-
- const InternalTagInfo* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
- if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->dataLen == 4) ) {
- XMP_Uns32 gpsOffset = this->GetUns32 ( gpsIFDTag->dataPtr );
- (void) this->ProcessMemoryIFD ( gpsOffset, kTIFF_GPSInfoIFD );
- }
-
- const InternalTagInfo* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
- if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->dataLen == 4) ) {
- XMP_Uns32 interopOffset = this->GetUns32 ( interopIFDTag->dataPtr );
- (void) this->ProcessMemoryIFD ( interopOffset, kTIFF_InteropIFD );
- }
-
- #if 0
- {
- printf ( "\nExiting TIFF_FileWriter::ParseMemoryStream\n" );
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- printf ( "\n IFD %d, count %d, mapped %d, offset %d (0x%X), next IFD %d (0x%X)\n",
- ifd, thisIFD.origCount, thisIFD.tagMap.size(),
- thisIFD.origDataOffset, thisIFD.origDataOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- printf ( " Tag %d, smallValue 0x%X, origDataLen %d, origDataOffset %d (0x%X)\n",
- thisTag.id, thisTag.smallValue, thisTag.origDataLen, thisTag.origDataOffset, thisTag.origDataOffset );
- }
- }
- printf ( "\n" );
- }
- #endif
-
-} // TIFF_FileWriter::ParseMemoryStream
-
-// =================================================================================================
-// TIFF_FileWriter::ProcessMemoryIFD
-// =================================
-
-XMP_Uns32 TIFF_FileWriter::ProcessMemoryIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
-{
- InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
-
- if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
- XMP_Throw ( "Bad IFD offset", kXMPErr_BadTIFF );
- }
-
- XMP_Uns8* ifdPtr = this->memStream + ifdOffset;
- XMP_Uns16 tagCount = this->GetUns16 ( ifdPtr );
- RawIFDEntry* ifdEntries = (RawIFDEntry*)(ifdPtr+2);
-
- if ( tagCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
- if ( (ifdOffset + 2 + tagCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
-
- ifdInfo.origIFDOffset = ifdOffset;
- ifdInfo.origCount = tagCount;
-
- for ( size_t i = 0; i < tagCount; ++i ) {
-
- RawIFDEntry* rawTag = &ifdEntries[i];
- XMP_Uns16 tagType = this->GetUns16 ( &rawTag->type );
- if ( (tagType < kTIFF_ByteType) || (tagType > kTIFF_LastType) ) continue; // Bad type, skip this tag.
-
- XMP_Uns16 tagID = this->GetUns16 ( &rawTag->id );
- XMP_Uns32 tagCount = this->GetUns32 ( &rawTag->count );
-
- InternalTagMap::value_type mapValue ( tagID, InternalTagInfo ( tagID, tagType, tagCount, kIsMemoryBased ) );
- InternalTagMap::iterator newPos = ifdInfo.tagMap.insert ( ifdInfo.tagMap.end(), mapValue );
- InternalTagInfo& mapTag = newPos->second;
-
- mapTag.dataLen = mapTag.origDataLen = mapTag.count * (XMP_Uns32)kTIFF_TypeSizes[mapTag.type];
- mapTag.smallValue = rawTag->dataOrOffset; // Keep the value or offset in stream byte ordering.
-
- if ( mapTag.dataLen <= 4 ) {
- mapTag.origDataOffset = ifdOffset + 2 + (12 * (XMP_Uns32)i) + 8; // Compute the data offset.
- } else {
- mapTag.origDataOffset = this->GetUns32 ( &rawTag->dataOrOffset ); // Extract the data offset.
- // printf ( "FW_ProcessMemoryIFD tag %d large value @ %.8X\n", mapTag.id, mapTag.dataPtr );
- }
- mapTag.dataPtr = this->memStream + mapTag.origDataOffset;
-
- }
-
- ifdPtr += (2 + tagCount*12);
- ifdInfo.origNextIFD = this->GetUns32 ( ifdPtr );
-
- return ifdInfo.origNextIFD;
-
-} // TIFF_FileWriter::ProcessMemoryIFD
-
-// =================================================================================================
-// TIFF_FileWriter::ParseFileStream
-// ================================
-//
-// The buffered I/O model is worth the logic complexity - as opposed to a simple seek/read for each
-// part of the TIFF stream. The vast majority of real-world TIFFs have the primary IFD, Exif IFD,
-// and all of their interesting tag values within the first 64K of the file. Well, at least before
-// we get around to our edit-by-append approach.
-
-void TIFF_FileWriter::ParseFileStream ( LFA_FileRef fileRef )
-{
- bool ok;
- IOBuffer ioBuf;
-
- this->DeleteExistingInfo();
- this->fileParsed = true;
- this->tiffLength = (XMP_Uns32) LFA_Measure ( fileRef );
- if ( this->tiffLength == 0 ) return;
-
- // Find and process the primary, Exif, GPS, and Interoperability IFDs.
-
- ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_SET );
- ok = CheckFileSpace ( fileRef, &ioBuf, 8 );
- if ( ! ok ) XMP_Throw ( "TIFF too small", kXMPErr_BadTIFF );
-
- XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( ioBuf.ptr, this->tiffLength );
-
- if ( primaryIFDOffset != 0 ) (void) this->ProcessFileIFD ( kTIFF_PrimaryIFD, primaryIFDOffset, fileRef, &ioBuf );
-
- const InternalTagInfo* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
- if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->count == 1) ) {
- XMP_Uns32 exifOffset = this->GetUns32 ( exifIFDTag->dataPtr );
- (void) this->ProcessFileIFD ( kTIFF_ExifIFD, exifOffset, fileRef, &ioBuf );
- }
-
- const InternalTagInfo* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
- if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->count == 1) ) {
- XMP_Uns32 gpsOffset = this->GetUns32 ( gpsIFDTag->dataPtr );
- (void) this->ProcessFileIFD ( kTIFF_GPSInfoIFD, gpsOffset, fileRef, &ioBuf );
- }
-
- const InternalTagInfo* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
- if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->dataLen == 4) ) {
- XMP_Uns32 interopOffset = this->GetUns32 ( interopIFDTag->dataPtr );
- (void) this->ProcessFileIFD ( kTIFF_InteropIFD, interopOffset, fileRef, &ioBuf );
- }
-
- #if 0
- {
- printf ( "\nExiting TIFF_FileWriter::ParseFileStream\n" );
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- printf ( "\n IFD %d, count %d, mapped %d, offset %d (0x%X), next IFD %d (0x%X)\n",
- ifd, thisIFD.origCount, thisIFD.tagMap.size(),
- thisIFD.origDataOffset, thisIFD.origDataOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- printf ( " Tag %d, smallValue 0x%X, origDataLen %d, origDataOffset %d (0x%X)\n",
- thisTag.id, thisTag.smallValue, thisTag.origDataLen, thisTag.origDataOffset, thisTag.origDataOffset );
- }
- }
- printf ( "\n" );
- }
- #endif
-
-} // TIFF_FileWriter::ParseFileStream
-
-// =================================================================================================
-// TIFF_FileWriter::ProcessFileIFD
-// ===============================
-
-XMP_Uns32 TIFF_FileWriter::ProcessFileIFD ( XMP_Uns8 ifd, XMP_Uns32 ifdOffset, LFA_FileRef fileRef, IOBuffer* ioBuf )
-{
- InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
-
- MoveToOffset ( fileRef, ifdOffset, ioBuf ); // Move to the start of the IFD.
-
- bool ok = CheckFileSpace ( fileRef, ioBuf, 2 );
- if ( ! ok ) XMP_Throw ( "IFD count missing", kXMPErr_BadTIFF );
- XMP_Uns16 tagCount = this->GetUns16 ( ioBuf->ptr );
-
- if ( tagCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
- if ( (ifdOffset + 2 + tagCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
-
- ifdInfo.origIFDOffset = ifdOffset;
- ifdInfo.origCount = tagCount;
-
- // ---------------------------------------------------------------------------------------------
- // First create all of the IFD map entries, capturing short values, and get the next IFD offset.
- // We're using a std::map for storage, it automatically eliminates duplicates and provides
- // sorted output. Plus the "map[key] = value" assignment conveniently keeps the last encountered
- // value, following Photoshop's behavior.
-
- ioBuf->ptr += 2; // Move to the first IFD entry.
-
- for ( XMP_Uns16 i = 0; i < tagCount; ++i, ioBuf->ptr += 12 ) {
-
- if ( ! CheckFileSpace ( fileRef, ioBuf, 12 ) ) XMP_Throw ( "EOF within IFD", kXMPErr_BadTIFF );
-
- RawIFDEntry* rawTag = (RawIFDEntry*)ioBuf->ptr;
- XMP_Uns16 tagType = this->GetUns16 ( &rawTag->type );
- if ( (tagType < kTIFF_ByteType) || (tagType > kTIFF_LastType) ) continue; // Bad type, skip this tag.
-
- XMP_Uns16 tagID = this->GetUns16 ( &rawTag->id );
- XMP_Uns32 tagCount = this->GetUns32 ( &rawTag->count );
-
- InternalTagMap::value_type mapValue ( tagID, InternalTagInfo ( tagID, tagType, tagCount, kIsFileBased ) );
- InternalTagMap::iterator newPos = ifdInfo.tagMap.insert ( ifdInfo.tagMap.end(), mapValue );
- InternalTagInfo& mapTag = newPos->second;
-
- mapTag.dataLen = mapTag.origDataLen = mapTag.count * (XMP_Uns32)kTIFF_TypeSizes[mapTag.type];
- mapTag.smallValue = rawTag->dataOrOffset; // Keep the value or offset in stream byte ordering.
-
- if ( mapTag.dataLen <= 4 ) {
- mapTag.dataPtr = (XMP_Uns8*) &mapTag.smallValue;
- mapTag.origDataOffset = ifdOffset + 2 + (12 * i) + 8; // Compute the data offset.
- } else {
- mapTag.origDataOffset = this->GetUns32 ( &rawTag->dataOrOffset ); // Extract the data offset.
- }
-
- }
-
- if ( ! CheckFileSpace ( fileRef, ioBuf, 4 ) ) XMP_Throw ( "EOF at next IFD offset", kXMPErr_BadTIFF );
- ifdInfo.origNextIFD = this->GetUns32 ( ioBuf->ptr );
-
- // ---------------------------------------------------------------------------------------------
- // Go back over the tag map and extract the data for large recognized tags. This is done in 2
- // passes, in order to lessen the typical amount of I/O. On the first pass make sure we have at
- // least 32K of data following the IFD in the buffer, and extract all of the values in that
- // portion. This should cover an original file, or the appended values with an appended IFD.
-
- if ( (ioBuf->limit - ioBuf->ptr) < 32*1024 ) RefillBuffer ( fileRef, ioBuf );
-
- InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
- InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
-
- const XMP_Uns16* knownTagPtr = sKnownTags[ifd]; // Points into the ordered recognized tag list.
-
- XMP_Uns32 bufBegin = (XMP_Uns32)ioBuf->filePos; // TIFF stream bounds for the current buffer.
- XMP_Uns32 bufEnd = bufBegin + (XMP_Uns32)ioBuf->len;
-
- for ( ; tagPos != tagEnd; ++tagPos ) {
-
- InternalTagInfo* currTag = &tagPos->second;
-
- if ( currTag->dataLen <= 4 ) continue; // Short values are already in the smallValue field.
- while ( *knownTagPtr < currTag->id ) ++knownTagPtr;
- if ( *knownTagPtr != currTag->id ) continue; // Skip unrecognized tags.
- if ( currTag->dataLen > 1024*1024 ) XMP_Throw ( "Outrageous data length", kXMPErr_BadTIFF );
-
- if ( (bufBegin <= currTag->origDataOffset) && ((currTag->origDataOffset + currTag->dataLen) <= bufEnd) ) {
- // This value is already fully within the current I/O buffer, copy it.
- MoveToOffset ( fileRef, currTag->origDataOffset, ioBuf );
- currTag->dataPtr = (XMP_Uns8*) malloc ( currTag->dataLen );
- if ( currTag->dataPtr == 0 ) XMP_Throw ( "No data block", kXMPErr_NoMemory );
- memcpy ( currTag->dataPtr, ioBuf->ptr, currTag->dataLen ); // AUDIT: Safe, malloc'ed currTag->dataLen bytes above.
- }
-
- }
-
- // ---------------------------------------------------------------------------------------------
- // Now the second large value pass. This will reposition the I/O buffer as necessary. Hopefully
- // just once, to pick up the span of data not covered in the first pass.
-
- tagPos = ifdInfo.tagMap.begin(); // Reset both map/array positions.
- knownTagPtr = sKnownTags[ifd];
-
- for ( ; tagPos != tagEnd; ++tagPos ) {
-
- InternalTagInfo* currTag = &tagPos->second;
-
- if ( (currTag->dataLen <= 4) || (currTag->dataPtr != 0) ) continue; // Done this tag?
- while ( *knownTagPtr < currTag->id ) ++knownTagPtr;
- if ( *knownTagPtr != currTag->id ) continue; // Skip unrecognized tags.
- if ( currTag->dataLen > 1024*1024 ) XMP_Throw ( "Outrageous data length", kXMPErr_BadTIFF );
-
- currTag->dataPtr = (XMP_Uns8*) malloc ( currTag->dataLen );
- if ( currTag->dataPtr == 0 ) XMP_Throw ( "No data block", kXMPErr_NoMemory );
-
- if ( currTag->dataLen > kIOBufferSize ) {
- // This value is bigger than the I/O buffer, read it directly and restore the file position.
- LFA_Seek ( fileRef, currTag->origDataOffset, SEEK_SET );
- LFA_Read ( fileRef, currTag->dataPtr, currTag->dataLen, kLFA_RequireAll );
- LFA_Seek ( fileRef, (ioBuf->filePos + ioBuf->len), SEEK_SET );
- } else {
- // This value can fit in the I/O buffer, so use that.
- MoveToOffset ( fileRef, currTag->origDataOffset, ioBuf );
- ok = CheckFileSpace ( fileRef, ioBuf, currTag->dataLen );
- if ( ! ok ) XMP_Throw ( "EOF in data block", kXMPErr_BadTIFF );
- memcpy ( currTag->dataPtr, ioBuf->ptr, currTag->dataLen ); // AUDIT: Safe, malloc'ed currTag->dataLen bytes above.
- }
-
- }
-
- // Done, return the next IFD offset.
-
- return ifdInfo.origNextIFD;
-
-} // TIFF_FileWriter::ProcessFileIFD
-
-// =================================================================================================
-// TIFF_FileWriter::IntegrateFromPShop6
-// ====================================
-//
-// See comments for ProcessPShop6IFD.
-
-void TIFF_FileWriter::IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen )
-{
- TIFF_MemoryReader buriedExif;
- buriedExif.ParseMemoryStream ( buriedPtr, (XMP_Uns32) buriedLen );
-
- this->ProcessPShop6IFD ( buriedExif, kTIFF_PrimaryIFD );
- this->ProcessPShop6IFD ( buriedExif, kTIFF_ExifIFD );
- this->ProcessPShop6IFD ( buriedExif, kTIFF_GPSInfoIFD );
-
-} // TIFF_FileWriter::IntegrateFromPShop6
-
-// =================================================================================================
-// TIFF_FileWriter::CopyTagToMasterIFD
-// ===================================
-//
-// Create a new master IFD entry from a buried Photoshop 6 IFD entry. Don't try to get clever with
-// large values, just create a new copy. This preserves a clean separation between the memory-based
-// and file-based TIFF processing.
-
-void* TIFF_FileWriter::CopyTagToMasterIFD ( const TagInfo & ps6Tag, InternalIFDInfo * masterIFD )
-{
- InternalTagMap::value_type mapValue ( ps6Tag.id, InternalTagInfo ( ps6Tag.id, ps6Tag.type, ps6Tag.count, this->fileParsed ) );
- InternalTagMap::iterator newPos = masterIFD->tagMap.insert ( masterIFD->tagMap.end(), mapValue );
- InternalTagInfo& newTag = newPos->second;
-
- newTag.dataLen = ps6Tag.dataLen;
-
- if ( newTag.dataLen <= 4 ) {
- newTag.dataPtr = (XMP_Uns8*) &newTag.smallValue;
- newTag.smallValue = *((XMP_Uns32*)ps6Tag.dataPtr);
- } else {
- newTag.dataPtr = (XMP_Uns8*) malloc ( newTag.dataLen );
- if ( newTag.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( newTag.dataPtr, ps6Tag.dataPtr, newTag.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
- }
-
- newTag.changed = true; // ! See comments with ProcessPShop6IFD.
- XMP_Assert ( (newTag.origDataLen == 0) && (newTag.origDataOffset == 0) );
-
- masterIFD->changed = true;
-
- return newPos->second.dataPtr; // ! Return the address within the map entry for small values.
-
-} // TIFF_FileWriter::CopyTagToMasterIFD
-
-// =================================================================================================
-// FlipCFATable
-// ============
-//
-// The CFA pattern table is trivial, a pair of short counts followed by n*m bytes.
-
-static bool FlipCFATable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
-{
- if ( tagLen < 4 ) return false;
-
- XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
-
- Flip2 ( &u16Ptr[0] ); // Flip the counts to match the master TIFF.
- Flip2 ( &u16Ptr[1] );
-
- XMP_Uns16 columns = GetUns16 ( &u16Ptr[0] ); // Fetch using the master TIFF's routine.
- XMP_Uns16 rows = GetUns16 ( &u16Ptr[1] );
-
- if ( tagLen != (XMP_Uns32)(4 + columns*rows) ) return false;
-
- return true;
-
-} // FlipCFATable
-
-// =================================================================================================
-// FlipDSDTable
-// ============
-//
-// The device settings description table is trivial, a pair of short counts followed by UTF-16
-// strings. So the whole value should be flipped as a sequence of 16 bit items.
-
-// ! The Exif 2.2 description is a bit garbled. It might be wrong. It would be nice to have a real example.
-
-static bool FlipDSDTable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
-{
- if ( tagLen < 4 ) return false;
-
- XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
- for ( size_t i = tagLen/2; i > 0; --i, ++u16Ptr ) Flip2 ( u16Ptr );
-
- return true;
-
-} // FlipDSDTable
-
-// =================================================================================================
-// FlipOECFSFRTable
-// ================
-//
-// The OECF and SFR tables have the same layout:
-// 2 short counts, columns and rows
-// c ASCII strings, null terminated, column names
-// c*r rationals
-
-static bool FlipOECFSFRTable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
-{
- XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
-
- Flip2 ( &u16Ptr[0] ); // Flip the data to match the master TIFF.
- Flip2 ( &u16Ptr[1] );
-
- XMP_Uns16 columns = GetUns16 ( &u16Ptr[0] ); // Fetch using the master TIFF's routine.
- XMP_Uns16 rows = GetUns16 ( &u16Ptr[1] );
-
- XMP_Uns32 minLen = 4 + columns + (8 * columns * rows); // Minimum legit tag size.
- if ( tagLen < minLen ) return false;
-
- // Compute the start of the rationals from the end of value. No need to walk through the names.
- XMP_Uns32* u32Ptr = (XMP_Uns32*) ((XMP_Uns8*)voidPtr + tagLen - (8 * columns * rows));
-
- for ( size_t i = 2*columns*rows; i > 0; --i, ++u32Ptr ) Flip4 ( u32Ptr );
-
- return true;
-
-} // FlipOECFSFRTable
-
-// =================================================================================================
-// TIFF_FileWriter::ProcessPShop6IFD
-// =================================
-//
-// Photoshop 6 wrote wacky TIFF files that have much of the Exif metadata buried inside of image
-// resource 1058, which is itself within tag 34377 in the 0th IFD. This routine moves the buried
-// tags up to the parent file. Existing tags are not replaced.
-//
-// While it is tempting to try to directly use the TIFF_MemoryReader's tweaked IFD info, making that
-// visible would compromise implementation separation. Better to pay the modest runtime cost of
-// using the official GetIFD method, letting it build the map.
-//
-// The tags that get moved are marked as being changed, as is the IFD they are moved into, but the
-// overall TIFF_FileWriter object is not. We don't want this integration on its own to force a file
-// update, but a file update should include these changes.
-
-// ! Be careful to not move tags that are the nasty Exif explicit offsets, e.g. the Exif or GPS IFD
-// ! "pointers". These are tags with a LONG type and count of 1, whose value is an offset into the
-// ! buried TIFF stream. We can't reliably plant that offset into the outer IFD structure.
-
-// ! To make things even more fun, the buried Exif might not have the same endianness as the outer!
-
-void TIFF_FileWriter::ProcessPShop6IFD ( const TIFF_MemoryReader& buriedExif, XMP_Uns8 ifd )
-{
- bool ok, found;
- TagInfoMap ps6IFD;
-
- found = buriedExif.GetIFD ( ifd, &ps6IFD );
- if ( ! found ) return;
-
- bool needsFlipping = (this->bigEndian != buriedExif.IsBigEndian());
-
- InternalIFDInfo* masterIFD = &this->containedIFDs[ifd];
-
- TagInfoMap::const_iterator ps6Pos = ps6IFD.begin();
- TagInfoMap::const_iterator ps6End = ps6IFD.end();
-
- for ( ; ps6Pos != ps6End; ++ps6Pos ) {
-
- // Copy buried tags to the master IFD if they don't already exist there.
-
- const TagInfo& ps6Tag = ps6Pos->second;
-
- if ( this->FindTagInIFD ( ifd, ps6Tag.id ) != 0 ) continue; // Keep existing master tags.
- if ( needsFlipping && (ps6Tag.id == 37500) ) continue; // Don't copy an unflipped MakerNote.
- if ( (ps6Tag.id == kTIFF_ExifIFDPointer) || // Skip the tags that are explicit offsets.
- (ps6Tag.id == kTIFF_GPSInfoIFDPointer) ||
- (ps6Tag.id == kTIFF_JPEGInterchangeFormat) ||
- (ps6Tag.id == kTIFF_InteroperabilityIFDPointer) ) continue;
-
- void* voidPtr = this->CopyTagToMasterIFD ( ps6Tag, masterIFD );
-
- if ( needsFlipping ) {
- switch ( ps6Tag.type ) {
-
- case kTIFF_ByteType:
- case kTIFF_SByteType:
- case kTIFF_ASCIIType:
- // Nothing more to do.
- break;
-
- case kTIFF_ShortType:
- case kTIFF_SShortType:
- {
- XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
- for ( size_t i = ps6Tag.count; i > 0; --i, ++u16Ptr ) Flip2 ( u16Ptr );
- }
- break;
-
- case kTIFF_LongType:
- case kTIFF_SLongType:
- case kTIFF_FloatType:
- {
- XMP_Uns32* u32Ptr = (XMP_Uns32*)voidPtr;
- for ( size_t i = ps6Tag.count; i > 0; --i, ++u32Ptr ) Flip4 ( u32Ptr );
- }
- break;
-
- case kTIFF_RationalType:
- case kTIFF_SRationalType:
- {
- XMP_Uns32* ratPtr = (XMP_Uns32*)voidPtr;
- for ( size_t i = (2 * ps6Tag.count); i > 0; --i, ++ratPtr ) Flip4 ( ratPtr );
- }
- break;
-
- case kTIFF_DoubleType:
- {
- XMP_Uns64* u64Ptr = (XMP_Uns64*)voidPtr;
- for ( size_t i = ps6Tag.count; i > 0; --i, ++u64Ptr ) Flip8 ( u64Ptr );
- }
- break;
-
- case kTIFF_UndefinedType:
- // Fix up the few kinds of special tables that Exif 2.2 defines.
- ok = true; // Keep everything that isn't a special table.
- if ( ps6Tag.id == kTIFF_CFAPattern ) {
- ok = FlipCFATable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
- } else if ( ps6Tag.id == kTIFF_DeviceSettingDescription ) {
- ok = FlipDSDTable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
- } else if ( (ps6Tag.id == kTIFF_OECF) || (ps6Tag.id == kTIFF_SpatialFrequencyResponse) ) {
- ok = FlipOECFSFRTable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
- }
- if ( ! ok ) this->DeleteTag ( ifd, ps6Tag.id );
- break;
-
- default:
- // ? XMP_Throw ( "Unexpected tag type", kXMPErr_InternalFailure );
- this->DeleteTag ( ifd, ps6Tag.id );
- break;
-
- }
- }
-
- }
-
-} // TIFF_FileWriter::ProcessPShop6IFD
-
-// =================================================================================================
-// TIFF_FileWriter::PreflightIFDLinkage
-// ====================================
-//
-// Preflight special cases for the linkage between IFDs. Three of the IFDs are found through an
-// explicit tag, the Exif, GPS, and Interop IFDs. The presence or absence of those IFDs affects the
-// presence or absence of the linkage tag, which can affect the IFD containing the linkage tag. The
-// thumbnail IFD is chained from the primary IFD, so if the thumbnail IFD is present we make sure
-// that the primary IFD isn't empty.
-
-void TIFF_FileWriter::PreflightIFDLinkage()
-{
-
- // Do the tag-linked IFDs bottom up, Interop then GPS then Exif.
-
- if ( this->containedIFDs[kTIFF_InteropIFD].tagMap.empty() ) {
- this->DeleteTag ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
- } else if ( ! this->GetTag ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, 0 ) ) {
- this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, 0xABADABAD );
- }
-
- if ( this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.empty() ) {
- this->DeleteTag ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
- } else if ( ! this->GetTag ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, 0 ) ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, 0xABADABAD );
- }
-
- if ( this->containedIFDs[kTIFF_ExifIFD].tagMap.empty() ) {
- this->DeleteTag ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
- } else if ( ! this->GetTag ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, 0 ) ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, 0xABADABAD );
- }
-
- // Make sure that the primary IFD is not empty if the thumbnail IFD is not empty.
-
- if ( this->containedIFDs[kTIFF_PrimaryIFD].tagMap.empty() &&
- (! this->containedIFDs[kTIFF_TNailIFD].tagMap.empty()) ) {
- this->SetTag_Short ( kTIFF_PrimaryIFD, kTIFF_ResolutionUnit, 2 ); // Set Resolution unit to inches.
- }
-
-} // TIFF_FileWriter::PreflightIFDLinkage
-
-// =================================================================================================
-// TIFF_FileWriter::DetermineVisibleLength
-// =======================================
-
-XMP_Uns32 TIFF_FileWriter::DetermineVisibleLength()
-{
- XMP_Uns32 visibleLength = 8; // Start with the TIFF header size.
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
- size_t tagCount = ifdInfo.tagMap.size();
- if ( tagCount == 0 ) continue;
-
- visibleLength += (XMP_Uns32)( 6 + (12 * tagCount) );
-
- InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
- InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
-
- for ( ; tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & currTag ( tagPos->second );
- if ( currTag.dataLen > 4 ) visibleLength += ((currTag.dataLen + 1) & 0xFFFFFFFE); // ! Round to even lengths.
- }
-
- }
-
- return visibleLength;
-
-} // TIFF_FileWriter::DetermineVisibleLength
-
-// =================================================================================================
-// TIFF_FileWriter::DetermineAppendInfo
-// ====================================
-
-#ifndef Trace_DetermineAppendInfo
- #define Trace_DetermineAppendInfo 0
-#endif
-
-XMP_Uns32 TIFF_FileWriter::DetermineAppendInfo ( XMP_Uns32 appendedOrigin,
- bool appendedIFDs[kTIFF_KnownIFDCount],
- XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount],
- bool appendAll /* = false */ )
-{
- XMP_Uns32 appendedLength = 0;
- XMP_Assert ( (appendedOrigin & 1) == 0 ); // Make sure it is even.
-
- #if Trace_DetermineAppendInfo
- {
- printf ( "\nEntering TIFF_FileWriter::DetermineAppendInfo%s\n", (appendAll ? ", append all" : "") );
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- printf ( "\n IFD %d, origCount %d, map.size %d, origIFDOffset %d (0x%X), origNextIFD %d (0x%X)",
- ifd, thisIFD.origCount, thisIFD.tagMap.size(),
- thisIFD.origIFDOffset, thisIFD.origIFDOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
- if ( thisIFD.changed ) printf ( ", changed" );
- if ( thisIFD.origCount < thisIFD.tagMap.size() ) printf ( ", should get appended" );
- printf ( "\n" );
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- printf ( " Tag %d, smallValue 0x%X, origDataLen %d, origDataOffset %d (0x%X)",
- thisTag.id, thisTag.smallValue, thisTag.origDataLen, thisTag.origDataOffset, thisTag.origDataOffset );
- if ( thisTag.changed ) printf ( ", changed" );
- if ( (thisTag.dataLen > thisTag.origDataLen) && (thisTag.dataLen > 4) ) printf ( ", should get appended" );
- printf ( "\n" );
- }
- }
- printf ( "\n" );
- }
- #endif
-
- // Determine which of the IFDs will be appended. If the Exif, GPS, or Interoperability IFDs are
- // appended, set dummy values for their offsets in the "owning" IFD. This must be done first
- // since this might cause the owning IFD to grow.
-
- if ( ! appendAll ) {
- for ( int i = 0; i < kTIFF_KnownIFDCount ;++i ) appendedIFDs[i] = false;
- } else {
- for ( int i = 0; i < kTIFF_KnownIFDCount ;++i ) appendedIFDs[i] = (this->containedIFDs[i].tagMap.size() > 0);
- }
-
- appendedIFDs[kTIFF_InteropIFD] |= (this->containedIFDs[kTIFF_InteropIFD].origCount <
- this->containedIFDs[kTIFF_InteropIFD].tagMap.size());
- if ( appendedIFDs[kTIFF_InteropIFD] ) {
- this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, 0xABADABAD );
- }
-
- appendedIFDs[kTIFF_GPSInfoIFD] |= (this->containedIFDs[kTIFF_GPSInfoIFD].origCount <
- this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.size());
- if ( appendedIFDs[kTIFF_GPSInfoIFD] ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, 0xABADABAD );
- }
-
- appendedIFDs[kTIFF_ExifIFD] |= (this->containedIFDs[kTIFF_ExifIFD].origCount <
- this->containedIFDs[kTIFF_ExifIFD].tagMap.size());
- if ( appendedIFDs[kTIFF_ExifIFD] ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, 0xABADABAD );
- }
-
- appendedIFDs[kTIFF_PrimaryIFD] |= (this->containedIFDs[kTIFF_PrimaryIFD].origCount <
- this->containedIFDs[kTIFF_PrimaryIFD].tagMap.size());
-
- // The appended data (if any) will be a sequence of an IFD followed by its large values.
- // Determine the new offsets for the appended IFDs and tag values, and the total amount of
- // appended stuff.
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount ;++ifd ) {
-
- InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
- size_t tagCount = ifdInfo.tagMap.size();
-
- if ( ! (appendAll | ifdInfo.changed) ) continue;
- if ( tagCount == 0 ) continue;
-
- newIFDOffsets[ifd] = ifdInfo.origIFDOffset;
- if ( appendedIFDs[ifd] ) {
- newIFDOffsets[ifd] = appendedOrigin + appendedLength;
- appendedLength += (XMP_Uns32)( 6 + (12 * tagCount) );
- }
-
- InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
- InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
-
- for ( ; tagPos != tagEnd; ++tagPos ) {
-
- InternalTagInfo & currTag ( tagPos->second );
- if ( (! (appendAll | currTag.changed)) || (currTag.dataLen <= 4) ) continue;
-
- if ( (currTag.dataLen <= currTag.origDataLen) && (! appendAll) ) {
- this->PutUns32 ( currTag.origDataOffset, &currTag.smallValue ); // Reuse the old space.
- } else {
- this->PutUns32 ( (appendedOrigin + appendedLength), &currTag.smallValue ); // Set the appended offset.
- appendedLength += ((currTag.dataLen + 1) & 0xFFFFFFFEUL); // Round to an even size.
- }
-
- }
-
- }
-
- // If the Exif, GPS, or Interoperability IFDs get appended, update the tag values for their new offsets.
-
- if ( appendedIFDs[kTIFF_ExifIFD] ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, newIFDOffsets[kTIFF_ExifIFD] );
- }
- if ( appendedIFDs[kTIFF_GPSInfoIFD] ) {
- this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, newIFDOffsets[kTIFF_GPSInfoIFD] );
- }
- if ( appendedIFDs[kTIFF_InteropIFD] ) {
- this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, newIFDOffsets[kTIFF_InteropIFD] );
- }
-
- #if Trace_DetermineAppendInfo
- {
- printf ( "Exiting TIFF_FileWriter::DetermineAppendInfo\n" );
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- printf ( "\n IFD %d, origCount %d, map.size %d, origIFDOffset %d (0x%X), origNextIFD %d (0x%X)",
- ifd, thisIFD.origCount, thisIFD.tagMap.size(),
- thisIFD.origIFDOffset, thisIFD.origIFDOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
- if ( thisIFD.changed ) printf ( ", changed" );
- if ( appendedIFDs[ifd] ) printf ( ", will be appended at %d (0x%X)", newIFDOffsets[ifd], newIFDOffsets[ifd] );
- printf ( "\n" );
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- printf ( " Tag %d, smallValue 0x%X, origDataLen %d, origDataOffset %d (0x%X)",
- thisTag.id, thisTag.smallValue, thisTag.origDataLen, thisTag.origDataOffset, thisTag.origDataOffset );
- if ( thisTag.changed ) printf ( ", changed" );
- if ( (thisTag.dataLen > thisTag.origDataLen) && (thisTag.dataLen > 4) ) {
- XMP_Uns32 newOffset = this->GetUns32 ( &thisTag.smallValue );
- printf ( ", will be appended at %d (0x%X)", newOffset, newOffset );
- }
- printf ( "\n" );
- }
- }
- printf ( "\n" );
- }
- #endif
-
- return appendedLength;
-
-} // TIFF_FileWriter::DetermineAppendInfo
-
-// =================================================================================================
-// TIFF_FileWriter::UpdateMemByAppend
-// ==================================
-//
-// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
-// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
-// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
-// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
-// common feature of proprietary MakerNotes.
-//
-// When doing the update-by-append we're only going to be modifying things that have changed. This
-// means IFDs with changed, added, or deleted tags, and large values for changed or added tags. The
-// IFDs and tag values are updated in-place if they fit, leaving holes in the stream if the new
-// value is smaller than the old.
-
-// ** Someday we might want to use the FreeOffsets and FreeByteCounts tags to track free space.
-// ** Probably not a huge win in practice though, and the TIFF spec says they are not recommended
-// ** for general interchange use.
-
-void TIFF_FileWriter::UpdateMemByAppend ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out,
- bool appendAll /* = false */, XMP_Uns32 extraSpace /* = 0 */ )
-{
- bool appendedIFDs[kTIFF_KnownIFDCount];
- XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount];
- XMP_Uns32 appendedOrigin = ((this->tiffLength + 1) & 0xFFFFFFFEUL); // Start at an even offset.
- XMP_Uns32 appendedLength = DetermineAppendInfo ( appendedOrigin, appendedIFDs, newIFDOffsets, appendAll );
-
- // Allocate the new block of memory for the full stream. Copy the original stream. Write the
- // modified IFDs and values. Finally rebuild the internal IFD info and tag map.
-
- XMP_Uns32 newLength = appendedOrigin + appendedLength;
- XMP_Uns8* newStream = (XMP_Uns8*) malloc ( newLength + extraSpace );
- if ( newStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
-
- memcpy ( newStream, this->memStream, this->tiffLength ); // AUDIT: Safe, malloc'ed newLength bytes above.
- if ( this->tiffLength < appendedOrigin ) {
- XMP_Assert ( appendedOrigin == (this->tiffLength + 1) );
- newStream[this->tiffLength] = 0; // Clear the pad byte.
- }
-
- try { // We might get exceptions from the next part and must delete newStream on the way out.
-
- // Write the modified IFDs and values. Rewrite the full IFD from scratch to make sure the
- // tags are now unique and sorted. Copy large changed values to their appropriate location.
-
- XMP_Uns32 appendedOffset = appendedOrigin;
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
- size_t tagCount = ifdInfo.tagMap.size();
-
- if ( ! (appendAll | ifdInfo.changed) ) continue;
- if ( tagCount == 0 ) continue;
-
- XMP_Uns8* ifdPtr = newStream + newIFDOffsets[ifd];
-
- if ( appendedIFDs[ifd] ) {
- XMP_Assert ( newIFDOffsets[ifd] == appendedOffset );
- appendedOffset += (XMP_Uns32)( 6 + (12 * tagCount) );
- }
-
- this->PutUns16 ( (XMP_Uns16)tagCount, ifdPtr );
- ifdPtr += 2;
-
- InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
- InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
-
- for ( ; tagPos != tagEnd; ++tagPos ) {
-
- InternalTagInfo & currTag ( tagPos->second );
-
- this->PutUns16 ( currTag.id, ifdPtr );
- ifdPtr += 2;
- this->PutUns16 ( currTag.type, ifdPtr );
- ifdPtr += 2;
- this->PutUns32 ( currTag.count, ifdPtr );
- ifdPtr += 4;
-
- *((XMP_Uns32*)ifdPtr) = currTag.smallValue;
-
- if ( (appendAll | currTag.changed) && (currTag.dataLen > 4) ) {
-
- XMP_Uns32 valueOffset = this->GetUns32 ( &currTag.smallValue );
-
- if ( (currTag.dataLen <= currTag.origDataLen) && (! appendAll) ) {
- XMP_Assert ( valueOffset == currTag.origDataOffset );
- } else {
- XMP_Assert ( valueOffset == appendedOffset );
- appendedOffset += ((currTag.dataLen + 1) & 0xFFFFFFFEUL);
- }
-
- if ( currTag.dataLen > (newLength - valueOffset) ) XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
- memcpy ( (newStream + valueOffset), currTag.dataPtr, currTag.dataLen ); // AUDIT: Protected by the above check.
- if ( (currTag.dataLen & 1) != 0 ) newStream[valueOffset+currTag.dataLen] = 0;
-
- }
-
- ifdPtr += 4;
-
- }
-
- this->PutUns32 ( ifdInfo.origNextIFD, ifdPtr );
- ifdPtr += 4;
-
- }
-
- XMP_Assert ( appendedOffset == newLength );
-
- // Back fill the offsets for the primary and thumnbail IFDs, if they are now appended.
-
- if ( appendedIFDs[kTIFF_PrimaryIFD] ) {
- this->PutUns32 ( newIFDOffsets[kTIFF_PrimaryIFD], (newStream + 4) );
- }
-
- } catch ( ... ) {
-
- free ( newStream );
- throw;
-
- }
-
- *newStream_out = newStream;
- *newLength_out = newLength;
-
-} // TIFF_FileWriter::UpdateMemByAppend
-
-// =================================================================================================
-// TIFF_FileWriter::UpdateMemByRewrite
-// ===================================
-//
-// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
-// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
-// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
-// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
-// common feature of proprietary MakerNotes.
-//
-// The condenseStream parameter can be used to rewrite the full stream instead of appending. This
-// will discard any MakerNote tag and risks breaking offsets that are hidden. This can be necessary
-// though to try to make the TIFF fit in a JPEG file.
-//
-// We don't do most of the actual rewrite here. We set things up so that UpdateMemByAppend can be
-// called to append onto a bare TIFF header. Additional hidden offsets are then handled here.
-//
-// These tags are recognized as being hidden offsets when composing a condensed stream:
-// 273 - StripOffsets, lengths in tag 279
-// 288 - FreeOffsets, lengths in tag 289
-// 324 - TileOffsets, lengths in tag 325
-// 330 - SubIFDs, lengths within the IFDs (Plus subIFD values and possible chaining!)
-// 513 - JPEGInterchangeFormat, length in tag 514
-// 519 - JPEGQTables, each table is 64 bytes
-// 520 - JPEGDCTables, lengths ???
-// 521 - JPEGACTables, lengths ???
-// Some of these will handled and kept, some will be thrown out, some will cause the rewrite to fail.
-//
-// The hidden offsets for the Exif, GPS, and Interoperability IFDs (tags 34665, 34853, and 40965)
-// are handled by the code in DetermineAppendInfo, which is called from UpdateMemByAppend, which is
-// called from here.
-
-// ! So far, a memory-based TIFF rewrite would only be done for the Exif portion of a JPEG file.
-// ! In which case we're probably OK to handle JPEGInterchangeFormat (used for compressed thumbnails)
-// ! and complain about any of the other hidden offset tags.
-
-// tag count type
-
-// 273 n short or long
-// 279 n short or long
-// 288 n long
-// 289 n long
-// 324 n long
-// 325 n short or long
-
-// 330 n long
-
-// 513 1 long
-// 514 1 long
-
-// 519 n long
-// 520 n long
-// 521 n long
-
-static XMP_Uns16 kNoGoTags[] =
- {
- kTIFF_StripOffsets, // 273 *** Should be handled?
- kTIFF_StripByteCounts, // 279 *** Should be handled?
- kTIFF_FreeOffsets, // 288 *** Should be handled?
- kTIFF_FreeByteCounts, // 289 *** Should be handled?
- kTIFF_TileOffsets, // 324 *** Should be handled?
- kTIFF_TileByteCounts, // 325 *** Should be handled?
- kTIFF_SubIFDs, // 330 *** Should be handled?
- kTIFF_JPEGQTables, // 519
- kTIFF_JPEGDCTables, // 520
- kTIFF_JPEGACTables, // 521
- 0xFFFF // Must be last as a sentinel.
- };
-
-static XMP_Uns16 kBanishedTags[] =
- {
- kTIFF_MakerNote, // *** Should someday support MakerNoteSafety.
- 0xFFFF // Must be last as a sentinel.
- };
-
-struct SimpleHiddenContentInfo {
- XMP_Uns8 ifd;
- XMP_Uns16 offsetTag, lengthTag;
-};
-
-struct SimpleHiddenContentLocations {
- XMP_Uns32 length, oldOffset, newOffset;
- SimpleHiddenContentLocations() : length(0), oldOffset(0), newOffset(0) {};
-};
-
-enum { kSimpleHiddenContentCount = 1 };
-
-static const SimpleHiddenContentInfo kSimpleHiddenContentInfo [kSimpleHiddenContentCount] =
- {
- { kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat, kTIFF_JPEGInterchangeFormatLength }
- };
-
-// -------------------------------------------------------------------------------------------------
-
-void TIFF_FileWriter::UpdateMemByRewrite ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out )
-{
- const InternalTagInfo* tagInfo;
-
- // Check for tags that we don't tolerate because they have data we can't (or refuse to) find.
-
- for ( XMP_Uns8 ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- for ( int i = 0; kNoGoTags[i] != 0xFFFF; ++i ) {
- tagInfo = this->FindTagInIFD ( ifd, kNoGoTags[i] );
- if ( tagInfo != 0 ) XMP_Throw ( "Tag not tolerated for TIFF rewrite", kXMPErr_Unimplemented );
- }
- }
-
- // Delete unwanted tags.
-
- for ( XMP_Uns8 ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
- for ( int i = 0; kBanishedTags[i] != 0xFFFF; ++i ) {
- this->DeleteTag ( ifd, kBanishedTags[i] );
- }
- }
-
- // Determine the offsets and additional size for the hidden offset content. Set the offset tags
- // to the new offset.
-
- XMP_Uns32 hiddenContentLength = 0;
- XMP_Uns32 hiddenContentOrigin = this->DetermineVisibleLength();
-
- SimpleHiddenContentLocations hiddenLocations [kSimpleHiddenContentCount];
-
- for ( int i = 0; i < kSimpleHiddenContentCount; ++i ) {
-
- const SimpleHiddenContentInfo & hiddenInfo ( kSimpleHiddenContentInfo[i] );
-
- bool haveLength = this->GetTag_Integer ( hiddenInfo.ifd, hiddenInfo.lengthTag, &hiddenLocations[i].length );
- bool haveOffset = this->GetTag_Integer ( hiddenInfo.ifd, hiddenInfo.offsetTag, &hiddenLocations[i].oldOffset );
- if ( haveLength != haveOffset ) XMP_Throw ( "Unpaired simple hidden content tag", kXMPErr_BadTIFF );
- if ( (! haveLength) || (hiddenLocations[i].length == 0) ) continue;
-
- hiddenLocations[i].newOffset = hiddenContentOrigin + hiddenContentLength;
- this->SetTag_Long ( hiddenInfo.ifd, hiddenInfo.offsetTag, hiddenLocations[i].newOffset );
- hiddenContentLength += ((hiddenLocations[i].length + 1) & 0xFFFFFFFE); // ! Round up for even offsets.
-
- }
-
- // Save any old memory stream for the content behind hidden offsets. Setup a bare TIFF header.
-
- XMP_Uns8* oldStream = this->memStream;
-
- XMP_Uns8 bareTIFF [8];
- if ( this->bigEndian ) {
- bareTIFF[0] = 0x4D; bareTIFF[1] = 0x4D; bareTIFF[2] = 0x00; bareTIFF[3] = 0x2A;
- } else {
- bareTIFF[0] = 0x49; bareTIFF[1] = 0x49; bareTIFF[2] = 0x2A; bareTIFF[3] = 0x00;
- }
- *((XMP_Uns32*)&bareTIFF[4]) = 0;
-
- this->memStream = &bareTIFF[0];
- this->tiffLength = sizeof ( bareTIFF );
- this->ownedStream = false;
-
- // Call UpdateMemByAppend to write the new stream, telling it to append everything.
-
- this->UpdateMemByAppend ( newStream_out, newLength_out, true, hiddenContentLength );
-
- // Copy the hidden content and update the output stream length;
-
- XMP_Assert ( *newLength_out == hiddenContentOrigin );
- *newLength_out += hiddenContentLength;
-
- for ( int i = 0; i < kSimpleHiddenContentCount; ++i ) {
-
- if ( hiddenLocations[i].length == 0 ) continue;
-
- XMP_Uns8* srcPtr = oldStream + hiddenLocations[i].oldOffset;
- XMP_Uns8* destPtr = *newStream_out + hiddenLocations[i].newOffset;
- memcpy ( destPtr, srcPtr, hiddenLocations[i].length ); // AUDIT: Safe copy, not user data, computed length.
-
- }
-
-} // TIFF_FileWriter::UpdateMemByRewrite
-
-// =================================================================================================
-// TIFF_FileWriter::UpdateMemoryStream
-// ===================================
-//
-// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
-// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
-// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
-// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
-// common feature of proprietary MakerNotes.
-//
-// The condenseStream parameter can be used to rewrite the full stream instead of appending. This
-// will discard any MakerNote tags and risks breaking offsets that are hidden. This can be necessary
-// though to try to make the TIFF fit in a JPEG file.
-
-XMP_Uns32 TIFF_FileWriter::UpdateMemoryStream ( void** dataPtr, bool condenseStream /* = false */ )
-{
- if ( this->fileParsed ) XMP_Throw ( "Not memory based", kXMPErr_EnforceFailure );
-
- if ( ! this->changed ) {
- if ( dataPtr != 0 ) *dataPtr = this->memStream;
- return this->tiffLength;
- }
-
- this->PreflightIFDLinkage();
-
- bool nowEmpty = true;
- for ( size_t i = 0; i < kTIFF_KnownIFDCount; ++i ) {
- if ( ! this->containedIFDs[i].tagMap.empty() ) {
- nowEmpty = false;
- break;
- }
- }
-
- XMP_Uns8* newStream = 0;
- XMP_Uns32 newLength = 0;
-
- if ( nowEmpty ) {
-
- this->DeleteExistingInfo(); // Prepare for an empty reparse.
-
- } else {
-
- if ( this->tiffLength == 0 ) { // ! An empty parse does set this->memParsed.
- condenseStream = true; // Makes "conjured" TIFF take the full rewrite path.
- }
-
- if ( condenseStream ) this->changed = true; // A prior regular call would have cleared this->changed.
-
- if ( condenseStream ) {
- this->UpdateMemByRewrite ( &newStream, &newLength );
- } else {
- this->UpdateMemByAppend ( &newStream, &newLength );
- }
-
- }
-
- // Parse the revised stream. This is the cleanest way to rebuild the tag map.
-
- this->ParseMemoryStream ( newStream, newLength, kDoNotCopyData );
- XMP_Assert ( this->tiffLength == newLength );
- this->ownedStream = (newLength > 0); // ! We really do own the new stream, if not empty.
-
- if ( dataPtr != 0 ) *dataPtr = this->memStream;
- return newLength;
-
-} // TIFF_FileWriter::UpdateMemoryStream
-
-// =================================================================================================
-// TIFF_FileWriter::UpdateFileStream
-// =================================
-//
-// Updating a file stream is done in the same general manner as updating a memory stream, the intro
-// comments for UpdateMemoryStream largely apply. The file update happens in 3 phases:
-// 1. Determine which IFDs will be appended, and the new offsets for the appended IFDs and tags.
-// 2. Do the in-place update for the IFDs and tag values that fit.
-// 3. Append the IFDs and tag values that grow.
-//
-// The file being updated must match the file that was previously parsed. Offsets and lengths saved
-// when parsing are used to decide if something can be updated in-place or must be appended.
-
-// *** The general linked structure of TIFF makes it very difficult to process the file in a single
-// *** sequential pass. This implementation uses a simple seek/write model for the in-place updates.
-// *** In the future we might want to consider creating a map of what gets updated, allowing use of
-// *** a possibly more efficient buffered model.
-
-// ** Someday we might want to use the FreeOffsets and FreeByteCounts tags to track free space.
-// ** Probably not a huge win in practice though, and the TIFF spec says they are not recommended
-// ** for general interchange use.
-
-#ifndef Trace_UpdateFileStream
- #define Trace_UpdateFileStream 0
-#endif
-
-void TIFF_FileWriter::UpdateFileStream ( LFA_FileRef fileRef )
-{
- if ( this->memParsed ) XMP_Throw ( "Not file based", kXMPErr_EnforceFailure );
- if ( ! this->changed ) return;
-
- XMP_Int64 origDataLength = LFA_Measure ( fileRef );
- if ( (origDataLength >> 32) != 0 ) XMP_Throw ( "TIFF files can't exceed 4GB", kXMPErr_BadTIFF );
-
- bool appendedIFDs[kTIFF_KnownIFDCount];
- XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount];
-
- #if Trace_UpdateFileStream
- printf ( "\nStarting update of TIFF file stream\n" );
- #endif
-
- XMP_Uns32 appendedOrigin = (XMP_Uns32)origDataLength;
- if ( (appendedOrigin & 1) != 0 ) {
- ++appendedOrigin; // Start at an even offset.
- LFA_Seek ( fileRef, 0, SEEK_END );
- LFA_Write ( fileRef, "\0", 1 );
- }
-
- this->PreflightIFDLinkage();
-
- XMP_Uns32 appendedLength = DetermineAppendInfo ( appendedOrigin, appendedIFDs, newIFDOffsets );
- if ( appendedLength > (0xFFFFFFFFUL - appendedOrigin) ) XMP_Throw ( "TIFF files can't exceed 4GB", kXMPErr_BadTIFF );
-
- // Do the in-place update for the IFDs and tag values that fit. This part does separate seeks
- // and writes for the IFDs and values. Things to be updated can be anywhere in the file.
-
- // *** This might benefit from a map of the in-place updates. This would allow use of a possibly
- // *** more efficient sequential I/O model. Could even incorporate the safe update file copying.
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- if ( ! thisIFD.changed ) continue;
-
- // In order to get a little bit of locality, write the IFD first then the changed tags that
- // have large values and fit in-place.
-
- if ( ! appendedIFDs[ifd] ) {
- #if Trace_UpdateFileStream
- printf ( " Updating IFD %d in-place at offset %d (0x%X)\n", ifd, thisIFD.origIFDOffset, thisIFD.origIFDOffset );
- #endif
- LFA_Seek ( fileRef, thisIFD.origIFDOffset, SEEK_SET );
- this->WriteFileIFD ( fileRef, thisIFD );
- }
-
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
-
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- if ( (! thisTag.changed) || (thisTag.dataLen <= 4) || (thisTag.dataLen > thisTag.origDataLen) ) continue;
- #if Trace_UpdateFileStream
- printf ( " Updating tag %d in IFD %d in-place at offset %d (0x%X)\n", thisTag.id, ifd, thisTag.origDataOffset, thisTag.origDataOffset );
- #endif
- LFA_Seek ( fileRef, thisTag.origDataOffset, SEEK_SET );
- LFA_Write ( fileRef, thisTag.dataPtr, thisTag.dataLen );
- }
-
- }
-
- // Append the IFDs and tag values that grow.
-
- XMP_Int64 fileEnd = LFA_Seek ( fileRef, 0, SEEK_END );
- XMP_Assert ( fileEnd == appendedOrigin );
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- if ( ! thisIFD.changed ) continue;
-
- if ( appendedIFDs[ifd] ) {
- #if Trace_UpdateFileStream
- printf ( " Updating IFD %d by append at offset %d (0x%X)\n", ifd, newIFDOffsets[ifd], newIFDOffsets[ifd] );
- #endif
- XMP_Assert ( newIFDOffsets[ifd] == LFA_Measure(fileRef) );
- this->WriteFileIFD ( fileRef, thisIFD );
- }
-
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
-
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- if ( (! thisTag.changed) || (thisTag.dataLen <= 4) || (thisTag.dataLen <= thisTag.origDataLen) ) continue;
- #if Trace_UpdateFileStream
- XMP_Uns32 newOffset = this->GetUns32(&thisTag.origDataOffset);
- printf ( " Updating tag %d in IFD %d by append at offset %d (0x%X)\n", thisTag.id, ifd, newOffset, newOffset );
- #endif
- XMP_Assert ( this->GetUns32(&thisTag.smallValue) == LFA_Measure(fileRef) );
- LFA_Write ( fileRef, thisTag.dataPtr, thisTag.dataLen );
- if ( (thisTag.dataLen & 1) != 0 ) LFA_Write ( fileRef, "\0", 1 );
- }
-
- }
-
- // Back-fill the offset for the primary IFD, if it is now appended.
-
- XMP_Uns32 newOffset;
-
- if ( appendedIFDs[kTIFF_PrimaryIFD] ) {
- this->PutUns32 ( newIFDOffsets[kTIFF_PrimaryIFD], &newOffset );
- #if TraceUpdateFileStream
- printf ( " Back-filling offset of primary IFD, pointing to %d (0x%X)\n", newOffset, newOffset );
- #endif
- LFA_Seek ( fileRef, 4, SEEK_SET );
- LFA_Write ( fileRef, &newOffset, 4 );
- }
-
- // Reset the changed flags and original length/offset values. This simulates a reparse of the
- // updated file.
-
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
-
- InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
- if ( ! thisIFD.changed ) continue;
-
- thisIFD.changed = false;
- thisIFD.origCount = (XMP_Uns16)( thisIFD.tagMap.size() );
- thisIFD.origIFDOffset = newIFDOffsets[ifd];
-
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
-
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
- InternalTagInfo & thisTag = tagPos->second;
- if ( ! thisTag.changed ) continue;
- thisTag.changed = false;
- thisTag.origDataLen = thisTag.dataLen;
- if ( thisTag.origDataLen > 4 ) thisTag.origDataOffset = this->GetUns32 ( &thisTag.smallValue );
- }
-
- }
-
- this->tiffLength = (XMP_Uns32) LFA_Measure ( fileRef );
- LFA_Seek ( fileRef, 0, SEEK_END ); // Can't hurt.
-
- #if Trace_UpdateFileStream
- printf ( "\nFinished update of TIFF file stream\n" );
- #endif
-
-} // TIFF_FileWriter::UpdateFileStream
-
-// =================================================================================================
-// TIFF_FileWriter::WriteFileIFD
-// =============================
-
-void TIFF_FileWriter::WriteFileIFD ( LFA_FileRef fileRef, InternalIFDInfo & thisIFD )
-{
- XMP_Uns16 tagCount;
- this->PutUns16 ( (XMP_Uns16)thisIFD.tagMap.size(), &tagCount );
- LFA_Write ( fileRef, &tagCount, 2 );
-
- InternalTagMap::iterator tagPos;
- InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
-
- for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
-
- InternalTagInfo & thisTag = tagPos->second;
- RawIFDEntry ifdEntry;
-
- this->PutUns16 ( thisTag.id, &ifdEntry.id );
- this->PutUns16 ( thisTag.type, &ifdEntry.type );
- this->PutUns32 ( thisTag.count, &ifdEntry.count );
- ifdEntry.dataOrOffset = thisTag.smallValue; // ! Already in stream endianness.
-
- LFA_Write ( fileRef, &ifdEntry, sizeof(ifdEntry) );
- XMP_Assert ( sizeof(ifdEntry) == 12 );
-
- }
-
- XMP_Uns32 nextIFD;
- this->PutUns32 ( thisIFD.origNextIFD, &nextIFD );
- LFA_Write ( fileRef, &nextIFD, 4 );
-
-} // TIFF_FileWriter::WriteFileIFD
diff --git a/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp b/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp
deleted file mode 100644
index 316cea0..0000000
--- a/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp
+++ /dev/null
@@ -1,592 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Support.hpp"
-
-// =================================================================================================
-/// \file TIFF_MemoryReader.cpp
-/// \brief Implementation of the memory-based read-only TIFF_Manager.
-///
-/// The read-only forms of TIFF_Manager are derived from TIFF_Reader. The GetTag methods are common
-/// implementations in TIFF_Reader. The parsing code is different in the TIFF_MemoryReader and
-/// TIFF_FileReader constructors. There are also separate destructors to release captured info.
-///
-/// The read-only implementations use runtime data that is simple tweaks on the stored form. The
-/// memory-based reader has one block of data for the whole TIFF stream. The file-based reader has
-/// one for each IFD, plus one for the collected non-local data for each IFD. Otherwise the logic
-/// is the same in both cases.
-///
-/// The count for each IFD is extracted and a pointer set to the first entry in each IFD (serving as
-/// a normal C array pointer). The IFD entries are tweaked as follows:
-///
-/// \li The id and type fields are converted to native values.
-/// \li The count field is converted to a native byte count.
-/// \li If the data is not inline the offset is converted to a pointer.
-///
-/// The tag values, whether inline or not, are not converted to native values. The values returned
-/// from the GetTag methods are converted on the fly. The id, type, and count fields are easier to
-/// convert because their types are fixed. They are used more, and more valuable to convert.
-// =================================================================================================
-
-// =================================================================================================
-// TIFF_MemoryReader::SortIFD
-// ==========================
-//
-// Does a fairly simple minded insertion-like sort. This sort is not going to be optimal for edge
-// cases like and IFD with lots of duplicates.
-
-// *** Might be better done using read and write pointers and two loops. The first loop moves out
-// *** of order tags by a modified bubble sort, shifting the middle down one at a time in the loop.
-// *** The first loop stops when a duplicate is hit. The second loop continues by moving the tail
-// *** entries up to the appropriate slot.
-
-void TIFF_MemoryReader::SortIFD ( TweakedIFDInfo* thisIFD )
-{
-
- XMP_Uns16 tagCount = thisIFD->count;
- TweakedIFDEntry* ifdEntries = thisIFD->entries;
- XMP_Uns16 prevTag = ifdEntries[0].id;
-
- for ( size_t i = 1; i < tagCount; ++i ) {
-
- XMP_Uns16 thisTag = ifdEntries[i].id;
-
- if ( thisTag > prevTag ) {
-
- // In proper order.
- prevTag = thisTag;
-
- } else if ( thisTag == prevTag ) {
-
- // Duplicate tag, keep the 2nd copy, move the tail of the array up, prevTag is unchanged.
- memcpy ( &ifdEntries[i-1], &ifdEntries[i], 12*(tagCount-i) ); // AUDIT: Safe, moving tail forward, i >= 1.
- --tagCount;
- --i; // ! Don't move forward in the array, we've moved the unseen part up.
-
- } else if ( thisTag < prevTag ) {
-
- // Out of order, move this tag up, prevTag is unchanged. Might still be a duplicate!
- XMP_Int32 j; // ! Need a signed value.
- for ( j = (XMP_Int32)i-1; j >= 0; --j ) {
- if ( ifdEntries[j].id <= thisTag ) break;
- }
-
- if ( (j >= 0) && (ifdEntries[j].id == thisTag) ) {
-
- // Out of order duplicate, move it to position j, move the tail of the array up.
- ifdEntries[j] = ifdEntries[i];
- memcpy ( &ifdEntries[i], &ifdEntries[i+1], 12*(tagCount-(i+1)) ); // AUDIT: Safe, moving tail forward, i >= 1.
- --tagCount;
- --i; // ! Don't move forward in the array, we've moved the unseen part up.
-
- } else {
-
- // Move the out of order entry to position j+1, move the middle of the array down.
- 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.
- ifdEntries[j] = temp;
-
- }
-
- }
-
- }
-
- thisIFD->count = tagCount; // Save the final count.
-
-} // TIFF_MemoryReader::SortIFD
-
-// =================================================================================================
-// TIFF_MemoryReader::GetIFD
-// =========================
-
-bool TIFF_MemoryReader::GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const
-{
- if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
- const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];
-
- if ( ifdMap != 0 ) ifdMap->clear();
- if ( thisIFD->count == 0 ) return false;
-
- if ( ifdMap != 0 ) {
-
- for ( size_t i = 0; i < thisIFD->count; ++i ) {
-
- TweakedIFDEntry* thisTag = &(thisIFD->entries[i]);
- if ( (thisTag->type < kTIFF_ByteType) || (thisTag->type > kTIFF_LastType) ) continue; // Bad type, skip this tag.
-
- TagInfo info ( thisTag->id, thisTag->type, 0, 0, thisTag->bytes );
- info.count = info.dataLen / (XMP_Uns32)kTIFF_TypeSizes[info.type];
- info.dataPtr = this->GetDataPtr ( thisTag );
-
- (*ifdMap)[info.id] = info;
-
- }
-
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetIFD
-
-// =================================================================================================
-// TIFF_MemoryReader::FindTagInIFD
-// ===============================
-
-const TIFF_MemoryReader::TweakedIFDEntry* TIFF_MemoryReader::FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const
-{
- if ( ifd == kTIFF_KnownIFD ) {
- // ... lookup the tag in the known tag map
- }
-
- if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
- const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];
-
- if ( thisIFD->count == 0 ) return 0;
-
- XMP_Uns32 spanLength = thisIFD->count;
- const TweakedIFDEntry* spanBegin = &(thisIFD->entries[0]);
-
- while ( spanLength > 1 ) {
-
- XMP_Uns32 halfLength = spanLength >> 1; // Since spanLength > 1, halfLength > 0.
- const TweakedIFDEntry* spanMiddle = spanBegin + halfLength;
-
- // There are halfLength entries below spanMiddle, then the spanMiddle entry, then
- // spanLength-halfLength-1 entries above spanMiddle (which can be none).
-
- if ( spanMiddle->id == id ) {
- spanBegin = spanMiddle;
- break;
- } else if ( spanMiddle->id > id ) {
- spanLength = halfLength; // Discard the middle.
- } else {
- spanBegin = spanMiddle; // Keep a valid spanBegin for the return check, don't use spanMiddle+1.
- spanLength -= halfLength;
- }
-
- }
-
- if ( spanBegin->id != id ) spanBegin = 0;
- return spanBegin;
-
-} // TIFF_MemoryReader::FindTagInIFD
-
-// =================================================================================================
-// TIFF_MemoryReader::GetValueOffset
-// =================================
-
-XMP_Uns32 TIFF_MemoryReader::GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return 0;
-
- XMP_Uns8 * valuePtr = (XMP_Uns8*) this->GetDataPtr ( thisTag );
-
- return (XMP_Uns32)(valuePtr - this->tiffStream); // ! TIFF streams can't exceed 4GB.
-
-} // TIFF_MemoryReader::GetValueOffset
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag
-// =========================
-
-bool TIFF_MemoryReader::GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type < kTIFF_ByteType) || (thisTag->type > kTIFF_LastType) ) return false; // Bad type, skip this tag.
-
- if ( info != 0 ) {
-
- info->id = thisTag->id;
- info->type = thisTag->type;
- info->count = thisTag->bytes / (XMP_Uns32)kTIFF_TypeSizes[thisTag->type];
- info->dataLen = thisTag->bytes;
-
- info->dataPtr = this->GetDataPtr ( thisTag );
-
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Integer
-// =================================
-
-bool TIFF_MemoryReader::GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
-
- if ( data != 0 ) {
- if ( thisTag->type == kTIFF_ShortType ) {
- if ( thisTag->bytes != 2 ) return false; // Wrong count.
- *data = this->GetUns16 ( this->GetDataPtr ( thisTag ) );
- } else if ( thisTag->type == kTIFF_LongType ) {
- if ( thisTag->bytes != 4 ) return false; // Wrong count.
- *data = this->GetUns32 ( this->GetDataPtr ( thisTag ) );
- } else {
- return false;
- }
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Integer
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Byte
-// ==============================
-
-bool TIFF_MemoryReader::GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_ByteType) || (thisTag->bytes != 1) ) return false;
-
- if ( data != 0 ) {
- *data = * ( (XMP_Uns8*) this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Byte
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_SByte
-// ===============================
-
-bool TIFF_MemoryReader::GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SByteType) || (thisTag->bytes != 1) ) return false;
-
- if ( data != 0 ) {
- *data = * ( (XMP_Int8*) this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_SByte
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Short
-// ===============================
-
-bool TIFF_MemoryReader::GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_ShortType) || (thisTag->bytes != 2) ) return false;
-
- if ( data != 0 ) {
- *data = this->GetUns16 ( this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Short
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_SShort
-// ================================
-
-bool TIFF_MemoryReader::GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SShortType) || (thisTag->bytes != 2) ) return false;
-
- if ( data != 0 ) {
- *data = (XMP_Int16) this->GetUns16 ( this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_SShort
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Long
-// ==============================
-
-bool TIFF_MemoryReader::GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_LongType) || (thisTag->bytes != 4) ) return false;
-
- if ( data != 0 ) {
- *data = this->GetUns32 ( this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Long
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_SLong
-// ===============================
-
-bool TIFF_MemoryReader::GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SLongType) || (thisTag->bytes != 4) ) return false;
-
- if ( data != 0 ) {
- *data = (XMP_Int32) this->GetUns32 ( this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_SLong
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Rational
-// ==================================
-
-bool TIFF_MemoryReader::GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_RationalType) || (thisTag->bytes != 8) ) return false;
-
- if ( data != 0 ) {
- XMP_Uns32* dataPtr = (XMP_Uns32*) this->GetDataPtr ( thisTag );
- data->num = this->GetUns32 ( dataPtr );
- data->denom = this->GetUns32 ( dataPtr+1 );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Rational
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_SRational
-// ===================================
-
-bool TIFF_MemoryReader::GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_SRationalType) || (thisTag->bytes != 8) ) return false;
-
- if ( data != 0 ) {
- XMP_Uns32* dataPtr = (XMP_Uns32*) this->GetDataPtr ( thisTag );
- data->num = (XMP_Int32) this->GetUns32 ( dataPtr );
- data->denom = (XMP_Int32) this->GetUns32 ( dataPtr+1 );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_SRational
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Float
-// ===============================
-
-bool TIFF_MemoryReader::GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_FloatType) || (thisTag->bytes != 4) ) return false;
-
- if ( data != 0 ) {
- *data = this->GetFloat ( this->GetDataPtr ( thisTag ) );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Float
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_Double
-// ================================
-
-bool TIFF_MemoryReader::GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( (thisTag->type != kTIFF_DoubleType) || (thisTag->bytes != 8) ) return false;
-
- if ( data != 0 ) {
- double* dataPtr = (double*) this->GetDataPtr ( thisTag );
- *data = this->GetDouble ( dataPtr );
- }
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_Double
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_ASCII
-// ===============================
-
-bool TIFF_MemoryReader::GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( thisTag->type != kTIFF_ASCIIType ) return false;
-
- if ( dataPtr != 0 ) {
- *dataPtr = (XMP_StringPtr) this->GetDataPtr ( thisTag );
- }
-
- if ( dataLen != 0 ) *dataLen = thisTag->bytes;
-
- return true;
-
-} // TIFF_MemoryReader::GetTag_ASCII
-
-// =================================================================================================
-// TIFF_MemoryReader::GetTag_EncodedString
-// =======================================
-
-bool TIFF_MemoryReader::GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const
-{
- const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
- if ( thisTag == 0 ) return false;
- if ( thisTag->type != kTIFF_UndefinedType ) return false;
-
- if ( utf8Str == 0 ) return true; // Return true if the converted string is not wanted.
-
- bool ok = this->DecodeString ( this->GetDataPtr ( thisTag ), thisTag->bytes, utf8Str );
- return ok;
-
-} // TIFF_MemoryReader::GetTag_EncodedString
-
-// =================================================================================================
-// TIFF_MemoryReader::ParseMemoryStream
-// ====================================
-
-// *** Need to tell TIFF/Exif from TIFF/EP, DNG files are the latter.
-
-void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
-{
- // Get rid of any current TIFF.
-
- if ( this->ownedStream ) free ( this->tiffStream );
- this->ownedStream = false;
- this->tiffStream = 0;
- this->tiffLength = 0;
-
- for ( size_t i = 0; i < kTIFF_KnownIFDCount; ++i ) {
- this->containedIFDs[i].count = 0;
- this->containedIFDs[i].entries = 0;
- }
-
- if ( length == 0 ) return;
-
- // Allocate space for the full in-memory stream and copy it.
-
- if ( ! copyData ) {
- XMP_Assert ( ! this->ownedStream );
- this->tiffStream = (XMP_Uns8*) data;
- } else {
- if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based TIFF", kXMPErr_BadTIFF );
- this->tiffStream = (XMP_Uns8*) malloc(length);
- if ( this->tiffStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
- memcpy ( this->tiffStream, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
- this->ownedStream = true;
- }
-
- this->tiffLength = length;
-
- // Find and process the primary, Exif, GPS, and Interoperability IFDs.
-
- XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->tiffStream, length );
- XMP_Uns32 tnailIFDOffset = 0;
-
- if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
-
- // ! Need the thumbnail IFD for checking full Exif APP1 in some JPEG files!
- if ( tnailIFDOffset != 0 ) (void) this->ProcessOneIFD ( tnailIFDOffset, kTIFF_TNailIFD );
-
- const TweakedIFDEntry* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
- if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->bytes == 4) ) {
- XMP_Uns32 exifOffset = this->GetUns32 ( &exifIFDTag->dataOrPos );
- (void) this->ProcessOneIFD ( exifOffset, kTIFF_ExifIFD );
- }
-
- const TweakedIFDEntry* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
- if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->bytes == 4) ) {
- XMP_Uns32 gpsOffset = this->GetUns32 ( &gpsIFDTag->dataOrPos );
- (void) this->ProcessOneIFD ( gpsOffset, kTIFF_GPSInfoIFD );
- }
-
- const TweakedIFDEntry* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
- if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->bytes == 4) ) {
- XMP_Uns32 interopOffset = this->GetUns32 ( &interopIFDTag->dataOrPos );
- (void) this->ProcessOneIFD ( interopOffset, kTIFF_InteropIFD );
- }
-
-} // TIFF_MemoryReader::ParseMemoryStream
-
-// =================================================================================================
-// TIFF_MemoryReader::ProcessOneIFD
-// ================================
-
-XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
-{
- TweakedIFDInfo& ifdInfo = this->containedIFDs[ifd];
-
- if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
- XMP_Throw ( "Bad IFD offset", kXMPErr_BadTIFF );
- }
-
- XMP_Uns8* ifdPtr = this->tiffStream + ifdOffset;
- XMP_Uns16 ifdCount = this->GetUns16 ( ifdPtr );
- TweakedIFDEntry* ifdEntries = (TweakedIFDEntry*)(ifdPtr+2);
-
- if ( ifdCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
- if ( (ifdOffset + 2 + ifdCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
-
- ifdInfo.count = ifdCount;
- ifdInfo.entries = ifdEntries;
-
- XMP_Int32 prevTag = -1; // ! The GPS IFD has a tag 0, so we need a signed initial value.
- bool needsSorting = false;
- for ( size_t i = 0; i < ifdCount; ++i ) {
-
- TweakedIFDEntry* thisEntry = &ifdEntries[i]; // Tweak the IFD entry to be more useful.
-
- if ( ! this->nativeEndian ) {
- Flip2 ( &thisEntry->id );
- Flip2 ( &thisEntry->type );
- Flip4 ( &thisEntry->bytes );
- }
-
- if ( thisEntry->id <= prevTag ) needsSorting = true;
- prevTag = thisEntry->id;
-
- if ( (thisEntry->type < kTIFF_ByteType) || (thisEntry->type > kTIFF_LastType) ) continue; // Bad type, skip this tag.
-
- thisEntry->bytes *= (XMP_Uns32)kTIFF_TypeSizes[thisEntry->type];
- if ( thisEntry->bytes > this->tiffLength ) XMP_Throw ( "Bad TIFF data size", kXMPErr_BadTIFF );
- if ( thisEntry->bytes > 4 ) {
- if ( ! this->nativeEndian ) Flip4 ( &thisEntry->dataOrPos );
- }
-
- }
-
- ifdPtr += (2 + ifdCount*12);
- XMP_Uns32 nextIFDOffset = this->GetUns32 ( ifdPtr );
-
- if ( needsSorting ) SortIFD ( &ifdInfo ); // ! Don't perturb the ifdCount used to find the next IFD offset.
-
- return nextIFDOffset;
-
-} // TIFF_MemoryReader::ProcessOneIFD
-
-// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/TIFF_Support.cpp b/source/XMPFiles/FormatSupport/TIFF_Support.cpp
deleted file mode 100644
index 87a96c9..0000000
--- a/source/XMPFiles/FormatSupport/TIFF_Support.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 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 "TIFF_Support.hpp"
-#include "EndianUtils.hpp"
-
-#include "UnicodeConversions.hpp"
-
-// =================================================================================================
-/// \file TIFF_Support.cpp
-/// \brief Manager for parsing and serializing TIFF streams.
-///
-// =================================================================================================
-
-// =================================================================================================
-// TIFF_Manager::TIFF_Manager
-// ==========================
-
-static bool sFirstCTor = true;
-
-TIFF_Manager::TIFF_Manager()
- : bigEndian(false), nativeEndian(false),
- GetUns16(0), GetUns32(0), GetFloat(0), GetDouble(0),
- PutUns16(0), PutUns32(0), PutFloat(0), PutDouble(0)
-{
-
- if ( sFirstCTor ) {
- sFirstCTor = false;
- #if XMP_DebugBuild
- for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) { // Make sure the known tag arrays are sorted.
- for ( const XMP_Uns16* idPtr = sKnownTags[ifd]; *idPtr != 0xFFFF; ++idPtr ) {
- XMP_Assert ( *idPtr < *(idPtr+1) );
- }
- }
- #endif
- }
-
-} // TIFF_Manager::TIFF_Manager
-
-// =================================================================================================
-// TIFF_Manager::CheckTIFFHeader
-// =============================
-//
-// Checks the 4 byte TIFF prefix for validity and endianness. Sets the endian flags and the Get
-// function pointers. Returns the 0th IFD offset.
-
-XMP_Uns32 TIFF_Manager::CheckTIFFHeader ( const XMP_Uns8* tiffPtr, XMP_Uns32 length )
-{
- if ( length < kEmptyTIFFLength ) XMP_Throw ( "The TIFF is too small", kXMPErr_BadTIFF );
-
- XMP_Uns32 tiffPrefix = (tiffPtr[0] << 24) | (tiffPtr[1] << 16) | (tiffPtr[2] << 8) | (tiffPtr[3]);
-
- if ( tiffPrefix == kBigEndianPrefix ) {
- this->bigEndian = true;
- } else if ( tiffPrefix == kLittleEndianPrefix ) {
- this->bigEndian = false;
- } else {
- XMP_Throw ( "Unrecognized TIFF prefix", kXMPErr_BadTIFF );
- }
-
- this->nativeEndian = (this->bigEndian == kBigEndianHost);
-
- if ( this->bigEndian ) {
-
- this->GetUns16 = GetUns16BE;
- this->GetUns32 = GetUns32BE;
- this->GetFloat = GetFloatBE;
- this->GetDouble = GetDoubleBE;
-
- this->PutUns16 = PutUns16BE;
- this->PutUns32 = PutUns32BE;
- this->PutFloat = PutFloatBE;
- this->PutDouble = PutDoubleBE;
-
- } else {
-
- this->GetUns16 = GetUns16LE;
- this->GetUns32 = GetUns32LE;
- this->GetFloat = GetFloatLE;
- this->GetDouble = GetDoubleLE;
-
- this->PutUns16 = PutUns16LE;
- this->PutUns32 = PutUns32LE;
- this->PutFloat = PutFloatLE;
- this->PutDouble = PutDoubleLE;
-
- }
-
- XMP_Uns32 mainIFDOffset = this->GetUns32 ( tiffPtr+4 ); // ! Do this after setting the Get/Put procs!
-
- if ( mainIFDOffset != 0 ) { // Tolerate empty TIFF even though formally invalid.
- if ( (length < (kEmptyTIFFLength + kEmptyIFDLength)) ||
- (mainIFDOffset < kEmptyTIFFLength) || (mainIFDOffset > (length - kEmptyIFDLength)) ) {
- XMP_Throw ( "Invalid primary IFD offset", kXMPErr_BadTIFF );
- }
- }
-
- return mainIFDOffset;
-
-} // TIFF_Manager::CheckTIFFHeader
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Integer
-// ============================
-
-void TIFF_Manager::SetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data32 )
-{
-
- if ( data32 > 0xFFFF ) {
- this->SetTag ( ifd, id, kTIFF_LongType, 1, &data32 );
- } else {
- XMP_Uns16 data16 = (XMP_Uns16)data32;
- this->SetTag ( ifd, id, kTIFF_ShortType, 1, &data16 );
- }
-
-} // TIFF_Manager::SetTag_Integer
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Byte
-// =========================
-
-void TIFF_Manager::SetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8 data )
-{
-
- this->SetTag ( ifd, id, kTIFF_ByteType, 1, &data );
-
-} // TIFF_Manager::SetTag_Byte
-
-// =================================================================================================
-// TIFF_Manager::SetTag_SByte
-// ==========================
-
-void TIFF_Manager::SetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8 data )
-{
-
- this->SetTag ( ifd, id, kTIFF_SByteType, 1, &data );
-
-} // TIFF_Manager::SetTag_SByte
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Short
-// ==========================
-
-void TIFF_Manager::SetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 clientData )
-{
- XMP_Uns16 streamData;
-
- this->PutUns16 ( clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_ShortType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_Short
-
-// =================================================================================================
-// TIFF_Manager::SetTag_SShort
-// ===========================
-
- void TIFF_Manager::SetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16 clientData )
-{
- XMP_Int16 streamData;
-
- this->PutUns16 ( (XMP_Uns16)clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_SShortType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_SShort
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Long
-// =========================
-
- void TIFF_Manager::SetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 clientData )
-{
- XMP_Uns32 streamData;
-
- this->PutUns32 ( clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_LongType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_Long
-
-// =================================================================================================
-// TIFF_Manager::SetTag_SLong
-// ==========================
-
- void TIFF_Manager::SetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 clientData )
-{
- XMP_Int32 streamData;
-
- this->PutUns32 ( (XMP_Uns32)clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_SLongType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_SLong
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Rational
-// =============================
-
-struct StreamRational { XMP_Uns32 num, denom; };
-
- void TIFF_Manager::SetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 clientNum, XMP_Uns32 clientDenom )
-{
- StreamRational streamData;
-
- this->PutUns32 ( clientNum, &streamData.num );
- this->PutUns32 ( clientDenom, &streamData.denom );
- this->SetTag ( ifd, id, kTIFF_RationalType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_Rational
-
-// =================================================================================================
-// TIFF_Manager::SetTag_SRational
-// ==============================
-
- void TIFF_Manager::SetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 clientNum, XMP_Int32 clientDenom )
-{
- StreamRational streamData;
-
- this->PutUns32 ( (XMP_Uns32)clientNum, &streamData.num );
- this->PutUns32 ( (XMP_Uns32)clientDenom, &streamData.denom );
- this->SetTag ( ifd, id, kTIFF_SRationalType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_SRational
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Float
-// ==========================
-
- void TIFF_Manager::SetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float clientData )
-{
- float streamData;
-
- this->PutFloat ( clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_FloatType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_Float
-
-// =================================================================================================
-// TIFF_Manager::SetTag_Double
-// ===========================
-
- void TIFF_Manager::SetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double clientData )
-{
- double streamData;
-
- this->PutDouble ( clientData, &streamData );
- this->SetTag ( ifd, id, kTIFF_DoubleType, 1, &streamData );
-
-} // TIFF_Manager::SetTag_Double
-
-// =================================================================================================
-// TIFF_Manager::SetTag_ASCII
-// ===========================
-
-void TIFF_Manager::SetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr data )
-{
-
- this->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)(strlen(data) + 1), data ); // ! Include trailing nul.
-
-} // TIFF_Manager::SetTag_ASCII
-
-// =================================================================================================
-// UTF16_to_UTF8
-// =============
-
-static void UTF16_to_UTF8 ( const UTF16Unit * utf16Ptr, size_t utf16Len, bool bigEndian, std::string * outStr )
-{
- UTF16_to_UTF8_Proc ToUTF8 = 0;
- if ( bigEndian ) {
- ToUTF8 = UTF16BE_to_UTF8;
- } else {
- ToUTF8 = UTF16LE_to_UTF8;
- }
-
- UTF8Unit buffer [1000];
- size_t inCount, outCount;
-
- outStr->erase();
- outStr->reserve ( utf16Len * 2 ); // As good a guess as any.
-
- while ( utf16Len > 0 ) {
- ToUTF8 ( utf16Ptr, utf16Len, buffer, sizeof(buffer), &inCount, &outCount );
- outStr->append ( (XMP_StringPtr)buffer, outCount );
- utf16Ptr += inCount;
- utf16Len -= inCount;
- }
-
-} // UTF16_to_UTF8
-
-// =================================================================================================
-// TIFF_Manager::DecodeString
-// ==========================
-//
-// Convert an explicitly encoded string to UTF-8. The input must be encoded according to table 6 of
-// the Exif 2.2 specification. The input pointer is to the start of the 8 byte header, the length is
-// the full length. In other words, the pointer and length from the IFD entry. Returns true if the
-// encoding is supported and the conversion succeeds.
-
-// *** JIS encoding is not supported yet. Need a static mapping table from JIS X 208-1990 to Unicode.
-
-bool TIFF_Manager::DecodeString ( const void * encodedPtr, size_t encodedLen, std::string* utf8Str ) const
-{
- XMP_StringPtr typePtr = (XMP_StringPtr)encodedPtr;
- XMP_StringPtr valuePtr = typePtr + 8;
- size_t valueLen = encodedLen - 8;
-
- utf8Str->erase();
-
- if ( *typePtr == 'A' ) {
-
- utf8Str->assign ( valuePtr, valueLen );
- return true;
-
- } else if ( *typePtr == 'U' ) {
-
- try {
-
- const UTF16Unit * utf16Ptr = (const UTF16Unit *) valuePtr;
- size_t utf16Len = valueLen >> 1; // The number of UTF-16 storage units, not bytes.
- if ( utf16Len == 0 ) return false;
- bool isBigEndian = this->bigEndian; // Default to stream endian, unless there is a BOM ...
- if ( (*utf16Ptr == 0xFEFF) || (*utf16Ptr == 0xFFFE) ) { // Check for an explicit BOM
- isBigEndian = (*((XMP_Uns8*)utf16Ptr) == 0xFE);
- utf16Ptr += 1; // Don't translate the BOM.
- utf16Len -= 1;
- if ( utf16Len == 0 ) return false;
- }
- UTF16_to_UTF8 ( utf16Ptr, utf16Len, isBigEndian, utf8Str );
- return true;
-
- } catch ( ... ) {
- return false; // Ignore the tag if there are conversion errors.
- }
-
- } else if ( *typePtr == 'J' ) {
-
- return false; // ! Ignore JIS for now.
-
- }
-
- return false; // ! Ignore all other encodings.
-
-} // TIFF_Manager::DecodeString
-
-// =================================================================================================
-// UTF8_to_UTF16
-// =============
-
-static void UTF8_to_UTF16 ( const UTF8Unit * utf8Ptr, size_t utf8Len, bool bigEndian, std::string * outStr )
-{
- UTF8_to_UTF16_Proc ToUTF16 = 0;
- if ( bigEndian ) {
- ToUTF16 = UTF8_to_UTF16BE;
- } else {
- ToUTF16 = UTF8_to_UTF16LE;
- }
-
- enum { kUTF16Len = 1000 };
- UTF16Unit buffer [kUTF16Len];
- size_t inCount, outCount;
-
- outStr->erase();
- outStr->reserve ( utf8Len * 2 ); // As good a guess as any.
-
- while ( utf8Len > 0 ) {
- ToUTF16 ( utf8Ptr, utf8Len, buffer, kUTF16Len, &inCount, &outCount );
- outStr->append ( (XMP_StringPtr)buffer, outCount*2 );
- utf8Ptr += inCount;
- utf8Len -= inCount;
- }
-
-} // UTF8_to_UTF16
-
-// =================================================================================================
-// TIFF_Manager::EncodeString
-// ==========================
-//
-// Convert a UTF-8 string to an explicitly encoded form according to table 6 of the Exif 2.2
-// specification. Returns true if the encoding is supported and the conversion succeeds.
-
-// *** JIS encoding is not supported yet. Need a static mapping table to JIS X 208-1990 from Unicode.
-
-bool TIFF_Manager::EncodeString ( const std::string& utf8Str, XMP_Uns8 encoding, std::string* encodedStr )
-{
- encodedStr -> erase();
-
- if ( encoding == kTIFF_EncodeASCII ) {
-
- encodedStr->assign ( "ASCII\0\0\0", 8 );
- XMP_Assert (encodedStr->size() == 8 );
-
- encodedStr->append ( utf8Str ); // ! Let the caller filter the value. (?)
-
- return true;
-
- } else if ( encoding == kTIFF_EncodeUnicode ) {
-
- encodedStr->assign ( "UNICODE\0", 8 );
- XMP_Assert (encodedStr->size() == 8 );
-
- try {
- std::string temp;
- UTF8_to_UTF16 ( (const UTF8Unit*)utf8Str.c_str(), utf8Str.size(), this->bigEndian, &temp );
- encodedStr->append ( temp );
- return true;
- } catch ( ... ) {
- return false; // Ignore the tag if there are conversion errors.
- }
-
- } else if ( encoding == kTIFF_EncodeJIS ) {
-
- XMP_Throw ( "Encoding to JIS is not implemented", kXMPErr_Unimplemented );
-
- // encodedStr->assign ( "JIS\0\0\0\0\0", 8 );
- // XMP_Assert (encodedStr->size() == 8 );
-
- // ...
-
- // return true;
-
- } else {
-
- XMP_Throw ( "Invalid TIFF string encoding", kXMPErr_BadParam );
-
- }
-
- return false; // ! Should never get here.
-
-} // TIFF_Manager::EncodeString
-
-// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/TIFF_Support.hpp b/source/XMPFiles/FormatSupport/TIFF_Support.hpp
deleted file mode 100644
index 94f6198..0000000
--- a/source/XMPFiles/FormatSupport/TIFF_Support.hpp
+++ /dev/null
@@ -1,915 +0,0 @@
-#ifndef __TIFF_Support_hpp__
-#define __TIFF_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <map>
-#include <stdlib.h>
-#include <string.h>
-
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "EndianUtils.hpp"
-
-// =================================================================================================
-/// \file TIFF_Support.hpp
-/// \brief XMPFiles support for TIFF streams.
-///
-/// This header provides TIFF stream support specific to the needs of XMPFiles. This is not intended
-/// for general purpose TIFF processing. TIFF_Manager is an abstract base class with 2 concrete
-/// derived classes, TIFF_MemoryReader and TIFF_FileWriter.
-///
-/// TIFF_MemoryReader provides read-only support for TIFF streams that are small enough to be kept
-/// entirely in memory. This allows optimizations to reduce heap usage and processing code. It is
-/// sufficient for browsing access to the Exif metadata in JPEG and Photoshop files. Think of
-/// TIFF_MemoryReader as "memory-based AND read-only". Since the entire TIFF stream is available,
-/// GetTag will return information about any tag in the stream.
-///
-/// TIFF_FileWriter is for cases where updates are needed or the TIFF stream is too large to be kept
-/// entirely in memory. Think of TIFF_FileWriter as "file-based OR read-write". TIFF_FileWriter only
-/// maintains information for tags of interest as metadata.
-///
-/// The needs of XMPFiles are well defined metadata access. Only 4 IFDs are processed:
-/// \li The 0th IFD, for the primary image, the first one in the outer list of IFDs.
-/// \li The Exif general metadata IFD, from tag 34665 in the primary image IFD.
-/// \li The Exif GPS Info metadata IFD, from tag 34853 in the primary image IFD.
-/// \li The Exif Interoperability IFD, from tag 40965 in the Exif general metadata IFD.
-///
-/// \note These classes are for use only when directly compiled and linked. They should not be
-/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
-// =================================================================================================
-
-
-// =================================================================================================
-// TIFF IFD and type constants
-// ===========================
-//
-// These aren't inside TIFF_Manager because static data members can't be initialized there.
-
-enum { // Constants for the recognized IFDs.
- kTIFF_PrimaryIFD = 0, // The primary image IFD, also called the 0th IFD.
- kTIFF_TNailIFD = 1, // The thumbnail image IFD also called the 1st IFD. (not used)
- kTIFF_ExifIFD = 2, // The Exif general metadata IFD.
- kTIFF_GPSInfoIFD = 3, // The Exif GPS Info IFD.
- kTIFF_InteropIFD = 4, // The Exif Interoperability IFD.
- kTIFF_LastRealIFD = 4,
- kTIFF_KnownIFDCount = 5,
- kTIFF_KnownIFD = 9 // The IFD that a tag is known to belong in.
-};
-
-enum { // Constants for the type field of a tag, as defined by TIFF.
- kTIFF_ShortOrLongType = 0, // ! Not part of the TIFF spec, never in a tag!
- kTIFF_ByteType = 1,
- kTIFF_ASCIIType = 2,
- kTIFF_ShortType = 3,
- kTIFF_LongType = 4,
- kTIFF_RationalType = 5,
- kTIFF_SByteType = 6,
- kTIFF_UndefinedType = 7,
- kTIFF_SShortType = 8,
- kTIFF_SLongType = 9,
- kTIFF_SRationalType = 10,
- kTIFF_FloatType = 11,
- kTIFF_DoubleType = 12,
- kTIFF_LastType = 12
-};
-
-static const size_t kTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
-
-static const char * kTIFF_TypeNames[] = { "ShortOrLong", "BYTE", "ASCII", "SHORT", "LONG", "RATIONAL",
- "SBYTE", "UNDEFINED", "SSHORT", "SLONG", "SRATIONAL",
- "FLOAT", "DOUBLE" };
-
-enum { // Encodings for SetTag_EncodedString.
- kTIFF_EncodeUndefined = 0,
- kTIFF_EncodeASCII = 1,
- kTIFF_EncodeUnicode = 2, // UTF-16 in the endianness of the TIFF stream.
- kTIFF_EncodeJIS = 3, // Exif 2.2 uses JIS X 208-1990.
- kTIFF_EncodeUnknown = 9
-};
-
-// =================================================================================================
-// Recognized TIFF tags
-// ====================
-
-// ---------------------------------------------------------------------------
-// An enum of IDs for all of the tags as potential interest as metadata.
-
-enum {
-
- // General 0th IFD tags. Some of these can also be in the thumbnail IFD.
-
- kTIFF_ImageWidth = 256,
- kTIFF_ImageLength = 257,
- kTIFF_BitsPerSample = 258,
- kTIFF_Compression = 259,
- kTIFF_PhotometricInterpretation = 262,
- kTIFF_ImageDescription = 270,
- kTIFF_Make = 271,
- kTIFF_Model = 272,
- kTIFF_Orientation = 274,
- kTIFF_SamplesPerPixel = 277,
- kTIFF_XResolution = 282,
- kTIFF_YResolution = 283,
- kTIFF_PlanarConfiguration = 284,
- kTIFF_ResolutionUnit = 296,
- kTIFF_TransferFunction = 301,
- kTIFF_Software = 305,
- kTIFF_DateTime = 306,
- kTIFF_Artist = 315,
- kTIFF_WhitePoint = 318,
- kTIFF_PrimaryChromaticities = 319,
- kTIFF_YCbCrCoefficients = 529,
- kTIFF_YCbCrSubSampling = 530,
- kTIFF_YCbCrPositioning = 531,
- kTIFF_ReferenceBlackWhite = 532,
- kTIFF_XMP = 700,
- kTIFF_Copyright = 33432,
- kTIFF_IPTC = 33723,
- kTIFF_PSIR = 34377,
- kTIFF_ExifIFDPointer = 34665,
- kTIFF_GPSInfoIFDPointer = 34853,
- kTIFF_DNGVersion = 50706,
- kTIFF_DNGBackwardVersion = 50707,
-
- // Additional thumbnail IFD tags. We also care about 256, 257, and 259 in thumbnails.
- kTIFF_JPEGInterchangeFormat = 513,
- kTIFF_JPEGInterchangeFormatLength = 514,
-
- // Additional tags that need special handling when rewriting memory-based TIFF.
- kTIFF_StripOffsets = 273,
- kTIFF_StripByteCounts = 279,
- kTIFF_FreeOffsets = 288,
- kTIFF_FreeByteCounts = 289,
- kTIFF_TileOffsets = 324,
- kTIFF_TileByteCounts = 325,
- kTIFF_SubIFDs = 330,
- kTIFF_JPEGQTables = 519,
- kTIFF_JPEGDCTables = 520,
- kTIFF_JPEGACTables = 521,
-
- // Exif IFD tags.
-
- kTIFF_ExposureTime = 33434,
- kTIFF_FNumber = 33437,
- kTIFF_ExposureProgram = 34850,
- kTIFF_SpectralSensitivity = 34852,
- kTIFF_ISOSpeedRatings = 34855,
- kTIFF_OECF = 34856,
- kTIFF_ExifVersion = 36864,
- kTIFF_DateTimeOriginal = 36867,
- kTIFF_DateTimeDigitized = 36868,
- kTIFF_ComponentsConfiguration = 37121,
- kTIFF_CompressedBitsPerPixel = 37122,
- kTIFF_ShutterSpeedValue = 37377,
- kTIFF_ApertureValue = 37378,
- kTIFF_BrightnessValue = 37379,
- kTIFF_ExposureBiasValue = 37380,
- kTIFF_MaxApertureValue = 37381,
- kTIFF_SubjectDistance = 37382,
- kTIFF_MeteringMode = 37383,
- kTIFF_LightSource = 37384,
- kTIFF_Flash = 37385,
- kTIFF_FocalLength = 37386,
- kTIFF_SubjectArea = 37396,
- kTIFF_UserComment = 37510,
- kTIFF_SubSecTime = 37520,
- kTIFF_SubSecTimeOriginal = 37521,
- kTIFF_SubSecTimeDigitized = 37522,
- kTIFF_FlashpixVersion = 40960,
- kTIFF_ColorSpace = 40961,
- kTIFF_PixelXDimension = 40962,
- kTIFF_PixelYDimension = 40963,
- kTIFF_RelatedSoundFile = 40964,
- kTIFF_InteroperabilityIFDPointer = 40965,
- kTIFF_FlashEnergy = 41483,
- kTIFF_SpatialFrequencyResponse = 41484,
- kTIFF_FocalPlaneXResolution = 41486,
- kTIFF_FocalPlaneYResolution = 41487,
- kTIFF_FocalPlaneResolutionUnit = 41488,
- kTIFF_SubjectLocation = 41492,
- kTIFF_ExposureIndex = 41493,
- kTIFF_SensingMethod = 41495,
- kTIFF_FileSource = 41728,
- kTIFF_SceneType = 41729,
- kTIFF_CFAPattern = 41730,
- kTIFF_CustomRendered = 41985,
- kTIFF_ExposureMode = 41986,
- kTIFF_WhiteBalance = 41987,
- kTIFF_DigitalZoomRatio = 41988,
- kTIFF_FocalLengthIn35mmFilm = 41989,
- kTIFF_SceneCaptureType = 41990,
- kTIFF_GainControl = 41991,
- kTIFF_Contrast = 41992,
- kTIFF_Saturation = 41993,
- kTIFF_Sharpness = 41994,
- kTIFF_DeviceSettingDescription = 41995,
- kTIFF_SubjectDistanceRange = 41996,
- kTIFF_ImageUniqueID = 42016,
-
- kTIFF_MakerNote = 37500, // Gets deleted when rewriting memory-based TIFF.
-
- // GPS IFD tags.
-
- kTIFF_GPSVersionID = 0,
- kTIFF_GPSLatitudeRef = 1,
- kTIFF_GPSLatitude = 2,
- kTIFF_GPSLongitudeRef = 3,
- kTIFF_GPSLongitude = 4,
- kTIFF_GPSAltitudeRef = 5,
- kTIFF_GPSAltitude = 6,
- kTIFF_GPSTimeStamp = 7,
- kTIFF_GPSSatellites = 8,
- kTIFF_GPSStatus = 9,
- kTIFF_GPSMeasureMode = 10,
- kTIFF_GPSDOP = 11,
- kTIFF_GPSSpeedRef = 12,
- kTIFF_GPSSpeed = 13,
- kTIFF_GPSTrackRef = 14,
- kTIFF_GPSTrack = 15,
- kTIFF_GPSImgDirectionRef = 16,
- kTIFF_GPSImgDirection = 17,
- kTIFF_GPSMapDatum = 18,
- kTIFF_GPSDestLatitudeRef = 19,
- kTIFF_GPSDestLatitude = 20,
- kTIFF_GPSDestLongitudeRef = 21,
- kTIFF_GPSDestLongitude = 22,
- kTIFF_GPSDestBearingRef = 23,
- kTIFF_GPSDestBearing = 24,
- kTIFF_GPSDestDistanceRef = 25,
- kTIFF_GPSDestDistance = 26,
- kTIFF_GPSProcessingMethod = 27,
- kTIFF_GPSAreaInformation = 28,
- kTIFF_GPSDateStamp = 29,
- kTIFF_GPSDifferential = 30
-
-};
-
-// ------------------------------------------------------------------
-// Sorted arrays of the tags that are recognized in the various IFDs.
-
-static const XMP_Uns16 sKnownPrimaryIFDTags[] =
-{
- kTIFF_ImageWidth, // 256
- kTIFF_ImageLength, // 257
- kTIFF_BitsPerSample, // 258
- kTIFF_Compression, // 259
- kTIFF_PhotometricInterpretation, // 262
- kTIFF_ImageDescription, // 270
- kTIFF_Make, // 271
- kTIFF_Model, // 272
- kTIFF_Orientation, // 274
- kTIFF_SamplesPerPixel, // 277
- kTIFF_XResolution, // 282
- kTIFF_YResolution, // 283
- kTIFF_PlanarConfiguration, // 284
- kTIFF_ResolutionUnit, // 296
- kTIFF_TransferFunction, // 301
- kTIFF_Software, // 305
- kTIFF_DateTime, // 306
- kTIFF_Artist, // 315
- kTIFF_WhitePoint, // 318
- kTIFF_PrimaryChromaticities, // 319
- kTIFF_YCbCrCoefficients, // 529
- kTIFF_YCbCrSubSampling, // 530
- kTIFF_YCbCrPositioning, // 531
- kTIFF_ReferenceBlackWhite, // 532
- kTIFF_XMP, // 700
- kTIFF_Copyright, // 33432
- kTIFF_IPTC, // 33723
- kTIFF_PSIR, // 34377
- kTIFF_ExifIFDPointer, // 34665
- kTIFF_GPSInfoIFDPointer, // 34853
- kTIFF_DNGVersion, // 50706
- kTIFF_DNGBackwardVersion, // 50707
- 0xFFFF // Must be last as a sentinel.
-};
-
-static const XMP_Uns16 sKnownThumbnailIFDTags[] =
-{
- kTIFF_ImageWidth, // 256
- kTIFF_ImageLength, // 257
- kTIFF_Compression, // 259
- kTIFF_JPEGInterchangeFormat, // 513
- kTIFF_JPEGInterchangeFormatLength, // 514
- 0xFFFF // Must be last as a sentinel.
-};
-
-static const XMP_Uns16 sKnownExifIFDTags[] =
-{
- kTIFF_ExposureTime, // 33434
- kTIFF_FNumber, // 33437
- kTIFF_ExposureProgram, // 34850
- kTIFF_SpectralSensitivity, // 34852
- kTIFF_ISOSpeedRatings, // 34855
- kTIFF_OECF, // 34856
- kTIFF_ExifVersion, // 36864
- kTIFF_DateTimeOriginal, // 36867
- kTIFF_DateTimeDigitized, // 36868
- kTIFF_ComponentsConfiguration, // 37121
- kTIFF_CompressedBitsPerPixel, // 37122
- kTIFF_ShutterSpeedValue, // 37377
- kTIFF_ApertureValue, // 37378
- kTIFF_BrightnessValue, // 37379
- kTIFF_ExposureBiasValue, // 37380
- kTIFF_MaxApertureValue, // 37381
- kTIFF_SubjectDistance, // 37382
- kTIFF_MeteringMode, // 37383
- kTIFF_LightSource, // 37384
- kTIFF_Flash, // 37385
- kTIFF_FocalLength, // 37386
- kTIFF_SubjectArea, // 37396
- kTIFF_UserComment, // 37510
- kTIFF_SubSecTime, // 37520
- kTIFF_SubSecTimeOriginal, // 37521
- kTIFF_SubSecTimeDigitized, // 37522
- kTIFF_FlashpixVersion, // 40960
- kTIFF_ColorSpace, // 40961
- kTIFF_PixelXDimension, // 40962
- kTIFF_PixelYDimension, // 40963
- kTIFF_RelatedSoundFile, // 40964
- kTIFF_FlashEnergy, // 41483
- kTIFF_SpatialFrequencyResponse, // 41484
- kTIFF_FocalPlaneXResolution, // 41486
- kTIFF_FocalPlaneYResolution, // 41487
- kTIFF_FocalPlaneResolutionUnit, // 41488
- kTIFF_SubjectLocation, // 41492
- kTIFF_ExposureIndex, // 41493
- kTIFF_SensingMethod, // 41495
- kTIFF_FileSource, // 41728
- kTIFF_SceneType, // 41729
- kTIFF_CFAPattern, // 41730
- kTIFF_CustomRendered, // 41985
- kTIFF_ExposureMode, // 41986
- kTIFF_WhiteBalance, // 41987
- kTIFF_DigitalZoomRatio, // 41988
- kTIFF_FocalLengthIn35mmFilm, // 41989
- kTIFF_SceneCaptureType, // 41990
- kTIFF_GainControl, // 41991
- kTIFF_Contrast, // 41992
- kTIFF_Saturation, // 41993
- kTIFF_Sharpness, // 41994
- kTIFF_DeviceSettingDescription, // 41995
- kTIFF_SubjectDistanceRange, // 41996
- kTIFF_ImageUniqueID, // 42016
- 0xFFFF // Must be last as a sentinel.
-};
-
-static const XMP_Uns16 sKnownGPSInfoIFDTags[] =
-{
- kTIFF_GPSVersionID, // 0
- kTIFF_GPSLatitudeRef, // 1
- kTIFF_GPSLatitude, // 2
- kTIFF_GPSLongitudeRef, // 3
- kTIFF_GPSLongitude, // 4
- kTIFF_GPSAltitudeRef, // 5
- kTIFF_GPSAltitude, // 6
- kTIFF_GPSTimeStamp, // 7
- kTIFF_GPSSatellites, // 8
- kTIFF_GPSStatus, // 9
- kTIFF_GPSMeasureMode, // 10
- kTIFF_GPSDOP, // 11
- kTIFF_GPSSpeedRef, // 12
- kTIFF_GPSSpeed, // 13
- kTIFF_GPSTrackRef, // 14
- kTIFF_GPSTrack, // 15
- kTIFF_GPSImgDirectionRef, // 16
- kTIFF_GPSImgDirection, // 17
- kTIFF_GPSMapDatum, // 18
- kTIFF_GPSDestLatitudeRef, // 19
- kTIFF_GPSDestLatitude, // 20
- kTIFF_GPSDestLongitudeRef, // 21
- kTIFF_GPSDestLongitude, // 22
- kTIFF_GPSDestBearingRef, // 23
- kTIFF_GPSDestBearing, // 24
- kTIFF_GPSDestDistanceRef, // 25
- kTIFF_GPSDestDistance, // 26
- kTIFF_GPSProcessingMethod, // 27
- kTIFF_GPSAreaInformation, // 28
- kTIFF_GPSDateStamp, // 29
- kTIFF_GPSDifferential, // 30
- 0xFFFF // Must be last as a sentinel.
-};
-
-static const XMP_Uns16 sKnownInteroperabilityIFDTags[] =
-{
- // ! Yes, there are none at present.
- 0xFFFF // Must be last as a sentinel.
-};
-
-// ! Make sure these are in the same order as the IFD enum!
-static const XMP_Uns16* sKnownTags[kTIFF_KnownIFDCount] = { sKnownPrimaryIFDTags,
- sKnownThumbnailIFDTags,
- sKnownExifIFDTags,
- sKnownGPSInfoIFDTags,
- sKnownInteroperabilityIFDTags };
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// TIFF_Manager
-// ============
-
-class TIFF_Manager { // The abstract base class.
-public:
-
- // ---------------------------------------------------------------------------------------------
- // Types and constants
-
- static const XMP_Uns32 kBigEndianPrefix = 0x4D4D002AUL;
- static const XMP_Uns32 kLittleEndianPrefix = 0x49492A00UL;
-
- static const size_t kEmptyTIFFLength = 8; // Just the header.
- static const size_t kEmptyIFDLength = 2 + 4; // Entry count and next-IFD offset.
- static const size_t kIFDEntryLength = 12;
-
- struct TagInfo {
- XMP_Uns16 id;
- XMP_Uns16 type;
- XMP_Uns32 count;
- const void* dataPtr; // ! The data must not be changed! Stream endian format!
- XMP_Uns32 dataLen; // The length in bytes.
- TagInfo() : id(0), type(0), count(0), dataPtr(0), dataLen(0) {};
- TagInfo ( XMP_Uns16 _id, XMP_Uns16 _type, XMP_Uns32 _count, const void* _dataPtr, XMP_Uns32 _dataLen )
- : id(_id), type(_type), count(_count), dataPtr(_dataPtr), dataLen(_dataLen) {};
- };
-
- typedef std::map<XMP_Uns16,TagInfo> TagInfoMap;
-
- struct Rational { XMP_Uns32 num, denom; };
- struct SRational { XMP_Int32 num, denom; };
-
- // ---------------------------------------------------------------------------------------------
- // The IsXyzEndian methods return the external endianness of the original parsed TIFF stream.
- // The \c GetTag methods return native endian values, the \c SetTag methods take native values.
- // The original endianness is preserved in output.
-
- bool IsBigEndian() const { return this->bigEndian; };
- bool IsLittleEndian() const { return (! this->bigEndian); };
- bool IsNativeEndian() const { return this->nativeEndian; };
-
- // ---------------------------------------------------------------------------------------------
- // The TIFF_Manager only keeps explicit knowledge of up to 4 IFDs:
- // - The primary image IFD, also known as the 0th IFD. This must be present.
- // - A possible Exif general metadata IFD, found from tag 34665 in the primary image IFD.
- // - A possible Exif GPS metadata IFD, found from tag 34853 in the primary image IFD.
- // - A possible Exif Interoperability IFD, found from tag 40965 in the Exif general metadata IFD.
- //
- // Parsing will silently forget about certain aspects of ill-formed streams. If any tags are
- // repeated in an IFD, only the last is kept. Any known tags that are in the wrong IFD are
- // removed. Parsing will sort the tags into ascending order, AppendTIFF and ComposeTIFF will
- // preserve the sorted order. These fixes do not cause IsChanged to return true, that only
- // happens if the client makes explicit changes using SetTag or DeleteTag.
-
- virtual bool HasExifIFD() const = 0;
- virtual bool HasGPSInfoIFD() const = 0;
-
- // ---------------------------------------------------------------------------------------------
- // These are the basic methods to get a map of all of the tags in an IFD, to get or set a tag,
- // or to delete a tag. The dataPtr returned by \c GetTag is consided read-only, the client must
- // not change it. The ifd parameter to \c GetIFD must be for one of the recognized actual IFDs.
- // The ifd parameter for the GetTag or SetTag methods can be a specific IFD of kTIFF_KnownIFD.
- // Using the specific IFD will be slightly faster, saving a lookup in the known tag map. An
- // exception is thrown if kTIFF_KnownIFD is passed to GetTag or SetTag and the tag is not known.
- // \c SetTag replaces an existing tag regardless of type or count. \c DeleteTag deletes a tag,
- // it is a no-op if the tag does not exist. \c GetValueOffset returns the offset within the
- // parsed stream of the tag's value. It returns 0 if the tag was not in the parsed input.
-
- virtual bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const = 0;
-
- virtual bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const = 0;
-
- virtual void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr ) = 0;
-
- virtual void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id ) = 0;
-
- virtual XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const = 0;
-
- // ---------------------------------------------------------------------------------------------
- // These methods are for tags whose type can be short or long, depending on the actual value.
- // \c GetTag_Integer returns false if an existing tag's type is not short, or long, or if the
- // count is not 1. \c SetTag_Integer replaces an existing tag regardless of type or count, the
- // new tag will have type short or long.
-
- virtual bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const = 0;
-
- void SetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data );
-
- // ---------------------------------------------------------------------------------------------
- // These are customized forms of GetTag that verify the type and return a typed value. False is
- // returned if the type does not match or if the count is not 1.
-
- // *** Should also add support for ASCII multi-strings?
-
- virtual bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const = 0;
- virtual bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const = 0;
- virtual bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const = 0;
- virtual bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const = 0;
- virtual bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const = 0;
- virtual bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const = 0;
-
- virtual bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const = 0;
- virtual bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const = 0;
-
- virtual bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const = 0;
- virtual bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const = 0;
-
- virtual bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const = 0;
-
- // ---------------------------------------------------------------------------------------------
-
- void SetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8 data );
- void SetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8 data );
- void SetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 data );
- void SetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16 data );
- void SetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data );
- void SetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 data );
-
- void SetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 num, XMP_Uns32 denom );
- void SetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 num, XMP_Int32 denom );
-
- void SetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float data );
- void SetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double data );
-
- void SetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr dataPtr );
-
- // ---------------------------------------------------------------------------------------------
-
- virtual bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const = 0;
- virtual void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding ) = 0;
-
- bool DecodeString ( const void * encodedPtr, size_t encodedLen, std::string* utf8Str ) const;
- bool EncodeString ( const std::string& utf8Str, XMP_Uns8 encoding, std::string* encodedStr );
-
- // ---------------------------------------------------------------------------------------------
- // \c IsChanged returns true if a read-write stream has changes that need to be saved. This is
- // only the case when a \c SetTag method has been called. It is not true for changes related to
- // parsing normalization such as sorting of tags. \c IsChanged returns false for read-only streams.
-
- virtual bool IsChanged() = 0;
-
- // ---------------------------------------------------------------------------------------------
- // \c IsLegacyChanged returns true if a read-write stream has changes that need to be saved to
- // tags other than the XMP (tag 700). This only the case when a \c SetTag method has been
- // called. It is not true for changes related to parsing normalization such as sorting of tags.
- // \c IsLegacyChanged returns false for read-only streams.
-
- virtual bool IsLegacyChanged() = 0;
-
- // ---------------------------------------------------------------------------------------------
- // \c UpdateMemoryStream is mainly applicable to memory-based read-write streams. It recomposes
- // the memory stream to incorporate all changes. The new length and data pointer are returned.
- // \c UpdateMemoryStream can be used with a read-only memory stream to get the raw stream info.
- //
- // \c UpdateFileStream updates file-based TIFF. The client must guarantee that the TIFF portion
- // of the file matches that from the parse in the file-based constructor. Offsets saved from that
- // parse must still be valid. The open file reference need not be the same, e.g. the client can
- // be doing a crash-safe update into a temporary copy.
- //
- // Both \c UpdateMemoryStream and \c UpdateFileStream use an update-by-append model. Changes are
- // written in-place where they fit, anything requiring growth is appended to the end and the old
- // space is abandoned. The end for memory-based TIFF is the end of the data block, the end for
- // file-based TIFF is the end of the file. This update-by-append model has the advantage of not
- // perturbing any hidden offsets, a common feature of proprietary MakerNotes.
- //
- // The condenseStream parameter to UpdateMemoryStream can be used to rewrite the full stream
- // instead of appending. This will discard any MakerNote tags and risks breaking offsets that
- // are hidden. This can be necessary though to try to make the TIFF fit in a JPEG file.
-
- virtual void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true ) = 0;
- virtual void ParseFileStream ( LFA_FileRef fileRef ) = 0;
-
- virtual void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) = 0;
-
- virtual XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false ) = 0;
- virtual void UpdateFileStream ( LFA_FileRef fileRef ) = 0;
-
- // ---------------------------------------------------------------------------------------------
-
- GetUns16_Proc GetUns16; // Get values from the TIFF stream.
- GetUns32_Proc GetUns32; // Always native endian on the outside, stream endian in the stream.
- GetFloat_Proc GetFloat;
- GetDouble_Proc GetDouble;
-
- PutUns16_Proc PutUns16; // Put values into the TIFF stream.
- PutUns32_Proc PutUns32; // Always native endian on the outside, stream endian in the stream.
- PutFloat_Proc PutFloat;
- PutDouble_Proc PutDouble;
-
- virtual ~TIFF_Manager() {};
-
-protected:
-
- bool bigEndian, nativeEndian;
-
- XMP_Uns32 CheckTIFFHeader ( const XMP_Uns8* tiffPtr, XMP_Uns32 length );
-
- TIFF_Manager(); // Force clients to use the reader or writer derived classes.
-
- struct RawIFDEntry {
- XMP_Uns16 id;
- XMP_Uns16 type;
- XMP_Uns32 count;
- XMP_Uns32 dataOrOffset;
- };
-
-}; // TIFF_Manager
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// TIFF_MemoryReader
-// =================
-
-class TIFF_MemoryReader : public TIFF_Manager { // The derived class for memory-based read-only access.
-public:
-
- bool HasExifIFD() const { return (containedIFDs[kTIFF_ExifIFD].count != 0); };
- bool HasGPSInfoIFD() const { return (containedIFDs[kTIFF_GPSInfoIFD].count != 0); };
-
- bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const;
-
- bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const;
-
- void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr ) { NotAppropriate(); };
-
- void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id ) { NotAppropriate(); };
-
- XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
-
- bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
-
- bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const;
- bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const;
- bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const;
- bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const;
- bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
- bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const;
-
- bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const;
- bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const;
-
- bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const;
- bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const;
-
- bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const;
-
- bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const;
-
- void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding ) { NotAppropriate(); };
-
- bool IsChanged() { return false; };
- bool IsLegacyChanged() { return false; };
-
- void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
- void ParseFileStream ( LFA_FileRef fileRef ) { NotAppropriate(); };
-
- void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) { NotAppropriate(); };
-
- XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false ) { if ( dataPtr != 0 ) *dataPtr = tiffStream; return tiffLength; };
- void UpdateFileStream ( LFA_FileRef fileRef ) { NotAppropriate(); };
-
- TIFF_MemoryReader() : ownedStream(false), tiffStream(0), tiffLength(0) {};
-
- virtual ~TIFF_MemoryReader() { if ( this->ownedStream ) free ( this->tiffStream ); };
-
-private:
-
- bool ownedStream;
-
- XMP_Uns8* tiffStream;
- XMP_Uns32 tiffLength;
-
- // Memory usage notes: TIFF_MemoryReader is for memory-based read-only usage (both apply). There
- // is no need to ever allocate separate blocks of memory, everything is used directly from the
- // TIFF stream. Data pointers are computed on the fly, the offset field is 4 bytes and pointers
- // will be 8 bytes for 64-bit platforms.
-
- struct TweakedIFDEntry { // ! Most fields are in native byte order, dataOrPos is for offsets only.
- XMP_Uns16 id;
- XMP_Uns16 type;
- XMP_Uns32 bytes;
- XMP_Uns32 dataOrPos;
- TweakedIFDEntry() : id(0), type(0), bytes(0), dataOrPos(0) {};
- };
-
- struct TweakedIFDInfo {
- XMP_Uns16 count;
- TweakedIFDEntry* entries;
- TweakedIFDInfo() : count(0), entries(0) {};
- };
-
- TweakedIFDInfo containedIFDs[kTIFF_KnownIFDCount];
-
- static void SortIFD ( TweakedIFDInfo* thisIFD );
-
- XMP_Uns32 ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd );
-
- const TweakedIFDEntry* FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
-
- const inline void* GetDataPtr ( const TweakedIFDEntry* tifdEntry ) const
- { if ( tifdEntry->bytes <= 4 ) return &tifdEntry->dataOrPos; else return (this->tiffStream + tifdEntry->dataOrPos); };
-
- static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for TIFF_Reader", kXMPErr_InternalFailure ); };
-
-}; // TIFF_MemoryReader
-
-
-// =================================================================================================
-// =================================================================================================
-
-
-// =================================================================================================
-// TIFF_FileWriter
-// ===============
-
-class TIFF_FileWriter : public TIFF_Manager { // The derived class for file-based or read-write access.
-public:
-
- bool HasExifIFD() const { return this->containedIFDs[kTIFF_ExifIFD].tagMap.size() != 0; };
- bool HasGPSInfoIFD() const { return this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.size() != 0; };
-
- bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const;
-
- bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const;
-
- void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr );
-
- void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id );
-
- XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
-
- bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
-
- bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const;
- bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const;
- bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const;
- bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const;
- bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
- bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const;
-
- bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const;
- bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const;
-
- bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const;
- bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const;
-
- bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const;
-
- bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const;
-
- void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding );
-
- bool IsChanged() { return this->changed; };
-
- bool IsLegacyChanged();
-
- enum { kDoNotCopyData = false };
-
- void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
- void ParseFileStream ( LFA_FileRef fileRef );
-
- void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen );
-
- XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false );
- void UpdateFileStream ( LFA_FileRef fileRef );
-
- TIFF_FileWriter();
-
- virtual ~TIFF_FileWriter();
-
-private:
-
- bool changed, legacyDeleted;
- bool memParsed, fileParsed;
- bool ownedStream;
-
- XMP_Uns8* memStream;
- XMP_Uns32 tiffLength;
-
- // Memory usage notes: TIFF_FileWriter is for file-based OR read/write usage. For memory-based
- // streams the dataPtr is initially into the stream, regardless of size. For file-based streams
- // the dataPtr is initially a separate allocation for large values (over 4 bytes), and points to
- // the smallValue field for small values. This is also the usage when a tag is changed (for both
- // memory and file cases), the dataPtr is a separate allocation for large values (over 4 bytes),
- // and points to the smallValue field for small values.
-
- // ! The working data values are always stream endian, no matter where stored. They are flipped
- // ! as necessary by GetTag and SetTag.
-
- static const bool kIsFileBased = true; // For use in the InternalTagInfo constructor.
- static const bool kIsMemoryBased = false;
-
- class InternalTagInfo {
- public:
-
- XMP_Uns16 id;
- XMP_Uns16 type;
- XMP_Uns32 count;
- XMP_Uns32 dataLen;
- XMP_Uns32 smallValue; // Small value in stream endianness, but "left" justified.
- XMP_Uns8* dataPtr; // Parsing captures all small values, only large ones that we care about.
- XMP_Uns32 origDataLen; // The original (parse time) data length in bytes.
- XMP_Uns32 origDataOffset; // The original data offset, regardless of length.
- bool changed;
- bool fileBased;
-
- inline void FreeData() {
- if ( this->fileBased || this->changed ) {
- if ( (this->dataLen > 4) && (this->dataPtr != 0) ) { free ( this->dataPtr ); this->dataPtr = 0; }
- }
- }
-
- InternalTagInfo ( XMP_Uns16 _id, XMP_Uns16 _type, XMP_Uns32 _count, bool _fileBased )
- : id(_id), type(_type), count(_count), dataLen(0), smallValue(0), dataPtr(0),
- origDataLen(0), origDataOffset(0), changed(false), fileBased(_fileBased) {};
- ~InternalTagInfo() { this->FreeData(); };
-
- void operator= ( const InternalTagInfo & in )
- {
- // ! Gag! Transfer ownership of the dataPtr!
- this->FreeData();
- memcpy ( this, &in, sizeof(*this) ); // AUDIT: Use of sizeof(InternalTagInfo) is safe.
- if ( this->dataLen <= 4 ) {
- this->dataPtr = (XMP_Uns8*) &this->smallValue; // Don't use the copied pointer.
- } else {
- *((XMP_Uns8**)&in.dataPtr) = 0; // The pointer is now owned by "this".
- }
- };
-
- private:
-
- InternalTagInfo() // Hidden on purpose, fileBased must be properly set.
- : id(0), type(0), count(0), dataLen(0), smallValue(0), dataPtr(0),
- origDataLen(0), origDataOffset(0), changed(false), fileBased(false) {};
-
- };
-
- typedef std::map<XMP_Uns16,InternalTagInfo> InternalTagMap;
-
- struct InternalIFDInfo {
- bool changed;
- XMP_Uns16 origCount; // Original number of IFD entries.
- XMP_Uns32 origIFDOffset; // Original stream offset of the IFD.
- XMP_Uns32 origNextIFD; // Original stream offset of the following IFD.
- InternalTagMap tagMap;
- InternalIFDInfo() : changed(false), origCount(0), origIFDOffset(0), origNextIFD(0) {};
- inline void clear()
- {
- this->changed = false;
- this->origCount = 0;
- this->origIFDOffset = this->origNextIFD = 0;
- this->tagMap.clear();
- };
- };
-
- InternalIFDInfo containedIFDs[kTIFF_KnownIFDCount];
-
- static XMP_Uns8 PickIFD ( XMP_Uns8 ifd, XMP_Uns16 id );
- const InternalTagInfo* FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
-
- void DeleteExistingInfo();
-
- XMP_Uns32 ProcessMemoryIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd );
- XMP_Uns32 ProcessFileIFD ( XMP_Uns8 ifd, XMP_Uns32 ifdOffset, LFA_FileRef fileRef, IOBuffer* ioBuf );
-
- void ProcessPShop6IFD ( const TIFF_MemoryReader& buriedExif, XMP_Uns8 ifd );
-
- void* CopyTagToMasterIFD ( const TagInfo& ps6Tag, InternalIFDInfo* masterIFD );
-
- void PreflightIFDLinkage();
-
- XMP_Uns32 DetermineVisibleLength();
-
- XMP_Uns32 DetermineAppendInfo ( XMP_Uns32 appendedOrigin,
- bool appendedIFDs[kTIFF_KnownIFDCount],
- XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount],
- bool appendAll = false );
-
- void UpdateMemByAppend ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out,
- bool appendAll = false, XMP_Uns32 extraSpace = 0 );
- void UpdateMemByRewrite ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out );
-
- void WriteFileIFD ( LFA_FileRef fileRef, InternalIFDInfo & thisIFD );
-
-}; // TIFF_FileWriter
-
-
-// =================================================================================================
-
-#endif // __TIFF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/XDCAM_Support.cpp b/source/XMPFiles/FormatSupport/XDCAM_Support.cpp
deleted file mode 100644
index b86e69e..0000000
--- a/source/XMPFiles/FormatSupport/XDCAM_Support.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XDCAM_Support.hpp"
-
-// =================================================================================================
-/// \file XDCAM_Support.cpp
-///
-// =================================================================================================
-
-namespace XDCAM_Support
-{
-
-// =================================================================================================
-// CreateChildElement
-// ==================
-
-namespace
-{
-XML_Node * CreateChildElement ( XML_Node * parent, XMP_StringPtr localName, XMP_StringPtr legacyNS, int indent /* = 0 */ )
-{
- XML_Node * wsNode;
- XML_Node * childNode = parent->GetNamedElement ( legacyNS, localName );
-
- if ( childNode == 0 ) {
-
- // The indenting is a hack, assuming existing 2 spaces per level.
-
- wsNode = new XML_Node ( parent, "", kCDataNode );
- wsNode->value = " "; // Add 2 spaces to the existing WS before the parent's close tag.
- parent->content.push_back ( wsNode );
-
- childNode = new XML_Node ( parent, localName, kElemNode );
- childNode->ns = parent->ns;
- childNode->nsPrefixLen = parent->nsPrefixLen;
- childNode->name.insert ( 0, parent->name, 0, parent->nsPrefixLen );
- parent->content.push_back ( childNode );
-
- wsNode = new XML_Node ( parent, "", kCDataNode );
- wsNode->value = '\n';
- for ( ; indent > 1; --indent ) wsNode->value += " "; // Indent less 1, to "outdent" the parent's close.
- parent->content.push_back ( wsNode );
-
- }
-
- return childNode;
-
-}
-}
-
-// =================================================================================================
-// XDCAM_Support::GetLegacyMetaData
-// =================================
-
-bool GetLegacyMetaData ( SXMPMeta * xmpObjPtr,
- XML_NodePtr rootElem,
- XMP_StringPtr legacyNS,
- bool digestFound,
- std::string& umid )
-{
- bool containsXMP = false;
-
- XML_NodePtr legacyContext = 0, legacyProp = 0;
-
- // UMID
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DC, "identifier" )) ) {
- legacyProp = rootElem->GetNamedElement ( legacyNS, "TargetMaterial" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr legacyValue = legacyProp->GetAttrValue ( "umidRef" );
- if ( legacyValue != 0 ) {
- umid = legacyValue;
- xmpObjPtr->SetProperty ( kXMP_NS_DC, "identifier", legacyValue, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Creation date
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_XMP, "CreateDate" )) ) {
- legacyProp = rootElem->GetNamedElement ( legacyNS, "CreationDate" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr legacyValue = legacyProp->GetAttrValue ( "value" );
- if ( legacyValue != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_XMP, "CreateDate", legacyValue, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Modify Date
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_XMP, "ModifyDate" )) ) {
- legacyProp = rootElem->GetNamedElement ( legacyNS, "LastUpdate" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr legacyValue = legacyProp->GetAttrValue ( "value" );
- if ( legacyValue != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_XMP, "ModifyDate", legacyValue, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Metadata Modify Date
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_XMP, "MetadataDate" )) ) {
- legacyProp = rootElem->GetNamedElement ( legacyNS, "lastUpdate" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr legacyValue = legacyProp->GetAttrValue ( "value" );
- if ( legacyValue != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_XMP, "MetadataDate", legacyValue, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Description
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DC, "description" )) ) {
- legacyProp = rootElem->GetNamedElement ( legacyNS, "Description" );
- if ( (legacyProp != 0) && legacyProp->IsLeafContentNode() ) {
- XMP_StringPtr legacyValue = legacyProp->GetLeafContentValue();
- if ( legacyValue != 0 ) {
- xmpObjPtr->SetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", legacyValue, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- legacyContext = rootElem->GetNamedElement ( legacyNS, "VideoFormat" );
-
- if ( legacyContext != 0 ) {
-
- // frame size
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "videoFrameSize" )) ) {
- legacyProp = legacyContext->GetNamedElement ( legacyNS, "VideoLayout" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
-
- XMP_StringPtr widthValue = legacyProp->GetAttrValue ( "pixel" );
- XMP_StringPtr heightValue = legacyProp->GetAttrValue ( "numOfVerticalLine" );
-
- if ( (widthValue != 0) && (heightValue != 0) ) {
-
- xmpObjPtr->DeleteProperty ( kXMP_NS_DM, "videoFrameSize" );
- xmpObjPtr->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "w", widthValue );
- xmpObjPtr->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "h", heightValue );
- xmpObjPtr->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "unit", "pixels" );
-
- containsXMP = true;
-
- }
-
- }
- }
-
- // Aspect ratio
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "videoPixelAspectRatio" )) ) {
- legacyProp = legacyContext->GetNamedElement ( legacyNS, "VideoLayout" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr aspectRatio = legacyProp->GetAttrValue ( "aspectRatio" );
- if ( aspectRatio != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_DM, "videoPixelAspectRatio", aspectRatio, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Frame rate
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "videoFrameRate" )) ) {
- legacyProp = legacyContext->GetNamedElement ( legacyNS, "VideoFrame" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr prop = legacyProp->GetAttrValue ( "formatFps" );
- if ( prop != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_DM, "videoFrameRate", prop, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- // Video codec
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "videoCompressor" )) ) {
- legacyProp = legacyContext->GetNamedElement ( legacyNS, "VideoFrame" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr prop = legacyProp->GetAttrValue ( "videoCodec" );
- if ( prop != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_DM, "videoCompressor", prop, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- } // VideoFormat
-
- legacyContext = rootElem->GetNamedElement ( legacyNS, "AudioFormat" );
-
- if ( legacyContext != 0 ) {
-
- // Audio codec
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "audioCompressor" )) ) {
- legacyProp = legacyContext->GetNamedElement ( legacyNS, "AudioRecPort" );
- if ( (legacyProp != 0) && legacyProp->IsEmptyLeafNode() ) {
- XMP_StringPtr prop = legacyProp->GetAttrValue ( "audioCodec" );
- if ( prop != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_DM, "audioCompressor", prop, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
- }
-
- } // AudioFormat
-
- // Duration
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "duration" )) ) {
-
- std::string durationFrames, timecodeFPS;
- legacyProp = rootElem->GetNamedElement ( legacyNS, "Duration" );
- if ( legacyProp != 0 ) {
- XMP_StringPtr durationValue = legacyProp->GetAttrValue ( "value" );
- if ( durationValue != 0 ) durationFrames = durationValue;
- }
-
- legacyProp = rootElem->GetNamedElement ( legacyNS, "LtcChangeTable" );
- if ( legacyProp != 0 ) {
- // [TODO] Verify that this is the correct framerate to use from the legacy metadata. gemiller
- XMP_StringPtr fps = legacyProp->GetAttrValue ( "tcFps" );
- if ( fps != 0 ) {
- timecodeFPS = "1/";
- timecodeFPS += fps;
- }
- }
-
- if ( (!timecodeFPS.empty()) && (!durationFrames.empty())) {
- xmpObjPtr->DeleteProperty ( kXMP_NS_DM, "duration" );
- xmpObjPtr->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "value", durationFrames );
- xmpObjPtr->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "scale", timecodeFPS );
- containsXMP = true;
- }
-
- }
-
- legacyContext = rootElem->GetNamedElement ( legacyNS, "Device" );
- if ( legacyContext != 0 ) {
-
- std::string model;
-
- // manufacturer string
- XMP_StringPtr manufacturer = legacyContext->GetAttrValue ( "manufacturer" );
- if ( manufacturer != 0 ) {
- model += manufacturer;
- }
-
- // model string
- XMP_StringPtr modelName = legacyContext->GetAttrValue ( "modelName" );
- if ( modelName != 0 ) {
- if ( model.size() > 0 ) {
- model += " ";
- }
- model += modelName;
- }
-
-
- // For the dm::cameraModel property, concat the make and model.
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_DM, "cameraModel" )) ) {
- if ( model.size() != 0 ) {
- xmpObjPtr->SetProperty ( kXMP_NS_DM, "cameraModel", model, kXMP_DeleteExisting );
- containsXMP = true;
- }
- }
-
- // EXIF Model
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_TIFF, "Model" )) ) {
- xmpObjPtr->SetProperty ( kXMP_NS_TIFF, "Model", modelName, kXMP_DeleteExisting );
- }
-
- // EXIF Make
- if ( digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_TIFF, "Make" )) ) {
- xmpObjPtr->SetProperty ( kXMP_NS_TIFF, "Make", manufacturer, kXMP_DeleteExisting );
- }
-
- // EXIF-AUX Serial number
- XMP_StringPtr serialNumber = legacyContext->GetAttrValue ( "serialNo" );
- if ( serialNumber != 0 && (digestFound || (! xmpObjPtr->DoesPropertyExist ( kXMP_NS_EXIF_Aux, "SerialNumber" ))) ) {
- xmpObjPtr->SetProperty ( kXMP_NS_EXIF_Aux, "SerialNumber", serialNumber, kXMP_DeleteExisting );
- }
-
- }
-
-
- return containsXMP;
-
-}
-
-// =================================================================================================
-// XDCAM_Support::SetLegacyMetaData
-// ================================
-
-bool SetLegacyMetaData ( XML_Node * clipMetadata,
- SXMPMeta * xmpObj,
- XMP_StringPtr legacyNS )
-{
- bool updateLegacyXML = false;
- bool xmpFound = false;
- std::string xmpValue;
- XML_Node * xmlNode = 0;
-
- xmpFound = xmpObj->GetProperty ( kXMP_NS_DC, "title", &xmpValue, 0 );
-
- if ( xmpFound ) {
-
- xmlNode = CreateChildElement ( clipMetadata, "Title", legacyNS, 3 );
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
- }
-
- }
-
- xmpFound = xmpObj->GetArrayItem ( kXMP_NS_DC, "creator", 1, &xmpValue, 0 );
-
- if ( xmpFound ) {
- xmlNode = CreateChildElement ( clipMetadata, "Creator", legacyNS, 3 );
- XMP_StringPtr creatorName = xmlNode->GetAttrValue ( "name" );
- if ( creatorName == 0 ) creatorName = "";
- if ( xmpValue != creatorName ) {
- xmlNode->SetAttrValue ( "name", xmpValue.c_str() );
- updateLegacyXML = true;
- }
- }
-
- xmpFound = xmpObj->GetProperty ( kXMP_NS_DC, "description", &xmpValue, 0 );
-
- if ( xmpFound ) {
- xmlNode = CreateChildElement ( clipMetadata, "Description", legacyNS, 3 );
- if ( xmpValue != xmlNode->GetLeafContentValue() ) {
- // description in non real time metadata is limited to 2047 bytes
- if ( xmpValue.size() > 2047 ) xmpValue.resize ( 2047 );
- xmlNode->SetLeafContentValue ( xmpValue.c_str() );
- updateLegacyXML = true;
- }
- }
-
- return updateLegacyXML;
-
-}
-
-// =================================================================================================
-
-} // namespace XDCAM_Support
diff --git a/source/XMPFiles/FormatSupport/XDCAM_Support.hpp b/source/XMPFiles/FormatSupport/XDCAM_Support.hpp
deleted file mode 100644
index 51811c7..0000000
--- a/source/XMPFiles/FormatSupport/XDCAM_Support.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __XDCAM_Support_hpp__
-#define __XDCAM_Support_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2008 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-#include "XMP_Const.h"
-#include "XMPFiles_Impl.hpp"
-#include "ExpatAdapter.hpp"
-
-// =================================================================================================
-/// \file XDCAM_Support.hpp
-/// \brief XMPFiles support for XDCAM streams.
-///
-// =================================================================================================
-
-namespace XDCAM_Support
-{
- // Read XDCAM legacy XML metadata and translate to appropriate XMP.
- bool GetLegacyMetaData ( SXMPMeta * xmpObjPtr,
- XML_NodePtr rootElem,
- XMP_StringPtr legacyNS,
- bool digestFound,
- std::string& umid );
-
- // Write XMP metadata back to legacy XDCAM XML.
- bool SetLegacyMetaData ( XML_Node * clipMetadata,
- SXMPMeta * xmpObj,
- XMP_StringPtr legacyNS );
-
-
-} // namespace XDCAM_Support
-
-// =================================================================================================
-
-#endif // __XDCAM_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/XMPScanner.cpp b/source/XMPFiles/FormatSupport/XMPScanner.cpp
deleted file mode 100644
index a67c2c6..0000000
--- a/source/XMPFiles/FormatSupport/XMPScanner.cpp
+++ /dev/null
@@ -1,1480 +0,0 @@
-// =================================================================================================
-// Copyright 2004 Adobe Systems Incorporated
-// All Rights Reserved.
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-//
-// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
-// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
-// =================================================================================================
-
-#if WIN32
- #pragma warning ( disable : 4127 ) // conditional expression is constant
- #pragma warning ( disable : 4510 ) // default constructor could not be generated
- #pragma warning ( disable : 4610 ) // user defined constructor required
- #pragma warning ( disable : 4786 ) // debugger can't handle long symbol names
-#endif
-
-
-#include "XMPScanner.hpp"
-
-#include <cassert>
-#include <string>
-#include <cstdlib>
-
-#if DEBUG
- #include <iostream>
- #include <iomanip>
- #include <fstream>
-#endif
-
-
-#ifndef UseStringPushBack // VC++ 6.x does not provide push_back for strings!
- #define UseStringPushBack 0
-#endif
-
-
-using namespace std;
-
-
-// *** Consider Boyer-Moore style search for "<?xpacket begin=". It isn't an obvious win, the
-// *** additional code might be slower than scanning every character. Especially if we will
-// *** read every cache line anyway.
-
-
-// =================================================================================================
-// =================================================================================================
-// class PacketMachine
-// ===================
-//
-// This is the packet recognizer state machine. The top of the machine is FindNextPacket, this
-// calls the specific state components and handles transitions. The states are described by an
-// array of RecognizerInfo records, indexed by the RecognizerKind enumeration. Each RecognizerInfo
-// record has a function that does that state's work, the success and failure transition states,
-// and a string literal that is passed to the state function. The literal lets a common MatchChar
-// or MatchString function be used in several places.
-//
-// The state functions are responsible for consuming input to recognize their particular state.
-// This includes intervening nulls for 16 and 32 bit character forms. For the simplicity, things
-// are treated as essentially little endian and the nulls are not actually checked. The opening
-// '<' is found with a byte-by-byte search, then the number of bytes per character is determined
-// by counting the following nulls. From then on, consuming a character means incrementing the
-// buffer pointer by the number of bytes per character. Thus the buffer pointer only points to
-// the "real" bytes. This also means that the pointer can go off the end of the buffer by a
-// variable amount. The amount of overrun is saved so that the pointer can be positioned at the
-// right byte to start the next buffer.
-//
-// The state functions return a TriState value, eTriYes means the pattern was found, eTriNo means
-// the pattern was definitely not found, eTriMaybe means that the end of the buffer was reached
-// while working through the pattern.
-//
-// When eTriYes is returned, the fBufferPtr data member is left pointing to the "real" byte
-// following the last actual byte. Which might not be addressable memory! This also means that
-// a state function can be entered with nothing available in the buffer. When eTriNo is returned,
-// the fBufferPtr data member is left pointing to the byte that caused the failure. The state
-// machine starts over from the failure byte.
-//
-// The state functions must preserve their internal micro-state before returning eTriMaybe, and
-// resume processing when called with the next buffer. The fPosition data member is used to denote
-// how many actual characters have been consumed. The fNullCount data member is used to denote how
-// many nulls are left before the next actual character.
-
-
-// =================================================================================================
-// PacketMachine
-// =============
-
-XMPScanner::PacketMachine::PacketMachine ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength ) :
-
- // Public members
- fPacketStart ( 0 ),
- fPacketLength ( 0 ),
- fBytesAttr ( -1 ),
- fCharForm ( eChar8Bit ),
- fAccess ( ' ' ),
- fBogusPacket ( false ),
-
- // Private members
- fBufferOffset ( bufferOffset ),
- fBufferOrigin ( (const char *) bufferOrigin ),
- fBufferPtr ( fBufferOrigin ),
- fBufferLimit ( fBufferOrigin + bufferLength ),
- fRecognizer ( eLeadInRecognizer ),
- fPosition ( 0 ),
- fBytesPerChar ( 1 ),
- fBufferOverrun ( 0 ),
- fQuoteChar ( ' ' )
-
-{
- /*
- REVIEW NOTES : Should the buffer stuff be in a class?
- */
-
- assert ( bufferOrigin != NULL );
- assert ( bufferLength != 0 );
-
-} // PacketMachine
-
-
-// =================================================================================================
-// ~PacketMachine
-// ==============
-
-XMPScanner::PacketMachine::~PacketMachine ()
-{
-
- // An empty placeholder.
-
-} // ~PacketMachine
-
-
-// =================================================================================================
-// AssociateBuffer
-// ===============
-
-void
-XMPScanner::PacketMachine::AssociateBuffer ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength )
-{
-
- fBufferOffset = bufferOffset;
- fBufferOrigin = (const char *) bufferOrigin;
- fBufferPtr = fBufferOrigin + fBufferOverrun;
- fBufferLimit = fBufferOrigin + bufferLength;
-
-} // AssociateBuffer
-
-
-// =================================================================================================
-// ResetMachine
-// ============
-
-void
-XMPScanner::PacketMachine::ResetMachine ()
-{
-
- fRecognizer = eLeadInRecognizer;
- fPosition = 0;
- fBufferOverrun = 0;
- fCharForm = eChar8Bit;
- fBytesPerChar = 1;
- fAccess = ' ';
- fBytesAttr = -1;
- fBogusPacket = false;
-
- fAttrName.erase ( fAttrName.begin(), fAttrName.end() );
- fAttrValue.erase ( fAttrValue.begin(), fAttrValue.end() );
- fEncodingAttr.erase ( fEncodingAttr.begin(), fEncodingAttr.end() );
-
-} // ResetMachine
-
-
-// =================================================================================================
-// FindLessThan
-// ============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::FindLessThan ( PacketMachine * ths, const char * which )
-{
-
- if ( *which == 'H' ) {
-
- // --------------------------------------------------------------------------------
- // We're looking for the '<' of the header. If we fail there is no packet in this
- // part of the input, so return eTriNo.
-
- ths->fCharForm = eChar8Bit; // We might have just failed from a bogus 16 or 32 bit case.
- ths->fBytesPerChar = 1;
-
- while ( ths->fBufferPtr < ths->fBufferLimit ) { // Don't skip nulls for the header's '<'!
- if ( *ths->fBufferPtr == '<' ) break;
- ths->fBufferPtr++;
- }
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriNo;
- ths->fBufferPtr++;
- return eTriYes;
-
- } else {
-
- // --------------------------------------------------------------------------------
- // We're looking for the '<' of the trailer. We're already inside the packet body,
- // looking for the trailer. So here if we fail we must return eTriMaybe so that we
- // keep looking for the trailer in the next buffer.
-
- const int bytesPerChar = ths->fBytesPerChar;
-
- while ( ths->fBufferPtr < ths->fBufferLimit ) {
- if ( *ths->fBufferPtr == '<' ) break;
- ths->fBufferPtr += bytesPerChar;
- }
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
- ths->fBufferPtr += bytesPerChar;
- return eTriYes;
-
- }
-
-} // FindLessThan
-
-
-// =================================================================================================
-// MatchString
-// ===========
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::MatchString ( PacketMachine * ths, const char * literal )
-{
- const int bytesPerChar = ths->fBytesPerChar;
- const char * litPtr = literal + ths->fPosition;
- const XMP_Int32 charsToGo = (XMP_Int32) strlen ( literal ) - ths->fPosition;
- int charsDone = 0;
-
- while ( (charsDone < charsToGo) && (ths->fBufferPtr < ths->fBufferLimit) ) {
- if ( *litPtr != *ths->fBufferPtr ) return eTriNo;
- charsDone++;
- litPtr++;
- ths->fBufferPtr += bytesPerChar;
- }
-
- if ( charsDone == charsToGo ) return eTriYes;
- ths->fPosition += charsDone;
- return eTriMaybe;
-
-} // MatchString
-
-
-// =================================================================================================
-// MatchChar
-// =========
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::MatchChar ( PacketMachine * ths, const char * literal )
-{
- const int bytesPerChar = ths->fBytesPerChar;
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const char currChar = *ths->fBufferPtr;
- if ( currChar != *literal ) return eTriNo;
- ths->fBufferPtr += bytesPerChar;
- return eTriYes;
-
-} // MatchChar
-
-
-// =================================================================================================
-// MatchOpenQuote
-// ==============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const char currChar = *ths->fBufferPtr;
- if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
- ths->fQuoteChar = currChar;
- ths->fBufferPtr += bytesPerChar;
- return eTriYes;
-
-} // MatchOpenQuote
-
-
-// =================================================================================================
-// MatchCloseQuote
-// ===============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ )
-{
-
- return MatchChar ( ths, &ths->fQuoteChar );
-
-} // MatchCloseQuote
-
-
-// =================================================================================================
-// CaptureAttrName
-// ===============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::CaptureAttrName ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
- char currChar;
-
- if ( ths->fPosition == 0 ) { // Get the first character in the name.
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- currChar = *ths->fBufferPtr;
- if ( ths->fAttrName.size() == 0 ) {
- if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
- ( ('A' <= currChar) && (currChar <= 'Z') ) ||
- (currChar == '_') || (currChar == ':') ) ) {
- return eTriNo;
- }
- }
-
- ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
- #if UseStringPushBack
- ths->fAttrName.push_back ( currChar );
- #else
- ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
- #endif
- ths->fBufferPtr += bytesPerChar;
-
- }
-
- while ( ths->fBufferPtr < ths->fBufferLimit ) { // Get the remainder of the name.
-
- currChar = *ths->fBufferPtr;
- if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
- ( ('A' <= currChar) && (currChar <= 'Z') ) ||
- ( ('0' <= currChar) && (currChar <= '9') ) ||
- (currChar == '-') || (currChar == '.') || (currChar == '_') || (currChar == ':') ) ) {
- break;
- }
-
- #if UseStringPushBack
- ths->fAttrName.push_back ( currChar );
- #else
- ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
- #endif
- ths->fBufferPtr += bytesPerChar;
-
- }
-
- if ( ths->fBufferPtr < ths->fBufferLimit ) return eTriYes;
- ths->fPosition = (long) ths->fAttrName.size(); // The name might span into the next buffer.
- return eTriMaybe;
-
-} // CaptureAttrName
-
-
-// =================================================================================================
-// CaptureAttrValue
-// ================
-//
-// Recognize the equal sign and the quoted string value, capture the value along the way.
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
- char currChar = 0;
- TriState result = eTriMaybe;
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- switch ( ths->fPosition ) {
-
- case 0 : // The name should haved ended at the '=', nulls already skipped.
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
- if ( *ths->fBufferPtr != '=' ) return eTriNo;
- ths->fBufferPtr += bytesPerChar;
- ths->fPosition = 1;
- // fall through OK because MatchOpenQuote will check the buffer limit and nulls ...
-
- case 1 : // Look for the open quote.
-
- result = MatchOpenQuote ( ths, NULL );
- if ( result != eTriYes ) return result;
- ths->fPosition = 2;
- // fall through OK because the buffer limit and nulls are checked below ...
-
- default : // Look for the close quote, capturing the value along the way.
-
- assert ( ths->fPosition == 2 );
-
- const char quoteChar = ths->fQuoteChar;
-
- while ( ths->fBufferPtr < ths->fBufferLimit ) {
- currChar = *ths->fBufferPtr;
- if ( currChar == quoteChar ) break;
- #if UseStringPushBack
- ths->fAttrValue.push_back ( currChar );
- #else
- ths->fAttrValue.insert ( ths->fAttrValue.end(), currChar );
- #endif
- ths->fBufferPtr += bytesPerChar;
- }
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
- assert ( currChar == quoteChar );
- ths->fBufferPtr += bytesPerChar; // Advance past the closing quote.
- return eTriYes;
-
- }
-
-} // CaptureAttrValue
-
-
-// =================================================================================================
-// RecordStart
-// ===========
-//
-// Note that this routine looks at bytes, not logical characters. It has to figure out how many
-// bytes per character there are so that the other recognizers can skip intervening nulls.
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::RecordStart ( PacketMachine * ths, const char * /* unused */ )
-{
-
- while ( true ) {
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const char currByte = *ths->fBufferPtr;
-
- switch ( ths->fPosition ) {
-
- case 0 : // Record the length.
- assert ( ths->fCharForm == eChar8Bit );
- assert ( ths->fBytesPerChar == 1 );
- ths->fPacketStart = ths->fBufferOffset + ((ths->fBufferPtr - 1) - ths->fBufferOrigin);
- ths->fPacketLength = 0;
- ths->fPosition = 1;
- // ! OK to fall through here, we didn't consume a byte in this step.
-
- case 1 : // Look for the first null byte.
- if ( currByte != 0 ) return eTriYes; // No nulls found.
- ths->fCharForm = eChar16BitBig; // Assume 16 bit big endian for now.
- ths->fBytesPerChar = 2;
- ths->fBufferPtr++;
- ths->fPosition = 2;
- break; // ! Don't fall through, have to check for the end of the buffer between each byte.
-
- case 2 : // One null was found, look for a second.
- if ( currByte != 0 ) return eTriYes; // Just one null found.
- ths->fBufferPtr++;
- ths->fPosition = 3;
- break;
-
- case 3 : // Two nulls were found, look for a third.
- if ( currByte != 0 ) return eTriNo; // Just two nulls is not valid.
- ths->fCharForm = eChar32BitBig; // Assume 32 bit big endian for now.
- ths->fBytesPerChar = 4;
- ths->fBufferPtr++;
- return eTriYes;
- break;
-
- }
-
- }
-
-} // RecordStart
-
-
-// =================================================================================================
-// RecognizeBOM
-// ============
-//
-// Recognizing the byte order marker is a surprisingly messy thing to do. It can't be done by the
-// normal string matcher, there are no intervening nulls. There are 4 transitions after the opening
-// quote, the closing quote or one of the three encodings. For the actual BOM there are then 1 or 2
-// following bytes that depend on which of the encodings we're in. Not to mention that the buffer
-// might end at any point.
-//
-// The intervening null count done earlier determined 8, 16, or 32 bits per character, but not the
-// big or little endian nature for the 16/32 bit cases. The BOM must be present for the 16 and 32
-// bit cases in order to determine the endian mode. There are six possible byte sequences for the
-// quoted BOM string, ignoring the differences for quoting with ''' versus '"'.
-//
-// Keep in mind that for the 16 and 32 bit cases there will be nulls for the quote. In the table
-// below the symbol <quote> means just the one byte containing the ''' or '"'. The nulls for the
-// quote character are explicitly shown.
-//
-// <quote> <quote> - 1: No BOM, this must be an 8 bit case.
-// <quote> \xEF \xBB \xBF <quote> - 1.12-13: The 8 bit form.
-//
-// <quote> \xFE \xFF \x00 <quote> - 1.22-23: The 16 bit, big endian form
-// <quote> \x00 \xFF \xFE <quote> - 1.32-33: The 16 bit, little endian form.
-//
-// <quote> \x00 \x00 \xFE \xFF \x00 \x00 \x00 <quote> - 1.32.43-45.56-57: The 32 bit, big endian form.
-// <quote> \x00 \x00 \x00 \xFF \xFE \x00 \x00 <quote> - 1.32.43.54-57: The 32 bit, little endian form.
-
-enum {
- eBOM_8_1 = 0xEF,
- eBOM_8_2 = 0xBB,
- eBOM_8_3 = 0xBF,
- eBOM_Big_1 = 0xFE,
- eBOM_Big_2 = 0xFF,
- eBOM_Little_1 = eBOM_Big_2,
- eBOM_Little_2 = eBOM_Big_1
-};
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::RecognizeBOM ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
-
- while ( true ) { // Handle one character at a time, the micro-state (fPosition) changes for each.
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const unsigned char currChar = *ths->fBufferPtr; // ! The BOM bytes look like integers bigger than 127.
-
- switch ( ths->fPosition ) {
-
- case 0 : // Look for the opening quote.
- if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
- ths->fQuoteChar = currChar;
- ths->fBufferPtr++;
- ths->fPosition = 1;
- break; // ! Don't fall through, have to check for the end of the buffer between each byte.
-
- case 1 : // Look at the byte immediately following the opening quote.
- if ( currChar == ths->fQuoteChar ) { // Closing quote, no BOM character, must be 8 bit.
- if ( ths->fCharForm != eChar8Bit ) return eTriNo;
- ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
- return eTriYes;
- } else if ( currChar == eBOM_8_1 ) { // Start of the 8 bit form.
- if ( ths->fCharForm != eChar8Bit ) return eTriNo;
- ths->fBufferPtr++;
- ths->fPosition = 12;
- } else if ( currChar == eBOM_Big_1 ) { // Start of the 16 bit big endian form.
- if ( ths->fCharForm != eChar16BitBig ) return eTriNo;
- ths->fBufferPtr++;
- ths->fPosition = 22;
- } else if ( currChar == 0 ) { // Start of the 16 bit little endian or either 32 bit form.
- if ( ths->fCharForm == eChar8Bit ) return eTriNo;
- ths->fBufferPtr++;
- ths->fPosition = 32;
- } else {
- return eTriNo;
- }
- break;
-
- case 12 : // Look for the second byte of the 8 bit form.
- if ( currChar != eBOM_8_2 ) return eTriNo;
- ths->fPosition = 13;
- ths->fBufferPtr++;
- break;
-
- case 13 : // Look for the third byte of the 8 bit form.
- if ( currChar != eBOM_8_3 ) return eTriNo;
- ths->fPosition = 99;
- ths->fBufferPtr++;
- break;
-
- case 22 : // Look for the second byte of the 16 bit big endian form.
- if ( currChar != eBOM_Big_2 ) return eTriNo;
- ths->fPosition = 23;
- ths->fBufferPtr++;
- break;
-
- case 23 : // Look for the null before the closing quote of the 16 bit big endian form.
- if ( currChar != 0 ) return eTriNo;
- ths->fBufferPtr++;
- ths->fPosition = 99;
- break;
-
- case 32 : // Look at the second byte of the 16 bit little endian or either 32 bit form.
- if ( currChar == eBOM_Little_1 ) {
- ths->fPosition = 33;
- } else if ( currChar == 0 ) {
- ths->fPosition = 43;
- } else {
- return eTriNo;
- }
- ths->fBufferPtr++;
- break;
-
- case 33 : // Look for the third byte of the 16 bit little endian form.
- if ( ths->fCharForm != eChar16BitBig ) return eTriNo; // Null count before assumed big endian.
- if ( currChar != eBOM_Little_2 ) return eTriNo;
- ths->fCharForm = eChar16BitLittle;
- ths->fPosition = 99;
- ths->fBufferPtr++;
- break;
-
- case 43 : // Look at the third byte of either 32 bit form.
- if ( ths->fCharForm != eChar32BitBig ) return eTriNo; // Null count before assumed big endian.
- if ( currChar == eBOM_Big_1 ) {
- ths->fPosition = 44;
- } else if ( currChar == 0 ) {
- ths->fPosition = 54;
- } else {
- return eTriNo;
- }
- ths->fBufferPtr++;
- break;
-
- case 44 : // Look for the fourth byte of the 32 bit big endian form.
- if ( currChar != eBOM_Big_2 ) return eTriNo;
- ths->fPosition = 45;
- ths->fBufferPtr++;
- break;
-
- case 45 : // Look for the first null before the closing quote of the 32 bit big endian form.
- if ( currChar != 0 ) return eTriNo;
- ths->fPosition = 56;
- ths->fBufferPtr++;
- break;
-
- case 54 : // Look for the fourth byte of the 32 bit little endian form.
- ths->fCharForm = eChar32BitLittle;
- if ( currChar != eBOM_Little_1 ) return eTriNo;
- ths->fPosition = 55;
- ths->fBufferPtr++;
- break;
-
- case 55 : // Look for the fifth byte of the 32 bit little endian form.
- if ( currChar != eBOM_Little_2 ) return eTriNo;
- ths->fPosition = 56;
- ths->fBufferPtr++;
- break;
-
- case 56 : // Look for the next to last null before the closing quote of the 32 bit forms.
- if ( currChar != 0 ) return eTriNo;
- ths->fPosition = 57;
- ths->fBufferPtr++;
- break;
-
- case 57 : // Look for the last null before the closing quote of the 32 bit forms.
- if ( currChar != 0 ) return eTriNo;
- ths->fPosition = 99;
- ths->fBufferPtr++;
- break;
-
- default : // Look for the closing quote.
- assert ( ths->fPosition == 99 );
- if ( currChar != ths->fQuoteChar ) return eTriNo;
- ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
- return eTriYes;
- break;
-
- }
-
- }
-
-} // RecognizeBOM
-
-
-// =================================================================================================
-// RecordHeadAttr
-// ==============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ )
-{
-
- if ( ths->fAttrName == "encoding" ) {
-
- assert ( ths->fEncodingAttr.empty() );
- ths->fEncodingAttr = ths->fAttrValue;
-
- } else if ( ths->fAttrName == "bytes" ) {
-
- long value = 0;
- int count = (int) ths->fAttrValue.size();
- int i;
-
- assert ( ths->fBytesAttr == -1 );
-
- if ( count > 0 ) { // Allow bytes='' to be the same as no bytes attribute.
-
- for ( i = 0; i < count; i++ ) {
- const char currChar = ths->fAttrValue[i];
- if ( ('0' <= currChar) && (currChar <= '9') ) {
- value = (value * 10) + (currChar - '0');
- } else {
- ths->fBogusPacket = true;
- value = -1;
- break;
- }
- }
- ths->fBytesAttr = value;
-
- if ( CharFormIs16Bit ( ths->fCharForm ) ) {
- if ( (ths->fBytesAttr & 1) != 0 ) ths->fBogusPacket = true;
- } else if ( CharFormIs32Bit ( ths->fCharForm ) ) {
- if ( (ths->fBytesAttr & 3) != 0 ) ths->fBogusPacket = true;
- }
-
- }
-
- }
-
- ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
- ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
-
- return eTriYes;
-
-} // RecordHeadAttr
-
-
-// =================================================================================================
-// CaptureAccess
-// =============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::CaptureAccess ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
-
- while ( true ) {
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const char currChar = *ths->fBufferPtr;
-
- switch ( ths->fPosition ) {
-
- case 0 : // Look for the opening quote.
- if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
- ths->fQuoteChar = currChar;
- ths->fBufferPtr += bytesPerChar;
- ths->fPosition = 1;
- break; // ! Don't fall through, have to check for the end of the buffer between each byte.
-
- case 1 : // Look for the 'r' or 'w'.
- if ( (currChar != 'r') && (currChar != 'w') ) return eTriNo;
- ths->fAccess = currChar;
- ths->fBufferPtr += bytesPerChar;
- ths->fPosition = 2;
- break;
-
- default : // Look for the closing quote.
- assert ( ths->fPosition == 2 );
- if ( currChar != ths->fQuoteChar ) return eTriNo;
- ths->fBufferPtr += bytesPerChar;
- return eTriYes;
- break;
-
- }
-
- }
-
-} // CaptureAccess
-
-
-// =================================================================================================
-// RecordTailAttr
-// ==============
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::RecordTailAttr ( PacketMachine * ths, const char * /* unused */ )
-{
-
- // There are no known "general" attributes for the packet trailer.
-
- ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
- ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
-
- return eTriYes;
-
-
-} // RecordTailAttr
-
-
-// =================================================================================================
-// CheckPacketEnd
-// ==============
-//
-// Check for trailing padding and record the packet length. We have trailing padding if the bytes
-// attribute is present and has a value greater than the current length.
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ )
-{
- const int bytesPerChar = ths->fBytesPerChar;
-
- if ( ths->fPosition == 0 ) { // First call, decide if there is trailing padding.
-
- const XMP_Int64 currLen64 = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
- if ( currLen64 > 0x7FFFFFFF ) throw std::runtime_error ( "Packet length exceeds 2GB-1" );
- const XMP_Int32 currLength = (XMP_Int32)currLen64;
-
- if ( (ths->fBytesAttr != -1) && (ths->fBytesAttr != currLength) ) {
- if ( ths->fBytesAttr < currLength ) {
- ths->fBogusPacket = true; // The bytes attribute value is too small.
- } else {
- ths->fPosition = ths->fBytesAttr - currLength;
- if ( (ths->fPosition % ths->fBytesPerChar) != 0 ) {
- ths->fBogusPacket = true; // The padding is not a multiple of the character size.
- ths->fPosition = (ths->fPosition / ths->fBytesPerChar) * ths->fBytesPerChar;
- }
- }
- }
-
- }
-
- while ( ths->fPosition > 0 ) {
-
- if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
-
- const char currChar = *ths->fBufferPtr;
-
- if ( (currChar != ' ') && (currChar != '\t') && (currChar != '\n') && (currChar != '\r') ) {
- ths->fBogusPacket = true; // The padding is not whitespace.
- break; // Stop the packet here.
- }
-
- ths->fPosition -= bytesPerChar;
- ths->fBufferPtr += bytesPerChar;
-
- }
-
- const XMP_Int64 currLen64 = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
- if ( currLen64 > 0x7FFFFFFF ) throw std::runtime_error ( "Packet length exceeds 2GB-1" );
- ths->fPacketLength = (XMP_Int32)currLen64;
- return eTriYes;
-
-} // CheckPacketEnd
-
-
-// =================================================================================================
-// CheckFinalNulls
-// ===============
-//
-// Do some special case processing for little endian characters. We have to make sure the presumed
-// nulls after the last character actually exist, i.e. that the stream does not end too soon. Note
-// that the prior character scanning has moved the buffer pointer to the address following the last
-// byte of the last character. I.e. we're already past the presumed nulls, so we can't check their
-// content. All we can do is verify that the stream does not end too soon.
-//
-// Doing this check is simple yet subtle. If we're still in the current buffer then the trailing
-// bytes obviously exist. If we're exactly at the end of the buffer then the bytes also exist.
-// The only question is when we're actually past this buffer, partly into the next buffer. This is
-// when "ths->fBufferPtr > ths->fBufferLimit" on entry. For that case we have to wait until we've
-// actually seen enough extra bytes of input.
-//
-// Since the normal buffer processing is already adjusting for this partial character overrun, all
-// that needs to be done here is wait until "ths->fBufferPtr <= ths->fBufferLimit" on entry. In
-// other words, if we're presently too far, ths->fBufferPtr will be adjusted by the amount of the
-// overflow the next time XMPScanner::Scan is called. This might still be too far, so just keep
-// waiting for enough data to pass by.
-//
-// Note that there is a corresponding special case for big endian characters, we must decrement the
-// starting offset by the number of leading nulls. But we don't do that here, we leave it to the
-// outer code. This is because the leading nulls might have been at the exact end of a previous
-// buffer, in which case we have to also decrement the length of that raw data snip.
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ )
-{
-
- if ( (ths->fCharForm != eChar8Bit) && CharFormIsLittleEndian ( ths->fCharForm ) ) {
- if ( ths->fBufferPtr > ths->fBufferLimit ) return eTriMaybe;
- }
-
- return eTriYes;
-
-} // CheckFinalNulls
-
-
-// =================================================================================================
-// SetNextRecognizer
-// =================
-
-void
-XMPScanner::PacketMachine::SetNextRecognizer ( RecognizerKind nextRecognizer )
-{
-
- fRecognizer = nextRecognizer;
- fPosition = 0;
-
-} // SetNextRecognizer
-
-
-// =================================================================================================
-// FindNextPacket
-// ==============
-
-// *** When we start validating intervening nulls for 2 and 4 bytes characters, throw an exception
-// *** for errors. Don't return eTriNo, that might skip at an optional point.
-
-XMPScanner::PacketMachine::TriState
-XMPScanner::PacketMachine::FindNextPacket ()
-{
-
- TriState status;
-
- #define kPacketHead "?xpacket begin="
- #define kPacketID "W5M0MpCehiHzreSzNTczkc9d"
- #define kPacketTail "?xpacket end="
-
- static const RecognizerInfo recognizerTable [eRecognizerCount] = { // ! Would be safer to assign these explicitly.
-
- // proc successNext failureNext literal
-
- { NULL, eFailureRecognizer, eFailureRecognizer, NULL}, // eFailureRecognizer
- { NULL, eSuccessRecognizer, eSuccessRecognizer, NULL}, // eSuccessRecognizer
-
- { FindLessThan, eHeadStartRecorder, eFailureRecognizer, "H" }, // eLeadInRecognizer
- { RecordStart, eHeadStartRecognizer, eLeadInRecognizer, NULL }, // eHeadStartRecorder
- { MatchString, eBOMRecognizer, eLeadInRecognizer, kPacketHead }, // eHeadStartRecognizer
-
- { RecognizeBOM, eIDTagRecognizer, eLeadInRecognizer, NULL }, // eBOMRecognizer
-
- { MatchString, eIDOpenRecognizer, eLeadInRecognizer, " id=" }, // eIDTagRecognizer
- { MatchOpenQuote, eIDValueRecognizer, eLeadInRecognizer, NULL }, // eIDOpenRecognizer
- { MatchString, eIDCloseRecognizer, eLeadInRecognizer, kPacketID }, // eIDValueRecognizer
- { MatchCloseQuote, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eIDCloseRecognizer
-
- { MatchChar, eAttrNameRecognizer_1, eHeadEndRecognizer, " " }, // eAttrSpaceRecognizer_1
- { CaptureAttrName, eAttrValueRecognizer_1, eLeadInRecognizer, NULL }, // eAttrNameRecognizer_1
- { CaptureAttrValue, eAttrValueRecorder_1, eLeadInRecognizer, NULL }, // eAttrValueRecognizer_1
- { RecordHeadAttr, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eAttrValueRecorder_1
-
- { MatchString, eBodyRecognizer, eLeadInRecognizer, "?>" }, // eHeadEndRecognizer
-
- { FindLessThan, eTailStartRecognizer, eBodyRecognizer, "T"}, // eBodyRecognizer
-
- { MatchString, eAccessValueRecognizer, eBodyRecognizer, kPacketTail }, // eTailStartRecognizer
- { CaptureAccess, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAccessValueRecognizer
-
- { MatchChar, eAttrNameRecognizer_2, eTailEndRecognizer, " " }, // eAttrSpaceRecognizer_2
- { CaptureAttrName, eAttrValueRecognizer_2, eBodyRecognizer, NULL }, // eAttrNameRecognizer_2
- { CaptureAttrValue, eAttrValueRecorder_2, eBodyRecognizer, NULL }, // eAttrValueRecognizer_2
- { RecordTailAttr, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAttrValueRecorder_2
-
- { MatchString, ePacketEndRecognizer, eBodyRecognizer, "?>" }, // eTailEndRecognizer
- { CheckPacketEnd, eCloseOutRecognizer, eBodyRecognizer, "" }, // ePacketEndRecognizer
- { CheckFinalNulls, eSuccessRecognizer, eBodyRecognizer, "" } // eCloseOutRecognizer
-
- };
-
- while ( true ) {
-
- switch ( fRecognizer ) {
-
- case eFailureRecognizer :
- return eTriNo;
-
- case eSuccessRecognizer :
- return eTriYes;
-
- default :
-
- // -------------------------------------------------------------------
- // For everything else, the normal cases, use the state machine table.
-
- const RecognizerInfo * thisState = &recognizerTable [fRecognizer];
-
- status = thisState->proc ( this, thisState->literal );
-
- switch ( status ) {
-
- case eTriNo :
- SetNextRecognizer ( thisState->failureNext );
- continue;
-
- case eTriYes :
- SetNextRecognizer ( thisState->successNext );
- continue;
-
- case eTriMaybe :
- fBufferOverrun = (unsigned char)(fBufferPtr - fBufferLimit);
- return eTriMaybe; // Keep this recognizer intact, to be resumed later.
-
- }
-
- } // switch ( fRecognizer ) { ...
-
- } // while ( true ) { ...
-
-} // FindNextPacket
-
-
-// =================================================================================================
-// =================================================================================================
-// class InternalSnip
-// ==================
-
-
-// =================================================================================================
-// InternalSnip
-// ============
-
-XMPScanner::InternalSnip::InternalSnip ( XMP_Int64 offset, XMP_Int64 length )
-{
-
- fInfo.fOffset = offset;
- fInfo.fLength = length;
-
-} // InternalSnip
-
-
-// =================================================================================================
-// InternalSnip
-// ============
-
-XMPScanner::InternalSnip::InternalSnip ( const InternalSnip & rhs ) :
- fInfo ( rhs.fInfo ),
- fMachine ( NULL )
-{
-
- assert ( rhs.fMachine.get() == NULL ); // Don't copy a snip with a machine.
- assert ( (rhs.fInfo.fEncodingAttr == 0) || (*rhs.fInfo.fEncodingAttr == 0) ); // Don't copy a snip with an encoding.
-
-} // InternalSnip
-
-
-// =================================================================================================
-// ~InternalSnip
-// =============
-
-XMPScanner::InternalSnip::~InternalSnip ()
-{
-} // ~InternalSnip
-
-
-
-// =================================================================================================
-// =================================================================================================
-// class XMPScanner
-// ================
-
-
-// =================================================================================================
-// DumpSnipList
-// ============
-
-#if DEBUG
-
-static const char * snipStateName [6] = { "not-seen", "pending", "raw-data", "good-packet", "partial", "bad-packet" };
-
-void
-XMPScanner::DumpSnipList ( const char * title )
-{
- InternalSnipIterator currPos = fInternalSnips.begin();
- InternalSnipIterator endPos = fInternalSnips.end();
-
- cout << endl << title << " snip list: " << fInternalSnips.size() << endl;
-
- for ( ; currPos != endPos; ++currPos ) {
- SnipInfo * currSnip = &currPos->fInfo;
- cout << '\t' << currSnip << ' ' << snipStateName[currSnip->fState] << ' '
- << currSnip->fOffset << ".." << (currSnip->fOffset + currSnip->fLength - 1)
- << ' ' << currSnip->fLength << ' ' << endl;
- }
-} // DumpSnipList
-
-#endif
-
-
-// =================================================================================================
-// PrevSnip and NextSnip
-// =====================
-
-XMPScanner::InternalSnipIterator
-XMPScanner::PrevSnip ( InternalSnipIterator snipPos )
-{
-
- InternalSnipIterator prev = snipPos;
- return --prev;
-
-} // PrevSnip
-
-XMPScanner::InternalSnipIterator
-XMPScanner::NextSnip ( InternalSnipIterator snipPos )
-{
-
- InternalSnipIterator next = snipPos;
- return ++next;
-
-} // NextSnip
-
-
-// =================================================================================================
-// XMPScanner
-// ==========
-//
-// Initialize the scanner object with one "not seen" snip covering the whole stream.
-
-XMPScanner::XMPScanner ( XMP_Int64 streamLength ) :
-
- fStreamLength ( streamLength )
-
-{
- InternalSnip rootSnip ( 0, streamLength );
-
- if ( streamLength > 0 ) fInternalSnips.push_front ( rootSnip ); // Be nice for empty files.
- // DumpSnipList ( "New XMPScanner" );
-
-} // XMPScanner
-
-
-// =================================================================================================
-// ~XMPScanner
-// ===========
-
-XMPScanner::~XMPScanner()
-{
-
-} // ~XMPScanner
-
-
-// =================================================================================================
-// GetSnipCount
-// ============
-
-long
-XMPScanner::GetSnipCount ()
-{
-
- return (long)fInternalSnips.size();
-
-} // GetSnipCount
-
-
-// =================================================================================================
-// StreamAllScanned
-// ================
-
-bool
-XMPScanner::StreamAllScanned ()
-{
- InternalSnipIterator currPos = fInternalSnips.begin();
- InternalSnipIterator endPos = fInternalSnips.end();
-
- for ( ; currPos != endPos; ++currPos ) {
- if ( currPos->fInfo.fState == eNotSeenSnip ) return false;
- }
- return true;
-
-} // StreamAllScanned
-
-
-// =================================================================================================
-// SplitInternalSnip
-// =================
-//
-// Split the given snip into up to 3 pieces. The new pieces are inserted before and after this one
-// in the snip list. The relOffset is the first byte to be kept, it is relative to this snip. If
-// the preceeding or following snips have the same state as this one, just shift the boundaries.
-// I.e. move the contents from one snip to the other, don't create a new snip.
-
-// *** To be thread safe we ought to lock the entire list during manipulation. Let data scanning
-// *** happen in parallel, serialize all mucking with the list.
-
-void
-XMPScanner::SplitInternalSnip ( InternalSnipIterator snipPos, XMP_Int64 relOffset, XMP_Int64 newLength )
-{
-
- assert ( (relOffset + newLength) > relOffset ); // Check for overflow.
- assert ( (relOffset + newLength) <= snipPos->fInfo.fLength );
-
- // -----------------------------------
- // First deal with the low offset end.
-
- if ( relOffset > 0 ) {
-
- InternalSnipIterator prevPos;
- if ( snipPos != fInternalSnips.begin() ) prevPos = PrevSnip ( snipPos );
-
- if ( (snipPos != fInternalSnips.begin()) && (snipPos->fInfo.fState == prevPos->fInfo.fState) ) {
- prevPos->fInfo.fLength += relOffset; // Adjust the preceeding snip.
- } else {
- InternalSnip headExcess ( snipPos->fInfo.fOffset, relOffset );
- headExcess.fInfo.fState = snipPos->fInfo.fState;
- headExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
- fInternalSnips.insert ( snipPos, headExcess ); // Insert the head piece before the middle piece.
- }
-
- snipPos->fInfo.fOffset += relOffset; // Adjust the remainder of this snip.
- snipPos->fInfo.fLength -= relOffset;
-
- }
-
- // ----------------------------------
- // Now deal with the high offset end.
-
- if ( newLength < snipPos->fInfo.fLength ) {
-
- InternalSnipIterator nextPos = NextSnip ( snipPos );
- const XMP_Int64 tailLength = snipPos->fInfo.fLength - newLength;
-
- if ( (nextPos != fInternalSnips.end()) && (snipPos->fInfo.fState == nextPos->fInfo.fState) ) {
- nextPos->fInfo.fOffset -= tailLength; // Adjust the following snip.
- nextPos->fInfo.fLength += tailLength;
- } else {
- InternalSnip tailExcess ( (snipPos->fInfo.fOffset + newLength), tailLength );
- tailExcess.fInfo.fState = snipPos->fInfo.fState;
- tailExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
- fInternalSnips.insert ( nextPos, tailExcess ); // Insert the tail piece after the middle piece.
- }
-
- snipPos->fInfo.fLength = newLength;
-
- }
-
-} // SplitInternalSnip
-
-
-// =================================================================================================
-// MergeInternalSnips
-// ==================
-
-XMPScanner::InternalSnipIterator
-XMPScanner::MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos )
-{
-
- firstPos->fInfo.fLength += secondPos->fInfo.fLength;
- fInternalSnips.erase ( secondPos );
- return firstPos;
-
-} // MergeInternalSnips
-
-
-// =================================================================================================
-// Scan
-// ====
-
-void
-XMPScanner::Scan ( const void * bufferOrigin, XMP_Int64 bufferOffset, XMP_Int64 bufferLength )
-{
- XMP_Int64 relOffset;
-
- #if 0
- cout << "Scan: @ " << bufferOrigin << ", " << bufferOffset << ", " << bufferLength << endl;
- #endif
-
- if ( bufferLength == 0 ) return;
-
- // ----------------------------------------------------------------
- // These comparisons are carefully done to avoid overflow problems.
-
- if ( (bufferOffset >= fStreamLength) ||
- (bufferLength > (fStreamLength - bufferOffset)) ||
- (bufferOrigin == 0) ) {
- throw ScanError ( "Bad origin, offset, or length" );
- }
-
- // ----------------------------------------------------------------------------------------------
- // This buffer must be within a not-seen snip. Find it and split it. The first snip whose whose
- // end is beyond the buffer must be the enclosing one.
-
- // *** It would be friendly for rescans for out of order problems to accept any buffer postion.
-
- const XMP_Int64 endOffset = bufferOffset + bufferLength - 1;
- InternalSnipIterator snipPos = fInternalSnips.begin();
-
- while ( endOffset > (snipPos->fInfo.fOffset + snipPos->fInfo.fLength - 1) ) ++ snipPos;
- if ( snipPos->fInfo.fState != eNotSeenSnip ) throw ScanError ( "Already seen" );
-
- relOffset = bufferOffset - snipPos->fInfo.fOffset;
- if ( (relOffset + bufferLength) > snipPos->fInfo.fLength ) throw ScanError ( "Not within existing snip" );
-
- SplitInternalSnip ( snipPos, relOffset, bufferLength ); // *** If sequential & prev is partial, just tack on,
-
- // --------------------------------------------------------
- // Merge this snip with the preceeding snip if appropriate.
-
- // *** When out of order I/O is supported we have to do something about buffers who's predecessor is not seen.
-
- if ( snipPos->fInfo.fOffset > 0 ) {
- InternalSnipIterator prevPos = PrevSnip ( snipPos );
- if ( prevPos->fInfo.fState == ePartialPacketSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
- }
-
- // ----------------------------------
- // Look for packets within this snip.
-
- snipPos->fInfo.fState = ePendingSnip;
- PacketMachine* thisMachine = snipPos->fMachine.get();
- // DumpSnipList ( "Before scan" );
-
- if ( thisMachine != 0 ) {
- thisMachine->AssociateBuffer ( bufferOffset, bufferOrigin, bufferLength );
- } else {
- // *** snipPos->fMachine.reset ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) ); VC++ lacks reset
- #if 0
- snipPos->fMachine = auto_ptr<PacketMachine> ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) );
- #else
- {
- // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
- PacketMachine * pm = new PacketMachine ( bufferOffset, bufferOrigin, bufferLength );
- auto_ptr<PacketMachine> ap ( pm );
- snipPos->fMachine = ap;
- }
- #endif
- thisMachine = snipPos->fMachine.get();
- }
-
- bool bufferDone = false;
- while ( ! bufferDone ) {
-
- PacketMachine::TriState foundPacket = thisMachine->FindNextPacket();
-
- if ( foundPacket == PacketMachine::eTriNo ) {
-
- // -----------------------------------------------------------------------
- // No packet, mark the snip as raw data and get rid of the packet machine.
- // We're done with this buffer.
-
- snipPos->fInfo.fState = eRawInputSnip;
- #if 0
- snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
- #else
- {
- // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
- auto_ptr<PacketMachine> ap ( 0 );
- snipPos->fMachine = ap;
- }
- #endif
- bufferDone = true;
-
- } else {
-
- // ---------------------------------------------------------------------------------------------
- // Either a full or partial packet. First trim any excess off of the front as a raw input snip.
- // If this is a partial packet mark the snip and keep the packet machine to be resumed later.
- // We're done with this buffer, the partial packet by definition extends to the end. If this is
- // a complete packet first extract the additional information from the packet machine. If there
- // is leftover data split the snip and transfer the packet machine to the new trailing snip.
-
- if ( thisMachine->fPacketStart > snipPos->fInfo.fOffset ) {
-
- // There is data at the front of the current snip that must be trimmed.
- SnipState savedState = snipPos->fInfo.fState;
- snipPos->fInfo.fState = eRawInputSnip; // ! So it gets propagated to the trimmed front part.
- relOffset = thisMachine->fPacketStart - snipPos->fInfo.fOffset;
- SplitInternalSnip ( snipPos, relOffset, (snipPos->fInfo.fLength - relOffset) );
- snipPos->fInfo.fState = savedState;
-
- }
-
- if ( foundPacket == PacketMachine::eTriMaybe ) {
-
- // We have only found a partial packet.
- snipPos->fInfo.fState = ePartialPacketSnip;
- bufferDone = true;
-
- } else {
-
- // We have found a complete packet. Extract all the info for it and split any trailing data.
-
- InternalSnipIterator packetSnip = snipPos;
- SnipState packetState = eValidPacketSnip;
-
- if ( thisMachine->fBogusPacket ) packetState = eBadPacketSnip;
-
- packetSnip->fInfo.fAccess = thisMachine->fAccess;
- packetSnip->fInfo.fCharForm = thisMachine->fCharForm;
- packetSnip->fInfo.fBytesAttr = thisMachine->fBytesAttr;
- packetSnip->fInfo.fEncodingAttr = thisMachine->fEncodingAttr.c_str();
- thisMachine->fEncodingAttr.erase ( thisMachine->fEncodingAttr.begin(), thisMachine->fEncodingAttr.end() );
-
- if ( (thisMachine->fCharForm != eChar8Bit) && CharFormIsBigEndian ( thisMachine->fCharForm ) ) {
-
- // ------------------------------------------------------------------------------
- // Handle a special case for big endian characters. The packet machine works as
- // though things were little endian. The packet starting offset points to the
- // byte containing the opening '<', and the length includes presumed nulls that
- // follow the last "real" byte. If the characters are big endian we now have to
- // decrement the starting offset of the packet, and also decrement the length of
- // the previous snip.
- //
- // Note that we can't do this before the head trimming above in general. The
- // nulls might have been exactly at the end of a buffer and already in the
- // previous snip. We are doing this before trimming the tail from the raw snip
- // containing the packet. We adjust the raw snip's size because it ends with
- // the input buffer. We don't adjust the packet's size, it is already correct.
- //
- // The raw snip (the one before the packet) might entirely disappear. A simple
- // example of this is when the packet is at the start of the file.
-
- assert ( packetSnip != fInternalSnips.begin() ); // Leading nulls were trimmed!
-
- if ( packetSnip != fInternalSnips.begin() ) { // ... but let's program defensibly.
-
- InternalSnipIterator prevSnip = PrevSnip ( packetSnip );
- const unsigned int nullsToAdd = ( CharFormIs16Bit ( thisMachine->fCharForm ) ? 1 : 3 );
-
- assert ( nullsToAdd <= prevSnip->fInfo.fLength );
- prevSnip->fInfo.fLength -= nullsToAdd;
- if ( prevSnip->fInfo.fLength == 0 ) (void) fInternalSnips.erase ( prevSnip );
-
- packetSnip->fInfo.fOffset -= nullsToAdd;
- packetSnip->fInfo.fLength += nullsToAdd;
- thisMachine->fPacketStart -= nullsToAdd;
-
- }
-
- }
-
- if ( thisMachine->fPacketLength == snipPos->fInfo.fLength ) {
-
- // This packet ends exactly at the end of the current snip.
- #if 0
- snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
- #else
- {
- // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
- auto_ptr<PacketMachine> ap ( 0 );
- snipPos->fMachine = ap;
- }
- #endif
- bufferDone = true;
-
- } else {
-
- // There is trailing data to split from the just found packet.
- SplitInternalSnip ( snipPos, 0, thisMachine->fPacketLength );
-
- InternalSnipIterator tailPos = NextSnip ( snipPos );
-
- tailPos->fMachine = snipPos->fMachine; // auto_ptr assignment - taking ownership
- thisMachine->ResetMachine ();
-
- snipPos = tailPos;
-
- }
-
- packetSnip->fInfo.fState = packetState; // Do this last to avoid messing up the tail split.
- // DumpSnipList ( "Found a packet" );
-
-
- }
-
- }
-
- }
-
- // --------------------------------------------------------
- // Merge this snip with the preceeding snip if appropriate.
-
- // *** When out of order I/O is supported we have to check the following snip too.
-
- if ( (snipPos->fInfo.fOffset > 0) && (snipPos->fInfo.fState == eRawInputSnip) ) {
- InternalSnipIterator prevPos = PrevSnip ( snipPos );
- if ( prevPos->fInfo.fState == eRawInputSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
- }
-
- // DumpSnipList ( "After scan" );
-
-} // Scan
-
-
-// =================================================================================================
-// Report
-// ======
-
-void
-XMPScanner::Report ( SnipInfoVector& snips )
-{
- const int count = (int)fInternalSnips.size();
- InternalSnipIterator snipPos = fInternalSnips.begin();
-
- int s;
-
- // DumpSnipList ( "Report" );
-
- snips.erase ( snips.begin(), snips.end() ); // ! Should use snips.clear, but VC++ doesn't have it.
- snips.reserve ( count );
-
- for ( s = 0; s < count; s += 1 ) {
- snips.push_back ( SnipInfo ( snipPos->fInfo.fState, snipPos->fInfo.fOffset, snipPos->fInfo.fLength ) );
- snips[s] = snipPos->fInfo; // Pick up all of the fields.
- ++ snipPos;
- }
-
-} // Report
diff --git a/source/XMPFiles/FormatSupport/XMPScanner.hpp b/source/XMPFiles/FormatSupport/XMPScanner.hpp
deleted file mode 100644
index 472a43e..0000000
--- a/source/XMPFiles/FormatSupport/XMPScanner.hpp
+++ /dev/null
@@ -1,330 +0,0 @@
-#ifndef __XMPScanner_hpp__
-#define __XMPScanner_hpp__
-
-// =================================================================================================
-// Copyright 2004 Adobe Systems Incorporated
-// All Rights Reserved.
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-//
-// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
-// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include.
-
-#include <list>
-#include <vector>
-#include <string>
-#include <memory>
-#include <stdexcept>
-
-#include "XMP_Const.h"
-
-// =================================================================================================
-// The XMPScanner class is used to scan a stream of input for XMP packets. A scanner object is
-// constructed then fed the input through a series of calls to Scan. Report may be called at any
-// time to get the current knowledge of the input.
-//
-// A packet starts when a valid header is found and ends when a valid trailer is found. If the
-// header contains a "bytes" attribute, additional whitespace must follow.
-//
-// *** RESTRICTIONS: The current implementation of the scanner has the the following restrictions:
-// - The input must be presented in order.
-// - Not fully thread safe, don't make concurrent calls to the same XMPScanner object.
-// =================================================================================================
-
-class XMPScanner {
-public:
-
- // =============================================================================================
- // The entire input stream is represented as a series of snips. Each snip defines one portion
- // of the input stream that either has not been seen, has been seen and contains no packets, is
- // exactly one packet, or contains the start of an unfinished packet. Adjacent snips with the
- // same state are merged, so the number of snips is always minimal.
- //
- // A newly constructed XMPScanner object has one snip covering the whole input with a state
- // of "not seen". A block of input that contains a full XMP packet is split into 3 parts: a
- // (possibly empty) raw input snip, the packet, and another (possibly empty) raw input snip. A
- // block of input that contains the start of an XMP packet is split into two snips, a (possibly
- // empty) raw input snip and the packet start; the following snip must be a "not seen" snip.
- //
- // It is possible to have ill-formed packets. These have a syntactically valid header and
- // trailer, but some semantic error. For example, if the "bytes" attribute length does not span
- // to the end of the trailer, or if the following packet begins within trailing padding.
-
- enum {
- eNotSeenSnip, // This snip has not been seen yet.
- ePendingSnip, // This snip is an input buffer being processed.
- eRawInputSnip, // This snip is raw input, it doesn't contain any part of an XMP packet.
- eValidPacketSnip, // This snip is a complete, valid XMP packet.
- ePartialPacketSnip, // This snip contains the start of a possible XMP packet.
- eBadPacketSnip // This snip contains a complete, but semantically incorrect XMP packet.
- };
- typedef XMP_Uns8 SnipState;
-
- enum { // The values allow easy testing for 16/32 bit and big/little endian.
- eChar8Bit = 0,
- eChar16BitBig = 2,
- eChar16BitLittle = 3,
- eChar32BitBig = 4,
- eChar32BitLittle = 5
- };
- typedef XMP_Uns8 CharacterForm;
-
- enum {
- eChar16BitMask = 2, // These constant shouldn't be used directly, they are mainly
- eChar32BitMask = 4, // for the CharFormIsXyz macros below.
- eCharLittleEndianMask = 1
- };
-
- #define CharFormIs16Bit(f) ( ((int)(f) & XMPScanner::eChar16BitMask) != 0 )
- #define CharFormIs32Bit(f) ( ((int)(f) & XMPScanner::eChar32BitMask) != 0 )
-
- #define CharFormIsBigEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) == 0 )
- #define CharFormIsLittleEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) != 0 )
-
- struct SnipInfo {
-
- XMP_Int64 fOffset; // The byte offset of this snip within the input stream.
- XMP_Int64 fLength; // The length in bytes of this snip.
- SnipState fState; // The state of this snip.
- bool fOutOfOrder; // If true, this snip was seen before the one in front of it.
- char fAccess; // The read-only/read-write access from the end attribute.
- CharacterForm fCharForm; // How the packet is divided into characters.
- const char * fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
- XMP_Int64 fBytesAttr; // The value of the bytes attribute, -1 if not present.
-
- SnipInfo() :
- fOffset ( 0 ),
- fLength ( 0 ),
- fState ( eNotSeenSnip ),
- fOutOfOrder ( false ),
- fAccess ( ' ' ),
- fCharForm ( eChar8Bit ),
- fEncodingAttr ( "" ),
- fBytesAttr( -1 )
- { }
-
- SnipInfo ( SnipState state, XMP_Int64 offset, XMP_Int64 length ) :
- fOffset ( offset ),
- fLength ( length ),
- fState ( state ),
- fOutOfOrder ( false ),
- fAccess ( ' ' ),
- fCharForm ( eChar8Bit ),
- fEncodingAttr ( "" ),
- fBytesAttr( -1 )
- { }
-
- };
-
- typedef std::vector<SnipInfo> SnipInfoVector;
-
- XMPScanner ( XMP_Int64 streamLength );
- // Constructs a new XMPScanner object for a stream with the given length.
-
- ~XMPScanner();
-
- long GetSnipCount();
- // Returns the number of snips that the stream has been divided into.
-
- bool StreamAllScanned();
- // Returns true if all of the stream has been seen.
-
- void Scan ( const void * bufferOrigin, XMP_Int64 bufferOffset, XMP_Int64 bufferLength );
- // Scans the given part of the input, incorporating it in to the known snips.
- // The bufferOffset is the offset of this block of input relative to the entire stream.
- // The bufferLength is the length in bytes of this block of input.
-
- void Report ( SnipInfoVector & snips );
- // Produces a report of what is known about the input stream.
-
- class ScanError : public std::logic_error {
- public:
- ScanError() throw() : std::logic_error ( "" ) {}
- explicit ScanError ( const char * message ) throw() : std::logic_error ( message ) {}
- virtual ~ScanError() throw() {}
- };
-
-private: // XMPScanner
-
- class PacketMachine;
-
- class InternalSnip {
- public:
-
- SnipInfo fInfo; // The public info about this snip.
- std::auto_ptr<PacketMachine> fMachine; // The state machine for "active" snips.
-
- InternalSnip ( XMP_Int64 offset, XMP_Int64 length );
- InternalSnip ( const InternalSnip & );
- ~InternalSnip ();
-
- }; // InternalSnip
-
- typedef std::list<InternalSnip> InternalSnipList;
- typedef InternalSnipList::iterator InternalSnipIterator;
-
- class PacketMachine {
- public:
-
- XMP_Int64 fPacketStart; // Byte offset relative to the entire stream.
- XMP_Int32 fPacketLength; // Length in bytes to the end of the trailer processing instruction.
- XMP_Int32 fBytesAttr; // The value of the bytes attribute, -1 if not present.
- std::string fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
- CharacterForm fCharForm; // How the packet is divided into characters.
- char fAccess; // The read-only/read-write access from the end attribute.
- bool fBogusPacket; // True if the packet has an error such as a bad "bytes" attribute value.
-
- void ResetMachine();
-
- enum TriState {
- eTriNo,
- eTriMaybe,
- eTriYes
- };
-
- TriState FindNextPacket();
-
- void AssociateBuffer ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength );
-
- PacketMachine ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength );
- ~PacketMachine();
-
- private: // PacketMachine
-
- PacketMachine() {}; // ! Hide the default constructor.
-
- enum RecognizerKind {
-
- eFailureRecognizer, // Not really recognizers, special states to end one buffer's processing.
- eSuccessRecognizer,
-
- eLeadInRecognizer, // Anything up to the next '<'.
- eHeadStartRecorder, // Save the starting offset, count intervening nulls.
- eHeadStartRecognizer, // The literal string "?xpacket begin=".
-
- eBOMRecognizer, // Recognize and record the quoted byte order marker.
-
- eIDTagRecognizer, // The literal string " id=".
- eIDOpenRecognizer, // The opening quote for the ID.
- eIDValueRecognizer, // The literal string "W5M0MpCehiHzreSzNTczkc9d".
- eIDCloseRecognizer, // The closing quote for the ID.
-
- eAttrSpaceRecognizer_1, // The space before an attribute.
- eAttrNameRecognizer_1, // The name of an attribute.
- eAttrValueRecognizer_1, // The equal sign and quoted string value for an attribute.
- eAttrValueRecorder_1, // Record the value of an attribute.
-
- eHeadEndRecognizer, // The string literal "?>".
-
- eBodyRecognizer, // The packet body, anything up to the next '<'.
-
- eTailStartRecognizer, // The string literal "?xpacket end=".
- eAccessValueRecognizer, // Recognize and record the quoted r/w access mode.
-
- eAttrSpaceRecognizer_2, // The space before an attribute.
- eAttrNameRecognizer_2, // The name of an attribute.
- eAttrValueRecognizer_2, // The equal sign and quoted string value for an attribute.
- eAttrValueRecorder_2, // Record the value of an attribute.
-
- eTailEndRecognizer, // The string literal "?>".
- ePacketEndRecognizer, // Look for trailing padding, check and record the packet size.
- eCloseOutRecognizer, // Look for final nulls for little endian multibyte characters.
-
- eRecognizerCount
-
- };
-
- XMP_Int64 fBufferOffset; // The offset of the data buffer within the input stream.
- const char * fBufferOrigin; // The starting address of the data buffer for this snip.
- const char * fBufferPtr; // The current postion in the data buffer.
- const char * fBufferLimit; // The address one past the last byte in the data buffer.
-
- RecognizerKind fRecognizer; // Which recognizer is currently active.
- signed long fPosition; // The internal position within a string literal, etc.
- unsigned char fBytesPerChar; // The number of bytes per logical character, 1, 2, or 4.
- unsigned char fBufferOverrun; // Non-zero if suspended while skipping intervening nulls.
- char fQuoteChar; // The kind of quote seen at the start of a quoted value.
- std::string fAttrName; // The name for an arbitrary attribute (other than "begin" and "id").
- std::string fAttrValue; // The value for an arbitrary attribute (other than "begin" and "id").
-
- void SetNextRecognizer ( RecognizerKind nextRecognizer );
-
- typedef TriState (* RecognizerProc) ( PacketMachine *, const char * );
-
- static TriState
- FindLessThan ( PacketMachine * ths, const char * which );
-
- static TriState
- MatchString ( PacketMachine * ths, const char * literal );
-
- static TriState
- MatchChar ( PacketMachine * ths, const char * literal );
-
- static TriState
- MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- CaptureAttrName ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- RecordStart ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- RecognizeBOM ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- CaptureAccess ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- RecordTailAttr ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ );
-
- static TriState
- CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ );
-
- struct RecognizerInfo {
- RecognizerProc proc;
- RecognizerKind successNext;
- RecognizerKind failureNext;
- const char * literal;
- };
-
- }; // PacketMachine
-
- XMP_Int64 fStreamLength;
- InternalSnipList fInternalSnips;
-
- void
- SplitInternalSnip ( InternalSnipIterator snipPos, XMP_Int64 relOffset, XMP_Int64 newLength );
-
- InternalSnipIterator
- MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos );
-
- InternalSnipIterator
- PrevSnip ( InternalSnipIterator snipPos );
-
- InternalSnipIterator
- NextSnip ( InternalSnipIterator snipPos );
-
- #if DEBUG
- void DumpSnipList ( const char * title );
- #endif
-
-}; // XMPScanner
-
-#endif // __XMPScanner_hpp__
diff --git a/source/XMPFiles/WXMPFiles.cpp b/source/XMPFiles/WXMPFiles.cpp
deleted file mode 100644
index 4e32607..0000000
--- a/source/XMPFiles/WXMPFiles.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h"
-#include "XMP_Const.h"
-
-#include "client-glue/WXMPFiles.hpp"
-
-#include "XMPFiles_Impl.hpp"
-#include "XMPFiles.hpp"
-
-#if XMP_WinBuild
- #if XMP_DebugBuild
- #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
- #endif
-#endif
-
-#if __cplusplus
-extern "C" {
-#endif
-
-// =================================================================================================
-
-static WXMP_Result voidResult; // Used for functions that don't use the normal result mechanism.
-
-// =================================================================================================
-
-void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo )
-{
- WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_NoLock ( "WXMPFiles_GetVersionInfo_1" )
-
- XMPFiles::GetVersionInfo ( versionInfo );
-
- XMP_EXIT_NoThrow
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_Initialize_1 ( XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_NoLock ( "WXMPFiles_Initialize_1" )
-
- wResult->int32Result = XMPFiles::Initialize ( options );
-
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_Terminate_1()
-{
- WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_NoLock ( "WXMPFiles_Terminate_1" )
-
- XMPFiles::Terminate();
-
- XMP_EXIT_NoThrow
-}
-
-// =================================================================================================
-
-void WXMPFiles_CTor_1 ( WXMP_Result * wResult )
-{
- XMP_ENTER_Static ( "WXMPFiles_CTor_1" ) // No lib object yet, use the static entry.
-
- XMPFiles * newObj = new XMPFiles();
- ++newObj->clientRefs;
- XMP_Assert ( newObj->clientRefs == 1 );
- wResult->ptrResult = newObj;
-
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_IncrementRefCount_1 ( XMPFilesRef xmpObjRef )
-{
- WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_IncrementRefCount_1" )
-
- ++thiz->clientRefs;
- XMP_Assert ( thiz->clientRefs > 0 );
-
- XMP_EXIT_NoThrow
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_DecrementRefCount_1 ( XMPFilesRef xmpObjRef )
-{
- WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_DecrementRefCount_1" )
-
- XMP_Assert ( thiz->clientRefs > 0 );
- --thiz->clientRefs;
- if ( thiz->clientRefs <= 0 ) {
- objLock.Release();
- delete ( thiz );
- }
-
- XMP_EXIT_NoThrow
-}
-
-// =================================================================================================
-
-void WXMPFiles_GetFormatInfo_1 ( XMP_FileFormat format,
- XMP_OptionBits * flags,
- WXMP_Result * wResult )
-{
- XMP_ENTER_Static ( "WXMPFiles_GetFormatInfo_1" )
-
- wResult->int32Result = XMPFiles::GetFormatInfo ( format, flags );
-
- XMP_EXIT
-}
-
-// =================================================================================================
-
-void WXMPFiles_CheckFileFormat_1 ( XMP_StringPtr filePath,
- WXMP_Result * wResult )
-{
- XMP_ENTER_Static ( "WXMPFiles_CheckFileFormat_1" )
-
- wResult->int32Result = XMPFiles::CheckFileFormat ( filePath );
-
- XMP_EXIT
-}
-
-// =================================================================================================
-
-void WXMPFiles_CheckPackageFormat_1 ( XMP_StringPtr folderPath,
- WXMP_Result * wResult )
-{
- XMP_ENTER_Static ( "WXMPFiles_CheckPackageFormat_1" )
-
- wResult->int32Result = XMPFiles::CheckPackageFormat ( folderPath );
-
- XMP_EXIT
-}
-
-// =================================================================================================
-
-void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpObjRef,
- XMP_StringPtr filePath,
- XMP_FileFormat format,
- XMP_OptionBits openFlags,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_OpenFile_1" )
- StartPerfCheck ( kAPIPerf_OpenFile, filePath );
-
- bool ok = thiz->OpenFile ( filePath, format, openFlags );
- wResult->int32Result = ok;
-
- EndPerfCheck ( kAPIPerf_OpenFile );
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpObjRef,
- XMP_OptionBits closeFlags,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_CloseFile_1" )
- StartPerfCheck ( kAPIPerf_CloseFile, "" );
-
- thiz->CloseFile ( closeFlags );
-
- EndPerfCheck ( kAPIPerf_CloseFile );
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpObjRef,
- void * clientPath,
- XMP_OptionBits * openFlags,
- XMP_FileFormat * format,
- XMP_OptionBits * handlerFlags,
- SetClientStringProc SetClientString,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjRead ( XMPFiles, "WXMPFiles_GetFileInfo_1" )
-
- XMP_StringPtr pathStr;
- XMP_StringLen pathLen;
-
- bool isOpen = thiz.GetFileInfo ( &pathStr, &pathLen, openFlags, format, handlerFlags );
- if ( isOpen && (clientPath != 0) ) (*SetClientString) ( clientPath, pathStr, pathLen );
- wResult->int32Result = isOpen;
-
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_SetAbortProc_1 ( XMPFilesRef xmpObjRef,
- XMP_AbortProc abortProc,
- void * abortArg,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_SetAbortProc_1" )
-
- thiz->SetAbortProc ( abortProc, abortArg );
-
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_GetXMP_1 ( XMPFilesRef xmpObjRef,
- XMPMetaRef xmpRef,
- void * clientPacket,
- XMP_PacketInfo * packetInfo,
- SetClientStringProc SetClientString,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_GetXMP_1" )
- StartPerfCheck ( kAPIPerf_GetXMP, "" );
-
- bool hasXMP = false;
- XMP_StringPtr packetStr;
- XMP_StringLen packetLen;
-
- if ( xmpRef == 0 ) {
- hasXMP = thiz->GetXMP ( 0, &packetStr, &packetLen, packetInfo );
- } else {
- SXMPMeta xmpObj ( xmpRef );
- hasXMP = thiz->GetXMP ( &xmpObj, &packetStr, &packetLen, packetInfo );
- }
-
- if ( hasXMP && (clientPacket != 0) ) (*SetClientString) ( clientPacket, packetStr, packetLen );
- wResult->int32Result = hasXMP;
-
- EndPerfCheck ( kAPIPerf_GetXMP );
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_PutXMP_1 ( XMPFilesRef xmpObjRef,
- XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
- XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_PutXMP_1" )
- StartPerfCheck ( kAPIPerf_PutXMP, "" );
-
- if ( xmpRef != 0 ) {
- thiz->PutXMP ( xmpRef );
- } else {
- thiz->PutXMP ( xmpPacket, xmpPacketLen );
- }
-
- EndPerfCheck ( kAPIPerf_PutXMP );
- XMP_EXIT
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void WXMPFiles_CanPutXMP_1 ( XMPFilesRef xmpObjRef,
- XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
- XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_ObjWrite ( XMPFiles, "WXMPFiles_CanPutXMP_1" )
- StartPerfCheck ( kAPIPerf_CanPutXMP, "" );
-
- if ( xmpRef != 0 ) {
- wResult->int32Result = thiz->CanPutXMP ( xmpRef );
- } else {
- wResult->int32Result = thiz->CanPutXMP ( xmpPacket, xmpPacketLen );
- }
-
- EndPerfCheck ( kAPIPerf_CanPutXMP );
- XMP_EXIT
-}
-
-// =================================================================================================
-
-#if __cplusplus
-}
-#endif
diff --git a/source/XMPFiles/XMPFiles.cpp b/source/XMPFiles/XMPFiles.cpp
deleted file mode 100644
index ba16e3f..0000000
--- a/source/XMPFiles/XMPFiles.cpp
+++ /dev/null
@@ -1,1536 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 <vector>
-#include <string.h>
-
-#include "XMPFiles_Impl.hpp"
-#include "UnicodeConversions.hpp"
-
-// These are the official, fully supported handlers.
-#include "FileHandlers/JPEG_Handler.hpp"
-#include "FileHandlers/TIFF_Handler.hpp"
-#include "FileHandlers/PSD_Handler.hpp"
-#include "FileHandlers/InDesign_Handler.hpp"
-#include "FileHandlers/PostScript_Handler.hpp"
-#include "FileHandlers/Scanner_Handler.hpp"
-#include "FileHandlers/MPEG2_Handler.hpp"
-#include "FileHandlers/PNG_Handler.hpp"
-#include "FileHandlers/RIFF_Handler.hpp"
-#include "FileHandlers/MP3_Handler.hpp"
-#include "FileHandlers/SWF_Handler.hpp"
-#include "FileHandlers/UCF_Handler.hpp"
-#include "FileHandlers/MPEG4_Handler.hpp"
-#include "FileHandlers/FLV_Handler.hpp"
-#include "FileHandlers/P2_Handler.hpp"
-#include "FileHandlers/SonyHDV_Handler.hpp"
-#include "FileHandlers/XDCAM_Handler.hpp"
-#include "FileHandlers/XDCAMEX_Handler.hpp"
-#include "FileHandlers/AVCHD_Handler.hpp"
-#include "FileHandlers/ASF_Handler.hpp"
-
-// =================================================================================================
-/// \file XMPFiles.cpp
-/// \brief High level support to access metadata in files of interest to Adobe applications.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// =================================================================================================
-
-XMP_Int32 sXMPFilesInitCount = 0;
-
-#if GatherPerformanceData
- APIPerfCollection* sAPIPerf = 0;
-#endif
-
-// These are embedded version strings.
-
-#if XMP_DebugBuild
- #define kXMPFiles_DebugFlag 1
-#else
- #define kXMPFiles_DebugFlag 0
-#endif
-
-#define kXMPFiles_VersionNumber ( (kXMPFiles_DebugFlag << 31) | \
- (XMP_API_VERSION_MAJOR << 24) | \
- (XMP_API_VERSION_MINOR << 16) | \
- (XMP_API_VERSION_MICRO << 8) )
-
- #define kXMPFilesName "XMP Files"
- #define kXMPFiles_VersionMessage kXMPFilesName " " XMP_API_VERSION_STRING
-const char * kXMPFiles_EmbeddedVersion = kXMPFiles_VersionMessage;
-const char * kXMPFiles_EmbeddedCopyright = kXMPFilesName " " kXMP_CopyrightStr;
-
-// =================================================================================================
-
-struct XMPFileHandlerInfo {
- XMP_FileFormat format;
- XMP_OptionBits flags;
- void * checkProc;
- XMPFileHandlerCTor handlerCTor;
- XMPFileHandlerInfo() : format(0), flags(0), checkProc(0), handlerCTor(0) {};
- XMPFileHandlerInfo ( XMP_FileFormat _format, XMP_OptionBits _flags,
- CheckFileFormatProc _checkProc, XMPFileHandlerCTor _handlerCTor )
- : format(_format), flags(_flags), checkProc((void*)_checkProc), handlerCTor(_handlerCTor) {};
- XMPFileHandlerInfo ( XMP_FileFormat _format, XMP_OptionBits _flags,
- CheckFolderFormatProc _checkProc, XMPFileHandlerCTor _handlerCTor )
- : format(_format), flags(_flags), checkProc((void*)_checkProc), handlerCTor(_handlerCTor) {};
-};
-
-// Don't use a map for the handler tables,
-typedef std::map <XMP_FileFormat, XMPFileHandlerInfo> XMPFileHandlerTable;
-typedef XMPFileHandlerTable::iterator XMPFileHandlerTablePos;
-typedef std::pair <XMP_FileFormat, XMPFileHandlerInfo> XMPFileHandlerTablePair;
-
-static XMPFileHandlerTable * sFolderHandlers = 0; // The directory-oriented handlers.
-static XMPFileHandlerTable * sNormalHandlers = 0; // The normal file-oriented handlers.
-static XMPFileHandlerTable * sOwningHandlers = 0; // The file-oriented handlers that "own" the file.
-
-static XMPFileHandlerInfo kScannerHandlerInfo ( kXMP_UnknownFile, kScanner_HandlerFlags, (CheckFileFormatProc)0, Scanner_MetaHandlerCTor );
-
-// =================================================================================================
-
-static void
-RegisterFolderHandler ( XMP_FileFormat format,
- XMP_OptionBits flags,
- CheckFolderFormatProc checkProc,
- XMPFileHandlerCTor handlerCTor )
-{
- XMP_Assert ( format != kXMP_UnknownFile );
- std::string noExt;
-
- XMP_Assert ( flags & kXMPFiles_HandlerOwnsFile );
- XMP_Assert ( flags & kXMPFiles_FolderBasedFormat );
- XMP_Assert ( (flags & kXMPFiles_CanInjectXMP) ? (flags & kXMPFiles_CanExpand) : 1 );
-
- XMP_Assert ( sFolderHandlers->find ( format ) == sFolderHandlers->end() );
- XMP_Assert ( sNormalHandlers->find ( format ) == sNormalHandlers->end() );
- XMP_Assert ( sOwningHandlers->find ( format ) == sOwningHandlers->end() );
-
- XMPFileHandlerInfo handlerInfo ( format, flags, checkProc, handlerCTor );
- sFolderHandlers->insert ( sFolderHandlers->end(), XMPFileHandlerTablePair ( format, handlerInfo ) );
-
-} // RegisterFolderHandler
-
-// =================================================================================================
-
-static void
-RegisterNormalHandler ( XMP_FileFormat format,
- XMP_OptionBits flags,
- CheckFileFormatProc checkProc,
- XMPFileHandlerCTor handlerCTor )
-{
- XMP_Assert ( format != kXMP_UnknownFile );
- std::string noExt;
-
- XMP_Assert ( ! (flags & kXMPFiles_HandlerOwnsFile) );
- XMP_Assert ( ! (flags & kXMPFiles_FolderBasedFormat) );
- XMP_Assert ( (flags & kXMPFiles_CanInjectXMP) ? (flags & kXMPFiles_CanExpand) : 1 );
-
- XMP_Assert ( sFolderHandlers->find ( format ) == sFolderHandlers->end() );
- XMP_Assert ( sNormalHandlers->find ( format ) == sNormalHandlers->end() );
- XMP_Assert ( sOwningHandlers->find ( format ) == sOwningHandlers->end() );
-
- XMPFileHandlerInfo handlerInfo ( format, flags, checkProc, handlerCTor );
- sNormalHandlers->insert ( sNormalHandlers->end(), XMPFileHandlerTablePair ( format, handlerInfo ) );
-
-} // RegisterNormalHandler
-
-// =================================================================================================
-
-static void
-RegisterOwningHandler ( XMP_FileFormat format,
- XMP_OptionBits flags,
- CheckFileFormatProc checkProc,
- XMPFileHandlerCTor handlerCTor )
-{
- XMP_Assert ( format != kXMP_UnknownFile );
- std::string noExt;
-
- XMP_Assert ( flags & kXMPFiles_HandlerOwnsFile );
- XMP_Assert ( ! (flags & kXMPFiles_FolderBasedFormat) );
- XMP_Assert ( (flags & kXMPFiles_CanInjectXMP) ? (flags & kXMPFiles_CanExpand) : 1 );
-
- XMP_Assert ( sFolderHandlers->find ( format ) == sFolderHandlers->end() );
- XMP_Assert ( sNormalHandlers->find ( format ) == sNormalHandlers->end() );
- XMP_Assert ( sOwningHandlers->find ( format ) == sOwningHandlers->end() );
-
- XMPFileHandlerInfo handlerInfo ( format, flags, checkProc, handlerCTor );
- sOwningHandlers->insert ( sOwningHandlers->end(), XMPFileHandlerTablePair ( format, handlerInfo ) );
-
-} // RegisterOwningHandler
-
-// =================================================================================================
-
-static XMPFileHandlerInfo *
-PickDefaultHandler ( XMP_FileFormat format, const std::string & fileExt )
-{
- if ( (format == kXMP_UnknownFile) && (! fileExt.empty()) ) {
- for ( int i = 0; kFileExtMap[i].format != 0; ++i ) {
- if ( fileExt == kFileExtMap[i].ext ) {
- format = kFileExtMap[i].format;
- break;
- }
- }
- }
-
- if ( format == kXMP_UnknownFile ) return 0;
-
- XMPFileHandlerTablePos handlerPos;
-
- handlerPos = sNormalHandlers->find ( format );
- if ( handlerPos != sNormalHandlers->end() ) return &handlerPos->second;
-
- handlerPos = sOwningHandlers->find ( format );
- if ( handlerPos != sOwningHandlers->end() ) return &handlerPos->second;
-
- handlerPos = sFolderHandlers->find ( format );
- if ( handlerPos != sFolderHandlers->end() ) return &handlerPos->second;
-
- return 0;
-
-} // PickDefaultHandler
-
-// =================================================================================================
-
-static const char * kP2ContentChildren[] = { "CLIP", "VIDEO", "AUDIO", "ICON", "VOICE", "PROXY", 0 };
-
-static inline bool CheckP2ContentChild ( const std::string & folderName )
-{
- for ( int i = 0; kP2ContentChildren[i] != 0; ++i ) {
- if ( folderName == kP2ContentChildren[i] ) return true;
- }
- return false;
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static XMP_FileFormat
-CheckParentFolderNames ( const std::string & rootPath, const std::string & gpName,
- const std::string & parentName, const std::string & leafName )
-{
- IgnoreParam ( parentName );
-
- // This is called when the input path to XMPFiles::OpenFile names an existing file. We need to
- // quickly decide if this might be inside a folder-handler's structure. See if the containing
- // folders might match any of the registered folder handlers. This check does not have to be
- // precise, the handler will do that. This does have to be fast.
- //
- // Since we don't have many folder handlers, this is simple hardwired code. Note that the caller
- // has already shifted the names to upper case.
-
- // P2 .../MyMovie/CONTENTS/<group>/<file>.<ext> - check CONTENTS and <group>
- if ( (gpName == "CONTENTS") && CheckP2ContentChild ( parentName ) ) return kXMP_P2File;
-
- // XDCAM-EX .../MyMovie/BPAV/CLPR/<clip>/<file>.<ext> - check for BPAV/CLPR
- // ! This must be checked before XDCAM-SAM because both have a "CLPR" grandparent.
- if ( gpName == "CLPR" ) {
- std::string tempPath, greatGP;
- tempPath = rootPath;
- SplitLeafName ( &tempPath, &greatGP );
- MakeUpperCase ( &greatGP );
- if ( greatGP == "BPAV" ) return kXMP_XDCAM_EXFile;
- }
-
- // XDCAM-FAM .../MyMovie/<group>/<file>.<ext> - check that <group> is CLIP, or EDIT, or SUB
- // ! The standard says Clip/Edit/Sub, but the caller has already shifted to upper case.
- if ( (parentName == "CLIP") || (parentName == "EDIT") || (parentName == "SUB") ) return kXMP_XDCAM_FAMFile;
-
- // XDCAM-SAM .../MyMovie/PROAV/<group>/<clip>/<file>.<ext> - check for PROAV and CLPR or EDTR
- if ( (gpName == "CLPR") || (gpName == "EDTR") ) {
- std::string tempPath, greatGP;
- tempPath = rootPath;
- SplitLeafName ( &tempPath, &greatGP );
- MakeUpperCase ( &greatGP );
- if ( greatGP == "PROAV" ) return kXMP_XDCAM_SAMFile;
- }
-
- // Sony HDV .../MyMovie/VIDEO/HVR/<file>.<ext> - check for VIDEO and HVR
- if ( (gpName == "VIDEO") && (parentName == "HVR") ) return kXMP_SonyHDVFile;
-
- // AVCHD .../MyMovie/BDMV/<group>/<file>.<ext> - check for BDMV and CLIPINF or STREAM
- if ( (gpName == "BDMV") && ((parentName == "CLIPINF") || (parentName == "STREAM")) ) return kXMP_AVCHDFile;
-
- return kXMP_UnknownFile;
-
-} // CheckParentFolderNames
-
-// =================================================================================================
-
-static XMP_FileFormat
-CheckTopFolderName ( const std::string & rootPath )
-{
- // This is called when the input path to XMPFiles::OpenFile does not name an existing file (or
- // existing anything). We need to quickly decide if this might be a logical path for a folder
- // handler. See if the root contains the top content folder for any of the registered folder
- // handlers. This check does not have to be precise, the handler will do that. This does have to
- // be fast.
- //
- // Since we don't have many folder handlers, this is simple hardwired code.
-
- std::string childPath = rootPath;
- childPath += kDirChar;
- size_t baseLen = childPath.size();
-
- // P2 .../MyMovie/CONTENTS/<group>/... - only check for CONTENTS/CLIP
- childPath += "CONTENTS";
- childPath += kDirChar;
- childPath += "CLIP";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) return kXMP_P2File;
- childPath.erase ( baseLen );
-
- // XDCAM-FAM .../MyMovie/<group>/... - only check for Clip and MEDIAPRO.XML
- childPath += "Clip"; // ! Yes, mixed case.
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) {
- childPath.erase ( baseLen );
- childPath += "MEDIAPRO.XML";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFile ) return kXMP_XDCAM_FAMFile;
- }
- childPath.erase ( baseLen );
-
- // XDCAM-SAM .../MyMovie/PROAV/<group>/... - only check for PROAV/CLPR
- childPath += "PROAV";
- childPath += kDirChar;
- childPath += "CLPR";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) return kXMP_XDCAM_SAMFile;
- childPath.erase ( baseLen );
-
- // XDCAM-EX .../MyMovie/BPAV/<group>/... - check for BPAV/CLPR
- childPath += "BPAV";
- childPath += kDirChar;
- childPath += "CLPR";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) return kXMP_XDCAM_EXFile;
- childPath.erase ( baseLen );
-
- // Sony HDV .../MyMovie/VIDEO/HVR/<file>.<ext> - check for VIDEO/HVR
- childPath += "VIDEO";
- childPath += kDirChar;
- childPath += "HVR";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) return kXMP_SonyHDVFile;
- childPath.erase ( baseLen );
-
- // AVCHD .../MyMovie/BDMV/CLIPINF/<file>.<ext> - check for BDMV/CLIPINF
- childPath += "BDMV";
- childPath += kDirChar;
- childPath += "CLIPINF";
- if ( GetFileMode ( childPath.c_str() ) == kFMode_IsFolder ) return kXMP_AVCHDFile;
- childPath.erase ( baseLen );
-
- return kXMP_UnknownFile;
-
-} // CheckTopFolderName
-
-// =================================================================================================
-
-static XMPFileHandlerInfo *
-TryFolderHandlers ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parentObj )
-{
- bool foundHandler = false;
- XMPFileHandlerInfo * handlerInfo = 0;
- XMPFileHandlerTablePos handlerPos;
-
- // We know we're in a possible context for a folder-oriented handler, so try them.
-
- if ( format != kXMP_UnknownFile ) {
-
- // Have an explicit format, pick that or nothing.
- handlerPos = sFolderHandlers->find ( format );
- if ( handlerPos != sFolderHandlers->end() ) {
- handlerInfo = &handlerPos->second;
- CheckFolderFormatProc CheckProc = (CheckFolderFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( handlerInfo->format, rootPath, gpName, parentName, leafName, parentObj );
- XMP_Assert ( foundHandler || (parentObj->tempPtr == 0) );
- }
-
- } else {
-
- // Try all of the folder handlers.
- for ( handlerPos = sFolderHandlers->begin(); handlerPos != sFolderHandlers->end(); ++handlerPos ) {
- handlerInfo = &handlerPos->second;
- CheckFolderFormatProc CheckProc = (CheckFolderFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( handlerInfo->format, rootPath, gpName, parentName, leafName, parentObj );
- XMP_Assert ( foundHandler || (parentObj->tempPtr == 0) );
- if ( foundHandler ) break; // ! Exit before incrementing handlerPos.
- }
-
- }
-
- if ( ! foundHandler ) handlerInfo = 0;
- return handlerInfo;
-
-} // TryFolderHandlers
-
-// =================================================================================================
-
-static XMPFileHandlerInfo *
-SelectSmartHandler ( XMPFiles * thiz, XMP_StringPtr clientPath, XMP_FileFormat format, XMP_OptionBits openFlags )
-{
-
- // There are 4 stages in finding a handler, ending at the first success:
- // 1. If the client passes in a format, try that handler.
- // 2. Try all of the folder-oriented handlers.
- // 3. Try a file-oriented handler based on the file extension.
- // 4. Try all of the file-oriented handlers.
- //
- // The most common case is almost certainly #3, so we want to get there quickly. Most of the
- // time the client won't pass in a format, so #1 takes no time. The folder-oriented handler
- // checks are preceded by minimal folder checks. These checks are meant to be fast in the
- // failure case. The folder-oriented checks have to go before the general file-oriented checks
- // because the client path might be to one of the inner files, and we might have a file-oriented
- // handler for that kind of file, but we want to recognize the clip. More details are below.
- //
- // In brief, the folder-oriented formats use shallow trees with specific folder names and
- // highly stylized file names. The user thinks of the tree as a collection of clips, each clip
- // is stored as multiple files for video, audio, metadata, etc. The folder-oriented stage has
- // to be first because there can be files in the structure that are also covered by a
- // file-oriented handler.
- //
- // In the file-oriented case, the CheckProc should do as little as possible to determine the
- // format, based on the actual file content. If that is not possible, use the format hint. The
- // initial CheckProc calls (steps 1 and 3) has the presumed format in this->format, the later
- // calls (step 4) have kXMP_UnknownFile there.
- //
- // The folder-oriented checks need to be well optimized since the formats are relatively rare,
- // but have to go first and could require multiple file system calls to identify. We want to
- // get to the first file-oriented guess as quickly as possible, that is the real handler most of
- // the time.
- //
- // The folder-oriented handlers are for things like P2 and XDCAM that use files distributed in a
- // well defined folder structure. Using a portion of P2 as an example:
- // .../MyMovie
- // CONTENTS
- // CLIP
- // 0001AB.XML
- // 0002CD.XML
- // VIDEO
- // 0001AB.MXF
- // 0002CD.MXF
- // VOICE
- // 0001AB.WAV
- // 0002CD.WAV
- //
- // The user thinks of .../MyMovie as the container of P2 stuff, in this case containing 2 clips
- // called 0001AB and 0002CD. The exact folder structure and file layout differs, but the basic
- // concepts carry across all of the folder-oriented handlers.
- //
- // The client path can be a conceptual clip path like .../MyMovie/0001AB, or a full path to any
- // of the contained files. For file paths we have to behave the same as the implied conceptual
- // path, e.g. we don't want .../MyMovie/CONTENTS/VOICE/0001AB.WAV to invoke the WAV handler.
- // There might also be a mapping from user friendly names to clip names (e.g. Intro to 0001AB).
- // If so that is private to the handler and does not affect this code.
- //
- // In order to properly handle the file path input we have to look for the folder-oriented case
- // before any of the file-oriented cases. And since these are relatively rare, hence fail most of
- // the time, we have to get in and out fast in the not handled case. That is what we do here.
- //
- // The folder-oriented processing done here is roughly:
- //
- // 1. Get the state of the client path: does-not-exist, is-file, is-folder, is-other.
- // 2. Reject is-folder and is-other, they can't possibly be a valid case.
- // 3. For does-not-exist:
- // 3a. Split the client path into a leaf component and root path.
- // 3b. Make sure the root path names an existing folder.
- // 3c. Make sure the root folder has a viable top level child folder (e.g. CONTENTS).
- // 4. For is-file:
- // 4a. Split the client path into a root path, grandparent folder, parent folder, and leaf name.
- // 4b. Make sure the parent or grandparent has a viable name (e.g. CONTENTS).
- // 5. Try the registered folder handlers.
- //
- // For the common case of "regular" files, we should only get as far as 3b. This is just 1 file
- // system call to get the client path state and some string processing.
-
- char openMode = 'r';
- if ( openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- XMPFileHandlerInfo * handlerInfo = 0;
- bool foundHandler = false;
-
- FileMode clientMode = GetFileMode ( clientPath );
- if ( (clientMode == kFMode_IsFolder) || (clientMode == kFMode_IsOther) ) return 0;
-
- // Extract some info from the clientPath, needed for various checks.
-
- std::string rootPath, leafName, fileExt;
-
- rootPath = clientPath;
- SplitLeafName ( &rootPath, &leafName );
- if ( leafName.empty() ) return 0;
-
- size_t extPos = leafName.size();
- for ( --extPos; extPos > 0; --extPos ) if ( leafName[extPos] == '.' ) break;
- if ( leafName[extPos] == '.' ) {
- fileExt.assign ( &leafName[extPos+1] );
- MakeLowerCase ( &fileExt );
- leafName.erase ( extPos );
- }
-
- thiz->format = kXMP_UnknownFile; // Make sure it is preset for later checks.
- thiz->openFlags = openFlags;
-
- // If the client passed in a format, try that first.
-
- if ( format != kXMP_UnknownFile ) {
-
- std::string emptyStr;
- handlerInfo = PickDefaultHandler ( format, emptyStr ); // Picks based on just the format.
-
- if ( handlerInfo != 0 ) {
-
- if ( (thiz->fileRef == 0) && (! (handlerInfo->flags & kXMPFiles_HandlerOwnsFile)) ) {
- thiz->fileRef = LFA_Open ( clientPath, openMode );
- XMP_Assert ( thiz->fileRef != 0 ); // LFA_Open must either succeed or throw.
- }
- thiz->format = format; // ! Hack to tell the CheckProc thiz is an initial call.
-
- if ( ! (handlerInfo->flags & kXMPFiles_FolderBasedFormat) ) {
- CheckFileFormatProc CheckProc = (CheckFileFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( format, clientPath, thiz->fileRef, thiz );
- } else {
- // *** Don't try here yet. These are messy, needing existence checking and path processing.
- // *** CheckFolderFormatProc CheckProc = (CheckFolderFormatProc) (handlerInfo->checkProc);
- // *** foundHandler = CheckProc ( handlerInfo->format, rootPath, gpName, parentName, leafName, thiz );
- // *** Don't let OpenStrictly cause an early exit:
- if ( openFlags & kXMPFiles_OpenStrictly ) openFlags ^= kXMPFiles_OpenStrictly;
- }
-
- XMP_Assert ( foundHandler || (thiz->tempPtr == 0) );
- if ( foundHandler ) return handlerInfo;
- handlerInfo = 0; // ! Clear again for later use.
-
- }
-
- if ( openFlags & kXMPFiles_OpenStrictly ) return 0;
-
- }
-
- // Try the folder handlers if appropriate.
-
- XMP_Assert ( handlerInfo == 0 );
- XMP_Assert ( (clientMode == kFMode_IsFile) || (clientMode == kFMode_DoesNotExist) );
-
- std::string gpName, parentName;
-
- if ( clientMode == kFMode_DoesNotExist ) {
-
- // 3. For does-not-exist:
- // 3a. Split the client path into a leaf component and root path.
- // 3b. Make sure the root path names an existing folder.
- // 3c. Make sure the root folder has a viable top level child folder.
-
- // ! This does "return 0" on failure, the file does not exist so a normal file handler can't apply.
-
- if ( GetFileMode ( rootPath.c_str() ) != kFMode_IsFolder ) return 0;
- thiz->format = CheckTopFolderName ( rootPath );
- if ( thiz->format == kXMP_UnknownFile ) return 0;
-
- handlerInfo = TryFolderHandlers ( thiz->format, rootPath, gpName, parentName, leafName, thiz ); // ! Parent and GP are empty.
- return handlerInfo; // ! Return found handler or 0.
-
- }
-
- XMP_Assert ( clientMode == kFMode_IsFile );
-
- // 4. For is-file:
- // 4a. Split the client path into root, grandparent, parent, and leaf.
- // 4b. Make sure the parent or grandparent has a viable name.
-
- // ! Don't "return 0" on failure, this has to fall through to the normal file handlers.
-
- SplitLeafName ( &rootPath, &parentName );
- SplitLeafName ( &rootPath, &gpName );
- std::string origGPName ( gpName ); // ! Save the original case for XDCAM-FAM.
- MakeUpperCase ( &parentName );
- MakeUpperCase ( &gpName );
-
- thiz->format = CheckParentFolderNames ( rootPath, gpName, parentName, leafName );
-
- if ( thiz->format != kXMP_UnknownFile ) {
-
- if ( (thiz->format == kXMP_XDCAM_FAMFile) &&
- ((parentName == "CLIP") || (parentName == "EDIT") || (parentName == "SUB")) ) {
- // ! The standard says Clip/Edit/Sub, but we just shifted to upper case.
- gpName = origGPName; // ! XDCAM-FAM has just 1 level of inner folder, preserve the "MyMovie" case.
- }
-
- handlerInfo = TryFolderHandlers ( thiz->format, rootPath, gpName, parentName, leafName, thiz );
- if ( handlerInfo != 0 ) return handlerInfo;
-
- }
-
- // Try an initial file-oriented handler based on the extension.
-
- handlerInfo = PickDefaultHandler ( kXMP_UnknownFile, fileExt ); // Picks based on just the extension.
-
- if ( handlerInfo != 0 ) {
- if ( (thiz->fileRef == 0) && (! (handlerInfo->flags & kXMPFiles_HandlerOwnsFile)) ) {
- thiz->fileRef = LFA_Open ( clientPath, openMode );
- XMP_Assert ( thiz->fileRef != 0 ); // LFA_Open must either succeed or throw.
- } else if ( (thiz->fileRef != 0) && (handlerInfo->flags & kXMPFiles_HandlerOwnsFile) ) {
- LFA_Close ( thiz->fileRef );
- thiz->fileRef = 0;
- }
- thiz->format = handlerInfo->format; // ! Hack to tell the CheckProc thiz is an initial call.
- CheckFileFormatProc CheckProc = (CheckFileFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( handlerInfo->format, clientPath, thiz->fileRef, thiz );
- XMP_Assert ( foundHandler || (thiz->tempPtr == 0) );
- if ( foundHandler ) return handlerInfo;
- }
-
- // Search the handlers that don't want to open the file themselves.
-
- if ( thiz->fileRef == 0 ) thiz->fileRef = LFA_Open ( clientPath, openMode );
- XMP_Assert ( thiz->fileRef != 0 ); // LFA_Open must either succeed or throw.
- XMPFileHandlerTablePos handlerPos = sNormalHandlers->begin();
-
- for ( ; handlerPos != sNormalHandlers->end(); ++handlerPos ) {
- thiz->format = kXMP_UnknownFile; // ! Hack to tell the CheckProc this is not an initial call.
- handlerInfo = &handlerPos->second;
- CheckFileFormatProc CheckProc = (CheckFileFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( handlerInfo->format, clientPath, thiz->fileRef, thiz );
- XMP_Assert ( foundHandler || (thiz->tempPtr == 0) );
- if ( foundHandler ) return handlerInfo;
- }
-
- // Search the handlers that do want to open the file themselves.
-
- LFA_Close ( thiz->fileRef );
- thiz->fileRef = 0;
- handlerPos = sOwningHandlers->begin();
-
- for ( ; handlerPos != sOwningHandlers->end(); ++handlerPos ) {
- thiz->format = kXMP_UnknownFile; // ! Hack to tell the CheckProc this is not an initial call.
- handlerInfo = &handlerPos->second;
- CheckFileFormatProc CheckProc = (CheckFileFormatProc) (handlerInfo->checkProc);
- foundHandler = CheckProc ( handlerInfo->format, clientPath, thiz->fileRef, thiz );
- XMP_Assert ( foundHandler || (thiz->tempPtr == 0) );
- if ( foundHandler ) return handlerInfo;
- }
-
- // Failed to find a smart handler.
-
- return 0;
-
-} // SelectSmartHandler
-
-// =================================================================================================
-
-/* class-static */
-void
-XMPFiles::GetVersionInfo ( XMP_VersionInfo * info )
-{
-
- memset ( info, 0, sizeof(XMP_VersionInfo) );
-
- info->major = XMP_API_VERSION_MAJOR;
- info->minor = XMP_API_VERSION_MINOR;
- info->micro = XMP_API_VERSION_MICRO;
- info->isDebug = kXMPFiles_DebugFlag;
- info->flags = 0; // ! None defined yet.
- info->message = kXMPFiles_VersionMessage;
-
-} // XMPFiles::GetVersionInfo
-
-// =================================================================================================
-
-#if XMP_TraceFilesCalls
- FILE * xmpFilesLog = stderr;
-#endif
-
-#if UseGlobalLibraryLock & (! XMP_StaticBuild )
- XMP_BasicMutex sLibraryLock; // ! Handled in XMPMeta for static builds.
-#endif
-
-/* class static */
-bool
-XMPFiles::Initialize ( XMP_OptionBits options /* = 0 */ )
-{
- ++sXMPFilesInitCount;
- if ( sXMPFilesInitCount > 1 ) return true;
-
- #if XMP_TraceFilesCallsToFile
- xmpFilesLog = fopen ( "XMPFilesLog.txt", "w" );
- if ( xmpFilesLog == 0 ) xmpFilesLog = stderr;
- #endif
-
- #if UseGlobalLibraryLock & (! XMP_StaticBuild )
- InitializeBasicMutex ( sLibraryLock ); // ! Handled in XMPMeta for static builds.
- #endif
-
- SXMPMeta::Initialize(); // Just in case the client does not.
-
- if ( ! Initialize_LibUtils() ) return false;
-
- #if GatherPerformanceData
- sAPIPerf = new APIPerfCollection;
- #endif
-
- XMP_Uns16 endianInt = 0x00FF;
- XMP_Uns8 endianByte = *((XMP_Uns8*)&endianInt);
- if ( kBigEndianHost ) {
- if ( endianByte != 0 ) XMP_Throw ( "Big endian flag mismatch", kXMPErr_InternalFailure );
- } else {
- if ( endianByte != 0xFF ) XMP_Throw ( "Little endian flag mismatch", kXMPErr_InternalFailure );
- }
-
- XMP_Assert ( kUTF8_PacketHeaderLen == strlen ( "<?xpacket begin='xxx' id='W5M0MpCehiHzreSzNTczkc9d'" ) );
- XMP_Assert ( kUTF8_PacketTrailerLen == strlen ( (const char *) kUTF8_PacketTrailer ) );
-
- sFolderHandlers = new XMPFileHandlerTable;
- sNormalHandlers = new XMPFileHandlerTable;
- sOwningHandlers = new XMPFileHandlerTable;
-
- InitializeUnicodeConversions();
-
- ignoreLocalText = XMP_OptionIsSet ( options, kXMPFiles_IgnoreLocalText );
- #if XMP_UNIXBuild
- if ( ! ignoreLocalText ) XMP_Throw ( "Generic UNIX clients must pass kXMPFiles_IgnoreLocalText", kXMPErr_EnforceFailure );
- #endif
-
- // -----------------------------------------
- // Register the directory-oriented handlers.
-
- RegisterFolderHandler ( kXMP_P2File, kP2_HandlerFlags, P2_CheckFormat, P2_MetaHandlerCTor );
- RegisterFolderHandler ( kXMP_SonyHDVFile, kSonyHDV_HandlerFlags, SonyHDV_CheckFormat, SonyHDV_MetaHandlerCTor );
- RegisterFolderHandler ( kXMP_XDCAM_FAMFile, kXDCAM_HandlerFlags, XDCAM_CheckFormat, XDCAM_MetaHandlerCTor );
- RegisterFolderHandler ( kXMP_XDCAM_SAMFile, kXDCAM_HandlerFlags, XDCAM_CheckFormat, XDCAM_MetaHandlerCTor );
- RegisterFolderHandler ( kXMP_XDCAM_EXFile, kXDCAMEX_HandlerFlags, XDCAMEX_CheckFormat, XDCAMEX_MetaHandlerCTor );
- RegisterFolderHandler ( kXMP_AVCHDFile, kAVCHD_HandlerFlags, AVCHD_CheckFormat, AVCHD_MetaHandlerCTor );
-
- // ------------------------------------------------------------------------------------------
- // Register the file-oriented handlers that don't want to open and close the file themselves.
-
- RegisterNormalHandler ( kXMP_JPEGFile, kJPEG_HandlerFlags, JPEG_CheckFormat, JPEG_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_TIFFFile, kTIFF_HandlerFlags, TIFF_CheckFormat, TIFF_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_PhotoshopFile, kPSD_HandlerFlags, PSD_CheckFormat, PSD_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_InDesignFile, kInDesign_HandlerFlags, InDesign_CheckFormat, InDesign_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_PNGFile, kPNG_HandlerFlags, PNG_CheckFormat, PNG_MetaHandlerCTor );
-
- // ! EPS and PostScript have the same handler, EPS is a proper subset of PostScript.
- RegisterNormalHandler ( kXMP_EPSFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_PostScriptFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_WMAVFile, kASF_HandlerFlags, ASF_CheckFormat, ASF_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_MP3File, kMP3_HandlerFlags, MP3_CheckFormat, MP3_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_WAVFile, kRIFF_HandlerFlags, RIFF_CheckFormat, RIFF_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_AVIFile, kRIFF_HandlerFlags, RIFF_CheckFormat, RIFF_MetaHandlerCTor );
-
- RegisterNormalHandler ( kXMP_SWFFile, kSWF_HandlerFlags, SWF_CheckFormat, SWF_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_UCFFile, kUCF_HandlerFlags, UCF_CheckFormat, UCF_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_MPEG4File, kMPEG4_HandlerFlags, MPEG4_CheckFormat, MPEG4_MetaHandlerCTor );
- RegisterNormalHandler ( kXMP_MOVFile, kMPEG4_HandlerFlags, MPEG4_CheckFormat, MPEG4_MetaHandlerCTor ); // ! Yes, MPEG-4 includes MOV.
- RegisterNormalHandler ( kXMP_FLVFile, kFLV_HandlerFlags, FLV_CheckFormat, FLV_MetaHandlerCTor );
-
- // ---------------------------------------------------------------------------------------
- // Register the file-oriented handlers that do want to open and close the file themselves.
-
- RegisterOwningHandler ( kXMP_MPEGFile, kMPEG2_HandlerFlags, MPEG2_CheckFormat, MPEG2_MetaHandlerCTor );
- RegisterOwningHandler ( kXMP_MPEG2File, kMPEG2_HandlerFlags, MPEG2_CheckFormat, MPEG2_MetaHandlerCTor );
-
- // Make sure the embedded info strings are referenced and kept.
- if ( (kXMPFiles_EmbeddedVersion[0] == 0) || (kXMPFiles_EmbeddedCopyright[0] == 0) ) return false;
- // Verify critical type sizes.
- XMP_Assert ( sizeof(XMP_Int8) == 1 );
- XMP_Assert ( sizeof(XMP_Int16) == 2 );
- XMP_Assert ( sizeof(XMP_Int32) == 4 );
- XMP_Assert ( sizeof(XMP_Int64) == 8 );
- XMP_Assert ( sizeof(XMP_Uns8) == 1 );
- XMP_Assert ( sizeof(XMP_Uns16) == 2 );
- XMP_Assert ( sizeof(XMP_Uns32) == 4 );
- XMP_Assert ( sizeof(XMP_Uns64) == 8 );
-
- return true;
-
-} // XMPFiles::Initialize
-
-// =================================================================================================
-
-#if GatherPerformanceData
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4996 ) // '...' was declared deprecated
-#endif
-
-#include "PerfUtils.cpp"
-
-static void ReportPerformanceData()
-{
- struct SummaryInfo {
- size_t callCount;
- double totalTime;
- SummaryInfo() : callCount(0), totalTime(0.0) {};
- };
-
- SummaryInfo perfSummary [kAPIPerfProcCount];
-
- XMP_DateTime now;
- SXMPUtils::CurrentDateTime ( &now );
- std::string nowStr;
- SXMPUtils::ConvertFromDate ( now, &nowStr );
-
- #if XMP_WinBuild
- #define kPerfLogPath "C:\\XMPFilesPerformanceLog.txt"
- #else
- #define kPerfLogPath "/XMPFilesPerformanceLog.txt"
- #endif
- FILE * perfLog = fopen ( kPerfLogPath, "ab" );
- if ( perfLog == 0 ) return;
-
- fprintf ( perfLog, "\n\n// =================================================================================================\n\n" );
- fprintf ( perfLog, "XMPFiles performance data\n" );
- fprintf ( perfLog, " %s\n", kXMPFiles_VersionMessage );
- fprintf ( perfLog, " Reported at %s\n", nowStr.c_str() );
- fprintf ( perfLog, " %s\n", PerfUtils::GetTimerInfo() );
-
- // Gather and report the summary info.
-
- for ( size_t i = 0; i < sAPIPerf->size(); ++i ) {
- SummaryInfo& summaryItem = perfSummary [(*sAPIPerf)[i].whichProc];
- ++summaryItem.callCount;
- summaryItem.totalTime += (*sAPIPerf)[i].elapsedTime;
- }
-
- fprintf ( perfLog, "\nSummary data:\n" );
-
- for ( size_t i = 0; i < kAPIPerfProcCount; ++i ) {
- long averageTime = 0;
- if ( perfSummary[i].callCount != 0 ) {
- averageTime = (long) (((perfSummary[i].totalTime/perfSummary[i].callCount) * 1000.0*1000.0) + 0.5);
- }
- fprintf ( perfLog, " %s, %d total calls, %d average microseconds per call\n",
- kAPIPerfNames[i], perfSummary[i].callCount, averageTime );
- }
-
- fprintf ( perfLog, "\nPer-call data:\n" );
-
- // Report the info for each call.
-
- for ( size_t i = 0; i < sAPIPerf->size(); ++i ) {
- long time = (long) (((*sAPIPerf)[i].elapsedTime * 1000.0*1000.0) + 0.5);
- fprintf ( perfLog, " %s, %d microSec, ref %.8X, \"%s\"\n",
- kAPIPerfNames[(*sAPIPerf)[i].whichProc], time,
- (*sAPIPerf)[i].xmpFilesRef, (*sAPIPerf)[i].extraInfo.c_str() );
- }
-
- fclose ( perfLog );
-
-} // ReportAReportPerformanceDataPIPerformance
-
-#endif
-
-// =================================================================================================
-
-/* class static */
-void
-XMPFiles::Terminate()
-{
- --sXMPFilesInitCount;
- if ( sXMPFilesInitCount != 0 ) return; // Not ready to terminate, or already terminated.
-
- #if GatherPerformanceData
- ReportPerformanceData();
- EliminateGlobal ( sAPIPerf );
- #endif
-
- EliminateGlobal ( sFolderHandlers );
- EliminateGlobal ( sNormalHandlers );
- EliminateGlobal ( sOwningHandlers );
-
- SXMPMeta::Terminate(); // Just in case the client does not.
-
- Terminate_LibUtils();
-
- #if UseGlobalLibraryLock & (! XMP_StaticBuild )
- TerminateBasicMutex ( sLibraryLock ); // ! Handled in XMPMeta for static builds.
- #endif
-
- #if XMP_TraceFilesCallsToFile
- if ( xmpFilesLog != stderr ) fclose ( xmpFilesLog );
- xmpFilesLog = stderr;
- #endif
-
-} // XMPFiles::Terminate
-
-// =================================================================================================
-
-XMPFiles::XMPFiles() :
- clientRefs(0),
- format(kXMP_UnknownFile),
- fileRef(0),
- openFlags(0),
- abortProc(0),
- abortArg(0),
- handler(0),
- tempPtr(0),
- tempUI32(0)
-{
- // Nothing more to do, clientRefs is incremented in wrapper.
-
-} // XMPFiles::XMPFiles
-
-// =================================================================================================
-
-XMPFiles::~XMPFiles()
-{
- XMP_Assert ( this->clientRefs <= 0 );
-
- if ( this->handler != 0 ) {
- delete this->handler;
- this->handler = 0;
- }
-
- if ( this->fileRef != 0 ) {
- LFA_Close ( this->fileRef );
- this->fileRef = 0;
- }
-
- if ( this->tempPtr != 0 ) free ( this->tempPtr ); // ! Must have been malloc-ed!
-
-} // XMPFiles::~XMPFiles
-
-// =================================================================================================
-
-/* class static */
-bool
-XMPFiles::GetFormatInfo ( XMP_FileFormat format,
- XMP_OptionBits * flags /* = 0 */ )
-{
- if ( flags == 0 ) flags = &voidOptionBits;
-
- XMPFileHandlerTablePos handlerPos;
-
- handlerPos = sFolderHandlers->find ( format );
- if ( handlerPos != sFolderHandlers->end() ) {
- *flags = handlerPos->second.flags;
- return true;
- }
-
- handlerPos = sNormalHandlers->find ( format );
- if ( handlerPos != sNormalHandlers->end() ) {
- *flags = handlerPos->second.flags;
- return true;
- }
-
- handlerPos = sOwningHandlers->find ( format );
- if ( handlerPos != sOwningHandlers->end() ) {
- *flags = handlerPos->second.flags;
- return true;
- }
-
- return false;
-
-} // XMPFiles::GetFormatInfo
-
-// =================================================================================================
-
-/* class static */
-XMP_FileFormat
-XMPFiles::CheckFileFormat ( XMP_StringPtr filePath )
-{
- if ( (filePath == 0) || (*filePath == 0) ) return kXMP_UnknownFile;
-
- XMPFiles bogus;
- XMPFileHandlerInfo * handlerInfo = SelectSmartHandler ( &bogus, filePath, kXMP_UnknownFile, kXMPFiles_OpenForRead );
- if ( handlerInfo == 0 ) return kXMP_UnknownFile;
- return handlerInfo->format;
-
-} // XMPFiles::CheckFileFormat
-
-// =================================================================================================
-
-/* class static */
-XMP_FileFormat
-XMPFiles::CheckPackageFormat ( XMP_StringPtr folderPath )
-{
- // This is called with a path to a folder, and checks to see if that folder is the top level of
- // a "package" that should be recognized by one of the folder-oriented handlers. The checks here
- // are not overly extensive, but hopefully enough to weed out false positives.
- //
- // Since we don't have many folder handlers, this is simple hardwired code.
-
- FileMode folderMode = GetFileMode ( folderPath );
- if ( folderMode != kFMode_IsFolder ) return kXMP_UnknownFile;
-
- return CheckTopFolderName ( std::string ( folderPath ) );
-
-} // XMPFiles::CheckPackageFormat
-
-// =================================================================================================
-
-bool
-XMPFiles::OpenFile ( XMP_StringPtr clientPath,
- XMP_FileFormat format /* = kXMP_UnknownFile */,
- XMP_OptionBits openFlags /* = 0 */ )
-{
- if ( this->handler != 0 ) XMP_Throw ( "File already open", kXMPErr_BadParam );
- if ( this->fileRef != 0 ) { // ! Sanity check to prevent open file leaks.
- LFA_Close ( this->fileRef );
- this->fileRef = 0;
- }
-
- this->format = kXMP_UnknownFile; // Make sure it is preset for later check.
- this->openFlags = openFlags;
-
- char openMode = 'r';
- if ( openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
-
- FileMode clientMode = GetFileMode ( clientPath );
- if ( (clientMode == kFMode_IsFolder) || (clientMode == kFMode_IsOther) ) return false;
- XMP_Assert ( (clientMode == kFMode_IsFile) || (clientMode == kFMode_DoesNotExist) );
-
- std::string fileExt; // Used to check for camera raw files and OK to scan files.
-
- if ( clientMode == kFMode_IsFile ) {
-
- // Find the file extension. OK to be "wrong" for something like "C:\My.dir\file". Any
- // filtering looks for matches with real extensions, "dir\file" won't match any of these.
- XMP_StringPtr extPos = clientPath + strlen ( clientPath );
- for ( ; (extPos != clientPath) && (*extPos != '.'); --extPos ) {}
- if ( *extPos == '.' ) {
- fileExt.assign ( extPos+1 );
- MakeLowerCase ( &fileExt );
- }
-
- // See if this file is one that XMPFiles should never process.
- for ( size_t i = 0; kKnownRejectedFiles[i] != 0; ++i ) {
- if ( fileExt == kKnownRejectedFiles[i] ) return false;
- }
-
- }
-
- // Find the handler, fill in the XMPFiles member variables, cache the desired file data.
-
- XMPFileHandlerInfo * handlerInfo = 0;
- XMPFileHandlerCTor handlerCTor = 0;
- XMP_OptionBits handlerFlags = 0;
-
- if ( ! (openFlags & kXMPFiles_OpenUsePacketScanning) ) {
- handlerInfo = SelectSmartHandler ( this, clientPath, format, openFlags );
- }
-
- if ( handlerInfo == 0 ) {
-
- // No smart handler, packet scan if appropriate.
-
- if ( clientMode != kFMode_IsFile ) return false;
- if ( openFlags & kXMPFiles_OpenUseSmartHandler ) return false;
-
- if ( openFlags & kXMPFiles_OpenLimitedScanning ) {
- bool scanningOK = false;
- for ( size_t i = 0; kKnownScannedFiles[i] != 0; ++i ) {
- if ( fileExt == kKnownScannedFiles[i] ) { scanningOK = true; break; }
- }
- if ( ! scanningOK ) return false;
- }
-
- handlerInfo = &kScannerHandlerInfo;
- if ( fileRef == 0 ) fileRef = LFA_Open ( clientPath, openMode );
-
- }
-
- XMP_Assert ( handlerInfo != 0 );
- handlerCTor = handlerInfo->handlerCTor;
- handlerFlags = handlerInfo->flags;
-
- this->filePath = clientPath;
-
- XMPFileHandler* handler = (*handlerCTor) ( this );
- XMP_Assert ( handlerFlags == handler->handlerFlags );
-
- this->handler = handler;
- if ( this->format == kXMP_UnknownFile ) this->format = handlerInfo->format; // ! The CheckProc might have set it.
-
- try {
- handler->CacheFileData();
- } catch ( ... ) {
- delete this->handler;
- this->handler = 0;
- if ( ! (handlerFlags & kXMPFiles_HandlerOwnsFile) ) {
- LFA_Close ( this->fileRef );
- this->fileRef = 0;
- }
- throw;
- }
-
- if ( handler->containsXMP ) FillPacketInfo ( handler->xmpPacket, &handler->packetInfo );
-
- if ( (! (openFlags & kXMPFiles_OpenForUpdate)) && (! (handlerFlags & kXMPFiles_HandlerOwnsFile)) ) {
- // Close the disk file now if opened for read-only access.
- LFA_Close ( this->fileRef );
- this->fileRef = 0;
- }
-
- return true;
-
-} // XMPFiles::OpenFile
-
-// =================================================================================================
-
-void
-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;
- XMP_OptionBits handlerFlags = this->handler->handlerFlags;
-
- // Decide if we're doing a safe update. If so, make sure the handler supports it. All handlers
- // that don't own the file tolerate safe update using common code below.
-
- bool doSafeUpdate = XMP_OptionIsSet ( closeFlags, kXMPFiles_UpdateSafely );
- #if GatherPerformanceData
- if ( doSafeUpdate ) sAPIPerf->back().extraInfo += ", safe update"; // Client wants safe update.
- #endif
-
- if ( ! (this->openFlags & kXMPFiles_OpenForUpdate) ) doSafeUpdate = false;
- if ( ! needsUpdate ) doSafeUpdate = false;
-
- bool safeUpdateOK = ( (handlerFlags & kXMPFiles_AllowsSafeUpdate) ||
- (! (handlerFlags & kXMPFiles_HandlerOwnsFile)) );
- if ( doSafeUpdate && (! safeUpdateOK) ) {
- XMP_Throw ( "XMPFiles::CloseFile - Safe update not supported", kXMPErr_Unavailable );
- }
-
- // Try really hard to make sure the file is closed and the handler is deleted.
-
- LFA_FileRef origFileRef = this->fileRef; // Used during crash-safe saves.
- std::string origFilePath ( this->filePath );
-
- LFA_FileRef tempFileRef = 0;
- std::string tempFilePath;
-
- LFA_FileRef copyFileRef = 0;
- std::string copyFilePath;
-
- try {
-
- if ( (! doSafeUpdate) || (handlerFlags & kXMPFiles_HandlerOwnsFile) ) { // ! Includes no update case.
-
- // Close the file without doing common crash-safe writing. The handler might do it.
-
- if ( needsUpdate ) {
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", direct update";
- #endif
- this->handler->UpdateFile ( doSafeUpdate );
- }
-
- delete this->handler;
- this->handler = 0;
- if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
- this->fileRef = 0;
-
- } else {
-
- // Update the file in a crash-safe manner. This somewhat convoluted approach preserves
- // the ownership, permissions, and Mac resources of the final file - at a slightly
- // higher risk of confusion in the event of a midstream crash.
-
- if ( handlerFlags & kXMPFiles_CanRewrite ) {
-
- // The handler can rewrite an entire file based on the original. Do this into a temp
- // file next to the original, with the same ownership and permissions if possible.
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", file rewrite";
- #endif
-
- CreateTempFile ( origFilePath, &tempFilePath, kCopyMacRsrc );
- XMP_Assert ( tempFileRef == 0 );
- tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
- this->fileRef = tempFileRef;
- tempFileRef = 0;
- this->filePath = tempFilePath;
- this->handler->WriteFile ( origFileRef, origFilePath );
-
- } else {
-
- // The handler can only update an existing file. Do a little dance so that the final
- // file is the updated original, thus preserving ownership, permissions, etc. This
- // does have the risk that the interim copy under the original name has "current"
- // ownership and permissions. The dance steps:
- // - Copy the original file to a temp name, the copyFile.
- // - Rename the original file to a different temp name, the tempFile.
- // - Rename the copyFile back to the original name.
- // - Call the handler's UpdateFile method for the tempFile.
- // A failure inside the handler's UpdateFile method will leave the copied file under
- // the original name.
-
- // *** A user abort might leave the copy file under the original name! Need better
- // *** duplicate code that handles all parts of a file, and for CreateTempFile to
- // *** preserve ownership and permissions. Then the original can stay put until
- // *** the final delete/rename.
-
- #if GatherPerformanceData
- sAPIPerf->back().extraInfo += ", copy update";
- #endif
-
- CreateTempFile ( origFilePath, &copyFilePath, kCopyMacRsrc );
- XMP_Assert ( copyFileRef == 0 );
- copyFileRef = LFA_Open ( copyFilePath.c_str(), 'w' );
- XMP_Int64 fileSize = LFA_Measure ( origFileRef );
- LFA_Seek ( origFileRef, 0, SEEK_SET );
- LFA_Copy ( origFileRef, copyFileRef, fileSize, this->abortProc, this->abortArg );
-
- LFA_Close ( origFileRef );
- LFA_Close ( copyFileRef );
- copyFileRef = origFileRef = this->fileRef = 0;
-
- CreateTempFile ( origFilePath, &tempFilePath );
- LFA_Delete ( tempFilePath.c_str() ); // ! Slight risk of name being grabbed before rename.
- LFA_Rename ( origFilePath.c_str(), tempFilePath.c_str() );
-
- LFA_Rename ( copyFilePath.c_str(), origFilePath.c_str() );
- copyFilePath.clear();
-
- XMP_Assert ( tempFileRef == 0 );
- tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
- this->fileRef = tempFileRef;
- tempFileRef = 0;
- this->filePath = tempFilePath;
-
- try {
- this->handler->UpdateFile ( false ); // We're doing the safe update, not the handler.
- } catch ( ... ) {
- this->fileRef = 0;
- this->filePath = origFilePath; // This is really the copied file.
- LFA_Close ( tempFileRef );
- LFA_Delete ( tempFilePath.c_str() );
- tempFileRef = 0;
- tempFilePath.clear();
- throw;
- }
-
- }
-
- delete this->handler;
- this->handler = 0;
-
- if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
- if ( origFileRef != 0 ) LFA_Close ( origFileRef );
-
- this->fileRef = 0;
- origFileRef = 0;
- tempFileRef = 0;
-
- LFA_Delete ( origFilePath.c_str() );
- LFA_Rename ( tempFilePath.c_str(), origFilePath.c_str() );
- tempFilePath.clear();
-
- }
-
- } catch ( ... ) {
-
- // *** Don't delete the temp or copy files, not sure which is best.
-
- try {
- if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( origFileRef != 0 ) LFA_Close ( origFileRef );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( tempFileRef != 0 ) LFA_Close ( tempFileRef );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( ! tempFilePath.empty() ) LFA_Delete ( tempFilePath.c_str() );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( copyFileRef != 0 ) LFA_Close ( copyFileRef );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( ! copyFilePath.empty() ) LFA_Delete ( copyFilePath.c_str() );
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
- try {
- if ( this->handler != 0 ) delete this->handler;
- } catch ( ... ) { /* Do nothing, throw the outer exception later. */ }
-
- this->handler = 0;
- this->format = kXMP_UnknownFile;
- this->fileRef = 0;
- this->filePath.clear();
- this->openFlags = 0;
-
- if ( this->tempPtr != 0 ) free ( this->tempPtr ); // ! Must have been malloc-ed!
- this->tempPtr = 0;
- this->tempUI32 = 0;
-
- throw;
-
- }
-
- // Clear the XMPFiles member variables.
-
- this->handler = 0;
- this->format = kXMP_UnknownFile;
- this->fileRef = 0;
- this->filePath.clear();
- this->openFlags = 0;
-
- if ( this->tempPtr != 0 ) free ( this->tempPtr ); // ! Must have been malloc-ed!
- this->tempPtr = 0;
- this->tempUI32 = 0;
-
-} // XMPFiles::CloseFile
-
-// =================================================================================================
-
-bool
-XMPFiles::GetFileInfo ( XMP_StringPtr * filePath /* = 0 */,
- XMP_StringLen * pathLen /* = 0 */,
- XMP_OptionBits * openFlags /* = 0 */,
- XMP_FileFormat * format /* = 0 */,
- XMP_OptionBits * handlerFlags /* = 0 */ ) const
-{
- if ( this->handler == 0 ) return false;
- XMPFileHandler * handler = this->handler;
-
- if ( filePath == 0 ) filePath = &voidStringPtr;
- if ( pathLen == 0 ) pathLen = &voidStringLen;
- if ( openFlags == 0 ) openFlags = &voidOptionBits;
- if ( format == 0 ) format = &voidFileFormat;
- if ( handlerFlags == 0 ) handlerFlags = &voidOptionBits;
-
- *filePath = this->filePath.c_str();
- *pathLen = (XMP_StringLen) this->filePath.size();
- *openFlags = this->openFlags;
- *format = this->format;
- *handlerFlags = this->handler->handlerFlags;
-
- return true;
-
-} // XMPFiles::GetFileInfo
-
-// =================================================================================================
-
-void
-XMPFiles::SetAbortProc ( XMP_AbortProc abortProc,
- void * abortArg )
-{
- this->abortProc = abortProc;
- this->abortArg = abortArg;
-
- XMP_Assert ( (abortProc != (XMP_AbortProc)0) || (abortArg != (void*)(unsigned long long)0xDEADBEEFULL) ); // Hack to test the assert callback.
-} // XMPFiles::SetAbortProc
-
-// =================================================================================================
-// SetClientPacketInfo
-// ===================
-//
-// Set the packet info returned to the client. This is the internal packet info at first, which
-// tells what is in the file. But once the file needs update (PutXMP has been called), we return
-// info about the latest XMP. The internal packet info is left unchanged since it is needed when
-// the file is updated to locate the old packet in the file.
-
-static void
-SetClientPacketInfo ( XMP_PacketInfo * clientInfo, const XMP_PacketInfo & handlerInfo,
- const std::string & xmpPacket, bool needsUpdate )
-{
-
- if ( clientInfo == 0 ) return;
-
- if ( ! needsUpdate ) {
- *clientInfo = handlerInfo;
- } else {
- clientInfo->offset = kXMPFiles_UnknownOffset;
- clientInfo->length = (XMP_Int32) xmpPacket.size();
- FillPacketInfo ( xmpPacket, clientInfo );
- }
-
-} // SetClientPacketInfo
-
-// =================================================================================================
-
-bool
-XMPFiles::GetXMP ( SXMPMeta * xmpObj /* = 0 */,
- XMP_StringPtr * xmpPacket /* = 0 */,
- XMP_StringLen * xmpPacketLen /* = 0 */,
- XMP_PacketInfo * packetInfo /* = 0 */ )
-{
- if ( this->handler == 0 ) XMP_Throw ( "XMPFiles::GetXMP - No open file", kXMPErr_BadObject );
-
- XMP_OptionBits applyTemplateFlags = kXMPTemplate_AddNewProperties | kXMPTemplate_IncludeInternalProperties;
-
- if ( ! this->handler->processedXMP ) {
- try {
- this->handler->ProcessXMP();
- } catch ( ... ) {
- // Return the outputs then rethrow the exception.
- if ( xmpObj != 0 ) {
- // ! Don't use Clone, that replaces the internal ref in the local xmpObj, leaving the client unchanged!
- xmpObj->Erase();
- SXMPUtils::ApplyTemplate ( xmpObj, this->handler->xmpObj, applyTemplateFlags );
- }
- if ( xmpPacket != 0 ) *xmpPacket = this->handler->xmpPacket.c_str();
- if ( xmpPacketLen != 0 ) *xmpPacketLen = (XMP_StringLen) this->handler->xmpPacket.size();
- SetClientPacketInfo ( packetInfo, this->handler->packetInfo,
- this->handler->xmpPacket, this->handler->needsUpdate );
- throw;
- }
- }
-
- if ( ! this->handler->containsXMP ) return false;
-
- #if 0 // *** See bug 1131815. A better way might be to pass the ref up from here.
- if ( xmpObj != 0 ) *xmpObj = this->handler->xmpObj.Clone();
- #else
- if ( xmpObj != 0 ) {
- // ! Don't use Clone, that replaces the internal ref in the local xmpObj, leaving the client unchanged!
- xmpObj->Erase();
- SXMPUtils::ApplyTemplate ( xmpObj, this->handler->xmpObj, applyTemplateFlags );
- }
- #endif
-
- if ( xmpPacket != 0 ) *xmpPacket = this->handler->xmpPacket.c_str();
- if ( xmpPacketLen != 0 ) *xmpPacketLen = (XMP_StringLen) this->handler->xmpPacket.size();
- SetClientPacketInfo ( packetInfo, this->handler->packetInfo,
- this->handler->xmpPacket, this->handler->needsUpdate );
-
- return true;
-
-} // XMPFiles::GetXMP
-
-// =================================================================================================
-
-static bool
-DoPutXMP ( XMPFiles * thiz, const SXMPMeta & xmpObj, const bool doIt )
-{
- // Check some basic conditions to see if the Put should be attempted.
-
- if ( thiz->handler == 0 ) XMP_Throw ( "XMPFiles::PutXMP - No open file", kXMPErr_BadObject );
- if ( ! (thiz->openFlags & kXMPFiles_OpenForUpdate) ) {
- XMP_Throw ( "XMPFiles::PutXMP - Not open for update", kXMPErr_BadObject );
- }
-
- XMPFileHandler * handler = thiz->handler;
- XMP_OptionBits handlerFlags = handler->handlerFlags;
- XMP_PacketInfo & packetInfo = handler->packetInfo;
- std::string & xmpPacket = handler->xmpPacket;
-
- if ( ! handler->processedXMP ) handler->ProcessXMP(); // Might have Open/Put with no GetXMP.
-
- size_t oldPacketOffset = (size_t)packetInfo.offset;
- size_t oldPacketLength = packetInfo.length;
-
- if ( oldPacketOffset == (size_t)kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
- if ( oldPacketLength == (size_t)kXMPFiles_UnknownLength ) oldPacketLength = 0;
-
- bool fileHasPacket = (oldPacketOffset != 0) && (oldPacketLength != 0);
-
- if ( ! fileHasPacket ) {
- if ( ! (handlerFlags & kXMPFiles_CanInjectXMP) ) {
- XMP_Throw ( "XMPFiles::PutXMP - Can't inject XMP", kXMPErr_Unavailable );
- }
- if ( handler->stdCharForm == kXMP_CharUnknown ) {
- XMP_Throw ( "XMPFiles::PutXMP - No standard character form", kXMPErr_InternalFailure );
- }
- }
-
- // Serialize the XMP and update the handler's info.
-
- XMP_Uns8 charForm = handler->stdCharForm;
- if ( charForm == kXMP_CharUnknown ) charForm = packetInfo.charForm;
-
- XMP_OptionBits options = handler->GetSerializeOptions() | XMP_CharToSerializeForm ( charForm );
- if ( handlerFlags & kXMPFiles_NeedsReadOnlyPacket ) options |= kXMP_ReadOnlyPacket;
- if ( fileHasPacket && (thiz->format == kXMP_UnknownFile) && (! packetInfo.writeable) ) options |= kXMP_ReadOnlyPacket;
-
- bool preferInPlace = ((handlerFlags & kXMPFiles_PrefersInPlace) != 0);
- bool tryInPlace = (fileHasPacket & preferInPlace) || (! (handlerFlags & kXMPFiles_CanExpand));
-
- if ( handlerFlags & kXMPFiles_UsesSidecarXMP ) tryInPlace = false;
-
- if ( tryInPlace ) {
- try {
- xmpObj.SerializeToBuffer ( &xmpPacket, (options | kXMP_ExactPacketLength), (XMP_StringLen) oldPacketLength );
- XMP_Assert ( xmpPacket.size() == oldPacketLength );
- } catch ( ... ) {
- if ( preferInPlace ) {
- tryInPlace = false; // ! Try again, out of place this time.
- } else {
- if ( ! doIt ) return false;
- throw;
- }
- }
- }
-
- if ( ! tryInPlace ) {
- try {
- xmpObj.SerializeToBuffer ( &xmpPacket, options );
- } catch ( ... ) {
- if ( ! doIt ) return false;
- throw;
- }
- }
-
- if ( doIt ) {
- handler->xmpObj = xmpObj.Clone();
- handler->containsXMP = true;
- handler->processedXMP = true;
- handler->needsUpdate = true;
- }
-
- return true;
-
-} // DoPutXMP
-
-// =================================================================================================
-
-void
-XMPFiles::PutXMP ( const SXMPMeta & xmpObj )
-{
- (void) DoPutXMP ( this, xmpObj, true );
-
-} // XMPFiles::PutXMP
-
-// =================================================================================================
-
-void
-XMPFiles::PutXMP ( XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen /* = kXMP_UseNullTermination */ )
-{
- SXMPMeta xmpObj ( xmpPacket, xmpPacketLen );
- this->PutXMP ( xmpObj );
-
-} // XMPFiles::PutXMP
-
-// =================================================================================================
-
-bool
-XMPFiles::CanPutXMP ( const SXMPMeta & xmpObj )
-{
- if ( this->handler == 0 ) XMP_Throw ( "XMPFiles::CanPutXMP - No open file", kXMPErr_BadObject );
-
- if ( ! (this->openFlags & kXMPFiles_OpenForUpdate) ) return false;
-
- if ( this->handler->handlerFlags & kXMPFiles_CanInjectXMP ) return true;
- if ( ! this->handler->containsXMP ) return false;
- if ( this->handler->handlerFlags & kXMPFiles_CanExpand ) return true;
-
- return DoPutXMP ( this, xmpObj, false );
-
-} // XMPFiles::CanPutXMP
-
-// =================================================================================================
-
-bool
-XMPFiles::CanPutXMP ( XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen /* = kXMP_UseNullTermination */ )
-{
- SXMPMeta xmpObj ( xmpPacket, xmpPacketLen );
- return this->CanPutXMP ( xmpObj );
-
-} // XMPFiles::CanPutXMP
-
-// =================================================================================================
diff --git a/source/XMPFiles/XMPFiles.hpp b/source/XMPFiles/XMPFiles.hpp
deleted file mode 100644
index 8744a31..0000000
--- a/source/XMPFiles/XMPFiles.hpp
+++ /dev/null
@@ -1,230 +0,0 @@
-#ifndef __XMPFiles_hpp__
-#define __XMPFiles_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 <string>
-
-#define TXMP_STRING_TYPE std::string
-#include "XMP.hpp"
-
-#if ! UNIX_ENV
- typedef void * LFA_FileRef;
-#else
- typedef XMP_Int32 LFA_FileRef;
-#endif
-
-class XMPFileHandler;
-
-// =================================================================================================
-/// \file XMPFiles.hpp
-/// \brief High level support to access metadata in files of interest to Adobe applications.
-///
-/// This header ...
-///
-// =================================================================================================
-
-// =================================================================================================
-// *** Usage Notes (eventually to become Doxygen comments) ***
-// ===========================================================
-//
-// This is the main part of the internal (DLL side) implementation of XMPFiles. Other parts are
-// the entry point wrappers and the file format handlers. The XMPFiles class distills the client
-// API from TXMPFiles.hpp, removing convenience overloads and substituting a pointer/length pair
-// for output strings.
-//
-// The wrapper functions provide a stable binary interface and perform minor impedance correction
-// between the client template API from TDocMeta.hpp and the DLL's XMPFiles class. The details of
-// the wrappers should be considered private.
-//
-// File handlers are registered during DLL initialization with hard coded calls in Init_XMPFiles.
-// Each file handler provides 2 standalone functions, CheckFormatProc and DocMetaHandlerCTor, plus a
-// class derived from DocMetaHandler. The format and capability flags are passed when registering.
-// This allows the same physical handler to be registered for multiple formats.
-//
-// -------------------------------------------------------------------------------------------------
-//
-// Basic outlines of the processing by the XMPFiles methods:
-//
-// Constructor:
-// - Minimal work to create an empty XMPFiles object, set the ref count to 1.
-//
-// Destructor:
-// - Decrement the ref count, return if greater than zero.
-// - Call LFA_Close if necessary.
-//
-// UnlockLib & UnlockObj:
-// - Release the thread lock. Same for now, no per-object lock.
-//
-// GetFormatInfo:
-// - Return the flags for the registered handler.
-//
-// OpenFile:
-// - The physical file is opened via LFA_OpenFile.
-// - A handler is selected by calling the registered format checkers.
-// - The handler object is created by calling the registered constructor proc.
-//
-// CloseFile:
-// - Return if there is no open file (not an error).
-// - If not a crash-safe update (includes read-only or no update), or the handler owns the file:
-// - Throw an exception if the handler owns the file but does not support safe update.
-// - If the file needs updating, call the handler's UpdateFile method.
-// - else:
-// - If the handler supports file rewrite:
-// - *** This might not preserve ownership and permissions.
-// - Create an empty temp file.
-// - Call the handler's WriteFile method, writing to the temp file.
-// - else
-// - *** This preserves ownership, permissions, and Mac resources.
-// - Copy the original file to a temp name (Mac data fork only).
-// - Rename the original file to a different temp name.
-// - Rename the copy file back to the original name.
-// - Call the handler's UpdateFile method for the "original as temp" file.
-// - Close both the original and temp files.
-// - Delete the file with the original name.
-// - Rename the temp file to the original name.
-// - Delete the handler object.
-// - Call LFA_Close if necessary.
-//
-// GetFileInfo:
-// - Return the file info from the XMPFiles member variables.
-//
-// GetXMP:
-// - Throw an exception if there is no open file.
-// - Call the handler's GetXMP method.
-//
-// PutXMP:
-// - Throw an exception if there is no open file.
-// - Call the handler's PutXMP method.
-//
-// CanPutXMP:
-// - Implement roughly as shown in TXMPFiles.hpp, there is no handler CanPutXMP method.
-//
-// -------------------------------------------------------------------------------------------------
-//
-// The format checker should do nothing but the minimal work to identify the overall file format.
-// In particular it should not look for XMP or other metadata. Note that the format checker has no
-// means to carry state forward, it just returns a yes/no answer about a particular file format.
-//
-// The format checker and file handler should use the LFA_* functions for all I/O. They should not
-// open or close the file themselves unless the handler sets the "handler-owns-file" flag.
-//
-// The format checker is passed the format being checked, allowing one checker to handle multiple
-// formats. It is passed the LFA file ref so that it can do additional reads if necessary. The
-// buffer is from the start of the file, the file will be positioned to the byte following the
-// buffer. The buffer length will be at least 4K, unless the file is smaller in which case it will
-// be the length of the file. This buffer may be reused for additional reads.
-//
-// Identifying some file formats can require checking variable length strings. Doing seeks and reads
-// for each is suboptimal. There are utilities to maintain a rolling buffer and ensure that a given
-// amount of data is available. See the template file handler code for details.
-//
-// -------------------------------------------------------------------------------------------------
-//
-// The file handler has no explicit open and close methods. These are implicit in the handler's
-// constructor and destructor. The file handler should use the XMPFiles member variables for the
-// active file ref (and path if necessary), unless it owns the file. Note that these might change
-// between the open and close in the case of crash-safe updates. Don't copy the XMPFiles member
-// variables in the handler's constructor, save the pointer to the XMPFiles object and access
-// directly as needed.
-//
-// The handler should have an UpdateFile method. This is called from XMPFiles::CloseFile if the
-// file needs to be updated. The handler's destructor must only close the file, not update it.
-// The handler can optionally have a WriteFile method, if it can rewrite the entire file.
-//
-// The handler is free to use its best judgement about caching parts of the file in memory. Overall
-// speed of a single open/get/put/close cycle is probably the best goal, assuming a modern processor
-// with a reasonable (significant but not enormous) amount of RAM.
-//
-// The handler methods will be called in a per-object thread safe manner. Concurrent access might
-// occur for different objects, but not for the same object. The handler's constructor and destructor
-// will always be globally serialized, so they can safely modify global data structures.
-//
-// (Testing issue: What about separate XMPFiles objects accessing the same file?)
-//
-// Handler's must not have any global objects that are heap allocated. Use pointers to objects that
-// are allocated and deleted during the XMPFiles initialization and termination process. Some
-// client apps are very picky about what they detect as memory leaks.
-//
-// static char gSomeBuffer [10*1000]; // OK, not from the heap.
-// static std::string gSomeString; // Not OK, content from the heap.
-// static std::vector<int> gSomeVector; // Not OK, content from the heap.
-// static std::string * gSomeString = 0; // OK, alloc at init, delete at term.
-// static std::vector<int> * gSomeVector = 0; // OK, alloc at init, delete at term.
-//
-// =================================================================================================
-
-class XMPFiles {
-public:
-
- static void GetVersionInfo ( XMP_VersionInfo * info );
-
- static bool Initialize ( XMP_OptionBits options = 0 );
- static void Terminate();
-
- XMPFiles();
- virtual ~XMPFiles();
-
- static bool GetFormatInfo ( XMP_FileFormat format,
- XMP_OptionBits * flags = 0 );
-
- static XMP_FileFormat CheckFileFormat ( XMP_StringPtr filePath );
- static XMP_FileFormat CheckPackageFormat ( XMP_StringPtr folderPath );
-
- bool OpenFile ( XMP_StringPtr filePath,
- XMP_FileFormat format = kXMP_UnknownFile,
- XMP_OptionBits openFlags = 0 );
-
- void CloseFile ( XMP_OptionBits closeFlags = 0 );
-
- bool GetFileInfo ( XMP_StringPtr * filePath = 0,
- XMP_StringLen * filePathLen = 0,
- XMP_OptionBits * openFlags = 0,
- XMP_FileFormat * format = 0,
- XMP_OptionBits * handlerFlags = 0 ) const;
-
- void SetAbortProc ( XMP_AbortProc abortProc,
- void * abortArg );
-
- bool GetXMP ( SXMPMeta * xmpObj = 0,
- XMP_StringPtr * xmpPacket = 0,
- XMP_StringLen * xmpPacketLen = 0,
- XMP_PacketInfo * packetInfo = 0 );
-
- void PutXMP ( const SXMPMeta & xmpObj );
-
- void PutXMP ( XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen = kXMP_UseNullTermination );
-
- bool CanPutXMP ( const SXMPMeta & xmpObj );
-
- bool CanPutXMP ( XMP_StringPtr xmpPacket,
- XMP_StringLen xmpPacketLen = kXMP_UseNullTermination );
-
- // Leave this data public so file handlers can see it.
-
- XMP_Int32 clientRefs; // ! Must be signed to allow decrement from zero.
- XMP_ReadWriteLock lock;
-
- XMP_FileFormat format;
- LFA_FileRef fileRef; // Non-zero if a file is open.
- std::string filePath;
- XMP_OptionBits openFlags;
- XMPFileHandler * handler; // Non-null if a file is open.
-
- void * tempPtr; // For use between the CheckProc and handler creation.
- XMP_Uns32 tempUI32;
-
- XMP_AbortProc abortProc;
- void * abortArg;
-
-}; // XMPFiles
-
-#endif /* __XMPFiles_hpp__ */
diff --git a/source/XMPFiles/XMPFiles_Impl.cpp b/source/XMPFiles/XMPFiles_Impl.cpp
deleted file mode 100644
index 1677141..0000000
--- a/source/XMPFiles/XMPFiles_Impl.cpp
+++ /dev/null
@@ -1,780 +0,0 @@
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 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 "XMPFiles_Impl.hpp"
-
-#include "UnicodeConversions.hpp"
-
-using namespace std;
-
-// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, or XMP_UNIXBuild.
-// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor
-// practice of defining the *_ENV macro with an empty value.
-#if defined ( MAC_ENV )
- #if ! MAC_ENV
- #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
- #endif
-#elif defined ( WIN_ENV )
- #if ! WIN_ENV
- #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
- #endif
-#elif defined ( UNIX_ENV )
- #if ! UNIX_ENV
- #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
- #endif
-#endif
-
-// =================================================================================================
-/// \file XMPFiles_Impl.cpp
-/// \brief ...
-///
-/// This file ...
-///
-// =================================================================================================
-
-#if XMP_WinBuild
- #pragma warning ( disable : 4290 ) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
- #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
-#endif
-
-bool ignoreLocalText = false;
-
-XMP_FileFormat voidFileFormat = 0; // Used as sink for unwanted output parameters.
-// =================================================================================================
-
-// Add all known mappings, multiple mappings (tif, tiff) are OK.
-const FileExtMapping kFileExtMap[] =
- { { "pdf", kXMP_PDFFile },
- { "ps", kXMP_PostScriptFile },
- { "eps", kXMP_EPSFile },
-
- { "jpg", kXMP_JPEGFile },
- { "jpeg", kXMP_JPEGFile },
- { "jpx", kXMP_JPEG2KFile },
- { "tif", kXMP_TIFFFile },
- { "tiff", kXMP_TIFFFile },
- { "dng", kXMP_TIFFFile }, // DNG files are well behaved TIFF.
- { "gif", kXMP_GIFFile },
- { "giff", kXMP_GIFFile },
- { "png", kXMP_PNGFile },
-
- { "swf", kXMP_SWFFile },
- { "flv", kXMP_FLVFile },
-
- { "aif", kXMP_AIFFFile },
-
- { "mov", kXMP_MOVFile },
- { "avi", kXMP_AVIFile },
- { "cin", kXMP_CINFile },
- { "wav", kXMP_WAVFile },
- { "mp3", kXMP_MP3File },
- { "mp4", kXMP_MPEG4File },
- { "m4v", kXMP_MPEG4File },
- { "m4a", kXMP_MPEG4File },
- { "f4v", kXMP_MPEG4File },
- { "ses", kXMP_SESFile },
- { "cel", kXMP_CELFile },
- { "wma", kXMP_WMAVFile },
- { "wmv", kXMP_WMAVFile },
-
- { "mpg", kXMP_MPEGFile },
- { "mpeg", kXMP_MPEGFile },
- { "mp2", kXMP_MPEGFile },
- { "mod", kXMP_MPEGFile },
- { "m2v", kXMP_MPEGFile },
- { "mpa", kXMP_MPEGFile },
- { "mpv", kXMP_MPEGFile },
- { "m2p", kXMP_MPEGFile },
- { "m2a", kXMP_MPEGFile },
- { "m2t", kXMP_MPEGFile },
- { "mpe", kXMP_MPEGFile },
- { "vob", kXMP_MPEGFile },
- { "ms-pvr", kXMP_MPEGFile },
- { "dvr-ms", kXMP_MPEGFile },
-
- { "html", kXMP_HTMLFile },
- { "xml", kXMP_XMLFile },
- { "txt", kXMP_TextFile },
- { "text", kXMP_TextFile },
-
- { "psd", kXMP_PhotoshopFile },
- { "ai", kXMP_IllustratorFile },
- { "indd", kXMP_InDesignFile },
- { "indt", kXMP_InDesignFile },
- { "aep", kXMP_AEProjectFile },
- { "aepx", kXMP_AEProjectFile },
- { "aet", kXMP_AEProjTemplateFile },
- { "ffx", kXMP_AEFilterPresetFile },
- { "ncor", kXMP_EncoreProjectFile },
- { "prproj", kXMP_PremiereProjectFile },
- { "prtl", kXMP_PremiereTitleFile },
- { "ucf", kXMP_UCFFile },
- { "xfl", kXMP_UCFFile },
- { "pdfxml", kXMP_UCFFile },
- { "mars", kXMP_UCFFile },
- { "idml", kXMP_UCFFile },
- { "idap", kXMP_UCFFile },
- { "icap", kXMP_UCFFile },
- { "", 0 } }; // ! Must be last as a sentinel.
-
-// Files known to contain XMP but have no smart handling, here or elsewhere.
-const char * kKnownScannedFiles[] =
- { "gif", // GIF, public format but no smart handler.
- "ai", // Illustrator, actually a PDF file.
- "ait", // Illustrator template, actually a PDF file.
- "svg", // SVG, an XML file.
- "aet", // After Effects template project file.
- "ffx", // After Effects filter preset file.
- "aep", // After Effects project file in proprietary format
- "aepx", // After Effects project file in XML format
- "inx", // InDesign interchange, an XML file.
- "inds", // InDesign snippet, an XML file.
- "inpk", // InDesign package for GoLive, a text file (not XML).
- "incd", // InCopy story, an XML file.
- "inct", // InCopy template, an XML file.
- "incx", // InCopy interchange, an XML file.
- "fm", // FrameMaker file, proprietary format.
- "book", // FrameMaker book, proprietary format.
- "icml", // an inCopy (inDesign) format
- "icmt", // an inCopy (inDesign) format
- "idms", // an inCopy (inDesign) format
- 0 }; // ! Keep a 0 sentinel at the end.
-
-
-// Extensions that XMPFiles never handles.
-const char * kKnownRejectedFiles[] =
- {
- // RAW files
- "cr2", "erf", "fff", "dcr", "kdc", "mos", "mfw", "mef",
- "raw", "nef", "orf", "pef", "arw", "sr2", "srf", "sti",
- "3fr", "rwl", "crw", "sraw", "mos", "mrw", "nrw", "rw2",
- "c3f",
- // UCF subformats
- "air",
- // Others
- "r3d",
- 0 }; // ! Keep a 0 sentinel at the end.
-
-// =================================================================================================
-
-// =================================================================================================
-
-void LFA_Throw ( const char* msg, int id )
-{
- switch ( id ) {
- case kLFAErr_InternalFailure:
- XMP_Throw ( msg, kXMPErr_InternalFailure );
- case kLFAErr_ExternalFailure:
- XMP_Throw ( msg, kXMPErr_ExternalFailure );
- case kLFAErr_UserAbort:
- XMP_Throw ( msg, kXMPErr_UserAbort );
- default:
- XMP_Throw ( msg, kXMPErr_UnknownException );
- }
-}
-
-// =================================================================================================
-
-#if XMP_MacBuild | XMP_UNIXBuild
- //copy from LargeFileAccess.cpp
- static bool FileExists ( const char * filePath )
- {
- struct stat info;
- int err = stat ( filePath, &info );
- return (err == 0);
- }
-#endif
-
-// =================================================================================================
-
-static bool CreateNewFile ( const char * newPath, const char * origPath, size_t filePos, bool copyMacRsrc )
-{
- // Try to create a new file with the same ownership and permissions as some other file.
- // *** The ownership and permissions are not handled on all platforms.
-
- #if XMP_MacBuild | XMP_UNIXBuild
-
- if ( FileExists ( newPath ) ) return false;
-
- #elif XMP_WinBuild
-
- {
- std::string wideName;
- const size_t utf8Len = strlen(newPath);
- const size_t maxLen = 2 * (utf8Len+1);
- wideName.reserve ( maxLen );
- wideName.assign ( maxLen, ' ' );
- int wideLen = MultiByteToWideChar ( CP_UTF8, 0, newPath, -1, (LPWSTR)wideName.data(), (int)maxLen );
- if ( wideLen == 0 ) return false;
- HANDLE temp = CreateFileW ( (LPCWSTR)wideName.data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
- (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
- if ( temp != INVALID_HANDLE_VALUE ) {
- CloseHandle ( temp );
- return false;
- }
- }
-
- #endif
-
- try {
- LFA_FileRef newFile = LFA_Create ( newPath );
- LFA_Close ( newFile );
- } catch ( ... ) {
- // *** Unfortunate that LFA_Create throws for an existing file.
- return false;
- }
-
- #if XMP_WinBuild
-
- IgnoreParam(origPath); IgnoreParam(filePos); IgnoreParam(copyMacRsrc);
-
- // *** Don't handle Windows specific info yet.
-
- #elif XMP_MacBuild
-
- IgnoreParam(filePos);
-
- OSStatus err;
- FSRef newFSRef, origFSRef; // Copy the "copyable" catalog info, includes the Finder info.
-
- err = FSPathMakeRef ( (XMP_Uns8*)origPath, &origFSRef, 0 );
- if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSPathMakeRef failure", kXMPErr_ExternalFailure );
- err = FSPathMakeRef ( (XMP_Uns8*)newPath, &newFSRef, 0 );
- if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSPathMakeRef failure", kXMPErr_ExternalFailure );
-
- FSCatalogInfo catInfo; // *** What about the GetInfo comment? The Finder label?
- memset ( &catInfo, 0, sizeof(FSCatalogInfo) );
-
- err = FSGetCatalogInfo ( &origFSRef, kFSCatInfoGettableInfo, &catInfo, 0, 0, 0 );
- if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSGetCatalogInfo failure", kXMPErr_ExternalFailure );
- err = FSSetCatalogInfo ( &newFSRef, kFSCatInfoSettableInfo, &catInfo );
-
- // *** [1841019] tolerate non mac filesystems, i.e. SMB mounts
- // this measure helps under 10.5, albeit not reliably under 10.4
- if ( err == afpAccessDenied )
- copyMacRsrc = false;
- else if ( err != noErr ) // all other errors are still an error
- XMP_Throw ( "CreateNewFile: FSSetCatalogInfo failure", kXMPErr_ExternalFailure );
-
- // *** [1841019] tolerate non mac filesystems, i.e. SMB mounts
- // this measure helps under 10.4 (and besides might be an optimization)
- if ( catInfo.rsrcLogicalSize == 0 )
- copyMacRsrc = false;
-
- if ( copyMacRsrc ) { // Copy the resource fork as a byte stream.
- LFA_FileRef origRsrcRef = 0;
- LFA_FileRef copyRsrcRef = 0;
- try {
- origRsrcRef = LFA_OpenRsrc ( origPath, 'r' );
- XMP_Int64 rsrcSize = LFA_Measure ( origRsrcRef );
- if ( rsrcSize > 0 ) {
- copyRsrcRef = LFA_OpenRsrc ( newPath, 'w' );
- LFA_Copy ( origRsrcRef, copyRsrcRef, rsrcSize, 0, 0 ); // ! Resource fork small enough to not need abort checking.
- LFA_Close ( copyRsrcRef );
- }
- LFA_Close ( origRsrcRef );
- } catch ( ... ) {
- if ( origRsrcRef != 0 ) LFA_Close ( origRsrcRef );
- if ( copyRsrcRef != 0 ) LFA_Close ( copyRsrcRef );
- throw;
- }
- }
-
-
- #elif XMP_UNIXBuild
-
- IgnoreParam(filePos); IgnoreParam(copyMacRsrc);
- // *** Can't use on Mac because of frigging CW POSIX header problems!
-
- // *** Don't handle UNIX specific info yet.
-
- int err, newRef;
- struct stat origInfo;
- err = stat ( origPath, &origInfo );
- if ( err != 0 ) XMP_Throw ( "CreateNewFile: stat failure", kXMPErr_ExternalFailure );
-
- (void) chmod ( newPath, origInfo.st_mode ); // Ignore errors.
-
- #endif
-
- return true;
-
-} // CreateNewFile
-
-// =================================================================================================
-
-void CreateTempFile ( const std::string & origPath, std::string * tempPath, bool copyMacRsrc )
-{
- // Create an empty temp file next to the source file with the same ownership and permissions.
- // The temp file has "._nn_" added as a prefix to the file name, where "nn" is a unique
- // sequence number. The "._" start is important for Bridge, telling it to ignore the file.
-
- // *** The ownership and permissions are not yet handled.
-
- #if XMP_WinBuild
- #define kUseBS true
- #else
- #define kUseBS false
- #endif
-
- // Break the full path into folder path and file name portions.
-
- size_t namePos; // The origPath index of the first byte of the file name part.
-
- for ( namePos = origPath.size(); namePos > 0; --namePos ) {
- if ( (origPath[namePos] == '/') || (kUseBS && (origPath[namePos] == '\\')) ) {
- ++namePos;
- break;
- }
- }
- if ( (origPath[namePos] == '/') || (kUseBS && (origPath[namePos] == '\\')) ) ++namePos;
- if ( namePos == origPath.size() ) XMP_Throw ( "CreateTempFile: Empty file name part", kXMPErr_InternalFailure );
-
- std::string folderPath ( origPath, 0, namePos );
- std::string origName ( origPath, namePos );
-
- // First try to create a file with "._nn_" added as a file name prefix.
-
- char tempPrefix[6] = "._nn_";
-
- tempPath->reserve ( origPath.size() + 5 );
- tempPath->assign ( origPath, 0, namePos );
- tempPath->append ( tempPrefix, 5 );
- tempPath->append ( origName );
-
- for ( char n1 = '0'; n1 <= '9'; ++n1 ) {
- (*tempPath)[namePos+2] = n1;
- for ( char n2 = '0'; n2 <= '9'; ++n2 ) {
- (*tempPath)[namePos+3] = n2;
- if ( CreateNewFile ( tempPath->c_str(), origPath.c_str(), namePos, copyMacRsrc ) ) return;
- }
- }
-
- // Now try to create a file with the name "._nn_XMPFilesTemp"
-
- tempPath->assign ( origPath, 0, namePos );
- tempPath->append ( tempPrefix, 5 );
- tempPath->append ( "XMPFilesTemp" );
-
- for ( char n1 = '0'; n1 <= '9'; ++n1 ) {
- (*tempPath)[namePos+2] = n1;
- for ( char n2 = '0'; n2 <= '9'; ++n2 ) {
- (*tempPath)[namePos+3] = n2;
- if ( CreateNewFile ( tempPath->c_str(), origPath.c_str(), namePos, copyMacRsrc ) ) return;
- }
- }
-
- XMP_Throw ( "CreateTempFile: Can't find unique name", kXMPErr_InternalFailure );
-
-} // CreateTempFile
-
-// =================================================================================================
-// File mode and folder info utilities
-// -----------------------------------
-
-#if XMP_WinBuild
-
- // ---------------------------------------------------------------------------------------------
-
- static DWORD kOtherAttrs = (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_OFFLINE);
-
- FileMode GetFileMode ( const char * path )
- {
- std::string utf16; // GetFileAttributes wants native UTF-16.
- ToUTF16Native ( (UTF8Unit*)path, strlen(path), &utf16 );
- utf16.append ( 2, '\0' ); // Make sure there are at least 2 final zero bytes.
-
- // ! A shortcut is seen as a file, we would need extra code to recognize it and find the target.
-
- DWORD fileAttrs = GetFileAttributesW ( (LPCWSTR) utf16.c_str() );
- if ( fileAttrs == INVALID_FILE_ATTRIBUTES ) return kFMode_DoesNotExist; // ! Any failure turns into does-not-exist.
-
- if ( fileAttrs & FILE_ATTRIBUTE_DIRECTORY ) return kFMode_IsFolder;
- if ( fileAttrs & kOtherAttrs ) return kFMode_IsOther;
- return kFMode_IsFile;
-
- } // GetFileMode
-
- // ---------------------------------------------------------------------------------------------
-
- void XMP_FolderInfo::Open ( const char * folderPath )
- {
-
- if ( this->dirRef != 0 ) this->Close();
-
- this->folderPath = folderPath;
-
- } // XMP_FolderInfo::Open
-
- // ---------------------------------------------------------------------------------------------
-
- void XMP_FolderInfo::Close()
- {
-
- if ( this->dirRef != 0 ) (void) FindClose ( this->dirRef );
- this->dirRef = 0;
- this->folderPath.erase();
-
- } // XMP_FolderInfo::Close
-
- // ---------------------------------------------------------------------------------------------
-
- bool XMP_FolderInfo::GetFolderPath ( std::string * folderPath )
- {
-
- if ( this->folderPath.empty() ) return false;
-
- *folderPath = this->folderPath;
- return true;
-
- } // XMP_FolderInfo::GetFolderPath
-
- // ---------------------------------------------------------------------------------------------
-
- bool XMP_FolderInfo::GetNextChild ( std::string * childName )
- {
- bool found = false;
- WIN32_FIND_DATAW childInfo;
-
- if ( this->dirRef != 0 ) {
-
- found = FindNextFile ( this->dirRef, &childInfo );
- if ( ! found ) return false;
-
- } else {
-
- if ( this->folderPath.empty() ) {
- XMP_Throw ( "XMP_FolderInfo::GetNextChild - not open", kXMPErr_InternalFailure );
- }
-
- std::string findPath = this->folderPath;
- findPath += "\\*";
- std::string utf16; // FindFirstFile wants native UTF-16.
- ToUTF16Native ( (UTF8Unit*)findPath.c_str(), findPath.size(), &utf16 );
- utf16.append ( 2, '\0' ); // Make sure there are at least 2 final zero bytes.
-
- this->dirRef = FindFirstFileW ( (LPCWSTR) utf16.c_str(), &childInfo );
- if ( this->dirRef == 0 ) return false;
- found = true;
-
- }
-
- // Ignore all children with names starting in '.'. This covers ., .., .DS_Store, etc.
- while ( found && (childInfo.cFileName[0] == '.') ) {
- found = FindNextFile ( this->dirRef, &childInfo );
- }
- if ( ! found ) return false;
-
- size_t len16 = 0;
- while ( childInfo.cFileName[len16] != 0 ) ++len16;
- FromUTF16Native ( (UTF16Unit*)childInfo.cFileName, len16, childName ); // The cFileName field is native UTF-16.
-
- return true;
-
- } // XMP_FolderInfo::GetNextChild
-
- // ---------------------------------------------------------------------------------------------
-
-#else // Mac and UNIX both use POSIX functions.
-
- // ---------------------------------------------------------------------------------------------
-
- FileMode GetFileMode ( const char * path )
- {
- struct stat fileInfo;
-
- int err = stat ( path, &fileInfo );
- if ( err != 0 ) return kFMode_DoesNotExist; // ! Any failure turns into does-not-exist.
-
- // ! The target of a symlink is properly recognized, not the symlink itself. A Mac alias is
- // ! seen as a file, we would need extra code to recognize it and find the target.
-
- if ( S_ISREG ( fileInfo.st_mode ) ) return kFMode_IsFile;
- if ( S_ISDIR ( fileInfo.st_mode ) ) return kFMode_IsFolder;
- return kFMode_IsOther;
-
- } // GetFileMode
-
- // ---------------------------------------------------------------------------------------------
-
- void XMP_FolderInfo::Open ( const char * folderPath )
- {
-
- if ( this->dirRef != 0 ) this->Close();
-
- this->dirRef = opendir ( folderPath );
- if ( this->dirRef == 0 ) XMP_Throw ( "XMP_FolderInfo::Open - opendir failed", kXMPErr_ExternalFailure );
- this->folderPath = folderPath;
-
- } // XMP_FolderInfo::Open
-
- // ---------------------------------------------------------------------------------------------
-
- void XMP_FolderInfo::Close()
- {
-
- if ( this->dirRef != 0 ) (void) closedir ( this->dirRef );
- this->dirRef = 0;
- this->folderPath.erase();
-
- } // XMP_FolderInfo::Close
-
- // ---------------------------------------------------------------------------------------------
-
- bool XMP_FolderInfo::GetFolderPath ( std::string * folderPath )
- {
-
- if ( this->folderPath.empty() ) return false;
-
- *folderPath = this->folderPath;
- return true;
-
- } // XMP_FolderInfo::GetFolderPath
-
- // ---------------------------------------------------------------------------------------------
-
- bool XMP_FolderInfo::GetNextChild ( std::string * childName )
- {
- struct dirent * childInfo = 0;
-
- if ( this->dirRef == 0 ) XMP_Throw ( "XMP_FolderInfo::GetNextChild - not open", kXMPErr_InternalFailure );
-
- while ( true ) {
- // Ignore all children with names starting in '.'. This covers ., .., .DS_Store, etc.
- childInfo = readdir ( this->dirRef ); // ! Depends on global lock, readdir is not thread safe.
- if ( childInfo == 0 ) return false;
- if ( *childInfo->d_name != '.' ) break;
- }
-
- *childName = childInfo->d_name;
- return true;
-
- } // XMP_FolderInfo::GetNextChild
-
- // ---------------------------------------------------------------------------------------------
-
-#endif
-
-// =================================================================================================
-// GetPacketCharForm
-// =================
-//
-// The first character must be U+FEFF or ASCII, typically '<' for an outermost element, initial
-// processing instruction, or XML declaration. The second character can't be U+0000.
-// The possible input sequences are:
-// Cases with U+FEFF
-// EF BB BF -- - UTF-8
-// FE FF -- -- - Big endian UTF-16
-// 00 00 FE FF - Big endian UTF 32
-// FF FE 00 00 - Little endian UTF-32
-// FF FE -- -- - Little endian UTF-16
-// Cases with ASCII
-// nn mm -- -- - UTF-8 -
-// 00 00 00 nn - Big endian UTF-32
-// 00 nn -- -- - Big endian UTF-16
-// nn 00 00 00 - Little endian UTF-32
-// nn 00 -- -- - Little endian UTF-16
-
-static XMP_Uns8 GetPacketCharForm ( XMP_StringPtr packetStr, XMP_StringLen packetLen )
-{
- XMP_Uns8 charForm = kXMP_CharUnknown;
- XMP_Uns8 * unsBytes = (XMP_Uns8*)packetStr; // ! Make sure comparisons are unsigned.
-
- if ( packetLen < 2 ) return kXMP_Char8Bit;
-
- if ( packetLen < 4 ) {
-
- // These cases are based on the first 2 bytes:
- // 00 nn Big endian UTF-16
- // nn 00 Little endian UTF-16
- // FE FF Big endian UTF-16
- // FF FE Little endian UTF-16
- // Otherwise UTF-8
-
- if ( packetStr[0] == 0 ) return kXMP_Char16BitBig;
- if ( packetStr[1] == 0 ) return kXMP_Char16BitLittle;
- if ( CheckBytes ( packetStr, "\xFE\xFF", 2 ) ) return kXMP_Char16BitBig;
- if ( CheckBytes ( packetStr, "\xFF\xFE", 2 ) ) return kXMP_Char16BitLittle;
- return kXMP_Char8Bit;
-
- }
-
- // If we get here the packet is at least 4 bytes, could be any form.
-
- if ( unsBytes[0] == 0 ) {
-
- // These cases are:
- // 00 nn -- -- - Big endian UTF-16
- // 00 00 00 nn - Big endian UTF-32
- // 00 00 FE FF - Big endian UTF 32
-
- if ( unsBytes[1] != 0 ) {
- charForm = kXMP_Char16BitBig; // 00 nn
- } else {
- if ( (unsBytes[2] == 0) && (unsBytes[3] != 0) ) {
- charForm = kXMP_Char32BitBig; // 00 00 00 nn
- } else if ( (unsBytes[2] == 0xFE) && (unsBytes[3] == 0xFF) ) {
- charForm = kXMP_Char32BitBig; // 00 00 FE FF
- }
- }
-
- } else {
-
- // These cases are:
- // FE FF -- -- - Big endian UTF-16, FE isn't valid UTF-8
- // FF FE 00 00 - Little endian UTF-32, FF isn't valid UTF-8
- // FF FE -- -- - Little endian UTF-16
- // nn mm -- -- - UTF-8, includes EF BB BF case
- // nn 00 00 00 - Little endian UTF-32
- // nn 00 -- -- - Little endian UTF-16
-
- if ( unsBytes[0] == 0xFE ) {
- if ( unsBytes[1] == 0xFF ) charForm = kXMP_Char16BitBig; // FE FF
- } else if ( unsBytes[0] == 0xFF ) {
- if ( unsBytes[1] == 0xFE ) {
- if ( (unsBytes[2] == 0) && (unsBytes[3] == 0) ) {
- charForm = kXMP_Char32BitLittle; // FF FE 00 00
- } else {
- charForm = kXMP_Char16BitLittle; // FF FE
- }
- }
- } else if ( unsBytes[1] != 0 ) {
- charForm = kXMP_Char8Bit; // nn mm
- } else {
- if ( (unsBytes[2] == 0) && (unsBytes[3] == 0) ) {
- charForm = kXMP_Char32BitLittle; // nn 00 00 00
- } else {
- charForm = kXMP_Char16BitLittle; // nn 00
- }
- }
-
- }
-
- // XMP_Assert ( charForm != kXMP_CharUnknown );
- return charForm;
-
-} // GetPacketCharForm
-
-// =================================================================================================
-// FillPacketInfo
-// ==============
-//
-// If a packet wrapper is present, the the packet string is roughly:
-// <?xpacket begin= ...?>
-// <outer-XML-element>
-// ... more XML ...
-// </outer-XML-element>
-// ... whitespace padding ...
-// <?xpacket end='.'?>
-
-// The 8-bit form is 14 bytes, the 16-bit form is 28 bytes, the 32-bit form is 56 bytes.
-#define k8BitTrailer "<?xpacket end="
-#define k16BitTrailer "<\0?\0x\0p\0a\0c\0k\0e\0t\0 \0e\0n\0d\0=\0"
-#define k32BitTrailer "<\0\0\0?\0\0\0x\0\0\0p\0\0\0a\0\0\0c\0\0\0k\0\0\0e\0\0\0t\0\0\0 \0\0\0e\0\0\0n\0\0\0d\0\0\0=\0\0\0"
-static XMP_StringPtr kPacketTrailiers[3] = { k8BitTrailer, k16BitTrailer, k32BitTrailer };
-
-void FillPacketInfo ( const std::string & packet, XMP_PacketInfo * info )
-{
- XMP_StringPtr packetStr = packet.c_str();
- XMP_StringLen packetLen = (XMP_StringLen) packet.size();
- if ( packetLen == 0 ) return;
-
- info->charForm = GetPacketCharForm ( packetStr, packetLen );
- XMP_StringLen charSize = XMP_GetCharSize ( info->charForm );
-
- // Look for a packet wrapper. For our purposes, we can be lazy and just look for the trailer PI.
- // If that is present we'll assume that a recognizable header is present. First do a bytewise
- // search for '<', then a char sized comparison for the start of the trailer. We don't really
- // care about big or little endian here. We're looking for ASCII bytes with zeroes between.
- // Shorten the range comparisons (n*charSize) by 1 to easily tolerate both big and little endian.
-
- XMP_StringLen padStart, padEnd;
- XMP_StringPtr packetTrailer = kPacketTrailiers [ charSize>>1 ];
-
- padEnd = packetLen - 1;
- for ( ; padEnd > 0; --padEnd ) if ( packetStr[padEnd] == '<' ) break;
- if ( (packetStr[padEnd] != '<') || ((packetLen - padEnd) < (18*charSize)) ) return;
- if ( ! CheckBytes ( &packetStr[padEnd], packetTrailer, (13*charSize) ) ) return;
-
- info->hasWrapper = true;
-
- char rwFlag = packetStr [padEnd + 15*charSize];
- if ( rwFlag == 'w' ) info->writeable = true;
-
- // Look for the start of the padding, right after the last XML end tag.
-
- padStart = padEnd; // Don't do the -charSize here, might wrap below zero.
- for ( ; padStart >= charSize; padStart -= charSize ) if ( packetStr[padStart] == '>' ) break;
- if ( padStart < charSize ) return;
- padStart += charSize; // The padding starts after the '>'.
-
- info->padSize = padEnd - padStart; // We want bytes of padding, not character units.
-
-} // FillPacketInfo
-
-// =================================================================================================
-// ReadXMPPacket
-// =============
-
-void ReadXMPPacket ( XMPFileHandler * handler )
-{
- LFA_FileRef fileRef = handler->parent->fileRef;
- std::string & xmpPacket = handler->xmpPacket;
- XMP_StringLen packetLen = handler->packetInfo.length;
-
- if ( packetLen == 0 ) XMP_Throw ( "ReadXMPPacket - No XMP packet", kXMPErr_BadXMP );
-
- xmpPacket.erase();
- xmpPacket.reserve ( packetLen );
- xmpPacket.append ( packetLen, ' ' );
-
- XMP_StringPtr packetStr = XMP_StringPtr ( xmpPacket.c_str() ); // Don't set until after reserving the space!
-
- LFA_Seek ( fileRef, handler->packetInfo.offset, SEEK_SET );
- LFA_Read ( fileRef, (char*)packetStr, packetLen, kLFA_RequireAll );
-
-} // ReadXMPPacket
-
-// =================================================================================================
-// XMPFileHandler::ProcessXMP
-// ==========================
-//
-// This base implementation just parses the XMP. If the derived handler does reconciliation then it
-// must have its own implementation of ProcessXMP.
-
-void XMPFileHandler::ProcessXMP()
-{
-
- if ( (!this->containsXMP) || this->processedXMP ) return;
-
- if ( this->handlerFlags & kXMPFiles_CanReconcile ) {
- XMP_Throw ( "Reconciling file handlers must implement ProcessXMP", kXMPErr_InternalFailure );
- }
-
- SXMPUtils::RemoveProperties ( &this->xmpObj, 0, 0, kXMPUtil_DoAllProperties );
- this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
- this->processedXMP = true;
-
-} // XMPFileHandler::ProcessXMP
-
-// =================================================================================================
-// XMPFileHandler::GetSerializeOptions
-// ===================================
-//
-// This base implementation just selects compact serialization. The character form and padding/in-place
-// settings are added in the common code before calling SerializeToBuffer.
-
-XMP_OptionBits XMPFileHandler::GetSerializeOptions()
-{
-
- return kXMP_UseCompactFormat;
-
-} // XMPFileHandler::GetSerializeOptions
-
-// =================================================================================================
diff --git a/source/XMPFiles/XMPFiles_Impl.hpp b/source/XMPFiles/XMPFiles_Impl.hpp
deleted file mode 100644
index 294ca5f..0000000
--- a/source/XMPFiles/XMPFiles_Impl.hpp
+++ /dev/null
@@ -1,446 +0,0 @@
-#ifndef __XMPFiles_Impl_hpp__
-#define __XMPFiles_Impl_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2004 Adobe Systems Incorporated
-// All Rights Reserved
-//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
-// of the Adobe license agreement accompanying it.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! Must be the first #include!
-#include "XMP_Const.h"
-#include "XMP_BuildInfo.h"
-#include "XMP_LibUtils.hpp"
-#include "EndianUtils.hpp"
-
-#include <string>
-#define TXMP_STRING_TYPE std::string
-#define XMP_INCLUDE_XMPFILES 1
-#include "XMP.hpp"
-
-#include "XMPFiles.hpp"
-#include "LargeFileAccess.hpp"
-
-#include <vector>
-#include <string>
-#include <map>
-
-#include <cassert>
-
-#if XMP_WinBuild
- #define snprintf _snprintf
-#else
- #if XMP_MacBuild
- #include <Files.h>
- #endif
- // POSIX headers for both Mac and generic UNIX.
- #include <fcntl.h>
- #include <unistd.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <sys/types.h>
-#endif
-
-// =================================================================================================
-// General global variables and macros
-
-extern bool ignoreLocalText;
-
-extern XMP_Int32 sXMPFilesInitCount;
-
-#ifndef GatherPerformanceData
- #define GatherPerformanceData 0
-#endif
-
-#if ! GatherPerformanceData
-
- #define StartPerfCheck(proc,info) /* do nothing */
- #define EndPerfCheck(proc) /* do nothing */
-
-#else
-
- #include "PerfUtils.hpp"
-
- enum {
- kAPIPerf_OpenFile,
- kAPIPerf_CloseFile,
- kAPIPerf_GetXMP,
- kAPIPerf_PutXMP,
- kAPIPerf_CanPutXMP,
- kAPIPerfProcCount // Last, count of the procs.
- };
-
- static const char* kAPIPerfNames[] =
- { "OpenFile", "CloseFile", "GetXMP", "PutXMP", "CanPutXMP", 0 };
-
- struct APIPerfItem {
- XMP_Uns8 whichProc;
- double elapsedTime;
- XMPFilesRef xmpFilesRef;
- std::string extraInfo;
- APIPerfItem ( XMP_Uns8 proc, double time, XMPFilesRef ref, const char * info )
- : whichProc(proc), elapsedTime(time), xmpFilesRef(ref), extraInfo(info) {};
- };
-
- typedef std::vector<APIPerfItem> APIPerfCollection;
-
- extern APIPerfCollection* sAPIPerf;
-
- #define StartPerfCheck(proc,info) \
- sAPIPerf->push_back ( APIPerfItem ( proc, 0.0, xmpFilesRef, info ) ); \
- APIPerfItem & thisPerf = sAPIPerf->back(); \
- PerfUtils::MomentValue startTime, endTime; \
- try { \
- startTime = PerfUtils::NoteThisMoment();
-
- #define EndPerfCheck(proc) \
- endTime = PerfUtils::NoteThisMoment(); \
- thisPerf.elapsedTime = PerfUtils::GetElapsedSeconds ( startTime, endTime ); \
- } catch ( ... ) { \
- endTime = PerfUtils::NoteThisMoment(); \
- thisPerf.elapsedTime = PerfUtils::GetElapsedSeconds ( startTime, endTime ); \
- thisPerf.extraInfo += " ** THROW **"; \
- throw; \
- }
-
-#endif
-
-extern XMP_FileFormat voidFileFormat; // Used as sink for unwanted output parameters.
-extern XMP_PacketInfo voidPacketInfo;
-extern void * voidVoidPtr;
-extern XMP_StringPtr voidStringPtr;
-extern XMP_StringLen voidStringLen;
-extern XMP_OptionBits voidOptionBits;
-
-static const XMP_Uns8 * kUTF8_PacketStart = (const XMP_Uns8 *) "<?xpacket begin=";
-static const XMP_Uns8 * kUTF8_PacketID = (const XMP_Uns8 *) "W5M0MpCehiHzreSzNTczkc9d";
-static const size_t kUTF8_PacketHeaderLen = 51; // ! strlen ( "<?xpacket begin='xxx' id='W5M0MpCehiHzreSzNTczkc9d'" )
-
-static const XMP_Uns8 * kUTF8_PacketTrailer = (const XMP_Uns8 *) "<?xpacket end=\"w\"?>";
-static const size_t kUTF8_PacketTrailerLen = 19; // ! strlen ( kUTF8_PacketTrailer )
-
-struct FileExtMapping {
- XMP_StringPtr ext;
- XMP_FileFormat format;
-};
-
-extern const FileExtMapping kFileExtMap[];
-extern const char * kKnownScannedFiles[];
-extern const char * kKnownRejectedFiles[];
-
-#define Uns8Ptr(p) ((XMP_Uns8 *) (p))
-
-#define IsNewline( ch ) ( ((ch) == kLF) || ((ch) == kCR) )
-#define IsSpaceOrTab( ch ) ( ((ch) == ' ') || ((ch) == kTab) )
-#define IsWhitespace( ch ) ( IsSpaceOrTab ( ch ) || IsNewline ( ch ) )
-
-static inline void MakeLowerCase ( std::string * str )
-{
- for ( size_t i = 0, limit = str->size(); i < limit; ++i ) {
- char ch = (*str)[i];
- if ( ('A' <= ch) && (ch <= 'Z') ) (*str)[i] += 0x20;
- }
-}
-
-static inline void MakeUpperCase ( std::string * str )
-{
- for ( size_t i = 0, limit = str->size(); i < limit; ++i ) {
- char ch = (*str)[i];
- if ( ('a' <= ch) && (ch <= 'z') ) (*str)[i] -= 0x20;
- }
-}
-
-#define XMP_LitMatch(s,l) (std::strcmp((s),(l)) == 0)
-#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
-
-// =================================================================================================
-// Support for call tracing
-
-#ifndef XMP_TraceFilesCalls
- #define XMP_TraceFilesCalls 0
- #define XMP_TraceFilesCallsToFile 0
-#endif
-
-#if XMP_TraceFilesCalls
-
- #undef AnnounceThrow
- #undef AnnounceCatch
-
- #undef AnnounceEntry
- #undef AnnounceNoLock
- #undef AnnounceExit
-
- extern FILE * xmpFilesLog;
-
- #define AnnounceThrow(msg) \
- fprintf ( xmpFilesLog, "XMP_Throw: %s\n", msg ); fflush ( xmpFilesLog )
- #define AnnounceCatch(msg) \
- fprintf ( xmpFilesLog, "Catch in %s: %s\n", procName, msg ); fflush ( xmpFilesLog )
-
- #define AnnounceEntry(proc) \
- const char * procName = proc; \
- fprintf ( xmpFilesLog, "Entering %s\n", procName ); fflush ( xmpFilesLog )
- #define AnnounceNoLock(proc) \
- const char * procName = proc; \
- fprintf ( xmpFilesLog, "Entering %s (no lock)\n", procName ); fflush ( xmpFilesLog )
- #define AnnounceExit() \
- fprintf ( xmpFilesLog, "Exiting %s\n", procName ); fflush ( xmpFilesLog )
-
-#endif
-
-// =================================================================================================
-// Support for memory leak tracking
-
-#ifndef TrackMallocAndFree
- #define TrackMallocAndFree 0
-#endif
-
-#if TrackMallocAndFree
-
- static void* ChattyMalloc ( size_t size )
- {
- void* ptr = malloc ( size );
- fprintf ( stderr, "Malloc %d bytes @ %.8X\n", size, ptr );
- return ptr;
- }
-
- static void ChattyFree ( void* ptr )
- {
- fprintf ( stderr, "Free @ %.8X\n", ptr );
- free ( ptr );
- }
-
- #define malloc(s) ChattyMalloc ( s )
- #define free(p) ChattyFree ( p )
-
-#endif
-
-// =================================================================================================
-// FileHandler declarations
-
-extern void ReadXMPPacket ( XMPFileHandler * handler );
-
-extern void FillPacketInfo ( const XMP_VarString & packet, XMP_PacketInfo * info );
-
-class XMPFileHandler { // See XMPFiles.hpp for usage notes.
-public:
-
- #define DefaultCTorPresets \
- handlerFlags(0), stdCharForm(kXMP_CharUnknown), \
- containsXMP(false), processedXMP(false), needsUpdate(false)
-
- XMPFileHandler() : parent(0), DefaultCTorPresets {};
- XMPFileHandler (XMPFiles * _parent) : parent(_parent), DefaultCTorPresets {};
-
- virtual ~XMPFileHandler() {}; // ! The specific handler is responsible for tnailInfo.tnailImage.
-
- virtual void CacheFileData() = 0;
- virtual void ProcessXMP(); // The default implementation just parses the XMP.
-
- virtual XMP_OptionBits GetSerializeOptions(); // The default is compact.
-
- virtual void UpdateFile ( bool doSafeUpdate ) = 0;
- virtual void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath ) = 0;
-
- // ! Leave the data members public so common code can see them.
-
- XMPFiles * parent; // Let's the handler see the file info.
- XMP_OptionBits handlerFlags; // Capabilities of this handler.
- XMP_Uns8 stdCharForm; // The standard character form for output.
-
- bool containsXMP; // True if the file has XMP or PutXMP has been called.
- bool processedXMP; // True if the XMP is parsed and reconciled.
- bool needsUpdate; // True if the file needs to be updated.
-
- XMP_PacketInfo packetInfo; // ! This is always info about the packet in the file, if any!
- std::string xmpPacket; // ! This is the current XMP, updated by XMPFiles::PutXMP.
- SXMPMeta xmpObj;
-
-}; // XMPFileHandler
-
-typedef XMPFileHandler * (* XMPFileHandlerCTor) ( XMPFiles * parent );
-
-typedef bool (* CheckFileFormatProc ) ( XMP_FileFormat format,
- XMP_StringPtr filePath,
- LFA_FileRef fileRef,
- XMPFiles * parent );
-
-typedef bool (*CheckFolderFormatProc ) ( XMP_FileFormat format,
- const std::string & rootPath,
- const std::string & gpName,
- const std::string & parentName,
- const std::string & leafName,
- XMPFiles * parent );
-
-// =================================================================================================
-
-#if XMP_MacBuild
- extern LFA_FileRef LFA_OpenRsrc ( const char * fileName, char openMode ); // Open the Mac resource fork.
-#endif
-
-extern void CreateTempFile ( const std::string & origPath, std::string * tempPath, bool copyMacRsrc = false );
-enum { kCopyMacRsrc = true };
-
-struct AutoFile { // Provides auto close of files on exit or exception.
- LFA_FileRef fileRef;
- AutoFile() : fileRef(0) {};
- ~AutoFile() { if ( fileRef != 0 ) LFA_Close ( fileRef ); };
-};
-
-enum { kFMode_DoesNotExist, kFMode_IsFile, kFMode_IsFolder, kFMode_IsOther };
-typedef XMP_Uns8 FileMode;
-
-#if XMP_WinBuild
- #define kDirChar '\\'
-#else
- #define kDirChar '/'
-#endif
-
-class XMP_FolderInfo {
-public:
-
- XMP_FolderInfo() : dirRef(0) {};
- ~XMP_FolderInfo() { if ( this->dirRef != 0 ) this->Close(); };
-
- void Open ( const char * folderPath );
- void Close();
-
- bool GetFolderPath ( XMP_VarString * folderPath );
- bool GetNextChild ( XMP_VarString * childName );
-
-private:
-
- std::string folderPath;
-
- #if XMP_WinBuild
- HANDLE dirRef; // Windows uses FindFirstFile and FindNextFile.
- #else
- DIR * dirRef; // Mac and UNIX use the POSIX opendir/readdir/closedir functions.
- #endif
-
-};
-
-extern FileMode GetFileMode ( const char * path );
-
-static inline FileMode GetChildMode ( std::string & path, XMP_StringPtr childName )
-{
- size_t pathLen = path.size();
- path += kDirChar;
- path += childName;
- FileMode mode = GetFileMode ( path.c_str() );
- path.erase ( pathLen );
- return mode;
-}
-
-static inline void SplitLeafName ( std::string * path, std::string * leafName )
-{
- size_t dirPos = path->size();
- if ( dirPos == 0 ) {
- leafName->erase();
- return;
- }
-
- for ( --dirPos; dirPos > 0; --dirPos ) {
- #if XMP_WinBuild
- if ( (*path)[dirPos] == '/' ) (*path)[dirPos] = kDirChar; // Tolerate both '\' and '/'.
- #endif
- if ( (*path)[dirPos] == kDirChar ) break;
- }
- if ( (*path)[dirPos] == kDirChar ) {
- leafName->assign ( &(*path)[dirPos+1] );
- path->erase ( dirPos );
- } else if ( dirPos == 0 ) {
- leafName->erase();
- leafName->swap ( *path );
- }
-
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static inline bool CheckBytes ( const void * left, const void * right, size_t length )
-{
- return (std::memcmp ( left, right, length ) == 0);
-}
-
-// -------------------------------------------------------------------------------------------------
-
-static inline bool CheckCString ( const void * left, const void * right )
-{
- return (std::strcmp ( (char*)left, (char*)right ) == 0);
-}
-
-// -------------------------------------------------------------------------------------------------
-// CheckFileSpace and RefillBuffer
-// -------------------------------
-//
-// There is always a problem in file scanning of managing what you want to check against what is
-// available in a buffer, trying to keep the logic understandable and minimize data movement. The
-// CheckFileSpace and RefillBuffer functions are used here for a standard scanning model.
-//
-// The format scanning routines have an outer, "infinite" loop that looks for file markers. There
-// is a local (on stack) buffer, a pointer to the current position in the buffer, and a pointer for
-// the end of the buffer. The end pointer is just past the end of the buffer, "bufPtr == bufLimit"
-// means you are out of data. The outer loop ends when the necessary markers are found or we reach
-// the end of the file.
-//
-// The filePos is the file offset of the start of the current buffer. This is maintained so that
-// we can tell where the packet is in the file, part of the info returned to the client.
-//
-// At each check CheckFileSpace is used to make sure there is enough data in the buffer for the
-// check to be made. It refills the buffer if necessary, preserving the unprocessed data, setting
-// bufPtr and bufLimit appropriately. If we are too close to the end of the file to make the check
-// a failure status is returned.
-
-enum { kIOBufferSize = 128*1024 };
-
-struct IOBuffer {
- XMP_Int64 filePos;
- XMP_Uns8* ptr;
- XMP_Uns8* limit;
- size_t len;
- XMP_Uns8 data [kIOBufferSize];
- IOBuffer() : filePos(0), ptr(&data[0]), limit(ptr), len(0) {};
-};
-
-static inline void FillBuffer ( LFA_FileRef fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
-{
- ioBuf->filePos = LFA_Seek ( fileRef, fileOffset, SEEK_SET );
- if ( ioBuf->filePos != fileOffset ) XMP_Throw ( "Seek failure in FillBuffer", kXMPErr_ExternalFailure );
- ioBuf->len = LFA_Read ( fileRef, &ioBuf->data[0], kIOBufferSize );
- ioBuf->ptr = &ioBuf->data[0];
- ioBuf->limit = ioBuf->ptr + ioBuf->len;
-}
-
-static inline void MoveToOffset ( LFA_FileRef fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
-{
- if ( (ioBuf->filePos <= fileOffset) && (fileOffset < (XMP_Int64)(ioBuf->filePos + ioBuf->len)) ) {
- size_t bufOffset = (size_t)(fileOffset - ioBuf->filePos);
- ioBuf->ptr = &ioBuf->data[bufOffset];
- } else {
- FillBuffer ( fileRef, fileOffset, ioBuf );
- }
-}
-
-static inline void RefillBuffer ( LFA_FileRef fileRef, IOBuffer* ioBuf )
-{
- ioBuf->filePos += (ioBuf->ptr - &ioBuf->data[0]); // ! Increment before the read.
- size_t bufTail = ioBuf->limit - ioBuf->ptr; // We'll re-read the tail portion of the buffer.
- if ( bufTail > 0 ) ioBuf->filePos = LFA_Seek ( fileRef, -((XMP_Int64)bufTail), SEEK_CUR );
- ioBuf->len = LFA_Read ( fileRef, &ioBuf->data[0], kIOBufferSize );
- ioBuf->ptr = &ioBuf->data[0];
- ioBuf->limit = ioBuf->ptr + ioBuf->len;
-}
-
-static inline bool CheckFileSpace ( LFA_FileRef fileRef, IOBuffer* ioBuf, size_t neededLen )
-{
- if ( size_t(ioBuf->limit - ioBuf->ptr) < size_t(neededLen) ) { // ! Avoid VS.Net compare warnings.
- RefillBuffer ( fileRef, ioBuf );
- }
- return (size_t(ioBuf->limit - ioBuf->ptr) >= size_t(neededLen));
-}
-
-#endif /* __XMPFiles_Impl_hpp__ */