/// @copydoc Serializer::SerializeWideString() void BinarySerializer::SerializeWideString( WideString& rValue ) { if( ShouldSerializeCurrentProperty() ) { HELIUM_ASSERT( rValue.GetSize() <= UINT32_MAX ); uint32_t stringLength = static_cast< uint32_t >( rValue.GetSize() ); m_pPropertyStream->Write( &stringLength, sizeof( stringLength ), 1 ); m_pPropertyStream->Write( rValue.GetData(), sizeof( wchar_t ), stringLength ); } }
/// Copy constructor. /// /// When copying, only the memory needed to hold onto the used contents of the source string will be allocated (i.e. /// if the source string has 10 elements but a capacity of 20, only memory for the 10 used elements will be /// allocated for this copy). /// /// @param[in] rSource String from which to copy. WideString::WideString( const WideString& rSource ) : StringBase( rSource.GetData(), rSource.GetSize() ) { }
/// Add or update an entry in the cache. /// /// @param[in] path GameObject path. /// @param[in] subDataIndex Sub-data index associated with the cached data. /// @param[in] pData Data to cache. /// @param[in] timestamp Timestamp value to associate with the entry in the cache. /// @param[in] size Number of bytes to cache. /// /// @return True if the cache was updated successfully, false if not. bool Cache::CacheEntry( GameObjectPath path, uint32_t subDataIndex, const void* pData, int64_t timestamp, uint32_t size ) { HELIUM_ASSERT( pData || size == 0 ); Path cacheFile( m_cacheFileName.GetData() ); int64_t cacheFileSize = cacheFile.Size(); uint64_t entryOffset = ( cacheFileSize == -1 ? 0 : static_cast< uint64_t >( cacheFileSize ) ); HELIUM_ASSERT( m_pEntryPool ); Entry* pEntryUpdate = m_pEntryPool->Allocate(); HELIUM_ASSERT( pEntryUpdate ); pEntryUpdate->offset = entryOffset; pEntryUpdate->timestamp = timestamp; pEntryUpdate->path = path; pEntryUpdate->subDataIndex = subDataIndex; pEntryUpdate->size = size; uint64_t originalOffset = 0; int64_t originalTimestamp = 0; uint32_t originalSize = 0; EntryKey key; key.path = path; key.subDataIndex = subDataIndex; EntryMapType::Accessor entryAccessor; bool bNewEntry = m_entryMap.Insert( entryAccessor, KeyValue< EntryKey, Entry* >( key, pEntryUpdate ) ); if( bNewEntry ) { HELIUM_TRACE( TRACE_INFO, TXT( "Cache: Adding \"%s\" to cache \"%s\".\n" ), *path.ToString(), *m_cacheFileName ); m_entries.Push( pEntryUpdate ); } else { HELIUM_TRACE( TRACE_INFO, TXT( "Cache: Updating \"%s\" in cache \"%s\".\n" ), *path.ToString(), *m_cacheFileName ); m_pEntryPool->Release( pEntryUpdate ); pEntryUpdate = entryAccessor->Second(); HELIUM_ASSERT( pEntryUpdate ); originalOffset = pEntryUpdate->offset; originalTimestamp = pEntryUpdate->timestamp; originalSize = pEntryUpdate->size; if( originalSize < size ) { pEntryUpdate->offset = entryOffset; } else { entryOffset = originalOffset; } pEntryUpdate->timestamp = timestamp; pEntryUpdate->size = size; } AsyncLoader& rLoader = AsyncLoader::GetStaticInstance(); rLoader.Lock(); bool bCacheSuccess = true; FileStream* pCacheStream = File::Open( m_cacheFileName, FileStream::MODE_WRITE, false ); if( !pCacheStream ) { HELIUM_TRACE( TRACE_ERROR, TXT( "Cache: Failed to open cache \"%s\" for writing.\n" ), *m_cacheFileName ); bCacheSuccess = false; } else { HELIUM_TRACE( TRACE_INFO, TXT( "Cache: Caching \"%s\" to \"%s\" (%" ) TPRIu32 TXT( " bytes @ offset %" ) TPRIu64 TXT( ").\n" ), *path.ToString(), *m_cacheFileName, size, entryOffset ); uint64_t seekOffset = static_cast< uint64_t >( pCacheStream->Seek( static_cast< int64_t >( entryOffset ), SeekOrigins::SEEK_ORIGIN_BEGIN ) ); if( seekOffset != entryOffset ) { HELIUM_TRACE( TRACE_ERROR, TXT( "Cache: Cache file offset seek failed.\n" ) ); if( bNewEntry ) { m_entries.Pop(); m_entryMap.Remove( entryAccessor ); m_pEntryPool->Release( pEntryUpdate ); } else { pEntryUpdate->offset = originalOffset; pEntryUpdate->timestamp = originalTimestamp; pEntryUpdate->size = originalSize; } bCacheSuccess = false; } else { size_t writeSize = pCacheStream->Write( pData, 1, size ); if( writeSize != size ) { HELIUM_TRACE( TRACE_ERROR, ( TXT( "Cache: Failed to write %" ) TPRIu32 TXT( " bytes to cache \"%s\" (%" ) TPRIuSZ TXT( " bytes written).\n" ) ), size, *m_cacheFileName, writeSize ); if( bNewEntry ) { m_entries.Pop(); m_entryMap.Remove( entryAccessor ); m_pEntryPool->Release( pEntryUpdate ); } else { pEntryUpdate->offset = originalOffset; pEntryUpdate->timestamp = originalTimestamp; pEntryUpdate->size = originalSize; } bCacheSuccess = false; } else { HELIUM_TRACE( TRACE_INFO, TXT( "Cache: Rewriting TOC file \"%s\".\n" ), *m_tocFileName ); FileStream* pTocStream = File::Open( m_tocFileName, FileStream::MODE_WRITE, true ); if( !pTocStream ) { HELIUM_TRACE( TRACE_ERROR, TXT( "Cache: Failed to open TOC \"%s\" for writing.\n" ), *m_tocFileName ); } else { BufferedStream* pBufferedStream = new BufferedStream( pTocStream ); HELIUM_ASSERT( pBufferedStream ); pBufferedStream->Write( &TOC_MAGIC, sizeof( TOC_MAGIC ), 1 ); pBufferedStream->Write( &sm_Version, sizeof( sm_Version ), 1 ); uint32_t entryCount = static_cast< uint32_t >( m_entries.GetSize() ); pBufferedStream->Write( &entryCount, sizeof( entryCount ), 1 ); WideString entryPath; #if !HELIUM_UNICODE CharString entryPathCharString; #endif uint_fast32_t entryCountFast = entryCount; for( uint_fast32_t entryIndex = 0; entryIndex < entryCountFast; ++entryIndex ) { Entry* pEntry = m_entries[ entryIndex ]; HELIUM_ASSERT( pEntry ); #if HELIUM_UNICODE pEntry->path.ToString( entryPath ); #else pEntry->path.ToString( entryPathCharString ); StringConverter< char, wchar_t >::Convert( entryPath, entryPathCharString ); #endif HELIUM_ASSERT( entryPath.GetSize() < UINT16_MAX ); uint16_t pathSize = static_cast< uint16_t >( entryPath.GetSize() ); pBufferedStream->Write( &pathSize, sizeof( pathSize ), 1 ); pBufferedStream->Write( *entryPath, sizeof( tchar_t ), pathSize ); pBufferedStream->Write( &pEntry->subDataIndex, sizeof( pEntry->subDataIndex ), 1 ); pBufferedStream->Write( &pEntry->offset, sizeof( pEntry->offset ), 1 ); pBufferedStream->Write( &pEntry->timestamp, sizeof( pEntry->timestamp ), 1 ); pBufferedStream->Write( &pEntry->size, sizeof( pEntry->size ), 1 ); } delete pBufferedStream; delete pTocStream; } } } delete pCacheStream; } rLoader.Unlock(); return bCacheSuccess; }