// 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; }
// 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; }
/*! 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; }
//! 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); }
/*! \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; }