static void CreatorAtom_ToBE ( CR8R_CreatorAtom * creator_atomP ) { creator_atomP->atom_vers_majorS = MakeUns16BE ( creator_atomP->atom_vers_majorS ); creator_atomP->atom_vers_minorS = MakeUns16BE ( creator_atomP->atom_vers_minorS ); creator_atomP->magicLu = MakeUns32BE ( creator_atomP->magicLu ); creator_atomP->atom_sizeL = MakeUns32BE ( creator_atomP->atom_sizeL ); creator_atomP->creator_codeLu = MakeUns32BE ( creator_atomP->creator_codeLu ); creator_atomP->creator_eventLu = MakeUns32BE ( creator_atomP->creator_eventLu ); }
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.boxType == ISOMedia::k_uuid ) // For uuid, additional 16 bytes is stored for ID { XMP_Enforce ( (XMP_Uns32)(newEnd - newPtr) >= ( 16 + node.contentSize ) ); memcpy( newPtr, node.idUUID, 16 ); IncrNewPtr ( 16 ); } if ( node.contentSize != 0 ) { const XMP_Uns8 * content = PickContentPtr( node ); memcpy ( newPtr, content, node.contentSize ); 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
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); if( isoInfo.boxType == ISOMedia::k_uuid ) parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns8 *)isoInfo.idUUID, (XMP_Uns32)isoInfo.contentSize ) ); else parentNode->children.push_back ( BoxNode ( childOffset, isoInfo.boxType, isoInfo.headerSize, (XMP_Uns32)isoInfo.contentSize ) ); BoxNode * newChild = &parentNode->children.back(); #if TraceParseMoovTree 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_edts : pathSuffix = "/edts"; break; case ISOMedia::k_mdia : pathSuffix = "/mdia"; break; case ISOMedia::k_minf : pathSuffix = "/minf"; break; case ISOMedia::k_dinf : pathSuffix = "/dinf"; break; case ISOMedia::k_stbl : pathSuffix = "/stbl"; break; } if ( pathSuffix != 0 ) { this->ParseNestedBoxes ( newChild, (parentPath + pathSuffix), ignoreMetaBoxes ); } } } // MOOV_Manager::ParseNestedBoxes
void MOOV_Manager::SetBox ( BoxRef theBox, const void* dataPtr, XMP_Uns32 size , const XMP_Uns8 * idUUID ) { XMP_Enforce ( size < moovBoxSizeLimit ); BoxNode * node = (BoxNode*)theBox; if ( node->contentSize == size ) { if( node->boxType == ISOMedia::k_uuid && idUUID != 0 ) { memcpy ( node->idUUID, idUUID, 16 ); this->moovNode.changed = true; } XMP_Uns8 * oldContent = PickContentPtr ( *node ); if ( memcmp ( oldContent, dataPtr, size ) == 0 ) return; // No change. memcpy ( oldContent, dataPtr, size ); // Update the old content in-place 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; if( node->boxType == ISOMedia::k_uuid && idUUID != 0) memcpy ( node->idUUID, idUUID, 16 ); 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
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
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
static inline XMP_Uns32 ReadUns32_BE ( XMP_IO* file ) { XMP_Uns32 value; file->ReadAll ( &value, 4 ); return MakeUns32BE ( value ); }
static inline void WriteUns32_BE ( XMP_IO* file, XMP_Uns32 value ) { XMP_Uns32 v = MakeUns32BE ( value ); file->Write ( &v, 4 ); }