/*! Moves the file pointer for the parent file to the start of the index data in this partition * \note If there is no index table data in this partition the pointer will not be moved */ bool mxflib::Partition::SeekIndex(void) { Int64 IndexSize = GetInt64(IndexByteCount_UL); if(IndexSize == 0) return false; MXFFilePtr ParentFile = Object->GetParentFile(); if(!ParentFile) { error("Call to Partition::SeekIndex() on a partition that is not read from a file\n"); return false; } Int64 MetadataSize = GetInt64(HeaderByteCount_UL); // Find the start of the index table // DRAGONS: not the most efficient way - we could store a pointer to the end of the metadata ParentFile->Seek(Object->GetLocation() + 16); Length Len = ParentFile->ReadBER(); Position Location = ParentFile->Tell() + Len; if((sizeof(size_t) < 8) && IndexSize > 0xffffffff) { error("Maximum read size on this platform is 4Gbytes - However, requested to read index data at 0x%s which has size of 0x%s\n", Int64toHexString(Location,8).c_str(), Int64toHexString(IndexSize,8).c_str()); return false; } ParentFile->Seek(Location); ULPtr FirstUL = ParentFile->ReadKey(); if(!FirstUL) { error("Error reading first KLV after %s at 0x%s in %s\n", FullName().c_str(), Int64toHexString(GetLocation(),8).c_str(), GetSource().c_str()); return false; } MDOTypePtr FirstType = MDOType::Find(FirstUL); if(FirstType->IsA(KLVFill_UL)) { // Skip over the filler Len = ParentFile->ReadBER(); Location = ParentFile->Tell() + Len; } // Move to the start of the index table segments ParentFile->Seek(Location + MetadataSize); return true; }
// skip over a KLV packet UInt64 mxflib::Partition::Skip( UInt64 start ) { if( !start ) return 0; MXFFilePtr PF = Object->GetParentFile(); PF->Seek( start ); ULPtr FirstUL = PF->ReadKey(); if(!FirstUL) return 0; // do the skip Length Len = PF->ReadBER(); PF->Seek( PF->Tell() + Len ); UInt64 ret = PF->Tell(); // check in case we've hit the next Partition Pack ULPtr NextUL = PF->ReadKey(); if(!NextUL) return 0; // Is this a partition pack? if(IsPartitionKey(NextUL->GetValue())) return 0; return ret; }
// goto start of body...set the member variables _BodyLocation, _NextBodyLocation // DRAGONS: Need to document return value!! bool mxflib::Partition::StartElements() { _BodyLocation = 0; if(!Object->GetParentFile()) { error("Call to Partition::StartElements() on a non-file partition\n"); return false; } MXFFilePtr PF = Object->GetParentFile(); UInt64 MetadataSize = GetInt64(HeaderByteCount_UL); UInt64 IndexSize = GetInt64(IndexByteCount_UL); // skip over Partition Pack (and any leading Fill on Header) PF->Seek( Object->GetLocation() + 16 ); Length Len = PF->ReadBER(); _NextBodyLocation = SkipFill( PF->Tell() + Len ); if( !_NextBodyLocation ) return false; // skip over Metadata (and any leading Fill on Index) _NextBodyLocation = SkipFill( _NextBodyLocation + MetadataSize ); if( !_NextBodyLocation ) return false; // skip over Index (and any leading Fill on Body) _NextBodyLocation = SkipFill( _NextBodyLocation + IndexSize ); return _NextBodyLocation != 0; }
/*! Moves the file pointer for the parent file to the start of the essence container in this partition * \note If there is no essence in this partition the pointer will be moved to the start of the following partition (or the start of the RIP if this is the footer) */ bool mxflib::Partition::SeekEssence(void) { MXFFilePtr File = Object->GetParentFile(); if(!File) { error("Call to Partition::SeekEssence() on a non-file partition\n"); return false; } Position BodyLocation = 0; Length MetadataSize = GetInt64(HeaderByteCount_UL); Length IndexSize = GetInt64(IndexByteCount_UL); // Skip over Partition Pack (and any trailing filler) File->Seek( GetUInt64(ThisPartition_UL) + 16 ); Length Len = File->ReadBER(); BodyLocation = SkipFill( File->Tell() + Len ); if(!BodyLocation) return false; // Skip over Metadata (and any trailing filler) BodyLocation += MetadataSize; // Skip over Index (and any trailing filler) BodyLocation += IndexSize; // Perform the seek File->Seek(BodyLocation); return true; }
//! Read any index table segments from this partition's source file MDObjectListPtr mxflib::Partition::ReadIndex(void) { UInt64 IndexSize = GetInt64(IndexByteCount_UL); if(IndexSize == 0) return new MDObjectList; MXFFilePtr ParentFile = Object->GetParentFile(); if(!ParentFile) { error("Call to Partition::ReadIndex() on a partition that is not read from a file\n"); return new MDObjectList; } UInt64 MetadataSize = GetInt64(HeaderByteCount_UL); // Find the start of the index table // DRAGONS: not the most efficient way - we could store a pointer to the end of the metadata ParentFile->Seek(Object->GetLocation() + 16); Length Len = ParentFile->ReadBER(); Position Location = ParentFile->Tell() + Len; ParentFile->Seek(Location); ULPtr FirstUL = ParentFile->ReadKey(); if(!FirstUL) { error("Error reading first KLV after %s at 0x%s in %s\n", FullName().c_str(), Int64toHexString(GetLocation(),8).c_str(), GetSource().c_str()); return new MDObjectList; } MDOTypePtr FirstType = MDOType::Find(FirstUL); if(FirstType->IsA(KLVFill_UL)) { // Skip over the filler Len = ParentFile->ReadBER(); Location = ParentFile->Tell() + Len; } // Move to the start of the index table segments ParentFile->Seek(Location + MetadataSize); return ReadIndex(ParentFile, IndexSize); }
// skip over any KLVFill // DRAGONS: does not iterate - only copes with single KLVFill UInt64 mxflib::Partition::SkipFill( UInt64 start ) { if( !start ) return 0; MXFFilePtr PF = Object->GetParentFile(); PF->Seek( start ); ULPtr FirstUL = PF->ReadKey(); if(!FirstUL) return 0; if(FirstUL->Matches(KLVFill_UL)) { // Skip over the KLVFill Length Len = PF->ReadBER(); PF->Seek( PF->Tell() + Len ); } else { // was not KLVFill, so stay where we are PF->Seek( start ); } UInt64 ret = PF->Tell(); // check in case we've hit the next Partition Pack ULPtr NextUL = PF->ReadKey(); if(!NextUL) return 0; // Is this a partition pack? if(IsPartitionKey(NextUL->GetValue())) { UInt8 byte14 = (NextUL->GetValue())[13]; if( byte14 == 2 || byte14 == 3 || byte14 == 4 ) return 0; // we've found a Partition Pack - end of Body -- DRAGONS:?? Not true!! if( byte14 == 0x11 ) return 0; // we've found a RIP - end of Body } return ret; }
/*! \return The number of bytes read (<b>including</b> any preceeding filler) * \return 0 if no header metadata in this partition */ Length mxflib::Partition::ReadMetadata(void) { Length MetadataSize = GetInt64(HeaderByteCount_UL); if(MetadataSize == 0) return 0; MXFFilePtr ParentFile = Object->GetParentFile(); if(!ParentFile) { error("Call to Partition::ReadMetadata() on a partition that is not read from a file\n"); return 0; } // Find the start of the metadata // DRAGONS: not the most efficient way - we could store a pointer to the end of the pack ParentFile->Seek(Object->GetLocation() + 16); Length Len = ParentFile->ReadBER(); ParentFile->Seek(ParentFile->Tell() + Len); return ReadMetadata(ParentFile, MetadataSize); }
/*! \note The value of "Size" does not include the size of any filler before * the primer, but the return value does * \return The number of bytes read (<b>including</b> any preceeding filler) */ Length mxflib::Partition::ReadMetadata(MXFFilePtr File, Length Size) { Length Bytes = 0; Length FillerBytes = 0; // Clear any existing metadata, including the primer ClearMetadata(false); // Quick return for NULL metadata if(Size == 0) return 0; // Record the position of the current item Position Location = File->Tell(); // Check for a leading filler item { ULPtr FirstUL = File->ReadKey(); if(!FirstUL) { error("Error reading first KLV after %s at 0x%s in %s\n", FullName().c_str(), Int64toHexString(GetLocation(),8).c_str(), GetSource().c_str()); return 0; } if(FirstUL->Matches(KLVFill_UL)) { // Skip over the filler, recording how far we went Position NewLocation = File->ReadBER(); NewLocation += File->Tell(); FillerBytes = NewLocation - Location; Location = NewLocation; } } // Sanity check the size for this platform // TODO: Should we fix this so that we can read larger metadata - but if so where in memory would we put it if its > 4GB on a 32-bit machine? if((sizeof(size_t) < 8) && Size > 0xffffffff) { error("Maximum read size on this platform is 4Gbytes - However, requested to read metadata at 0x%s which has size of 0x%s\n", Int64toHexString(Location,8).c_str(), Int64toHexString(Size,8).c_str()); return 0; } // Read enough bytes for the metadata File->Seek(Location); DataChunkPtr Data = File->Read(static_cast<size_t>(Size)); if(Data->Size != static_cast<size_t>(Size)) { error("Header Metadata starting at 0x%s should contain 0x%s bytes, but only 0x%s could be read\n", Int64toHexString(Location,8).c_str(), Int64toHexString(Size,8).c_str(), Int64toHexString(Data->Size,8).c_str()); Size = static_cast<Length>(Data->Size); } // Start of data buffer const UInt8 *BuffPtr = Data->Data; while(Size) { Length BytesAtItemStart = Bytes; if(Size < 16) { error("Less than 16-bytes of header metadata available after reading 0x%s bytes at 0x%s in file \"%s\"\n", Int64toHexString(Bytes, 8).c_str(), Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() ); break; } /* // Sanity check the keys if((BuffPtr[0] != 6) || (BuffPtr[1] != 0x0e)) { error("Invalid KLV key found at 0x%s in file \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() ); break; } */ // Build an object (it may come back as an "unknown") ULPtr NewUL = new UL(BuffPtr); /* If we are loading metadictionaries, we do so when we first read the Preface key */ if(Feature(FeatureLoadMetadict)) { if(NewUL->Matches(Preface_UL)) { LoadMetadict(); } } MDObjectPtr NewItem = new MDObject(NewUL); mxflib_assert(NewItem); BuffPtr += 16; Size -= 16; Bytes += 16; if(Size < 1) { error("Incomplete BER length at 0x%s in file \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() ); break; } Length Len = *BuffPtr++; Size--; Bytes++; if(Len >= 0x80) { UInt32 i = (UInt32)Len & 0x7f; if(Size < i) { error("Incomplete BER length at 0x%s in \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() ); break; } Len = 0; while(i--) { Len = ((Len<<8) + *(BuffPtr++)); Size--; Bytes++; } } // DRAGONS: KLV Size limit!! if(Len > 0xffffffff) { error("Current implementation KLV size limit of 0xffffffff bytes exceeded at 0x%s in file \"%s\"\n", Int64toHexString(Location + Bytes,8).c_str(), File->Name.c_str() ); break; } if(Size < Len) { error("KLV length is %s but available data size is only %s after reading 0x%s of header metadata at 0x%s in \"%s\"\n", UInt64toString(Len).c_str(), UInt64toString(Size).c_str(), Int64toHexString(Bytes, 8).c_str(), Int64toHexString(Location + Bytes,8).c_str(), File->Name.c_str() ); // Try reading what we have Len = Size; } // Check for the primer until we have found it if(!PartitionPrimer) { if(NewItem->IsA(Primer_UL)) { PartitionPrimer = new Primer; UInt32 ThisBytes = PartitionPrimer->ReadValue(BuffPtr, (UInt32)Len); Size -= ThisBytes; Bytes += ThisBytes; BuffPtr += ThisBytes; // Skip further processing for the primer continue; } } // Skip any filler items if(NewItem->IsA(KLVFill_UL)) { Size -= Len; Bytes += Len; BuffPtr += Len; // Don't add the filler continue; } if(Len) { NewItem->SetParent(File, BytesAtItemStart + Location,(UInt32)( Bytes - BytesAtItemStart)); NewItem->ReadValue(BuffPtr,(UInt32) Len, PartitionPrimer); // Skip total length, not just the length actually consumed Size -= Len; Bytes += Len; BuffPtr += Len; } AddMetadata(NewItem); } return Bytes + FillerBytes; }