Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
6.5 KiB

  1. //===== Copyright c 1996-2008, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Implementation of various variants of resource stream
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #if defined( _WIN32 )
  8. #include <windows.h>
  9. #else
  10. #include <sys/mman.h>
  11. #endif
  12. #include "resourcefile/resourcestream.h"
  13. #include "dbg.h"
  14. #include "memalloc.h"
  15. CResourceStream::CResourceStream( )
  16. {
  17. m_pData = NULL;
  18. m_nCommitted = 0;
  19. m_nUsed = 0;
  20. m_nAlignBits = 3;
  21. m_nMaxAlignment = 4;
  22. }
  23. CResourceStreamVM::CResourceStreamVM( uint nReserveSize )
  24. {
  25. m_pData = NULL;
  26. m_nReserved = 0;
  27. ReserveVirtualMemory( nReserveSize );
  28. m_nAlignBits = 3; // alignment 4 is default
  29. m_nMaxAlignment = 4;
  30. m_nUsed = 0;
  31. m_nCommitted = 0;
  32. }
  33. CResourceStreamVM::~CResourceStreamVM( )
  34. {
  35. ReleaseVirtualMemory( );
  36. }
  37. CResourceStreamFixed::CResourceStreamFixed( void *pPreallocatedData, uint nPreallocatedDataSize ):
  38. m_bOwnMemory( false )
  39. {
  40. m_pData = ( uint8* )pPreallocatedData;
  41. m_nCommitted = nPreallocatedDataSize;
  42. // 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
  43. Assert( pPreallocatedData == m_pData );
  44. V_memset( pPreallocatedData, 0, nPreallocatedDataSize );
  45. }
  46. CResourceStreamFixed::CResourceStreamFixed( uint nPreallocatedDataSize ):
  47. m_bOwnMemory( true )
  48. {
  49. m_pData = new uint8[ nPreallocatedDataSize ];
  50. m_nCommitted = nPreallocatedDataSize;
  51. // 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
  52. V_memset( m_pData, 0, nPreallocatedDataSize );
  53. }
  54. CResourceStreamFixed::~CResourceStreamFixed()
  55. {
  56. // prevent the parent class from trying to deallocate the buffer that doesn't belong to it
  57. m_pData = NULL;
  58. m_nCommitted = 0;
  59. }
  60. void CResourceStreamFixed::Commit( uint nNewCommit )
  61. {
  62. if ( nNewCommit > m_nCommitted )
  63. {
  64. Plat_FatalError( "CResourceStreamFixed: trying to write past the end of allocated memory (new commit %u, allocated %u)\n", nNewCommit, m_nCommitted );
  65. }
  66. }
  67. CResourceStreamGrowable::CResourceStreamGrowable( uint nReserveDataSize )
  68. {
  69. m_pData = nReserveDataSize ? new uint8[ nReserveDataSize ] : NULL;
  70. m_nCommitted = nReserveDataSize;
  71. }
  72. CResourceStreamGrowable::~CResourceStreamGrowable( )
  73. {
  74. delete[] m_pData;
  75. }
  76. void CResourceStreamGrowable::Commit( uint nNewCommit )
  77. {
  78. if ( nNewCommit > m_nCommitted )
  79. {
  80. uint nPaddedCommit = ( nNewCommit * 2 + 63 ) & ~63;
  81. uint8 *pNewData = new uint8[ nPaddedCommit ];
  82. V_memcpy( pNewData, m_pData, m_nUsed );
  83. AssertDbg( !( ( ( uintp ) pNewData ) & 0xF ) );
  84. delete[]m_pData;
  85. m_pData = pNewData;
  86. m_nCommitted = nPaddedCommit;
  87. }
  88. }
  89. void CResourceStreamVM::ReserveVirtualMemory( uint nAddressSize )
  90. {
  91. Assert ( m_pData == NULL );
  92. nAddressSize = ( nAddressSize + COMMIT_STEP - 1 ) & ~( COMMIT_STEP - 1 );
  93. m_nReserved = MAX( nAddressSize, COMMIT_STEP );
  94. for ( ;; )
  95. {
  96. #if defined( PLATFORM_WINDOWS )
  97. m_pData = ( uint8* )VirtualAlloc( NULL, m_nReserved, MEM_RESERVE, PAGE_READWRITE );
  98. #else
  99. #ifdef PLATFORM_OSX
  100. int nFlags = MAP_ANON | MAP_PRIVATE;
  101. #else
  102. int nFlags = MAP_ANONYMOUS | MAP_PRIVATE;
  103. #endif
  104. m_pData = ( uint8* )::mmap( NULL, m_nReserved, PROT_WRITE | PROT_READ, nFlags, -1, 0 );
  105. #endif
  106. if ( !m_pData )
  107. {
  108. m_nReserved /= 2;
  109. if ( m_nReserved < COMMIT_STEP )
  110. {
  111. Plat_FatalError( "Cannot allocate virtual address space in CResourceStreamVM::ReserveVirtualMemory, error %u\n", errno );
  112. }
  113. }
  114. else
  115. {
  116. return;
  117. }
  118. }
  119. }
  120. void CResourceStreamVM::ReleaseVirtualMemory()
  121. {
  122. if ( m_pData != NULL )
  123. {
  124. #if defined( PLATFORM_WINDOWS )
  125. VirtualFree( m_pData, m_nReserved, MEM_RELEASE );
  126. #else
  127. munmap( m_pData, m_nReserved );
  128. #endif
  129. }
  130. m_pData = NULL;
  131. m_nReserved = 0;
  132. m_nUsed = 0;
  133. m_nCommitted = 0;
  134. }
  135. void CResourceStreamVM::CloneStream( CResourceStreamVM& copyFromStream )
  136. {
  137. // see if we need to reinitialize
  138. if ( m_nReserved != copyFromStream.m_nReserved )
  139. {
  140. ReleaseVirtualMemory();
  141. ReserveVirtualMemory( copyFromStream.m_nReserved );
  142. }
  143. else
  144. {
  145. if ( m_nUsed > 0)
  146. {
  147. memset( m_pData, 0, m_nUsed );
  148. }
  149. m_nUsed = 0;
  150. }
  151. Assert ( m_nReserved >= copyFromStream.m_nUsed );
  152. memcpy ( AllocateBytes( copyFromStream.m_nUsed ), copyFromStream.m_pData, copyFromStream.m_nUsed );
  153. m_nAlignBits = copyFromStream.m_nAlignBits;
  154. m_nMaxAlignment = copyFromStream.m_nMaxAlignment;
  155. }
  156. void* CResourceStream::AllocateBytes( uint numBytes )
  157. {
  158. EnsureAvailable( numBytes );
  159. void *pBlock = m_pData + m_nUsed;
  160. m_nUsed += numBytes;
  161. return pBlock;
  162. }
  163. void CResourceStreamVM::Commit( uint nNewCommit )
  164. {
  165. if ( nNewCommit > m_nReserved )
  166. {
  167. Warning( "--------------------WARNING----------------------\n" );
  168. Warning( "--------------------WARNING----------------------\n" );
  169. Warning( "--------------------WARNING----------------------\n" );
  170. Warning( "-- Increase the size of the resource stream --\n" );
  171. Warning( "-- Need %d bytes, but only have %d bytes\n", nNewCommit, m_nReserved );
  172. Warning( "--------------------WARNING----------------------\n" );
  173. Warning( "--------------------WARNING----------------------\n" );
  174. Warning( "--------------------WARNING----------------------\n" );
  175. Plat_FatalError( "Failed trying to Commit %u bytes, used %u bytes, reserved %u bytes\n", nNewCommit, m_nUsed, m_nReserved );
  176. }
  177. else if ( nNewCommit > m_nCommitted )
  178. {
  179. nNewCommit = ( nNewCommit + COMMIT_STEP - 1 ) & ~( COMMIT_STEP - 1 );
  180. // expensive call. Not to be called frequently
  181. #if defined( PLATFORM_WINDOWS )
  182. VirtualAlloc( m_pData + m_nCommitted, nNewCommit - m_nCommitted, MEM_COMMIT, PAGE_READWRITE );
  183. #else
  184. mprotect( m_pData + m_nCommitted, nNewCommit - m_nCommitted, PROT_READ|PROT_WRITE );
  185. #endif
  186. m_nCommitted = nNewCommit;
  187. }
  188. }
  189. void CResourceStream::Align( uint nAlignment, int nOffset )
  190. {
  191. m_nMaxAlignment = MAX( m_nMaxAlignment, nAlignment );
  192. if ( uintp( m_pData ) & ( nAlignment - 1 ) )
  193. {
  194. Plat_FatalError( "You can't align data in resource stream more than its memory buffer. Please allocate the memory aligned." );
  195. }
  196. else if ( nAlignment & ( nAlignment - 1 ) )
  197. {
  198. Plat_FatalError( "Wrong alignment %d\n", nAlignment );
  199. }
  200. else
  201. {
  202. int padSize = ( nOffset - m_nUsed ) & ( nAlignment - 1 );
  203. if ( padSize > 0 )
  204. {
  205. // Extend the buffer to align and fill the hole with a constant value
  206. void *pBuffer = AllocateBytes( padSize );
  207. V_memset( pBuffer, 0, padSize );
  208. }
  209. }
  210. }
  211. void CResourceStream::PrintStats()
  212. {
  213. Msg( "ResourceFile: %d/%d @%p align %u\n", m_nUsed, m_nCommitted, m_pData, m_nAlignBits );
  214. }
  215. void CResourceStream::ClearStats()
  216. {
  217. }