/* * Copyright (C) 2017-2024 Adrien Gesta-Fline * * This file is part of libAAF. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "aaf/AAFCore.h" #include "aaf/AAFDump.h" #include "aaf/AAFToText.h" #include "aaf/AAFTypes.h" #include "aaf/AAFDefs/AAFClassDefUIDs.h" #include "aaf/AAFDefs/AAFFileKinds.h" #include "aaf/AAFDefs/AAFPropertyIDs.h" #include "aaf/AAFDefs/AAFTypeDefUIDs.h" #include "aaf/log.h" #include "aaf/AAFClass.h" #include "aaf/utils.h" #define debug(...) \ AAF_LOG (aafd->log, aafd, LOG_SRC_ID_AAF_CORE, VERB_DEBUG, __VA_ARGS__) #define warning(...) \ AAF_LOG (aafd->log, aafd, LOG_SRC_ID_AAF_CORE, VERB_WARNING, __VA_ARGS__) #define error(...) \ AAF_LOG (aafd->log, aafd, LOG_SRC_ID_AAF_CORE, VERB_ERROR, __VA_ARGS__) /** * Loops through each aafStrongRefSetEntry_t of a StrongRefSet Index node stream. * * @param Header Pointer to the stream's aafStrongRefSetHeader_t struct. * @param Entry Pointer that will receive each aafStrongRefSetEntry_t struct. * @param i uint32_t iterator. */ #define foreachStrongRefSetEntry(Header, Entry, i) \ for (i = 0; \ i < Header->_entryCount && \ memcpy (&Entry, ((char*)(Header)) + (sizeof (aafStrongRefSetHeader_t) + (Header->_identificationSize + sizeof (aafStrongRefSetEntry_t)) * i), sizeof (aafStrongRefSetEntry_t) + Header->_identificationSize); \ i++) /** * Loops through each aafStrongRefVectorEntry_t of a StrongRefVector Index node stream. * * @param Header Pointer to the stream's aafStrongRefVectorHeader_t struct. * @param Entry Pointer that will receive each aafStrongRefVectorEntry_t struct. * @param i uint32_t iterator. */ #define foreachStrongRefVectorEntry(vectorStream, Header, Entry, i) \ for (i = 0; \ i < Header._entryCount && \ memcpy (&Entry, (vectorStream + (sizeof (aafStrongRefVectorHeader_t) + (sizeof (aafStrongRefVectorEntry_t) * i))), sizeof (aafStrongRefVectorEntry_t)); \ i++) #define attachNewProperty(Class, PDef, Pid, IsReq) \ PDef = calloc (1, sizeof (aafPropertyDef)); \ if (!PDef) { \ error ("Out of memory"); \ return NULL; \ } \ PDef->pid = Pid; \ PDef->isReq = IsReq; \ PDef->meta = 0; \ PDef->name = NULL; \ PDef->next = Class->Properties; \ Class->Properties = PDef; /* * Retrieves useful file informations out of Header Object. * * @param aafd Pointer to the AAF_Data structure. * * @return 0 on success\n * -1 on error. */ static int parse_Header (AAF_Data* aafd); /* * Retrieves useful file informations out of Identification Object. * * @param aafd Pointer to the AAF_Data structure. * * @return 0 on success\n * -1 on error. */ static int parse_Identification (AAF_Data* aafd); /* * Tests the CFB_Data.hdr._clsid field for a valid AAF file. * * @note The spec says that the AAFFileKind signature should be retrieved from the CLSID * of the Root IStorage. In practice, this CLSID holds the #AAFClassID_Root value, and * the AAFFileKind is (sometimes) found in the CLSID of the CFB_Header, which according * to the CFB spec should be zero. All of this has been observed in AAF files built with * the official AAFSDK. * * As a conclusion, the way to test for a valid AAF file is not a valid test itself.. or * not sufficiently documented. Thus, this function shall not be trusted until further * knowledge improvement. * * @param aafd Pointer to the AAF_Data structure. * * @return 1 if the file *looks like* a valid AAF\n * 0 otherwise. */ // static int isValidAAF( AAF_Data *aafd ); /** * Sets the AAF_Data structure's pointers to the main AAF Tree objects. These pointers * can then be used for quick conveniant objects access. * * @param aafd Pointer to the AAF_Data structure. */ static void setObjectShortcuts (AAF_Data* aafd); /** * Parses the entire Compound File Binary Tree and retrieves Objets and Properties. * * This function first parses the Root Object, then follows the Root::MetaDictionary to * retrieve potential custom Classes and Properties with retrieveMetaDictionaryClass(), * and then parses the rest of the Tree starting at Root::Header. * * This function should be called after the AAF Classes has been defined by * #aafclass_setDefaultClasses(). This function is called by aaf_load_file(). * * @param aafd Pointer to the AAF_Data structure. */ static int retrieveObjectTree (AAF_Data* aafd); /** * Parses the entire MetaDictionary, retrieving potential custom classes and properties. * This function is to be called within a loop that iterates through the * MetaDictionary::ClassDefinitions Objects, and by itself when looking for parent * Classes. * * @param aafd Pointer to the AAF_Data structure. * @param TargetClassDef Pointer to the current ClassDefinition Object. * * @return A pointer to the retrieved Class. */ static aafClass* retrieveMetaDictionaryClass (AAF_Data* aafd, aafObject* TargetClassDef); /** * Allocates a new aafObject structure, and adds it to the AAF_Data.Objects list. * * @param aafd Pointer to the AAF_Data structure. * @param node Pointer to the corresponding cfbNode structure. * @param Class Pointer to the corresponding class definition aafClass structure. * @param parent Pointer to the new Object's parent object, that is the one that has an * ownership reference (Strong Ref Set/Vector) to the new Object. * * @return A pointer to the newly created aafObject. */ static aafObject* newObject (AAF_Data* aafd, cfbNode* node, aafClass* Class, aafObject* parent); /** * Allocates a new aafProperty structure. * * @param Def Pointer to the corresponding property definition aafPropertyDef structure. * * @return A pointer to the newly created aafProperty. */ static aafProperty* newProperty (AAF_Data* aafd, aafPropertyDef* Def); /** * Test whether or not, a property ID (property definition) was already retrieved for a given Class. * * @param Class Pointer to the aafClass. * @param Pid Property ID. * * @return A pointer to the retrieved property definition\n * NULL otherwise. */ static aafPropertyDef* propertyIdExistsInClass (aafClass* Class, aafPID_t Pid); /** * Sets the aafStrongRefSetHeader_t Obj->Header and aafStrongRefSetEntry_t Obj->Entry, * when parsing an Object from a StrongReferenceSet. This function is called by the * #retrieveStrongReferenceSet() function. * * @param Obj Pointer to an aafObject structure. * @param Header Pointer to an aafStrongRefSetHeader_t structure. * @param Entry Pointer to an aafStrongRefSetEntry_t structure. */ static int setObjectStrongRefSet (aafObject* Obj, aafStrongRefSetHeader_t* Header, aafStrongRefSetEntry_t* Entry); /** * Sets the aafStrongRefVectorHeader_t Obj->Header and aafStrongRefVectorEntry_t * Obj->Entry, when parsing an Object from a StrongReferenceSet. This function is called * by the retrieveStrongReferenceVector() function. * * @param Obj Pointer to an aafObject structure. * @param Header Pointer to an aafStrongRefVectorHeader_t structure. * @param Entry Pointer to an aafStrongRefVectorEntry_t structure. */ static int setObjectStrongRefVector (aafObject* Obj, aafStrongRefVectorHeader_t* Header, aafStrongRefVectorEntry_t* Entry); /** * Retrieves and parses a single StrongReference Object. This function is called by * retrieveProperty() when it encounters an SF_STRONG_OBJECT_REFERENCE property. * * @param aafd Pointer to the AAF_Data structure. * @param Prop Pointer to the property holding the SF_STRONG_OBJECT_REFERENCE. * @param parent Pointer to the parent Object which holds the Prop property. */ static int retrieveStrongReference (AAF_Data* aafd, aafProperty* Prop, aafObject* Parent); /** * Retrieves and parses StrongReferenceSet Objects. This function is called by * retrieveProperty() when it encounters an SF_STRONG_OBJECT_REFERENCE_SET property. * * @param aafd Pointer to the AAF_Data structure. * @param Prop Pointer to the property holding the SF_STRONG_OBJECT_REFERENCE_SET. * @param parent Pointer to the parent Object which holds the Prop property. */ static int retrieveStrongReferenceSet (AAF_Data* aafd, aafProperty* Prop, aafObject* parent); /** * Retrieve and parse StrongReferenceVector Objects. This function is called by * retrieveProperty() when it encounters an SF_STRONG_OBJECT_REFERENCE_VECTOR property. * * @param aafd Pointer to the AAF_Data structure. * @param Prop Pointer to the property holding the SF_STRONG_OBJECT_REFERENCE_VECTOR. * @param parent Pointer to the parent Object which holds the Prop property. */ static int retrieveStrongReferenceVector (AAF_Data* aafd, aafProperty* Prop, aafObject* Parent); /** * Adds a new aafProperty to an Object->properties list. If the property Stored Form is * either SF_STRONG_OBJECT_REFERENCE, SF_STRONG_OBJECT_REFERENCE_SET or * SF_STRONG_OBJECT_REFERENCE_VECTOR, then the function follows the "link" to the * Object(s) by calling respectively retrieveStrongReference(), * retrieveStrongReferenceSet() or retrieveStrongReferenceVector(). This function is * called by retrieveObjectProperties(). * * @param aafd Pointer to the AAF_Data structure. * @param Obj Pointer to the aafObject structure holding this property. * @param Def Pointer to the aafPropertyDef structure defining this property. * @param p Pointer to the aafPropertyIndexEntry_t structure representing the property * in the file. * @param v Pointer to a p->_length long byte array holding the actual property value. * @param bo uint8_t specifying the property's Byte Order. TO BE IMPLEMENTED * * @TODO Take ByteOrder into account */ static int retrieveProperty (AAF_Data* aafd, aafObject* Obj, aafPropertyDef* Def, aafPropertyIndexEntry_t* p, aafByte_t* v, uint8_t bo); /** * Retrieves the properties for a given aafObject. * * @param aafd Pointer to the AAF_Data structure. * @param Obj Pointer to the aafObject holding the properties. */ static int retrieveObjectProperties (AAF_Data* aafd, aafObject* Obj); /** * Retrieves a StrongRef Set/Vector Index Node in the Compound File Tree. This function * is called by both retrieveStrongReferenceSet() and retrieveStrongReferenceVector(). * * @param aafd Pointer to the AAF_Data structure. * @param parent Pointer to the parent aafObject. * @param refName Pointer to a null terminated string holding the reference name. * * @return Pointer to the retrieved Node cfbNode structure. */ static cfbNode* getStrongRefIndexNode (AAF_Data* aafd, aafObject* Parent, const char* refName); /** * Retrieves a StrongRef Set or Vector Entry Node in the Compound File Tree. This * function is called by both retrieveStrongReferenceSet() and * retrieveStrongReferenceVector(). * * @param aafd Pointer to the AAF_Data structure. * @param parent Pointer to the parent Index Node. * @param baseName Pointer to a null terminated string holding the reference base name. * @param index uint32_t number representing the index number of the reference. * * @return Pointer to the retrieved Node cfbNode structure. */ static cfbNode* getStrongRefEntryNode (AAF_Data* aafd, aafObject* Parent, const char* refName, uint32_t index); /** * Retrieves and returns a list of aafPropertyIndexHeader_t. * For a given cfbNode, retrieves its /properties Stream Node and returns the stream as * a pointer to an aafPropertyIndexHeader_t structure, wich the stream should begin with. * * @param aafd Pointer to the AAF_Data structure. * @param node Pointer to a cfbNode structure. * * @return Pointer to an aafPropertyIndexHeader_t structure, followed by _entryCount * aafPropertyIndexEntry_t structures. */ static aafByte_t* getNodeProperties (AAF_Data* aafd, cfbNode* node); /** * Retrieves and returns a list of StrongReferenceSet. * * For a given Index cfbNode, retrieves its Stream and returns it as a pointer to an * aafStrongRefSetHeader_t structure, wich the stream should begin with. * * @param aafd Pointer to the AAF_Data structure. * @param node Pointer to an Index cfbNode structure. * @param parent Pointer to the aafObject parent, only used on error printing. * * @return Pointer to an aafStrongRefSetHeader_t structure, followed by _entryCount * aafStrongRefSetEntry_t structures. */ static aafStrongRefSetHeader_t* getStrongRefSetList (AAF_Data* aafd, cfbNode* Node, aafObject* Parent); /** * Retrieves and returns a list of StrongReferenceVectors. * * For a given Index cfbNode, retrieves its Stream and returns it as a pointer to an * aafStrongRefVectorHeader_t structure, wich the stream should begin with. * * @param aafd Pointer to the AAF_Data structure. * @param node Pointer to an Index cfbNode structure. * @param parent Pointer to the aafObject parent, only used on error printing. * * @return Pointer to an aafStrongRefVectorHeader_t structure, followed by * _entryCount aafStrongRefVectorEntry_t structures. */ static aafByte_t* getStrongRefVectorList (AAF_Data* aafd, cfbNode* Node, aafObject* Parent); AAF_Data* aaf_alloc (struct aafLog* log) { AAF_Data* aafd = calloc (1, sizeof (AAF_Data)); if (!aafd) { goto err; } aafd->cfbd = NULL; aafd->Identification.CompanyName = NULL; aafd->Identification.ProductName = NULL; aafd->Identification.ProductVersionString = NULL; aafd->Identification.Platform = NULL; aafd->Classes = NULL; aafd->Objects = NULL; aafd->log = log; aafd->cfbd = cfb_alloc (log); if (!aafd->cfbd) { goto err; } return aafd; err: if (aafd) { if (aafd->cfbd) { cfb_release (&aafd->cfbd); } free (aafd); } return NULL; } int aaf_load_file (AAF_Data* aafd, const char* file) { if (!aafd || !file) return 1; aafd->Objects = NULL; aafd->Classes = NULL; if (cfb_load_file (&aafd->cfbd, file) < 0) { return 1; } /* * NOTE: at least Avid Media Composer doesn't respect * the standard clsid AAFFileKind_Aaf4KBinary identifier. * Therefore isValidAAF() is useless until futher findings.. */ // if ( isValidAAF( aafd ) == 0 ) { // return 1; // } if (aafclass_setDefaultClasses (aafd) < 0) { return -1; } if (retrieveObjectTree (aafd) < 0) { return -1; } if (parse_Header (aafd) < 0) { return -1; } if (parse_Identification (aafd) < 0) { return -1; } return 0; } void aaf_release (AAF_Data** aafd) { if (!aafd || !(*aafd)) return; if ((*aafd)->cfbd != NULL) cfb_release (&((*aafd)->cfbd)); aafClass* Class = NULL; aafClass* tmpClass = NULL; for (Class = (*aafd)->Classes; Class != NULL; Class = tmpClass) { tmpClass = Class->next; aafPropertyDef* PDef = NULL; aafPropertyDef* tmpPDef = NULL; free (Class->name); for (PDef = Class->Properties; PDef != NULL; PDef = tmpPDef) { tmpPDef = PDef->next; free (PDef->name); free (PDef); } free (Class); } aafObject* Object = NULL; aafObject* tmpObject = NULL; for (Object = (*aafd)->Objects; Object != NULL; Object = tmpObject) { tmpObject = Object->nextObj; free (Object->Header); free (Object->Entry); free (Object->Name); aafProperty* Prop = NULL; aafProperty* tmpProp = NULL; for (Prop = Object->Properties; Prop != NULL; Prop = tmpProp) { tmpProp = Prop->next; switch (Prop->sf) { case SF_STRONG_OBJECT_REFERENCE: case SF_STRONG_OBJECT_REFERENCE_SET: case SF_STRONG_OBJECT_REFERENCE_VECTOR: break; default: free (Prop->val); } free (Prop); } free (Object); } free ((*aafd)->Identification.CompanyName); free ((*aafd)->Identification.ProductName); free ((*aafd)->Identification.ProductVersionString); free ((*aafd)->Identification.Platform); free (*aafd); *aafd = NULL; } char* aaf_get_ObjectPath (aafObject* Obj) { static char path[CFB_PATH_NAME_SZ]; uint32_t offset = CFB_PATH_NAME_SZ; path[--offset] = '\0'; while (Obj != NULL) { for (int i = (int)strlen (Obj->Name) - 1; i >= 0 && offset > 0; i--) { path[--offset] = Obj->Name[i]; } if (offset == 0) break; path[--offset] = '/'; Obj = Obj->Parent; } return path + offset; } int _aaf_foreach_ObjectInSet (aafObject** Obj, aafObject* head, const aafUID_t* filter) { if (!(*Obj)) *Obj = head; else *Obj = (*Obj)->next; if (filter != NULL) for (; *Obj != NULL; *Obj = (*Obj)->next) if (aafUIDCmp ((*Obj)->Class->ID, filter)) break; return (!(*Obj)) ? 0 : 1; } aafObject* aaf_get_ObjectByWeakRef (aafObject* list, aafWeakRef_t* ref) { if (!ref || !list || !list->Entry) { return NULL; } AAF_Data* aafd = list->aafd; /* Target is a Reference Vector */ if (list->Header->_identificationSize == 0) { // debug( "Has local key" ); for (; list != NULL; list = list->next) { if (list->Entry->_localKey == ref->_referencedPropertyIndex) { // debug( "list->Entry->_localKey : 0x%x", list->Entry->_localKey ); // debug( "list->Header->_identificationSize : %u", list->Header->_identificationSize ); // debug( "FOUND : 0x%x", list->Entry->_localKey ); return list; } } } /* Target is a Reference Set */ else { for (; list != NULL; list = list->next) { if (memcmp (list->Entry->_identification, ref->_identification, ref->_identificationSize) == 0) { if (list->Header->_identificationSize != ref->_identificationSize) { /* TODO : is it possible ? is it an error ? */ debug ("list->Header->_identificationSize (%i bytes) doesn't match ref->_identificationSize (%i bytes)", list->Header->_identificationSize, ref->_identificationSize); } return list; } } } return NULL; } aafUID_t* aaf_get_InterpolationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* InterpolationDefWeakRef) { aafObject* InterpolationDefinition = aaf_get_ObjectByWeakRef (aafd->InterpolationDefinition, InterpolationDefWeakRef); if (!InterpolationDefinition) { error ("Could not find InterpolationDefinition."); return NULL; } aafUID_t* InterpolationIdentification = aaf_get_propertyValue (InterpolationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); if (!InterpolationIdentification) { error ("Missing DefinitionObject::Identification."); return NULL; } return InterpolationIdentification; } aafUID_t* aaf_get_OperationIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* OperationDefWeakRef) { aafObject* OperationDefinition = aaf_get_ObjectByWeakRef (aafd->OperationDefinition, OperationDefWeakRef); if (!OperationDefinition) { error ("Could not retrieve OperationDefinition from dictionary."); return NULL; } aafUID_t* OperationIdentification = aaf_get_propertyValue (OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); if (!OperationIdentification) { error ("Missing DefinitionObject::Identification."); return NULL; } return OperationIdentification; } aafUID_t* aaf_get_ContainerIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* ContainerDefWeakRef) { aafObject* ContainerDefinition = aaf_get_ObjectByWeakRef (aafd->ContainerDefinition, ContainerDefWeakRef); if (!ContainerDefinition) { warning ("Could not retrieve WeakRef from Dictionary::ContainerDefinitions."); return NULL; } aafUID_t* ContainerIdentification = aaf_get_propertyValue (ContainerDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); if (!ContainerIdentification) { warning ("Missing ContainerDefinition's DefinitionObject::Identification."); return NULL; } return ContainerIdentification; } aafUID_t* aaf_get_DataIdentificationByWeakRef (AAF_Data* aafd, aafWeakRef_t* DataDefWeakRef) { aafObject* DataDefinition = aaf_get_ObjectByWeakRef (aafd->DataDefinition, DataDefWeakRef); if (!DataDefinition) { warning ("Could not retrieve WeakRef from Dictionary::DataDefinition."); return NULL; } aafUID_t* DataIdentification = aaf_get_propertyValue (DataDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); if (!DataIdentification) { warning ("Missing DataDefinition's DefinitionObject::Identification."); return NULL; } return DataIdentification; } aafObject* aaf_get_ObjectAncestor (aafObject* Obj, const aafUID_t* ClassID) { /* * NOTE : AAFClassID_ContentStorage is the container of Mob and EssenceData, * not of Identification, Dictionary and MetaDictionary. If needed, the func * should work for them too thanks to Obj != NULL. */ while (Obj != NULL && !aafUIDCmp (Obj->Class->ID, &AAFClassID_ContentStorage)) { if (aafUIDCmp (ClassID, Obj->Class->ID)) { return Obj; } if (aaf_ObjectInheritsClass (Obj, ClassID)) { return Obj; } Obj = Obj->Parent; } return NULL; } int aaf_ObjectInheritsClass (aafObject* Obj, const aafUID_t* classID) { // AAF_Data *aafd = Obj->aafd; aafClass* classObj = NULL; foreachClassInheritance (classObj, Obj->Class) { if (aafUIDCmp (classObj->ID, classID)) { // debug( "%s is a parent of class %s", // aaft_ClassIDToText( aafd, classObj->ID ), // aaft_ClassIDToText( aafd, Obj->Class->ID ) ); return 1; } } return 0; } aafObject* aaf_get_MobByID (aafObject* Mobs, aafMobID_t* MobID) { aafObject* Mob = NULL; if (!MobID) return NULL; AAF_foreach_ObjectInSet (&Mob, Mobs, NULL) { aafMobID_t* Current = aaf_get_propertyValue (Mob, PID_Mob_MobID, &AAFTypeID_MobIDType); if (!Current || aafMobIDCmp (Current, MobID)) break; } return Mob; } aafObject* aaf_get_MobSlotBySlotID (aafObject* MobSlots, aafSlotID_t SlotID) { aafObject* MobSlot = NULL; AAF_foreach_ObjectInSet (&MobSlot, MobSlots, NULL) { aafSlotID_t* CurrentSlotID = aaf_get_propertyValue (MobSlot, PID_MobSlot_SlotID, &AAFTypeID_UInt32); if (!CurrentSlotID || *CurrentSlotID == SlotID) break; } return MobSlot; } aafObject* aaf_get_EssenceDataByMobID (AAF_Data* aafd, aafMobID_t* MobID) { aafMobID_t* DataMobID = NULL; aafObject* EssenceData = NULL; for (EssenceData = aafd->EssenceData; EssenceData != NULL; EssenceData = EssenceData->next) { DataMobID = aaf_get_propertyValue (EssenceData, PID_EssenceData_MobID, &AAFTypeID_MobIDType); if (aafMobIDCmp (DataMobID, MobID)) break; } return EssenceData; } aafUID_t* aaf_get_ParamDefIDByName (AAF_Data* aafd, const char* name) { aafUID_t* ParamDefIdent = NULL; aafObject* ParameterDefinitions = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_ParameterDefinitions, &AAFTypeID_ParameterDefinitionStrongReferenceSet); aafObject* ParameterDefinition = NULL; AAF_foreach_ObjectInSet (&ParameterDefinition, ParameterDefinitions, NULL) { char* paramName = aaf_get_propertyValue (ParameterDefinition, PID_DefinitionObject_Name, &AAFTypeID_String); if (!paramName) { continue; } if (strcmp (paramName, name) == 0) { ParamDefIdent = aaf_get_propertyValue (ParameterDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); free (paramName); break; } free (paramName); } return ParamDefIdent; } void* aaf_get_TaggedValueByName (AAF_Data* aafd, aafObject* TaggedValueVector, const char* name, const aafUID_t* type) { struct aafLog* log = aafd->log; aafObject* TaggedValue = NULL; AAF_foreach_ObjectInSet (&TaggedValue, TaggedValueVector, NULL) { if (!aafUIDCmp (TaggedValue->Class->ID, &AAFClassID_TaggedValue)) { LOG_BUFFER_WRITE (log, " %sObject > %s\n", ANSI_COLOR_RESET (log), aaft_ClassIDToText (aafd, TaggedValue->Class->ID)); continue; } char* taggedName = aaf_get_propertyValue (TaggedValue, PID_TaggedValue_Name, &AAFTypeID_String); aafIndirect_t* taggedIndirect = aaf_get_propertyValue (TaggedValue, PID_TaggedValue_Value, &AAFTypeID_Indirect); if (strcmp (taggedName, name) == 0) { if (aafUIDCmp (&taggedIndirect->TypeDef, type)) { debug ("Found TaggedValue \"%s\" of type %s", taggedName, aaft_TypeIDToText (&taggedIndirect->TypeDef)); free (taggedName); void* value = aaf_get_indirectValue (aafd, taggedIndirect, type); return value; } debug ("Got TaggedValue \"%s\" but of type %s instead of %s", taggedName, aaft_TypeIDToText (&taggedIndirect->TypeDef), aaft_TypeIDToText (type)); } // LOG_BUFFER_WRITE( log, " %sTagged > Name: %s%s%s%*s Value: %s(%s)%s %s%s%s", // ANSI_COLOR_RESET(log), // ANSI_COLOR_DARKGREY(log), // (name) ? name : "", // ANSI_COLOR_RESET(log), // (name) ? (size_t)(24-(int)strlen(name)) : (size_t)(24-strlen("")), " ", // ANSI_COLOR_DARKGREY(log), // aaft_TypeIDToText( &taggedIndirect->TypeDef ), // ANSI_COLOR_RESET(log), // ANSI_COLOR_DARKGREY(log), // aaft_IndirectValueToText( aafd, taggedIndirect ), // ANSI_COLOR_RESET(log) ); free (taggedName); } debug ("TaggedValue not found \"%s\"", name); return NULL; } /* * TODO Works when the property was retrieved from MetaDictionary. What if the property is standard ? */ aafPID_t aaf_get_PropertyIDByName (AAF_Data* aafd, const char* name) { aafClass* Class = NULL; foreachClass (Class, aafd->Classes) { aafPropertyDef* PDef = NULL; foreachPropertyDefinition (PDef, Class->Properties) { if (PDef->name != NULL && strcmp (PDef->name, name) == 0) { return PDef->pid; } } } return 0; } aafUID_t* aaf_get_OperationDefIDByName (AAF_Data* aafd, const char* OpDefName) { aafObject* OperationDefinitions = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_OperationDefinitions, &AAFTypeID_OperationDefinitionStrongReferenceSet); aafObject* OperationDefinition = NULL; while (_aaf_foreach_ObjectInSet (&OperationDefinition, OperationDefinitions, NULL)) { aafUID_t* OpDefIdent = aaf_get_propertyValue (OperationDefinition, PID_DefinitionObject_Identification, &AAFTypeID_AUID); char* name = aaf_get_propertyValue (OperationDefinition, PID_DefinitionObject_Name, &AAFTypeID_String); if (strcmp (name, OpDefName) == 0) { free (name); return OpDefIdent; } free (name); } return NULL; } aafProperty* aaf_get_property (aafObject* Obj, aafPID_t pid) { if (!Obj) return NULL; AAF_Data* aafd = Obj->aafd; aafProperty* Prop = NULL; for (Prop = Obj->Properties; Prop != NULL; Prop = Prop->next) if (Prop->pid == pid) break; if (!Prop) { aafPropertyDef* PDef = aafclass_getPropertyDefinitionByID (Obj->Class, pid); if (!PDef) { warning ("Could not retrieve 0x%04x (%s) of Class %s", pid, aaft_PIDToText (aafd, pid), aaft_ClassIDToText (aafd, Obj->Class->ID)); return NULL; } if (PDef->isReq) { error ("Could not retrieve %s required property 0x%04x (%s)", aaft_ClassIDToText (aafd, Obj->Class->ID), pid, aaft_PIDToText (aafd, pid)); } else { debug ("Could not retrieve %s optional property 0x%04x (%s)", aaft_ClassIDToText (aafd, Obj->Class->ID), pid, aaft_PIDToText (aafd, pid)); } } return Prop; } void* aaf_get_propertyValue (aafObject* Obj, aafPID_t pid, const aafUID_t* typeID) { if (!Obj) { return NULL; } AAF_Data* aafd = Obj->aafd; aafProperty* Prop = aaf_get_property (Obj, pid); if (!Prop) { return NULL; } void* value = Prop->val; uint16_t len = Prop->len; if (Prop->sf == SF_DATA_STREAM || aafUIDCmp (typeID, &AAFTypeID_Indirect)) { /* * DATA_STREAM stored form and IndirectValues start with a byte identifying byte order : 0x4c, 0x42, 0x55 * We must skip that byte. */ value = (void*)(((char*)value) + 1); len--; } if (aafUIDCmp (typeID, &AAFTypeID_String)) { if (((uint16_t*)value)[(len / 2) - 1] != 0x0000) { error ("Object %s string property 0x%04x (%s) does not end with NULL", aaft_ClassIDToText (aafd, Obj->Class->ID), pid, aaft_PIDToText (aafd, pid)); return NULL; } return cfb_w16toUTF8 (value, len); } if (aafUIDCmp (typeID, &AAFTypeID_Indirect)) { /* * In case of Indirect with string value we check NULL termination here, * because when calling next aaf_get_indirectValue() we wont have access * to Prop->len anymore. */ aafIndirect_t* Indirect = value; if (aafUIDCmp (&Indirect->TypeDef, &AAFTypeID_String) && ((uint16_t*)value)[(len / 2) - 1] != 0x0000) { error ("Object %s Indirect::string property 0x%04x (%s) does not end with NULL", aaft_ClassIDToText (aafd, Obj->Class->ID), pid, aaft_PIDToText (aafd, pid)); return NULL; } } if ((aafUIDCmp (typeID, &AAFTypeID_Boolean) && len != sizeof (aafBoolean_t)) || (aafUIDCmp (typeID, &AAFTypeID_Int8) && len != sizeof (int8_t)) || (aafUIDCmp (typeID, &AAFTypeID_UInt8) && len != sizeof (uint8_t)) || (aafUIDCmp (typeID, &AAFTypeID_Int16) && len != sizeof (int16_t)) || (aafUIDCmp (typeID, &AAFTypeID_UInt16) && len != sizeof (uint16_t)) || (aafUIDCmp (typeID, &AAFTypeID_Int32) && len != sizeof (int32_t)) || (aafUIDCmp (typeID, &AAFTypeID_UInt32) && len != sizeof (uint32_t)) || (aafUIDCmp (typeID, &AAFTypeID_Int64) && len != sizeof (int64_t)) || (aafUIDCmp (typeID, &AAFTypeID_UInt64) && len != sizeof (uint64_t)) || (aafUIDCmp (typeID, &AAFTypeID_PositionType) && len != sizeof (aafPosition_t)) || (aafUIDCmp (typeID, &AAFTypeID_LengthType) && len != sizeof (aafLength_t)) || (aafUIDCmp (typeID, &AAFTypeID_Rational) && len != sizeof (aafRational_t)) || (aafUIDCmp (typeID, &AAFTypeID_TimeStamp) && len != sizeof (aafTimeStamp_t)) || (aafUIDCmp (typeID, &AAFTypeID_VersionType) && len != sizeof (aafVersionType_t)) || (aafUIDCmp (typeID, &AAFTypeID_ProductVersion) && len != sizeof (aafProductVersion_t)) || (aafUIDCmp (typeID, &AAFTypeID_UsageType) && len != sizeof (aafUID_t)) || (aafUIDCmp (typeID, &AAFTypeID_AUID) && len != sizeof (aafUID_t)) || (aafUIDCmp (typeID, &AAFTypeID_MobIDType) && len != sizeof (aafMobID_t))) { error ("Object %s property 0x%04x (%s) size (%u) does not match type %s", aaft_ClassIDToText (aafd, Obj->Class->ID), pid, aaft_PIDToText (aafd, pid), len, aaft_TypeIDToText (typeID)); return NULL; } return value; } void* aaf_get_indirectValue (AAF_Data* aafd, aafIndirect_t* Indirect, const aafUID_t* typeDef) { if (!Indirect) { error ("Indirect is NULL"); return NULL; } if (typeDef && aafUIDCmp (&Indirect->TypeDef, typeDef) == 0) { error ("Requested Indirect value of type %s but has type %s", aaft_TypeIDToText (typeDef), aaft_TypeIDToText (&Indirect->TypeDef)); return NULL; } if (aafUIDCmp (typeDef, &AAFTypeID_String)) { /* * Indirect->Value is guaranted by aaf_get_property() to be NULL terminated */ size_t indirectValueSize = 0; for (size_t i = 0; (i % 2 || !(Indirect->Value[i] == 0x00 && Indirect->Value[i + 1] == 0x00)); i++) { indirectValueSize++; } indirectValueSize += 2; uint16_t* w16 = malloc (indirectValueSize); if (!w16) { error ("Out of memory"); return NULL; } memcpy (w16, Indirect->Value, indirectValueSize); char* str = cfb_w16toUTF8 (w16, indirectValueSize); free (w16); return str; } return &Indirect->Value; } static int parse_Header (AAF_Data* aafd) { aafObject* Header = aafd->Header.obj; if (!Header) { error ("Missing Header Object."); return -1; } int16_t* ByteOrder = aaf_get_propertyValue (Header, PID_Header_ByteOrder, &AAFTypeID_Int16); if (!ByteOrder) { warning ("Missing Header::ByteOrder."); } else { aafd->Header.ByteOrder = *ByteOrder; } aafTimeStamp_t* LastModified = aaf_get_propertyValue (Header, PID_Header_LastModified, &AAFTypeID_TimeStamp); if (!LastModified) { warning ("Missing Header::LastModified."); } else { aafd->Header.LastModified = LastModified; } aafVersionType_t* Version = aaf_get_propertyValue (Header, PID_Header_Version, &AAFTypeID_VersionType); if (!Version) { warning ("Missing Header::Version."); } else { aafd->Header.Version = Version; } uint32_t* ObjectModelVersion = aaf_get_propertyValue (Header, PID_Header_ObjectModelVersion, &AAFTypeID_UInt32); if (!ObjectModelVersion) { warning ("Missing Header::ObjectModelVersion."); } else { aafd->Header.ObjectModelVersion = *ObjectModelVersion; } const aafUID_t* OperationalPattern = aaf_get_propertyValue (Header, PID_Header_OperationalPattern, &AAFTypeID_AUID); if (!OperationalPattern) { warning ("Missing Header::OperationalPattern."); aafd->Header.OperationalPattern = (const aafUID_t*)&AUID_NULL; } else { aafd->Header.OperationalPattern = OperationalPattern; } return 0; } static int parse_Identification (AAF_Data* aafd) { aafObject* Identif = aafd->Identification.obj; if (!Identif) { error ("Missing Identification Object."); return -1; } char* Company = aaf_get_propertyValue (Identif, PID_Identification_CompanyName, &AAFTypeID_String); if (!Company) { warning ("Missing Identification::CompanyName."); } else { aafd->Identification.CompanyName = Company; } char* ProductName = aaf_get_propertyValue (Identif, PID_Identification_ProductName, &AAFTypeID_String); if (!ProductName) { warning ("Missing Identification::ProductName."); } else { aafd->Identification.ProductName = ProductName; } aafProductVersion_t* ProductVersion = aaf_get_propertyValue (Identif, PID_Identification_ProductVersion, &AAFTypeID_ProductVersion); if (!ProductVersion) { warning ("Missing Identification::ProductVersion."); } else { aafd->Identification.ProductVersion = ProductVersion; } char* ProductVersionString = aaf_get_propertyValue (Identif, PID_Identification_ProductVersionString, &AAFTypeID_String); if (!ProductVersionString) { warning ("Missing Identification::ProductVersionString."); } else { aafd->Identification.ProductVersionString = ProductVersionString; } aafUID_t* ProductID = aaf_get_propertyValue (Identif, PID_Identification_ProductID, &AAFTypeID_AUID); if (!ProductID) { warning ("Missing Identification::ProductID."); } else { aafd->Identification.ProductID = ProductID; } aafTimeStamp_t* Date = aaf_get_propertyValue (Identif, PID_Identification_Date, &AAFTypeID_TimeStamp); if (!Date) { warning ("Missing Identification::Date."); } else { aafd->Identification.Date = Date; } aafProductVersion_t* ToolkitVersion = aaf_get_propertyValue (Identif, PID_Identification_ToolkitVersion, &AAFTypeID_ProductVersion); if (!ToolkitVersion) { warning ("Missing Identification::ToolkitVersion."); } else { aafd->Identification.ToolkitVersion = ToolkitVersion; } char* Platform = aaf_get_propertyValue (Identif, PID_Identification_Platform, &AAFTypeID_String); if (!Platform) { warning ("Missing Identification::Platform."); } else { aafd->Identification.Platform = Platform; } aafUID_t* GenerationAUID = aaf_get_propertyValue (Identif, PID_Identification_GenerationAUID, &AAFTypeID_AUID); if (!GenerationAUID) { warning ("Missing Identification::GenerationAUID."); } else { aafd->Identification.GenerationAUID = GenerationAUID; } return 0; } // static int isValidAAF( AAF_Data *aafd ) // { // aafUID_t *hdrClsID = (aafUID_t*)&aafd->cfbd->hdr->_clsid; // // if ( aafUIDCmp( hdrClsID, &AAFFileKind_Aaf512Binary ) || // aafUIDCmp( hdrClsID, &AAFFileKind_Aaf4KBinary ) ) // return 1; // // // warning( "Unsuported AAF encoding (%s).", aaft_FileKindToText( hdrClsID ) ); // // return 0; // } static void setObjectShortcuts (AAF_Data* aafd) { // aafd->Root = aafd->Root; aafd->Header.obj = aaf_get_propertyValue (aafd->Root, PID_Root_Header, &AAFUID_NULL); // aafd->MetaDictionary = aaf_get_propertyValue( aafd->Root, PID_Root_MetaDictionary ); aafd->ClassDefinition = aaf_get_propertyValue (aafd->MetaDictionary, PID_MetaDictionary_ClassDefinitions, &AAFTypeID_ClassDefinitionStrongReferenceSet); aafd->TypeDefinition = aaf_get_propertyValue (aafd->MetaDictionary, PID_MetaDictionary_TypeDefinitions, &AAFTypeID_TypeDefinitionStrongReferenceSet); aafd->Identification.obj = aaf_get_propertyValue (aafd->Header.obj, PID_Header_IdentificationList, &AAFTypeID_IdentificationStrongReferenceVector); aafd->Content = aaf_get_propertyValue (aafd->Header.obj, PID_Header_Content, &AAFTypeID_ContentStorageStrongReference); aafd->Dictionary = aaf_get_propertyValue (aafd->Header.obj, PID_Header_Dictionary, &AAFTypeID_DictionaryStrongReference); aafd->Mobs = aaf_get_propertyValue (aafd->Content, PID_ContentStorage_Mobs, &AAFTypeID_MobStrongReferenceSet); aafd->EssenceData = aaf_get_propertyValue (aafd->Content, PID_ContentStorage_EssenceData, &AAFTypeID_EssenceDataStrongReferenceSet); aafd->OperationDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_OperationDefinitions, &AAFTypeID_OperationDefinitionStrongReferenceSet); aafd->ParameterDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_ParameterDefinitions, &AAFTypeID_ParameterDefinitionStrongReferenceSet); aafd->DataDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_DataDefinitions, &AAFTypeID_DataDefinitionStrongReferenceSet); aafd->PluginDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_PluginDefinitions, &AAFTypeID_PluginDefinitionStrongReferenceSet); aafd->CodecDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_CodecDefinitions, &AAFTypeID_CodecDefinitionStrongReferenceSet); aafd->ContainerDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_ContainerDefinitions, &AAFTypeID_ContainerDefinitionStrongReferenceSet); aafd->InterpolationDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_InterpolationDefinitions, &AAFTypeID_InterpolationDefinitionStrongReferenceSet); aafd->KLVDataDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_KLVDataDefinitions, &AAFTypeID_KLVDataDefinitionStrongReferenceSet); aafd->TaggedValueDefinition = aaf_get_propertyValue (aafd->Dictionary, PID_Dictionary_TaggedValueDefinitions, &AAFTypeID_TaggedValueDefinitionStrongReferenceSet); } static int retrieveObjectTree (AAF_Data* aafd) { int rc = 0; aafByte_t* propStream = NULL; cfbNode* Node = &aafd->cfbd->nodes[0]; aafClass* Class = aafclass_getClassByID (aafd, (aafUID_t*)&Node->_clsId); if (!Class) { error ("Could not retrieve class by id"); goto err; } aafd->Root = newObject (aafd, Node, Class, NULL); if (!aafd->Root) { goto err; } propStream = getNodeProperties (aafd, aafd->Root->Node); if (!propStream) { error ("Could not retrieve properties for %s.", aaf_get_ObjectPath (aafd->Root)); goto err; } aafPropertyIndexHeader_t Header; aafPropertyIndexEntry_t Prop; aafPropertyIndexEntry_t AAFHeaderProp; aafPropertyIndexEntry_t AAFMetaDcProp; memcpy (&Header, propStream, sizeof (aafPropertyIndexHeader_t)); aafByte_t* AAFHeaderVal = NULL; aafByte_t* AAFMetaDcVal = NULL; aafByte_t* value = NULL; aafPropertyDef* PDef = NULL; uint32_t i = 0; size_t valueOffset = 0; foreachPropertyEntry (propStream, Header, Prop, value, valueOffset, i) { if (Prop._pid == PID_Root_Header) { memcpy (&AAFHeaderProp, &Prop, sizeof (aafPropertyIndexEntry_t)); AAFHeaderVal = value; } if (Prop._pid == PID_Root_MetaDictionary) { memcpy (&AAFMetaDcProp, &Prop, sizeof (aafPropertyIndexEntry_t)); AAFMetaDcVal = value; } } PDef = aafclass_getPropertyDefinitionByID (aafd->Root->Class, PID_Root_MetaDictionary); /* Start recursive parsing of /Root/Header/{*} */ rc = retrieveProperty (aafd, aafd->Root, PDef, &AAFMetaDcProp, AAFMetaDcVal, Header._byteOrder); if (rc < 0) { error ("Could not retrieve property %s.", aaft_PIDToText (aafd, PDef->pid)); goto err; } /* * Retrieve MetaDictionary. */ aafObject* MetaDic = aaf_get_propertyValue (aafd->Root, PID_Root_MetaDictionary, &AAFUID_NULL); if (!MetaDic) { error ("Missing PID_Root_MetaDictionary."); goto err; } aafObject* ClassDefs = aaf_get_propertyValue (MetaDic, PID_MetaDictionary_ClassDefinitions, &AAFTypeID_ClassDefinitionStrongReferenceSet); if (!ClassDefs) { error ("Missing PID_MetaDictionary_ClassDefinitions."); goto err; } aafObject* ClassDef = NULL; AAF_foreach_ObjectInSet (&ClassDef, ClassDefs, NULL) { retrieveMetaDictionaryClass (aafd, ClassDef); } PDef = aafclass_getPropertyDefinitionByID (aafd->Root->Class, PID_Root_Header); /* Starts recursive parsing of /Root/Header/{*} */ rc = retrieveProperty (aafd, aafd->Root, PDef, &AAFHeaderProp, AAFHeaderVal, Header._byteOrder); if (rc < 0) { error ("Could not retrieve property %s.", aaft_PIDToText (aafd, PDef->pid)); goto err; } setObjectShortcuts (aafd); rc = 0; goto end; err: rc = -1; end: free (propStream); return rc; } static aafClass* retrieveMetaDictionaryClass (AAF_Data* aafd, aafObject* TargetClassDef) { aafObject* MetaDic = aaf_get_propertyValue (aafd->Root, PID_Root_MetaDictionary, &AAFUID_NULL); if (!MetaDic) { /* req */ debug ("Could not retrieve PID_Root_MetaDictionary property from Root."); return NULL; } aafObject* ClassDefs = aaf_get_propertyValue (MetaDic, PID_MetaDictionary_ClassDefinitions, &AAFTypeID_ClassDefinitionStrongReferenceSet); aafObject* ClassDef = NULL; if (!ClassDefs) { /* opt */ debug ("Could not retrieve PID_MetaDictionary_ClassDefinitions property from MetaDic."); return NULL; } AAF_foreach_ObjectInSet (&ClassDef, ClassDefs, NULL) { if (ClassDef == TargetClassDef) break; } if (!ClassDef) { error ("Could not retrieve ClassDefinition %p", (void*)TargetClassDef); return NULL; } aafUID_t* ClassID = aaf_get_propertyValue (ClassDef, PID_MetaDefinition_Identification, &AAFTypeID_AUID); if (!ClassID) { /* req */ error ("Could not retrieve PID_MetaDefinition_Identification property from ClassDef."); return NULL; } aafWeakRef_t* parent = aaf_get_propertyValue (ClassDef, PID_ClassDefinition_ParentClass, &AAFTypeID_ClassDefinitionWeakReference); if (!parent) { error ("Could not retrieve PID_ClassDefinition_ParentClass property from ClassDef."); return NULL; } aafObject* Parent = aaf_get_ObjectByWeakRef (ClassDefs, parent); if (!Parent) { error ("Could not retrieve object by weakRef (PID_ClassDefinition_ParentClass)"); return NULL; } aafClass* ParentClass = NULL; if (Parent != ClassDef) { ParentClass = retrieveMetaDictionaryClass (aafd, Parent); } else if (aafUIDCmp (ClassID, &AAFClassID_InterchangeObject) == 0 && aafUIDCmp (ClassID, &AAFClassID_MetaDefinition) == 0 && aafUIDCmp (ClassID, &AAFClassID_MetaDictionary) == 0) { /* * TODO: what is this ? when does it happen ? */ error ("Parent's Class equals Child's : %s.", aaft_ClassIDToText (aafd, ClassID)); return NULL; } aafClass* Class = aafclass_getClassByID (aafd, ClassID); if (!Class) { aafBoolean_t* isCon = aaf_get_propertyValue (ClassDef, PID_ClassDefinition_IsConcrete, &AAFTypeID_Boolean); if (!isCon) { error ("Missing ClassDefinition::IsConcrete."); return NULL; } Class = aafclass_defineNewClass (aafd, ClassID, *isCon, ParentClass); if (!Class) { error ("Could set new class"); return NULL; } Class->meta = 1; Class->name = aaf_get_propertyValue (ClassDef, PID_MetaDefinition_Name, &AAFTypeID_String); if (!Class->name) { debug ("Could not retrieve PID_MetaDefinition_Name property from ClassDef (%s)", aaft_ClassIDToText (aafd, ClassID)); } } else { /* if class is standard, we only set its name */ if (!Class->name) { Class->name = aaf_get_propertyValue (ClassDef, PID_MetaDefinition_Name, &AAFTypeID_String); if (!Class->name) { debug ("Could not retrieve PID_MetaDefinition_Name property from ClassDef (%s)", aaft_ClassIDToText (aafd, ClassID)); } } } aafObject* Props = aaf_get_propertyValue (ClassDef, PID_ClassDefinition_Properties, &AAFTypeID_PropertyDefinitionStrongReferenceSet); if (!Props) { /* opt */ debug ("Could not retrieve PID_ClassDefinition_Properties property from ClassDef (%s)", aaft_ClassIDToText (aafd, ClassID)); } aafObject* Prop = NULL; AAF_foreach_ObjectInSet (&Prop, Props, NULL) { aafPID_t* Pid = aaf_get_propertyValue (Prop, PID_PropertyDefinition_LocalIdentification, &AAFTypeID_UInt16); if (!Pid) { error ("Missing PropertyDefinition::LocalIdentification."); return NULL; } aafBoolean_t* isOpt = aaf_get_propertyValue (Prop, PID_PropertyDefinition_IsOptional, &AAFTypeID_Boolean); if (!isOpt) { error ("Missing PropertyDefinition::IsOptional."); return NULL; } /* * We skip all the properties that were already defined in aafclass_setDefaultClasses(). */ aafPropertyDef* PDef = propertyIdExistsInClass (Class, *Pid); if (!PDef) { attachNewProperty (Class, PDef, *Pid, (*isOpt) ? 0 : 1); PDef->meta = 1; } else { // debug( "Property %d exists.", *Pid ); continue; } PDef->name = aaf_get_propertyValue (Prop, PID_MetaDefinition_Name, &AAFTypeID_String); if (!PDef->name) { warning ("Could not retrieve PID_MetaDefinition_Name property from PropertyDefinition."); } aafObject* TypeDefs = aaf_get_propertyValue (MetaDic, PID_MetaDictionary_TypeDefinitions, &AAFTypeID_TypeDefinitionStrongReferenceSet); if (!TypeDefs) { error ("Missing TypeDefinitions from MetaDictionary"); return NULL; } aafWeakRef_t* WeakRefToType = aaf_get_propertyValue (Prop, PID_PropertyDefinition_Type, &AAFTypeID_PropertyDefinitionWeakReference); if (!WeakRefToType) { error ("Missing PID_PropertyDefinition_Type"); return NULL; } aafObject* TypeDef = aaf_get_ObjectByWeakRef (TypeDefs, WeakRefToType); if (!TypeDef) { error ("Could not retrieve TypeDefinition from dictionary."); return NULL; } aafUID_t* typeUID = aaf_get_propertyValue (TypeDef, PID_MetaDefinition_Identification, &AAFTypeID_AUID); if (!typeUID) { /* req */ error ("Missing PID_MetaDefinition_Identification"); return NULL; } /* * Looks like nobody cares about AAF standard TypeDefinition. All observed files * had incorrect values for Type Name and Identification, even Avid's files. So... */ memcpy (&PDef->type, typeUID, sizeof (aafUID_t)); // char *typeName = aaf_get_propertyValue( TypeDef, PID_MetaDefinition_Name, &AAFTypeID_String ); // // debug( "TypeName : %s (%s) | name : %s.", // typeName, // aaft_TypeIDToText( typeUID ), // PDef->name ); // // free( typeName ); } return Class; } static aafObject* newObject (AAF_Data* aafd, cfbNode* Node, aafClass* Class, aafObject* Parent) { aafObject* Obj = calloc (1, sizeof (aafObject)); if (!Obj) { error ("Out of memory"); return NULL; } Obj->Name = cfb_w16toUTF8 (Node->_ab, Node->_cb); Obj->aafd = aafd; Obj->Class = Class; Obj->Node = Node; Obj->Properties = NULL; Obj->Parent = Parent; Obj->Header = NULL; Obj->Entry = NULL; Obj->next = NULL; Obj->prev = NULL; Obj->nextObj = aafd->Objects; aafd->Objects = Obj; return Obj; } static aafProperty* newProperty (AAF_Data* aafd, aafPropertyDef* Def) { aafProperty* Prop = calloc (1, sizeof (aafProperty)); if (!Prop) { error ("Out of memory"); return NULL; } Prop->pid = Def->pid; Prop->def = Def; return Prop; } static aafPropertyDef* propertyIdExistsInClass (aafClass* Class, aafPID_t Pid) { aafPropertyDef* PDef = NULL; foreachPropertyDefinition (PDef, Class->Properties) if (PDef->pid == Pid) return PDef; return NULL; } static int setObjectStrongRefSet (aafObject* Obj, aafStrongRefSetHeader_t* Header, aafStrongRefSetEntry_t* Entry) { AAF_Data* aafd = Obj->aafd; Obj->Header = malloc (sizeof (aafStrongRefSetHeader_t)); if (!Obj->Header) { error ("Out of memory"); return -1; } memcpy (Obj->Header, Header, sizeof (aafStrongRefSetHeader_t)); /* Real entrySize, taking _identification into account. */ uint32_t entrySize = sizeof (aafStrongRefSetEntry_t) + Header->_identificationSize; Obj->Entry = malloc (entrySize); if (!Obj->Entry) { error ("Out of memory"); return -1; } memcpy (Obj->Entry, Entry, entrySize); return 0; } static int setObjectStrongRefVector (aafObject* Obj, aafStrongRefVectorHeader_t* Header, aafStrongRefVectorEntry_t* Entry) { /* * aafStrongRefVectorHeader_t and aafStrongRefSetHeader_t begins with the same * data bytes, so we can safely memcpy to the first one from the second one, * the remaining bytes simply remaining null. * The same applies to aafStrongRefVectorEntry_t and aafStrongRefVectorHeader_t. */ AAF_Data* aafd = Obj->aafd; Obj->Header = calloc (1, sizeof (aafStrongRefSetHeader_t)); if (!Obj->Header) { error ("Out of memory"); return -1; } memcpy (Obj->Header, Header, sizeof (aafStrongRefVectorHeader_t)); Obj->Entry = calloc (1, sizeof (aafStrongRefSetEntry_t)); if (!Obj->Entry) { error ("Out of memory"); return -1; } memcpy (Obj->Entry, Entry, sizeof (aafStrongRefVectorEntry_t)); return 0; } static int retrieveStrongReference (AAF_Data* aafd, aafProperty* Prop, aafObject* Parent) { /* * Initial property value is a unicode string holding the name of a child node. * This child node being the object referenced, we store that object directly * as the property value, instead of the initial child node name. */ char* name = cfb_w16toUTF8 (Prop->val, Prop->len); free (Prop->val); Prop->val = NULL; cfbNode* Node = cfb_getChildNode (aafd->cfbd, name, Parent->Node); free (name); if (!Node) { error ("Could not find child node."); return -1; } aafClass* Class = aafclass_getClassByID (aafd, (aafUID_t*)&Node->_clsId); if (!Class) { error ("Could not retrieve Class %s @ \"%s\".", aaft_ClassIDToText (aafd, (aafUID_t*)&Node->_clsId), aaf_get_ObjectPath (Parent)); return -1; } Prop->val = newObject (aafd, Node, Class, Parent); if (!Prop->val) { return -1; } int rc = retrieveObjectProperties (aafd, Prop->val); if (rc < 0) { return -1; } return 0; } static int retrieveStrongReferenceSet (AAF_Data* aafd, aafProperty* Prop, aafObject* Parent) { aafStrongRefSetHeader_t* Header = NULL; aafStrongRefSetEntry_t* Entry = NULL; char* refName = cfb_w16toUTF8 (Prop->val, Prop->len); free (Prop->val); Prop->val = NULL; cfbNode* Node = getStrongRefIndexNode (aafd, Parent, refName); if (!Node) { error ("Could not retrieve StrongReferenceSet's Index node."); goto err; } Header = getStrongRefSetList (aafd, Node, Parent); if (!Header) { error ("Could not retrieve StrongReferenceSet's CFB Stream."); goto err; } Entry = malloc (sizeof (aafStrongRefSetEntry_t) + Header->_identificationSize); if (!Entry) { error ("Out of memory"); goto err; } memset (Entry, 0x00, sizeof (aafStrongRefSetEntry_t)); uint32_t i = 0; int rc = 0; foreachStrongRefSetEntry (Header, (*Entry), i) { Node = getStrongRefEntryNode (aafd, Parent, refName, Entry->_localKey); if (!Node) { continue; } aafClass* Class = aafclass_getClassByID (aafd, (aafUID_t*)&Node->_clsId); if (!Class) { error ("Could not retrieve Class %s.", aaft_ClassIDToText (aafd, (aafUID_t*)&Node->_clsId)); continue; } aafObject* Obj = newObject (aafd, Node, Class, Parent); if (!Obj) { goto err; } rc = setObjectStrongRefSet (Obj, Header, Entry); if (rc < 0) { goto err; } rc = retrieveObjectProperties (aafd, Obj); if (rc < 0) { goto err; } Obj->next = Prop->val; Prop->val = Obj; } rc = 0; goto end; err: rc = -1; end: free (refName); free (Header); free (Entry); return rc; } static int retrieveStrongReferenceVector (AAF_Data* aafd, aafProperty* Prop, aafObject* Parent) { int rc = 0; aafByte_t* vectorStream = NULL; char* refName = cfb_w16toUTF8 (Prop->val, Prop->len); free (Prop->val); Prop->val = NULL; cfbNode* Node = getStrongRefIndexNode (aafd, Parent, refName); if (!Node) { goto err; } vectorStream = getStrongRefVectorList (aafd, Node, Parent); if (!vectorStream) { error ("Could not retrieve StrongRefVectorList"); goto err; } aafStrongRefVectorHeader_t Header; aafStrongRefVectorEntry_t Entry; memcpy (&Header, vectorStream, sizeof (aafStrongRefVectorHeader_t)); uint32_t i = 0; foreachStrongRefVectorEntry (vectorStream, Header, Entry, i) { Node = getStrongRefEntryNode (aafd, Parent, refName, Entry._localKey); if (!Node) { continue; } aafClass* Class = aafclass_getClassByID (aafd, (aafUID_t*)&Node->_clsId); if (!Class) { warning ("Could not retrieve Class ID %s.", aaft_ClassIDToText (aafd, (aafUID_t*)&Node->_clsId)); continue; } aafObject* Obj = newObject (aafd, Node, Class, Parent); if (!Obj) { goto err; } rc = setObjectStrongRefVector (Obj, &Header, &Entry); if (rc < 0) { goto err; } rc = retrieveObjectProperties (aafd, Obj); if (rc < 0) { goto err; } /* * Vectors are ordered. */ if (Prop->val != NULL) { aafObject* tmp = Prop->val; for (; tmp != NULL; tmp = tmp->next) if (!tmp->next) break; Obj->prev = tmp; tmp->next = Obj; } else { Obj->prev = NULL; Prop->val = Obj; } } rc = 0; goto end; err: rc = -1; end: free (refName); free (vectorStream); return rc; } static int retrieveProperty (AAF_Data* aafd, aafObject* Obj, aafPropertyDef* Def, aafPropertyIndexEntry_t* p, aafByte_t* v, uint8_t bo) { (void)bo; // TODO: ByteOrder support ? aafProperty* Prop = newProperty (aafd, Def); if (!Prop) { return -1; } Prop->sf = p->_storedForm; /* TODO Prop->len / Prop->val ---> retrieveStrongReference() retrieveStrongReferenceSet() retrieveStrongReferenceVector() only used to retrieve node name ? There could be a better approach. */ Prop->len = p->_length; Prop->val = malloc (p->_length); if (!Prop->val) { error ("Out of memory"); free (Prop); return -1; } memcpy (Prop->val, v, p->_length); Prop->next = Obj->Properties; Obj->Properties = Prop; switch (p->_storedForm) { case SF_STRONG_OBJECT_REFERENCE: return retrieveStrongReference (aafd, Prop, Obj); case SF_STRONG_OBJECT_REFERENCE_SET: return retrieveStrongReferenceSet (aafd, Prop, Obj); case SF_STRONG_OBJECT_REFERENCE_VECTOR: return retrieveStrongReferenceVector (aafd, Prop, Obj); default: break; } return 0; } static int retrieveObjectProperties (AAF_Data* aafd, aafObject* Obj) { int rc = 0; aafByte_t* propStream = getNodeProperties (aafd, Obj->Node); if (!propStream) { error ("Could not retrieve object %s properties : %s", aaft_ClassIDToText (aafd, Obj->Class->ID), aaf_get_ObjectPath (Obj)); goto err; } aafPropertyIndexHeader_t Header; aafPropertyIndexEntry_t Prop; memcpy (&Header, propStream, sizeof (aafPropertyIndexHeader_t)); aafByte_t* value = NULL; aafPropertyDef* PDef = NULL; size_t valueOffset = 0; uint32_t i = 0; foreachPropertyEntry (propStream, Header, Prop, value, valueOffset, i) { PDef = aafclass_getPropertyDefinitionByID (Obj->Class, Prop._pid); if (!PDef) { warning ("Unknown property 0x%04x (%s) of object %s", Prop._pid, aaft_PIDToText (aafd, Prop._pid), aaft_ClassIDToText (aafd, Obj->Class->ID)); continue; } rc = retrieveProperty (aafd, Obj, PDef, &Prop, value, Header._byteOrder); if (rc < 0) { error ("Could not retrieve property %s of object %s", aaft_PIDToText (aafd, PDef->pid), aaft_ClassIDToText (aafd, Obj->Class->ID)); goto err; } } rc = 0; goto end; err: rc = -1; end: free (propStream); return rc; } static cfbNode* getStrongRefIndexNode (AAF_Data* aafd, aafObject* Parent, const char* refName) { char name[CFB_NODE_NAME_SZ]; int rc = snprintf (name, CFB_NODE_NAME_SZ, "%s index", refName); if (rc < 0 || (size_t)rc >= CFB_NODE_NAME_SZ) { error ("snprintf() error"); return NULL; } cfbNode* Node = cfb_getChildNode (aafd->cfbd, name, Parent->Node); if (!Node) { error ("Could not retrieve Reference Set/Vector Index Node @ \"%s/%s index\"", aaf_get_ObjectPath (Parent), refName); return NULL; } return Node; } static cfbNode* getStrongRefEntryNode (AAF_Data* aafd, aafObject* Parent, const char* refName, uint32_t index) { char name[CFB_NODE_NAME_SZ]; int rc = snprintf (name, CFB_NODE_NAME_SZ, "%s{%x}", refName, index); if (rc < 0 || (size_t)rc >= CFB_NODE_NAME_SZ) { error ("snprintf() error"); return NULL; } cfbNode* Node = cfb_getChildNode (aafd->cfbd, name, Parent->Node); if (!Node) { error ("Could not retrieve Reference Set/vector Entry Node @ \"%s/%s index\"", aaf_get_ObjectPath (Parent), refName); return NULL; } return Node; } static aafByte_t* getNodeProperties (AAF_Data* aafd, cfbNode* Node) { if (!Node) { error ("Node is NULL"); return NULL; } uint64_t stream_sz = 0; aafByte_t* stream = NULL; cfbNode* propNode = cfb_getChildNode (aafd->cfbd, "properties", Node); if (!propNode) { error ("Could not retrieve Property Node"); return NULL; } cfb_getStream (aafd->cfbd, propNode, &stream, &stream_sz); if (!stream) { error ("Could not retrieve Property Stream"); return NULL; } /* * Ensures PropHeader + all PropEntries + all PropValues matches the Stream size. * TODO : is the following test important ? */ /* uint32_t prop_sz = sizeof(aafPropertyIndexHeader_t); uint32_t i = 0; for ( i = 0; i < ((aafPropertyIndexHeader_t*)stream)->_entryCount; i++ ) prop_sz += (((aafPropertyIndexEntry_t*)(stream+((sizeof(aafPropertyIndexEntry_t)*i)+sizeof(aafPropertyIndexHeader_t))))->_length) + sizeof(aafPropertyIndexEntry_t); if ( prop_sz != stream_sz ) warning( L"Stream length (%lu Bytes) does not match property length (%u Bytes).", stream_sz, prop_sz ); */ return stream; } static aafStrongRefSetHeader_t* getStrongRefSetList (AAF_Data* aafd, cfbNode* Node, aafObject* Parent) { if (!Node) return NULL; aafByte_t* stream = NULL; uint64_t stream_sz = 0; cfb_getStream (aafd->cfbd, Node, &stream, &stream_sz); if (!stream) { char* refName = cfb_w16toUTF8 (Node->_ab, Node->_cb); error ("Could not retrieve StrongReferenceSet Index Stream @ \"%s/%s index\"", aaf_get_ObjectPath (Parent), refName); free (refName); return NULL; } return (aafStrongRefSetHeader_t*)stream; } static aafByte_t* getStrongRefVectorList (AAF_Data* aafd, cfbNode* Node, aafObject* Parent) { if (!Node) return NULL; aafByte_t* stream = NULL; uint64_t stream_sz = 0; cfb_getStream (aafd->cfbd, Node, &stream, &stream_sz); if (!stream) { char* refName = cfb_w16toUTF8 (Node->_ab, Node->_cb); error ("Could not retrieve StrongReferenceVector Index Stream \"%s/%s index\"", aaf_get_ObjectPath (Parent), refName); return NULL; } return stream; }