Esempio n. 1
0
bool ProjectViewModel::IsContainer( const wxDataViewItem& item ) const
{
	// root node can have children
	if ( !item.IsOk() )
	{
		return true;
	}

	AssetPath *node = static_cast< AssetPath* >( item.GetID() );
	return node ? node->IsPackage() : false;
}
Esempio n. 2
0
/// Find an object based on its path name.
///
/// @param[in] path  FilePath of the object to locate.
///
/// @return  Pointer to the object if found, null pointer if not found.
Asset* Asset::FindObject( AssetPath path )
{
	// Make sure the path isn't empty.
	if( path.IsEmpty() )
	{
		return NULL;
	}

	// Assemble a list of object names and instance indices, from the top level on down.
	size_t pathDepth = 0;
	size_t packageDepth = 0;
	for( AssetPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() )
	{
		++pathDepth;

		if( testPath.IsPackage() )
		{
			++packageDepth;
		}
	}

	StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap();
	StackMemoryHeap<>::Marker stackMarker( rStackHeap );

	Name* pPathNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * pathDepth ) );
	HELIUM_ASSERT( pPathNames );

	uint32_t* pInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * pathDepth ) );
	HELIUM_ASSERT( pInstanceIndices );

	size_t pathIndex = pathDepth;
	for( AssetPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() )
	{
		HELIUM_ASSERT( pathIndex != 0 );
		--pathIndex;

		pPathNames[ pathIndex ] = testPath.GetName();
		pInstanceIndices[ pathIndex ] = testPath.GetInstanceIndex();
	}

	HELIUM_ASSERT( pathIndex == 0 );

	// Search from the root.
	return FindChildOf( NULL, pPathNames, pInstanceIndices, pathDepth, packageDepth );
}
Esempio n. 3
0
/// Initialize this package loader.
///
/// @param[in] packagePath  Asset path of the package to load.
///
/// @return  True if this loader was initialized successfully, false if not.
///
/// @see Shutdown()
bool LoosePackageLoader::Initialize( AssetPath packagePath )
{
	Shutdown();

	// Make sure the path represents a package.
	if( packagePath.IsEmpty() )
	{
		HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader::Initialize(): Empty package path specified.\n" ) );

		return false;
	}

	HELIUM_TRACE(
		TraceLevels::Debug,
		TXT( "LoosePackageLoader::Initialize(): Initializing loader for package \"%s\".\n" ),
		*packagePath.ToString() );

	if( !packagePath.IsPackage() )
	{
		HELIUM_TRACE(
			TraceLevels::Error,
			TXT( "LoosePackageLoader::Initialize(): \"%s\" does not represent a package path.\n" ),
			*packagePath.ToString() );

		return false;
	}

	// Store the package path.
	m_packagePath = packagePath;

	// Attempt to locate the specified package if it already happens to exist.
	m_spPackage = Asset::Find< Package >( packagePath );
	Package* pPackage = m_spPackage;
	if( pPackage )
	{
		if( pPackage->GetLoader() )
		{
			HELIUM_TRACE(
				TraceLevels::Error,
				TXT( "LoosePackageLoader::Initialize(): Package \"%s\" already has a loader.\n" ),
				*packagePath.ToString() );

			m_spPackage.Release();

			return false;
		}

		pPackage->SetLoader( this );
	}
	else
	{
		// Make sure we don't have a name clash with a non-package object.
		AssetPtr spObject( Asset::FindObject( packagePath ) );
		if( spObject )
		{
			HELIUM_ASSERT( !spObject->IsPackage() );

			HELIUM_TRACE(
				TraceLevels::Error,
				( TXT( "PackageLoader::Initialize(): Package loader cannot be initialized for \"%s\", as an " )
				TXT( "object with the same name exists that is not a package.\n" ) ),
				*packagePath.ToString() );

			return false;
		}
	}

	// Build the package file path.  If the package is a user configuration package, use the user data directory,
	// otherwise use the global data directory.
	Config& rConfig = Config::GetStaticInstance();
	FilePath dataDirectory;

	if ( !FileLocations::GetDataDirectory( dataDirectory ) )
	{
		HELIUM_TRACE(
			TraceLevels::Error,
			TXT( "PackageLoader::Initialize(): Could not obtain user data directory." ) );

		return false;
	}

	// Set up to read the TOC (which may not exist)
	//SetInvalid( m_packageTocFileSize );

	// First do this check without a trailing "/" so that FilePath has to actually look at the file system
	FilePath package_dir = dataDirectory + packagePath.ToFilePathString().GetData();
	
	if (!package_dir.Exists())
	{
		// Some packages like types or uninitialized user config packages may not exist on file system
		m_packageDirPath = package_dir + TXT("/");
		return true;
	}

	if (!package_dir.IsDirectory())
	{
		// Packages should not be files
		return false;
	}
	
	// But internally we will store this 
	m_packageDirPath = package_dir + TXT("/");

	return true;
}
/// @copydoc PackageLoader::BeginLoadObject()
size_t CachePackageLoader::BeginLoadObject( AssetPath path, Reflect::ObjectResolver *pResolver, bool forceReload )
{
	HELIUM_ASSERT( m_pCache );
	HELIUM_ASSERT( !forceReload ); // Not supported

	// Don't load packages from the cache, but instead create them dynamically.
	if( path.IsPackage() )
	{
		HELIUM_TRACE(
			TraceLevels::Debug,
			"CachePackageLoader::BeginLoadObject(): \"%s\" is a package, resolving immediately.\n",
			*path.ToString() );

		LoadRequest* pRequest = m_loadRequestPool.Allocate();
		HELIUM_ASSERT( pRequest );
		pRequest->pEntry = NULL;
		pRequest->pResolver = pResolver;

		ResolvePackage( pRequest->spObject, path );
		HELIUM_ASSERT( pRequest->spObject );

		SetInvalid( pRequest->asyncLoadId );
		pRequest->pAsyncLoadBuffer = NULL;
		pRequest->pPropertyDataBegin = NULL;
		pRequest->pPropertyDataEnd = NULL;
		pRequest->pPersistentResourceDataBegin = NULL;
		pRequest->pPersistentResourceDataEnd = NULL;
		SetInvalid( pRequest->ownerLoadIndex );
		HELIUM_ASSERT( !pRequest->spOwner );
		pRequest->forceReload = forceReload;

		pRequest->flags = LOAD_FLAG_PRELOADED;

		size_t requestId = m_loadRequests.Add( pRequest );

		return requestId;
	}

	const Cache::Entry* pEntry = m_pCache->FindEntry( path, 0 );
	if( !pEntry )
	{
		HELIUM_TRACE(
			TraceLevels::Debug,
			"CachePackageLoader::BeginLoadObject(): \"%s\" is not cached in this package.  No load request added.\n",
			*path.ToString() );

		return Invalid< size_t >();
	}

#ifndef NDEBUG
	size_t loadRequestSize = m_loadRequests.GetSize();
	for( size_t loadRequestIndex = 0; loadRequestIndex < loadRequestSize; ++loadRequestIndex )
	{
		if( !m_loadRequests.IsElementValid( loadRequestIndex ) )
		{
			continue;
		}

		LoadRequest* pRequest = m_loadRequests[ loadRequestIndex ];
		HELIUM_ASSERT( pRequest );
		HELIUM_ASSERT( pRequest->pEntry != pEntry );
		if( pRequest->pEntry == pEntry )
		{
			HELIUM_TRACE(
				TraceLevels::Error,
				"CachePackageLoader::BeginLoadObject(): Duplicate load request of \"%s\".  No load request added.\n",
				*path.ToString() );

			return Invalid< size_t >();
		}
	}
#endif

	LoadRequest* pRequest = m_loadRequestPool.Allocate();
	HELIUM_ASSERT( pRequest );
	pRequest->pEntry = pEntry;
	pRequest->pResolver = pResolver;
	HELIUM_ASSERT( !pRequest->spObject );
	SetInvalid( pRequest->asyncLoadId );
	pRequest->pAsyncLoadBuffer = NULL;
	pRequest->pPropertyDataBegin = NULL;
	pRequest->pPropertyDataEnd = NULL;
	pRequest->pPersistentResourceDataBegin = NULL;
	pRequest->pPersistentResourceDataEnd = NULL;
	SetInvalid( pRequest->ownerLoadIndex );
	HELIUM_ASSERT( !pRequest->spOwner );
	pRequest->forceReload = forceReload;

	pRequest->flags = 0;

	// If a fully-loaded object already exists with the same name, do not attempt to re-load the object (just mark
	// the request as complete).
	pRequest->spObject = Asset::FindObject( pEntry->path );

	Asset* pObject = pRequest->spObject;
	if( pObject && pObject->IsFullyLoaded() )
	{
		HELIUM_TRACE(
			TraceLevels::Debug,
			"CachePackageLoader::BeginLoadObject(): \"%s\" is already fully loaded.  Bypassing load process.\n",
			*path.ToString() );

		pRequest->flags = LOAD_FLAG_PRELOADED;
	}
	else
	{
		HELIUM_ASSERT( !pObject || !pObject->GetAnyFlagSet( Asset::FLAG_LOADED | Asset::FLAG_LINKED ) );

		HELIUM_TRACE(
			TraceLevels::Debug,
			"CachePackageLoader::BeginLoadObject(): Issuing async load of property data for \"%s\".\n",
			*path.ToString() );

		size_t entrySize = pEntry->size;
		pRequest->pAsyncLoadBuffer = static_cast< uint8_t* >( DefaultAllocator().Allocate( entrySize ) );
		HELIUM_ASSERT( pRequest->pAsyncLoadBuffer );

		AsyncLoader* pAsyncLoader = AsyncLoader::GetInstance();
		HELIUM_ASSERT( pAsyncLoader );

		pRequest->asyncLoadId = pAsyncLoader->QueueRequest(
			pRequest->pAsyncLoadBuffer,
			m_pCache->GetCacheFileName(),
			pEntry->offset,
			entrySize );
		HELIUM_ASSERT( IsValid( pRequest->asyncLoadId ) );
	}

	size_t requestId = m_loadRequests.Add( pRequest );

	HELIUM_TRACE(
		TraceLevels::Debug,
		"CachePackageLoader::BeginLoadObject(): Load request for \"%s\" added (ID: %" PRIuSZ ").\n",
		*path.ToString(),
		requestId );

	return requestId;
}
    /// Get the package loader to use to load the object with the given path, creating it if necessary.
    ///
    /// @param[in] path  Asset path.
    ///
    /// @return  Package loader to use to load the specified object.
    LoosePackageLoader* LoosePackageLoaderMap::GetPackageLoader( AssetPath path )
    {
        HELIUM_ASSERT( !path.IsEmpty() );

        // Resolve the object's package.
        AssetPath packagePath = path;
        while( !packagePath.IsPackage() )
        {
            packagePath = packagePath.GetParent();
            if( packagePath.IsEmpty() )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "LoosePackageLoaderMap::GetPackageLoader(): Cannot resolve package loader for \"%s\", as it " )
                    TXT( "is not located in a package.\n" ) ),
                    *path.ToString() );

                return NULL;
            }
        }

        // Locate an existing package loader.
        ConcurrentHashMap< AssetPath, LoosePackageLoader* >::ConstAccessor constMapAccessor;
        if( m_packageLoaderMap.Find( constMapAccessor, packagePath ) )
        {
            LoosePackageLoader* pLoader = constMapAccessor->Second();
            HELIUM_ASSERT( pLoader );

            return pLoader;
        }

        // Add a new package loader entry.
        ConcurrentHashMap< AssetPath, LoosePackageLoader* >::Accessor mapAccessor;
        bool bInserted = m_packageLoaderMap.Insert(
            mapAccessor,
            KeyValue< AssetPath, LoosePackageLoader* >( packagePath, NULL ) );
        if( bInserted )
        {
            // Entry added, so create and initialize the package loader.
            LoosePackageLoader* pLoader = new LoosePackageLoader;
            HELIUM_ASSERT( pLoader );

            bool bInitResult = pLoader->Initialize( packagePath );
            HELIUM_ASSERT( bInitResult );
            if( !bInitResult )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    TXT( "LoosePackageLoaderMap::GetPackageLoader(): Failed to initialize package loader for \"%s\".\n" ),
                    *packagePath.ToString() );

                m_packageLoaderMap.Remove( mapAccessor );

                return NULL;
            }

            HELIUM_VERIFY( pLoader->BeginPreload() );

            mapAccessor->Second() = pLoader;
        }

        // PMD: I am not 100% sure this is all thread safe. I think it could break if:
        // - Thread 1 inserts a key/value of path and NULL, as above
        // - Thread 2 returns false from the insert so we come straight here
        //   - Thread 2 tries to use pLoader before thread 1 assigns ploader to the value of the key
        // Note: If we did not do this assert here, we could potentially get nulls from this same thread later when
        // trying to find pLoader.
        //
        // Leaving it alone for now since I'm not sure, but if this assert gets tripped, we need to revisit this.
        // Easy fix may be to allocate and construct (but don't completely init) an LoosePackageLoader, and try
        // to insert that directly rather than the null above. If insert succeeds, finish, else ditch our loader
        // and grab the one out of the array
        LoosePackageLoader* pLoader = mapAccessor->Second();
        HELIUM_ASSERT( pLoader );

        return pLoader;
    }
Esempio n. 6
0
/// @copydoc AssetLoader::CacheObject()
bool LooseAssetLoader::CacheObject( Asset* pAsset, bool bEvictPlatformPreprocessedResourceData )
{
	HELIUM_ASSERT( pAsset );
	
	HELIUM_TRACE(
		TraceLevels::Info,
		TXT( "LooseAssetLoader::CacheObject(): Caching asset %s.\n" ), *pAsset->GetPath().ToString() );

	// Don't cache broken objects or packages.
	if( pAsset->GetAnyFlagSet( Asset::FLAG_BROKEN ) || pAsset->IsPackage() )
	{
		return false;
	}

	// Make sure we have an object preprocessor instance with which to cache the object.
	AssetPreprocessor* pAssetPreprocessor = AssetPreprocessor::GetStaticInstance();
	if( !pAssetPreprocessor )
	{
		HELIUM_TRACE(
			TraceLevels::Warning,
			TXT( "LooseAssetLoader::CacheObject(): Missing AssetPreprocessor to use for caching.\n" ) );

		return false;
	}

	// User configuration objects should not be cached.
	AssetPath objectPath = pAsset->GetPath();

	Config& rConfig = Config::GetStaticInstance();

	// Only cache the files we care about
	if ( rConfig.IsAssetPathInUserConfigPackage(objectPath) )
	{
		return false;
	}

	int64_t objectTimestamp = pAsset->GetAssetFileTimeStamp();

	if( !pAsset->IsDefaultTemplate() )
	{
		Resource* pResource = Reflect::SafeCast< Resource >( pAsset );
		if( pResource )
		{
			AssetPath baseResourcePath = pResource->GetPath();
			HELIUM_ASSERT( !baseResourcePath.IsPackage() );
			for( ; ; )
			{
				AssetPath parentPath = baseResourcePath.GetParent();
				if( parentPath.IsEmpty() || parentPath.IsPackage() )
				{
					break;
				}

				baseResourcePath = parentPath;
			}

			FilePath sourceFilePath;
			if ( !FileLocations::GetDataDirectory( sourceFilePath ) )
			{
				HELIUM_TRACE(
					TraceLevels::Warning,
					TXT( "LooseAssetLoader::CacheObject(): Could not obtain data directory.\n" ) );

				return false;
			}

			sourceFilePath += baseResourcePath.ToFilePathString().GetData();

			Status stat;
			stat.Read( sourceFilePath.Get().c_str() );

			int64_t sourceFileTimestamp = stat.m_ModifiedTime;
			if( sourceFileTimestamp > objectTimestamp )
			{
				objectTimestamp = sourceFileTimestamp;
			}
		}
	}

	// Cache the object.
	bool bSuccess = pAssetPreprocessor->CacheObject(
		pAsset,
		objectTimestamp,
		bEvictPlatformPreprocessedResourceData );
	if( !bSuccess )
	{
		HELIUM_TRACE(
			TraceLevels::Error,
			TXT( "LooseAssetLoader: Failed to cache object \"%s\".\n" ),
			*objectPath.ToString() );
	}

	return bSuccess;
}
Esempio n. 7
0
/// Set this path to the combination of two paths.
///
/// @param[in] pRootPath  Root portion of the path.
/// @param[in] subPath    Sub-path component.
///
/// @return  True if the paths could be joined into a valid path (to which this path was set), false if joining was
///          invalid.
bool AssetPath::Join( const char* pRootPath, AssetPath subPath )
{
	if( !pRootPath || pRootPath[ 0 ] == TXT( '\0' ) )
	{
		m_pEntry = subPath.m_pEntry;

		return true;
	}

	// Parse the root path into a series of names.
	StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap();
	StackMemoryHeap<>::Marker stackMarker( rStackHeap );

	Name* pRootPathNames;
	uint32_t* pRootPathIndices;
	size_t rootPathNameCount;
	size_t rootPathPackageCount;
	if( !Parse( pRootPath, rStackHeap, pRootPathNames, pRootPathIndices, rootPathNameCount, rootPathPackageCount ) )
	{
		return false;
	}

	if( rootPathNameCount != rootPathPackageCount )
	{
		AssetPath testSubPathComponent = subPath.GetParent();
		AssetPath subPathComponent;
		do
		{
			subPathComponent = testSubPathComponent;
			testSubPathComponent = testSubPathComponent.GetParent();

			if( subPathComponent.IsPackage() )
			{
				HELIUM_TRACE(
					TraceLevels::Error,
					( TXT( "AssetPath::Join(): Cannot combine \"%s\" and \"%s\" (second path is rooted in a " )
					TXT( "package, while the first path ends in an object).\n" ) ),
					pRootPath,
					*subPath.ToString() );

				return false;
			}
		} while( !testSubPathComponent.IsEmpty() );
	}

	// Assemble the list of path names in reverse order for performing the object path lookup/add.
	size_t nameCount = rootPathNameCount;
	size_t packageCount = rootPathPackageCount;

	AssetPath testPath;

	for( testPath = subPath; !testPath.IsEmpty(); testPath = testPath.GetParent() )
	{
		++nameCount;
		if( testPath.IsPackage() )
		{
			++packageCount;
		}
	}

	Name* pEntryNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * nameCount ) );
	HELIUM_ASSERT( pEntryNames );

	uint32_t* pInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * nameCount ) );
	HELIUM_ASSERT( pInstanceIndices );

	Name* pCurrentName = pEntryNames;
	uint32_t* pCurrentIndex = pInstanceIndices;

	for( testPath = subPath; !testPath.IsEmpty(); testPath = testPath.GetParent() )
	{
		*pCurrentName = testPath.GetName();
		*pCurrentIndex = testPath.GetInstanceIndex();
		++pCurrentName;
		++pCurrentIndex;
	}

	ArrayCopy( pCurrentName, pRootPathNames, rootPathNameCount );
	ArrayCopy( pCurrentIndex, pRootPathIndices, rootPathNameCount );

	// Set the path.
	Set( pEntryNames, pInstanceIndices, nameCount, packageCount );

	return true;
}