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 ReadBuffer ( XMP_IO* fileRef, XMP_Uns64 & pos, XMP_Uns32 len, char * outBuffer ) { try { if ( (fileRef == 0) || (outBuffer == 0) ) return false; fileRef->Seek ( pos, kXMP_SeekFromStart ); long bytesRead = fileRef->Read ( outBuffer, len ); if ( XMP_Uns32(bytesRead) != len ) return false; return true; } catch ( ... ) {} return false; }
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; }
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
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; }
bool ASF_Support::ReadHeaderObject ( XMP_IO* 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, ' ' ); fileRef->Seek ( pos, kXMP_SeekFromStart ); fileRef->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; while ( read < newObject.len ) { fileRef->Seek ( pos, kXMP_SeekFromStart ); if ( kASF_ObjectBaseLen != fileRef->Read ( &objectBase, kASF_ObjectBaseLen, true ) ) break; fileRef->Seek ( pos, kXMP_SeekFromStart ); 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 ), ' ' ); fileRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); // 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 ), ' ' ); fileRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ), ' ' ); fileRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ), ' ' ); fileRef->ReadAll ( const_cast<char*>(buffer.data()), XMP_Int32(objectBase.size) ); 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 ); } else if (objectBase.size == 0) { break; } pos += objectBase.size; read += objectBase.size; } } catch ( ... ) { return false; } legacyManager->ComputeDigest(); return true; }
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. We're using a map keyed by ID, so only one // resource of each ID is recognized. Redundant resources are not legit, but have been seen in // the field. In particular, one case has been seen of a duplicate IIM block with one empty. // In general we keep the first seen copy to be compatible with Photoshop. A later non-empty // copy will be taken though if the current one is empty. // ! Don't use map[id] to lookup, that creates a default entry if none exists! 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 ) { 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 ) ); } else { InternalRsrcInfo newInfo ( id, dataLen, kIsMemoryBased ); newInfo.dataPtr = psirPtr; newInfo.origOffset = dataOffset; if ( nameLen != 0 ) newInfo.rsrcName = namePtr; InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id ); if ( rsrcPos == this->imgRsrcs.end() ) { this->imgRsrcs.insert ( rsrcPos, InternalRsrcMap::value_type ( id, newInfo ) ); } else if ( (rsrcPos->second.dataLen == 0) && (newInfo.dataLen != 0) ) { rsrcPos->second = newInfo; } } psirPtr = nextRsrc; } } // PSIR_FileWriter::ParseMemoryResources