266 lines
6.5 KiB
C++
266 lines
6.5 KiB
C++
//===== Copyright c 1996-2008, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose: Implementation of various variants of resource stream
|
|
//
|
|
// $NoKeywords: $
|
|
//===========================================================================//
|
|
|
|
#if defined( _WIN32 )
|
|
#include <windows.h>
|
|
#else
|
|
#include <sys/mman.h>
|
|
#endif
|
|
#include "resourcefile/resourcestream.h"
|
|
#include "dbg.h"
|
|
#include "memalloc.h"
|
|
|
|
|
|
CResourceStream::CResourceStream( )
|
|
{
|
|
m_pData = NULL;
|
|
m_nCommitted = 0;
|
|
m_nUsed = 0;
|
|
m_nAlignBits = 3;
|
|
m_nMaxAlignment = 4;
|
|
}
|
|
|
|
|
|
CResourceStreamVM::CResourceStreamVM( uint nReserveSize )
|
|
{
|
|
m_pData = NULL;
|
|
m_nReserved = 0;
|
|
ReserveVirtualMemory( nReserveSize );
|
|
m_nAlignBits = 3; // alignment 4 is default
|
|
m_nMaxAlignment = 4;
|
|
m_nUsed = 0;
|
|
m_nCommitted = 0;
|
|
}
|
|
|
|
CResourceStreamVM::~CResourceStreamVM( )
|
|
{
|
|
ReleaseVirtualMemory( );
|
|
}
|
|
|
|
|
|
|
|
CResourceStreamFixed::CResourceStreamFixed( void *pPreallocatedData, uint nPreallocatedDataSize ):
|
|
m_bOwnMemory( false )
|
|
{
|
|
m_pData = ( uint8* )pPreallocatedData;
|
|
m_nCommitted = nPreallocatedDataSize;
|
|
// pre-initialized stream; the memory passed to this function may not be initialized to zero, and resource stream assumes it to be, so clear it
|
|
Assert( pPreallocatedData == m_pData );
|
|
V_memset( pPreallocatedData, 0, nPreallocatedDataSize );
|
|
}
|
|
|
|
|
|
CResourceStreamFixed::CResourceStreamFixed( uint nPreallocatedDataSize ):
|
|
m_bOwnMemory( true )
|
|
{
|
|
m_pData = new uint8[ nPreallocatedDataSize ];
|
|
m_nCommitted = nPreallocatedDataSize;
|
|
// pre-initialized stream; the memory passed to this function may not be initialized to zero, and resource stream assumes it to be, so clear it
|
|
V_memset( m_pData, 0, nPreallocatedDataSize );
|
|
}
|
|
|
|
CResourceStreamFixed::~CResourceStreamFixed()
|
|
{
|
|
// prevent the parent class from trying to deallocate the buffer that doesn't belong to it
|
|
m_pData = NULL;
|
|
m_nCommitted = 0;
|
|
}
|
|
|
|
void CResourceStreamFixed::Commit( uint nNewCommit )
|
|
{
|
|
if ( nNewCommit > m_nCommitted )
|
|
{
|
|
Plat_FatalError( "CResourceStreamFixed: trying to write past the end of allocated memory (new commit %u, allocated %u)\n", nNewCommit, m_nCommitted );
|
|
}
|
|
}
|
|
|
|
|
|
CResourceStreamGrowable::CResourceStreamGrowable( uint nReserveDataSize )
|
|
{
|
|
m_pData = nReserveDataSize ? new uint8[ nReserveDataSize ] : NULL;
|
|
m_nCommitted = nReserveDataSize;
|
|
}
|
|
|
|
|
|
CResourceStreamGrowable::~CResourceStreamGrowable( )
|
|
{
|
|
delete[] m_pData;
|
|
}
|
|
|
|
|
|
void CResourceStreamGrowable::Commit( uint nNewCommit )
|
|
{
|
|
if ( nNewCommit > m_nCommitted )
|
|
{
|
|
uint nPaddedCommit = ( nNewCommit * 2 + 63 ) & ~63;
|
|
uint8 *pNewData = new uint8[ nPaddedCommit ];
|
|
V_memcpy( pNewData, m_pData, m_nUsed );
|
|
AssertDbg( !( ( ( uintp ) pNewData ) & 0xF ) );
|
|
delete[]m_pData;
|
|
m_pData = pNewData;
|
|
m_nCommitted = nPaddedCommit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CResourceStreamVM::ReserveVirtualMemory( uint nAddressSize )
|
|
{
|
|
Assert ( m_pData == NULL );
|
|
|
|
nAddressSize = ( nAddressSize + COMMIT_STEP - 1 ) & ~( COMMIT_STEP - 1 );
|
|
m_nReserved = MAX( nAddressSize, COMMIT_STEP );
|
|
for ( ;; )
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
m_pData = ( uint8* )VirtualAlloc( NULL, m_nReserved, MEM_RESERVE, PAGE_READWRITE );
|
|
#else
|
|
#ifdef PLATFORM_OSX
|
|
int nFlags = MAP_ANON | MAP_PRIVATE;
|
|
#else
|
|
int nFlags = MAP_ANONYMOUS | MAP_PRIVATE;
|
|
#endif
|
|
m_pData = ( uint8* )::mmap( NULL, m_nReserved, PROT_WRITE | PROT_READ, nFlags, -1, 0 );
|
|
#endif
|
|
if ( !m_pData )
|
|
{
|
|
m_nReserved /= 2;
|
|
if ( m_nReserved < COMMIT_STEP )
|
|
{
|
|
Plat_FatalError( "Cannot allocate virtual address space in CResourceStreamVM::ReserveVirtualMemory, error %u\n", errno );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CResourceStreamVM::ReleaseVirtualMemory()
|
|
{
|
|
if ( m_pData != NULL )
|
|
{
|
|
#if defined( PLATFORM_WINDOWS )
|
|
VirtualFree( m_pData, m_nReserved, MEM_RELEASE );
|
|
#else
|
|
munmap( m_pData, m_nReserved );
|
|
#endif
|
|
}
|
|
|
|
m_pData = NULL;
|
|
m_nReserved = 0;
|
|
m_nUsed = 0;
|
|
m_nCommitted = 0;
|
|
}
|
|
|
|
|
|
void CResourceStreamVM::CloneStream( CResourceStreamVM& copyFromStream )
|
|
{
|
|
// see if we need to reinitialize
|
|
if ( m_nReserved != copyFromStream.m_nReserved )
|
|
{
|
|
ReleaseVirtualMemory();
|
|
ReserveVirtualMemory( copyFromStream.m_nReserved );
|
|
}
|
|
else
|
|
{
|
|
if ( m_nUsed > 0)
|
|
{
|
|
memset( m_pData, 0, m_nUsed );
|
|
}
|
|
m_nUsed = 0;
|
|
}
|
|
|
|
Assert ( m_nReserved >= copyFromStream.m_nUsed );
|
|
|
|
memcpy ( AllocateBytes( copyFromStream.m_nUsed ), copyFromStream.m_pData, copyFromStream.m_nUsed );
|
|
|
|
m_nAlignBits = copyFromStream.m_nAlignBits;
|
|
m_nMaxAlignment = copyFromStream.m_nMaxAlignment;
|
|
|
|
}
|
|
|
|
|
|
void* CResourceStream::AllocateBytes( uint numBytes )
|
|
{
|
|
EnsureAvailable( numBytes );
|
|
void *pBlock = m_pData + m_nUsed;
|
|
m_nUsed += numBytes;
|
|
return pBlock;
|
|
}
|
|
|
|
|
|
void CResourceStreamVM::Commit( uint nNewCommit )
|
|
{
|
|
if ( nNewCommit > m_nReserved )
|
|
{
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
Warning( "-- Increase the size of the resource stream --\n" );
|
|
Warning( "-- Need %d bytes, but only have %d bytes\n", nNewCommit, m_nReserved );
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
Warning( "--------------------WARNING----------------------\n" );
|
|
|
|
Plat_FatalError( "Failed trying to Commit %u bytes, used %u bytes, reserved %u bytes\n", nNewCommit, m_nUsed, m_nReserved );
|
|
}
|
|
else if ( nNewCommit > m_nCommitted )
|
|
{
|
|
nNewCommit = ( nNewCommit + COMMIT_STEP - 1 ) & ~( COMMIT_STEP - 1 );
|
|
// expensive call. Not to be called frequently
|
|
#if defined( PLATFORM_WINDOWS )
|
|
VirtualAlloc( m_pData + m_nCommitted, nNewCommit - m_nCommitted, MEM_COMMIT, PAGE_READWRITE );
|
|
#else
|
|
mprotect( m_pData + m_nCommitted, nNewCommit - m_nCommitted, PROT_READ|PROT_WRITE );
|
|
#endif
|
|
m_nCommitted = nNewCommit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CResourceStream::Align( uint nAlignment, int nOffset )
|
|
{
|
|
m_nMaxAlignment = MAX( m_nMaxAlignment, nAlignment );
|
|
if ( uintp( m_pData ) & ( nAlignment - 1 ) )
|
|
{
|
|
Plat_FatalError( "You can't align data in resource stream more than its memory buffer. Please allocate the memory aligned." );
|
|
}
|
|
else if ( nAlignment & ( nAlignment - 1 ) )
|
|
{
|
|
Plat_FatalError( "Wrong alignment %d\n", nAlignment );
|
|
}
|
|
else
|
|
{
|
|
int padSize = ( nOffset - m_nUsed ) & ( nAlignment - 1 );
|
|
if ( padSize > 0 )
|
|
{
|
|
// Extend the buffer to align and fill the hole with a constant value
|
|
void *pBuffer = AllocateBytes( padSize );
|
|
V_memset( pBuffer, 0, padSize );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CResourceStream::PrintStats()
|
|
{
|
|
Msg( "ResourceFile: %d/%d @%p align %u\n", m_nUsed, m_nCommitted, m_pData, m_nAlignBits );
|
|
}
|
|
|
|
void CResourceStream::ClearStats()
|
|
{
|
|
}
|
|
|