//! Scan a metadata object for strong references in sub-objects and add those to this partition void Partition::AddMetadataSubs(MDObjectPtr &NewObject, bool ForceFirst) { MDObjectULList::iterator it = NewObject->begin(); MDObjectULList::iterator itend = NewObject->end(); while(it != itend) { if((*it).second->GetRefType() == DICT_REF_STRONG) { MDObjectPtr Link = (*it).second->GetLink(); if(Link) { AddMetadata(Link, ForceFirst); // Prevent the new item being top-level (which it may be as we are not added yet) // DRAGONS: There is surely a better way than this!! TopLevelMetadata.remove(Link); } } else if(!((*it).second->empty())) { AddMetadataSubs((*it).second, ForceFirst); } it++; } }
/*! Note that any strongly linked objects are also added */ void mxflib::Partition::AddMetadata(MDObjectPtr NewObject, bool ForceFirst /*=false*/) { // Start out without a target bool has_target = false; // Start out not (strong) reffed bool linked = false; // Add us to the list of all items - done last if forcing first as the child items will get added first if(!ForceFirst) AllMetadata.push_back(NewObject); // Add this object to the ref target list if it is one. At the same time any objects // linked from this object (before this function was called) are added as well // Note: although nothing currently does it it is theoretically possible to // have more than one target entry in a set MDObjectULList::iterator it = NewObject->begin(); while(it != NewObject->end()) { ClassRef RefType = (*it).second->GetRefType(); if(RefType == ClassRefTarget) { if((*it).second->Value->GetData().Size != 16) { error("Metadata Object \"%s/%s\" should be a reference target (a UUID), but has size %d\n", NewObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size); } else { has_target = true; UUIDPtr ID = new UUID((*it).second->Value->PutData()->Data); RefTargets.insert(std::map<UUID, MDObjectPtr>::value_type(*ID, NewObject)); // Try and satisfy all refs to this set for(;;) { std::multimap<UUID, MDObjectPtr>::iterator mit = UnmatchedRefs.find(*ID); // Exit when no more refs to this object if(mit == UnmatchedRefs.end()) break; // Sanity check! if((*mit).second->GetLink()) { error("Internal error - %s at 0x%s in UnmatchedRefs but already linked!\n", (*mit).second->FullName().c_str() , Int64toHexString((*mit).second->GetLocation(), 8).c_str()); } // Make the link (*mit).second->SetLink(NewObject); // If we are the tagert of a strong ref we won't get added to the top level if((*mit).second->GetRefType() == DICT_REF_STRONG) linked = true; // Remove from the unmatched refs map UnmatchedRefs.erase(mit); // loop for any more refs to this set } } } else if(RefType == ClassRefStrong) { MDObjectPtr Link = (*it).second->GetLink(); if(Link) { AddMetadata(Link, ForceFirst); // Prevent the new item being top-level (which it may be as we are not added yet) // DRAGONS: There is surely a better way than this!! TopLevelMetadata.remove(Link); } // If this item is not a link, it may contain links else if((*it).second->size()) { MDObject::iterator subit = (*it).second->begin(); while(subit != (*it).second->end()) { Link = (*subit).second->GetLink(); if(Link) { AddMetadata(Link, ForceFirst); // Prevent the new item being top-level (which it may be as we are not added yet) // DRAGONS: There is surely a better way than this!! TopLevelMetadata.remove(Link); } subit++; } } } else if(!((*it).second->empty())) { AddMetadataSubs((*it).second, ForceFirst); } it++; } // Add any forced-first items after thier children if(ForceFirst) AllMetadata.push_front(NewObject); // If we are not yet (strong) reffed then we are top level if(!linked) { if(ForceFirst) TopLevelMetadata.push_front(NewObject); else TopLevelMetadata.push_back(NewObject); } // Satisfy, or record as un-matched, all outgoing references ProcessChildRefs(NewObject); }
//! Load any metadictionaties that are in the list of currently loaded objects bool mxflib::Partition::LoadMetadict(void) { bool Ret = true; /* Search for the metadictionary */ MDObjectList::iterator it = AllMetadata.begin(); while(it != AllMetadata.end()) { if((*it)->IsA(MetaDictionary_UL)) { /* We need to set up a symbol space for this metadictionary At the moment we attach it to one named with the instance ID of this metadictionary item */ std::string SymSpaceName = (*it)->GetString(InstanceUID_UL); // If there was no InstanceUID, add a random symspace if(SymSpaceName.empty()) SymSpaceName = RandomUL()->GetString(); // See if we already have this symbol space (may have already loaded a copy of this metadictionary) - if not, build it SymbolSpacePtr SymSpace = SymbolSpace::FindSymbolSpace(SymSpaceName); if(!SymSpace) SymSpace = new SymbolSpace(SymSpaceName); // Load the metdictionary and update the running status if(!LoadMetadictionary(*it, SymSpace)) Ret = false; } else if((*it)->IsA(Root_UL)) { // FIXME: Use UL when ready //MDObjectPtr RootExtensions = (*it)->Child(RootExtensions_UL); MDObjectPtr RootExtensions = (*it)->Child("RootExtensions"); if(RootExtensions) { MDObject::iterator Ext_it = RootExtensions->begin(); while(Ext_it != RootExtensions->end()) { // Get the actual data group MDObjectPtr ExtensionGroup = (*Ext_it).second->GetRef(); if(!ExtensionGroup) { error("Broken link in ExtensionGroup reference at %s\n", (*Ext_it).second->GetSourceLocation().c_str()); } else { /* We need to set up a symbol space for this metadictionary */ // FIXME: Use UL when ready //std::string SymSpaceName = ExtensionGroup->GetString(SymbolSpace_UL); std::string SymSpaceName = ExtensionGroup->GetString("SymbolSpace"); // If there was no SymbolSpace property, add a random symspace if(SymSpaceName.empty()) SymSpaceName = RandomUL()->GetString(); // See if we already have this symbol space (may have already loaded a copy of this metadictionary) - if not, build it SymbolSpacePtr SymSpace = SymbolSpace::FindSymbolSpace(SymSpaceName); if(!SymSpace) SymSpace = new SymbolSpace(SymSpaceName); // Load the metdictionary and update the running status if(!LoadMetadictionary(ExtensionGroup, SymSpace)) Ret = false; } Ext_it++; } } } it++; } return Ret; }
//! Satisfy, or record as un-matched, all outgoing references void mxflib::Partition::ProcessChildRefs(MDObjectPtr ThisObject) { MDObjectULList::iterator it = ThisObject->begin(); while(it != ThisObject->end()) { // Only try to match references if not already matched if(!(*it).second->GetLink()) { ClassRef Ref = (*it).second->GetRefType(); if(IsRefSource(Ref)) { if(!(*it).second->Value) { if(Ref != ClassRefGlobal) { error("Metadata Object \"%s/%s\" should be a reference source (a UUID), but has no valid value\n", ThisObject->Name().c_str(), (*it).second->Name().c_str()); } } // Container for child items else if((*it).second->Value->GetData().Size == 0) { // Recurse to add refs for our children if((*it).second->size()) ProcessChildRefs((*it).second); } else if((*it).second->Value->GetData().Size != 16) { if(Ref == ClassRefGlobal) { error("Metadata Object \"%s/%s\" should be a global reference (a UL or UUID), but has size %d\n", ThisObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size); } else { error("Metadata Object \"%s/%s\" should be a reference source (a UUID), but has size %d\n", ThisObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size); } } else { UUIDPtr ID = new UUID((*it).second->Value->PutData()->Data); std::map<UUID, MDObjectPtr>::iterator mit = RefTargets.find(*ID); if(mit == RefTargets.end()) { // Not matched yet, so add to the list of outstanding refs UnmatchedRefs.insert(std::multimap<UUID, MDObjectPtr>::value_type(*ID, (*it).second)); } else { // Make the link (*it).second->SetLink((*mit).second); // If we have made a strong ref, remove the target from the top level if(Ref == DICT_REF_STRONG) TopLevelMetadata.remove((*mit).second); } } } } it++; } }
//! Dump an object and any physical or logical children void DumpObject(MDObjectPtr Object, std::string Prefix) { if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str()); if(Object->IsModified()) printf("%s%s is *MODIFIED*\n", Object->FullName().c_str(), Prefix.c_str() ); #ifdef OPTION3ENABLED if(ShowBaseline) { if(!Object->IsBaseline()) { if(Object->GetBaselineUL()) { MDOTypePtr BaselineClass = MDOType::Find(Object->GetBaselineUL()); if(BaselineClass) { printf("%sBaseline: %s\n", Prefix.c_str(), BaselineClass->Name().c_str()); } else { printf("%sNote: Current dictionary does not contain a set with the baseline UL used to wrap this non-baseline class\n", Prefix.c_str()); printf("%sBaseline: %s\n", Prefix.c_str(), Object->GetBaselineUL()->GetString().c_str()); } Prefix += " "; } else { printf("%sNote: Current dictionary flags this class as non-baseline, but it is not wrapped in a baseline class\n", Prefix.c_str()); } } else { if(Object->GetBaselineUL()) { printf("%sNote: Current dictionary flags this class as baseline, but it is wrapped as a non-baseline class\n", Prefix.c_str()); MDOTypePtr BaselineClass = MDOType::Find(Object->GetBaselineUL()); if(BaselineClass) { printf("%sBaseline: %s\n", Prefix.c_str(), BaselineClass->Name().c_str()); } else { printf("%sNote: Current dictionary does not contain a set with the baseline UL used to wrap this non-baseline class\n", Prefix.c_str()); printf("%sBaseline: %s\n", Prefix.c_str(), Object->GetBaselineUL()->GetString().c_str()); } Prefix += " "; } } } #endif // OPTION3ENABLED if(Object->GetLink()) { if(Object->GetRefType() == ClassRefStrong) { printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str()); if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str()); printf("%s%s -> Strong Reference to %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str()); DumpObject(Object->GetLink(), Prefix + " "); } else if(Object->GetRefType() == ClassRefGlobal) { if(FollowGlobals) { printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str()); if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str()); printf("%s%s -> Global Reference to %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str()); DumpObject(Object->GetLink(), Prefix + " "); } else { printf("%s%s -> Global Reference to %s, %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str(), Object->GetString().c_str()); } } else if(Object->GetRefType() == ClassRefMeta) { std::string TargetName = Object->GetLink()->GetString(MetaDefinitionName_UL, Object->GetLink()->Name()); printf("%s%s -> MetaDictionary Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), TargetName.c_str(), Object->GetString().c_str()); } else if(Object->GetRefType() == ClassRefDict) { std::string TargetName = Object->GetLink()->GetString(DefinitionObjectName_UL, Object->GetLink()->Name()); printf("%s%s -> Dictionary Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), TargetName.c_str(), Object->GetString().c_str()); } else { printf("%s%s -> Weak Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str(), Object->GetString().c_str()); } } else { if(Object->IsDValue()) { printf("%s%s = <Unknown>\n", Prefix.c_str(), Object->Name().c_str()); } else { // Check first for values that are not reference batches if(Object->IsAValue()) { //if(Object->Name().find("Unknown") == std::string::npos) printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str()); //else printf("%s%s\n", Prefix.c_str(), Object->Name().c_str()); if(Object->GetRefType() == ClassRefMeta) printf("%s%s is an unsatisfied MetaRef\n", Prefix.c_str(), Object->Name().c_str()); else if(Object->GetRefType() == ClassRefDict) printf("%s%s is an unsatisfied DictRef\n", Prefix.c_str(), Object->Name().c_str()); } else { printf("%s%s\n", Prefix.c_str(), Object->Name().c_str()); MDObjectULList::iterator it = Object->begin(); if(!SortedDump) { /* Dump Objects in the order stored */ while(it != Object->end()) { DumpObject((*it).second, Prefix + " "); it++; } } else { /* Dump Objects in alphabetical order - to allow easier file comparisons */ std::multimap<std::string, MDObjectPtr> ChildMap; std::multimap<std::string, MDObjectPtr>::iterator CM_Iter; while(it != Object->end()) { ChildMap.insert(std::multimap<std::string, MDObjectPtr>::value_type((*it).second->Name(), (*it).second)); it++; } CM_Iter = ChildMap.begin(); while(CM_Iter != ChildMap.end()) { DumpObject((*CM_Iter).second, Prefix + " "); CM_Iter++; } } } } } return; }
//! Get the offset to add to lines in field 2 int ANCVBISource::Field2Offset(void) { if(F2Offset >= 0) return F2Offset; MDObjectPtr Descriptor = MasterSource->GetDescriptor(); if(!Descriptor) { error("EssenceDescriptor not defined for master source of ANCVBISource before calling Field2Offset()\n"); F2Offset = 0; return F2Offset; } // If this is a multpile descriptor, locate the video // DRAGONS: If we can't find a picture descriptor we will drop through with the MultipleDescriptor and give a "does not have a VideoLineMap" error if(Descriptor->IsA(MultipleDescriptor_UL)) { MDObject::iterator it = Descriptor->begin(); while(it != Descriptor->end()) { if((*it).second->IsA(GenericPictureEssenceDescriptor_UL)) { Descriptor = (*it).second; break; } it++; } } /* Check if this is interlaced essence */ if(Descriptor->IsDValue(FrameLayout_UL)) { warning("EssenceDescriptor for ANCVBISource does not have a valid FrameLayout\n"); F2Offset = 0; return F2Offset; } if(Descriptor->GetInt(FrameLayout_UL) != 1) { F2Offset = 0; return F2Offset; } /* Calculate F1 to F2 distance from Video Line Map */ MDObjectPtr VideoLineMap = Descriptor->Child(VideoLineMap_UL); if(!VideoLineMap) { error("EssenceDescriptor for ANCVBISource does not have a valid VideoLineMap\n"); F2Offset = 0; return F2Offset; } MDObjectPtr F1Entry = VideoLineMap->Child(0); MDObjectPtr F2Entry = VideoLineMap->Child(1); if((!F1Entry) || (!F2Entry)) { error("EssenceDescriptor for ANCVBISource does not have a valid VideoLineMap\n"); F2Offset = 0; return F2Offset; } F2Offset = static_cast<int>(F2Entry->GetInt() - F1Entry->GetInt()); return F2Offset; }