bool Helium::AssetIdentifier::Identify( Reflect::Object* object, Name& identity ) { Asset *pAsset = Reflect::SafeCast<Asset>(object); if ( pAsset ) { identity.Set(pAsset->GetPath().ToString()); HELIUM_TRACE( TraceLevels::Info, TXT( "Identifying object [%s]\n" ), identity.Get() ); return true; } else if ( object ) { HELIUM_TRACE( TraceLevels::Info, TXT( "Deferring identification of object of type [%s]\n" ), object->GetMetaClass()->m_Name ); } return false; }
/// Create a type object. /// /// @param[in] name Type name. /// @param[in] pTypePackage Package in which the template object should be stored. /// @param[in] pParent Parent type. /// @param[in] pTemplate Template object. /// @param[in] flags Type flags. /// /// @return Pointer to the type object if created successfully, null if not. /// /// @see Unregister() // PMD: Removing const because: // - Objects must be able to have properties of the same type as the outer type (i.e. Asset has reference to Asset that is the template) // - So, s_MetaClass must be set before calling PopulateMetaType // - So, this function must return a pointer that PopulateMetaType can work on, rather than calling PopulateMetaType directly // - If not for this restriction, I'd want to see if we could call MetaClass::Create and Composite::Create, rather than doing duplicate set-up work here // - To prevent un-consting parameter to PopulateMetaType, making AssetType return non-const AssetType* AssetType::Create( const Reflect::MetaClass* pClass, Package* pTypePackage, const AssetType* pParent, Asset* pTemplate, uint32_t flags ) { HELIUM_ASSERT( pClass ); HELIUM_ASSERT( pTypePackage ); HELIUM_ASSERT( pTemplate ); Name name; name.Set( pClass->m_Name ); HELIUM_ASSERT( !name.IsEmpty() ); // Register the template object with the object system. if( !Asset::RegisterObject( pTemplate ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetType::Initialize(): Failed to register type \"%s\" template object.\n" ), *name ); return NULL; } // Set up the template object name, and set this object as its parent. Asset::RenameParameters nameParameters; nameParameters.name = name; nameParameters.spOwner = pTypePackage; if( !pTemplate->Rename( nameParameters ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetType::Initialize(): Failed to set type \"%s\" template object name and owner.\n" ), *name ); Asset::UnregisterObject( pTemplate ); return NULL; } // Flag the object as the default template object for the type being created. pTemplate->SetFlags( Asset::FLAG_DEFAULT_TEMPLATE | Asset::FLAG_TRANSIENT | Asset::FLAG_PRELOADED | Asset::FLAG_LINKED | Asset::FLAG_PRECACHED | Asset::FLAG_LOADED); // Create the type object and store its parameters. AssetType* pType = new AssetType; HELIUM_ASSERT( pType ); pType->m_class = pClass; pClass->m_Tag = pType; const_cast< Reflect::MetaClass* >( pType->m_class )->m_Default = pTemplate; const_cast< Reflect::MetaClass* >( pType->m_class )->MetaStruct::m_Default = pTemplate; pType->m_name = name; pType->m_flags = flags; // Lazily initialize the lookup map. Note that this is not inherently thread-safe, but there should always be // at least one type registered before any sub-threads are spawned. if( !sm_pLookupMap ) { sm_pLookupMap = new LookupMap; HELIUM_ASSERT( sm_pLookupMap ); } // Register the type (note that a type with the same name should not already exist in the lookup map). LookupMap::Iterator typeIterator; HELIUM_VERIFY( sm_pLookupMap->Insert( typeIterator, KeyValue< Name, AssetTypePtr >( pType->GetName(), pType ) ) ); return pType; }
/// Parse a string into separate path name components. /// /// @param[in] pString String to parse. This must *not* be empty. /// @param[in] rStackHeap Stack memory heap from which to allocate the resulting name array. /// @param[out] rpNames Parsed array of names, in reverse order (top-level path name stored at the end of /// the array). Note that this will be allocated using the given heap and must be /// deallocated by the caller. /// @param[out] rpInstanceIndices Parsed array of instance indices, with each index corresponding to each name /// entry in the parsed names array. This is also allocated using the given heap and /// must be deallocated by the caller. /// @param[out] rNameCount Number of names in the parsed array. /// @param[out] rPackageCount Number of names specifying packages. /// /// @return True if the string was parsed successfully, false if not. bool AssetPath::Parse( const char* pString, StackMemoryHeap<>& rStackHeap, Name*& rpNames, uint32_t*& rpInstanceIndices, size_t& rNameCount, size_t& rPackageCount ) { HELIUM_ASSERT( pString ); HELIUM_ASSERT( pString[ 0 ] != TXT( '\0' ) ); rpNames = NULL; rpInstanceIndices = NULL; rNameCount = 0; rPackageCount = 0; // Make sure the entry specifies an absolute path. if( pString[ 0 ] != HELIUM_PACKAGE_PATH_CHAR && pString[ 0 ] != HELIUM_OBJECT_PATH_CHAR ) { HELIUM_TRACE( TraceLevels::Warning, TXT( "AssetPath: FilePath string \"%s\" does not contain a leading path separator.\n" ), pString ); return false; } // Count the number of path separators in the path. size_t nameCount = 0; size_t packageCount = 0; size_t nameLengthMax = 0; const char* pTestCharacter = pString; const char* pNameStartPos = pTestCharacter; for( ; ; ) { char character = *pTestCharacter; if( character == TXT( '\0' ) ) { size_t nameLength = static_cast< size_t >( pTestCharacter - pNameStartPos ); if( nameLength > nameLengthMax ) { nameLengthMax = nameLength; } break; } if( character == HELIUM_PACKAGE_PATH_CHAR ) { if( packageCount != nameCount ) { HELIUM_TRACE( TraceLevels::Warning, ( TXT( "AssetPath: Unexpected package path separator at character %" ) PRIdPD TXT( " of " ) TXT( "path string \"%s\".\n" ) ), pTestCharacter - pString, pString ); return false; } ++nameCount; ++packageCount; size_t nameLength = static_cast< size_t >( pTestCharacter - pNameStartPos ); if( nameLength > nameLengthMax ) { nameLengthMax = nameLength; } pNameStartPos = pTestCharacter + 1; } else if( character == HELIUM_OBJECT_PATH_CHAR ) { ++nameCount; size_t nameLength = static_cast< size_t >( pTestCharacter - pNameStartPos ); if( nameLength > nameLengthMax ) { nameLengthMax = nameLength; } pNameStartPos = pTestCharacter + 1; } ++pTestCharacter; } HELIUM_ASSERT( nameCount != 0 ); // Parse the names from the string. rpNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * nameCount ) ); HELIUM_ASSERT( rpNames ); rpInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * nameCount ) ); HELIUM_ASSERT( rpInstanceIndices ); char* pTempNameString = static_cast< char* >( rStackHeap.Allocate( sizeof( char ) * ( nameLengthMax + 1 ) ) ); HELIUM_ASSERT( pTempNameString ); char* pTempNameCharacter = pTempNameString; Name* pTargetName = &rpNames[ nameCount - 1 ]; uint32_t* pTargetIndex = &rpInstanceIndices[ nameCount - 1 ]; bool bParsingName = true; pTestCharacter = pString + 1; for( ; ; ) { char character = *pTestCharacter; if( character != HELIUM_PACKAGE_PATH_CHAR && character != HELIUM_OBJECT_PATH_CHAR && character != TXT( '\0' ) ) { // Make sure the character is a valid number when parsing the instance index. if( !bParsingName && ( character < TXT( '0' ) || character > TXT( '9' ) ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetPath: Encountered non-numeric instance index value in path string \"%s\".\n" ), *pString ); return false; } if( bParsingName && character == HELIUM_INSTANCE_PATH_CHAR ) { // Encountered a separator for the instance index, so begin parsing it. *pTempNameCharacter = TXT( '\0' ); pTargetName->Set( pTempNameString ); --pTargetName; pTempNameCharacter = pTempNameString; bParsingName = false; } else { HELIUM_ASSERT( static_cast< size_t >( pTempNameCharacter - pTempNameString ) < nameLengthMax ); *pTempNameCharacter = character; ++pTempNameCharacter; } } else { *pTempNameCharacter = TXT( '\0' ); if( bParsingName ) { pTargetName->Set( pTempNameString ); --pTargetName; SetInvalid( *pTargetIndex ); --pTargetIndex; } else { if( pTempNameCharacter == pTempNameString ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetPath: Empty instance index encountered in path string \"%s\".\n" ), pString ); return false; } if( pTempNameCharacter - pTempNameString > 1 && *pTempNameString == TXT( '0' ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "AssetPath: Encountered instance index \"%s\" with leading zeros in path string " ) TXT( "\"%s\".\n" ) ), pTempNameString, pString ); return false; } int parseCount = StringScan( pTempNameString, TXT( "%" ) SCNu32, pTargetIndex ); if( parseCount != 1 ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetPath: Failed to parse object instance index \"%s\" in path string \"%s\".\n" ), pTempNameString, pString ); return false; } if( IsInvalid( *pTargetIndex ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetPath: Instance index \"%s\" in path string \"%s\" is a reserved value.\n" ), pTempNameString, pString ); return false; } --pTargetIndex; } if( character == TXT( '\0' ) ) { break; } pTempNameCharacter = pTempNameString; bParsingName = true; } ++pTestCharacter; } rNameCount = nameCount; rPackageCount = packageCount; return true; }