bool ASF_Support::UpdateFileSize ( XMP_IO* fileRef ) { if ( fileRef == 0 ) return false; XMP_Uns64 posCurrent = fileRef->Seek ( 0, kXMP_SeekFromCurrent ); XMP_Uns64 newSizeLE = MakeUns64LE ( fileRef->Length() ); if ( this->posFileSizeInfo != 0 ) { fileRef->Seek ( this->posFileSizeInfo, kXMP_SeekFromStart ); } 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. fileRef->Rewind(); fileRef->ReadAll ( &objHeader, kASF_ObjectBaseLen ); if ( ! IsEqualGUID ( ASF_Header_Object, objHeader.guid ) ) return false; XMP_Uns32 childCount; fileRef->ReadAll ( &childCount, 4 ); childCount = GetUns32LE ( &childCount ); fileRef->Seek ( 2, kXMP_SeekFromCurrent ); // Skip the 2 reserved bytes. // Look for the File Properties object in the Header's children. for ( ; childCount > 0; --childCount ) { fileRef->ReadAll ( &objHeader, kASF_ObjectBaseLen ); if ( IsEqualGUID ( ASF_File_Properties_Object, objHeader.guid ) ) break; XMP_Uns64 dataLen = GetUns64LE ( &objHeader.size ) - 24; fileRef->Seek ( dataLen, kXMP_SeekFromCurrent ); // 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; fileRef->Seek ( 16, kXMP_SeekFromCurrent ); // Skip to the file size field. } fileRef->Write ( &newSizeLE, 8 ); // Write the new file size. fileRef->Seek ( posCurrent, kXMP_SeekFromStart ); return true; }
bool ASF_Support::WriteXMPObject ( XMP_IO* fileRef, XMP_Uns32 len, const char* inBuffer ) { bool ret = false; ASF_ObjectBase objectBase = { ASF_XMP_Metadata, 0 }; objectBase.size = MakeUns64LE ( len + kASF_ObjectBaseLen ); try { fileRef->Write ( &objectBase, kASF_ObjectBaseLen ); fileRef->Write ( inBuffer, len ); ret = true; } catch ( ... ) {} return ret; }
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::WriteHeaderObject ( XMP_IO* sourceRef, XMP_IO* destRef, const ObjectData& object, ASF_LegacyManager& _legacyManager, bool usePadding ) { if ( ! IsEqualGUID ( ASF_Header_Object, object.guid ) ) return 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, ' ' ); sourceRef->Seek ( pos, kXMP_SeekFromStart ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), bufferSize ); 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 ) { sourceRef->Seek ( pos, kXMP_SeekFromStart ); if ( kASF_ObjectBaseLen != sourceRef->Read ( &objectBase, kASF_ObjectBaseLen, true ) ) break; sourceRef->Seek ( pos, kXMP_SeekFromStart ); 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); // 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); // 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); // 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ), ' ' ); sourceRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ) destRef->Seek ( object.pos, kXMP_SeekFromStart ); if ( this->progressTracker != 0 ) { XMP_Assert ( this->progressTracker->WorkInProgress() ); this->progressTracker->AddTotalWork ( (float)header.size() ); } // write header destRef->Write ( header.c_str(), header.size() ); } catch ( ... ) { return false; } return true; }
static inline void WriteUns64_LE ( XMP_IO* file, XMP_Uns64 value ) { XMP_Uns64 v = MakeUns64LE ( value ); file->Write ( &v, 8 ); }
static inline XMP_Uns64 ReadUns64_LE ( XMP_IO* file ) { XMP_Uns64 value; file->ReadAll ( &value, 8 ); return MakeUns64LE ( value ); }