// 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; }
/*! If the UL has not yet been used the correct static or dynamic tag will * be determined and added to the primer * \return The tag to use, or 0 if no more dynamic tags available */ Tag Primer::Lookup(ULPtr ItemUL, Tag TryTag /*=0*/) { // If a tag has been suggested then try that if(TryTag != 0) { // Is it known by us? Primer::iterator it = find(TryTag); if(it != end()) { // Only use it if the UL matches if(!memcmp((*it).second.GetValue(), ItemUL->GetValue(), 16)) return TryTag; } else { // It could be the right tag, but not yet in this primer // DRAGONS: Not implementer yet!!! } } // Do we have this UL already? std::map<UL, Tag>::iterator it = TagLookup.find(ItemUL); if(it != TagLookup.end()) { return (*it).second; } // Try and find the type with this UL MDOTypePtr Type = MDOType::Find(ItemUL); if(Type) { if(Type->GetKey().Size != 2) { // No static tag supplied - fall through and use a dynamic tag } else { Tag ThisTag = (Type->GetKey().Data[0] << 8) + Type->GetKey().Data[1]; insert(Primer::value_type(ThisTag, ItemUL)); return ThisTag; } } // Generate a dynamic tag // DRAGONS: Not very efficient while(NextDynamic >= 0x8000) { if(find(NextDynamic) == end()) { Tag Ret = NextDynamic; NextDynamic--; insert(Primer::value_type(Ret, ItemUL)); return Ret; } NextDynamic--; } //! Out of dynamic tags! error("Run out of dynamic tags!\n"); return 0; }
// 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; }
/*! \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; }