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.

469 lines
12 KiB

  1. //========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "datalinker.h"
  8. #include "dbg.h"
  9. #include "memalloc.h"
  10. namespace DataLinker
  11. {
  12. const char g_cFillChar = '\xDE';
  13. Stream::Stream()
  14. {
  15. m_data.reserve( 16 );
  16. m_lastTarget = 1; // target 0 and 1 are special targets
  17. m_alignBits = 3; // alignment 4 is default
  18. m_size = 0;
  19. m_stackBlocks.reserve( 4 ); // we'll probably never nest deeper than this
  20. }
  21. Chunk::Chunk( uint reserve, uint offset )
  22. {
  23. m_offset = offset;
  24. m_capacity = reserve;
  25. m_size = 0;
  26. m_recentSize = 0;
  27. m_data = ( byte* )MemAlloc_AllocAligned( reserve, 16 );
  28. memset( m_data, g_cFillChar, reserve );
  29. }
  30. void Chunk::Free()
  31. {
  32. MemAlloc_FreeAligned( m_data );
  33. }
  34. Stream::~Stream()
  35. {
  36. for ( std::vector<Chunk>::iterator it = m_data.begin(); it != m_data.end(); ++it )
  37. it->Free();
  38. }
  39. void* Stream::WriteBytes( uint numBytes )
  40. {
  41. EnsureAvailable( numBytes );
  42. Chunk &chunk = m_data.back();
  43. byte *p = chunk.m_data + chunk.m_size;
  44. memset( p, 0, numBytes );
  45. chunk.m_recentSize = m_size;
  46. chunk.m_size += numBytes;
  47. m_size += numBytes;
  48. return p;
  49. }
  50. void Stream::EnsureAvailable( uint addCapacity )
  51. {
  52. Assert( addCapacity < 0x10000000 ); // we don't support >1Gb of data yet
  53. if ( m_data.empty() )
  54. {
  55. // first allocation
  56. m_data.push_back( Chunk( MAX( addCapacity*4u, 4096u ), 0 ) );
  57. }
  58. else if ( m_data.back().GetAvailable() < addCapacity )
  59. {
  60. m_data.push_back( Chunk( MAX( addCapacity*4u, m_data.back().m_capacity*2u ), m_size ) );
  61. }
  62. }
  63. int Stream::GetOffsetTo( const void *ptr )const
  64. {
  65. for ( std::vector<Chunk>::const_reverse_iterator it = m_data.rbegin(); it != m_data.rend(); ++it )
  66. {
  67. uint offsetOfPtr = ( uint )( ( ( const byte* )ptr ) - it->m_data );
  68. if ( offsetOfPtr <= it->m_size )
  69. return offsetOfPtr + it->m_offset;
  70. }
  71. return -1; // invalid offset
  72. }
  73. bool Stream::Compile( void *pBuffer )
  74. {
  75. {
  76. byte *p = ( byte* )pBuffer;
  77. uint offset = 0;
  78. for ( std::vector<Chunk>::const_iterator it = m_data.begin(); it != m_data.end(); ++it )
  79. {
  80. Assert( it->m_offset == offset );
  81. memcpy( p + offset, it->m_data, it->m_size );
  82. offset += it->m_size;
  83. }
  84. Assert( m_size == offset );
  85. }
  86. byte *data = ( byte* )pBuffer;
  87. // for all link sources, try to resolve them
  88. uint numUnresolved = 0;
  89. for ( LinkSourceMap::const_iterator it = m_mapSources.begin(); it != m_mapSources.end(); ++it )
  90. {
  91. const LinkSourceDesc_t &source = it->second;
  92. int offsetOfSource = it->first;
  93. Assert( uint( offsetOfSource ) < m_size ); // check alignment?
  94. int* pOffset = ( int* )( data + offsetOfSource );
  95. if ( source.m_targetId == kSpecialTargetNull )
  96. {
  97. *pOffset = 0; // special case of target fixed to NULL
  98. }
  99. else if ( source.m_targetId < 0 || source.m_targetId > m_lastTarget )
  100. {
  101. Msg( "Unresolved link source @0x%X '%s'\n", offsetOfSource, source.m_pDescription );
  102. numUnresolved ++;
  103. }
  104. else
  105. {
  106. // try to find the target
  107. // if special target (id == 0): target is not in the target map; all the information is resolved directly through the LinkSourceDesc_t
  108. const LinkTargetDesc_t &target = source.m_targetId == kSpecialTargetDefault ? source.m_defaultTarget : m_mapTargets[source.m_targetId];
  109. switch ( target.m_type )
  110. {
  111. case kTargetNull:
  112. *pOffset = 0; // special case of target set to NULL later
  113. break;
  114. case kTargetResolved:
  115. switch ( source.m_type )
  116. {
  117. case kOtRelative32bit:
  118. *pOffset = target.m_resolvedOffset - offsetOfSource;
  119. break;
  120. case kOtRelative16bit:
  121. {
  122. int offset = target.m_resolvedOffset - offsetOfSource;
  123. if ( offset > 0x7FFF || offset < -0x8000 )
  124. {
  125. Msg( "Link source @%d '%s' is out of range (%d doesn't fit to 16 bits)\n", offsetOfSource, source.m_pDescription, offset );
  126. numUnresolved++;
  127. }
  128. else
  129. {
  130. *( short* )pOffset = ( short )offset;
  131. }
  132. }
  133. break;
  134. case kOtAbsolute32bit:
  135. *pOffset = target.m_resolvedOffset;
  136. break;
  137. }
  138. break;
  139. default:
  140. Msg( "Unresolved link source @%d '%s'\n", offsetOfSource, source.m_pDescription );
  141. numUnresolved++;
  142. break;
  143. }
  144. }
  145. }
  146. if ( numUnresolved )
  147. {
  148. Error( "%u unresolved links found\n", numUnresolved );
  149. return false;
  150. }
  151. else
  152. return true;
  153. }
  154. void Stream::Align( uint nAlignment, int nOffset )
  155. {
  156. if ( nAlignment & ( nAlignment - 1 ) )
  157. {
  158. Error( "Wrong alignment %d\n", nAlignment );
  159. }
  160. //WriteBytes(((m_size+nAlignment-1) & ~(nAlignment-1)) - m_size);
  161. WriteBytes( ( nOffset - m_size ) & ( nAlignment - 1 ) );
  162. }
  163. void Stream::Link( LinkSource_t linkSource, LinkTarget_t linkTarget, const char *szDescription )
  164. {
  165. LinkSourceMap::iterator itFind = m_mapSources.find( linkSource.m_offset );
  166. if ( itFind == m_mapSources.end() )
  167. {
  168. Error( "cannot find source @%d - %s\n", linkSource.m_offset, szDescription );
  169. }
  170. itFind->second.m_targetId = linkTarget.m_id;
  171. itFind->second.m_defaultTarget.m_type = kTargetUnresolved; // un-set default target for validation; we are not referring to it any more
  172. Assert( linkTarget.m_id != kSpecialTargetDefault );
  173. }
  174. LinkSource_t Stream::LinkToHere( int *pOffset, const char *szDescription )
  175. {
  176. return Link( pOffset, NewTargetHere(), szDescription );
  177. }
  178. LinkSource_t Stream::Link( int32 *pOffset, LinkTarget_t linkTarget, const char *szDescription )
  179. {
  180. int offsetToOffset = GetOffsetTo( pOffset );
  181. LinkSource_t linkSource = NewLinkSource( offsetToOffset, kOtRelative32bit, linkTarget.m_id, szDescription );
  182. return linkSource;
  183. }
  184. void Stream::Link( int32 *pOffset, const void *pTarget )
  185. {
  186. if ( !pTarget )
  187. {
  188. *pOffset = 0;
  189. return;
  190. }
  191. int offsetToOffset = GetOffsetTo( pOffset );
  192. int offsetToTarget = GetOffsetTo( pTarget );
  193. if ( offsetToOffset < 0 || offsetToTarget < 0 )
  194. {
  195. Error( "Link(%p,%p) can't find offsets (%d,%d)\n", pOffset, pTarget, offsetToOffset, offsetToTarget );
  196. }
  197. if ( offsetToOffset == offsetToTarget )
  198. {
  199. Warning( "Link(%p,%p) is self-referencing (%d==%d), this is prohibited by this kind of offset. It'll be interpreted as Null offset at runtime\n", pOffset, pTarget, offsetToOffset, offsetToTarget );
  200. }
  201. *pOffset = offsetToTarget - offsetToOffset;
  202. }
  203. void Stream::Link( int16 *pOffset, const void *pTarget )
  204. {
  205. if ( !pTarget )
  206. {
  207. *pOffset = 0;
  208. return;
  209. }
  210. int offsetToOffset = GetOffsetTo( pOffset );
  211. int offsetToTarget = GetOffsetTo( pTarget );
  212. if ( offsetToOffset < 0 || offsetToTarget < 0 )
  213. {
  214. Error( "Link(%p,%p) can't find offsets (%d,%d)\n", pOffset, pTarget, offsetToOffset, offsetToTarget );
  215. }
  216. int offset = offsetToTarget - offsetToOffset;
  217. int16 offset16 = ( int16 )offset;
  218. if ( offset != ( int )offset16 )
  219. {
  220. Error( "Link16(%p,%p) offsets are too far (%d,%d)\n", pOffset, pTarget, offsetToOffset, offsetToTarget );
  221. }
  222. *pOffset = offset16;
  223. }
  224. LinkSource_t Stream::NewOffset( int *pOffset, const char *szDescription )
  225. {
  226. return NewLinkSource( GetOffsetTo( pOffset ), kOtRelative32bit, kSpecialTargetUndefined, szDescription );
  227. }
  228. LinkSource_t Stream::NewLinkSource( int offsetToOffset, OffsetTypeEnum type, int linkTargetId, const char *szDescription )
  229. {
  230. Assert( !( offsetToOffset & 3 ) );
  231. if ( offsetToOffset < 0 && offsetToOffset + sizeof( int ) > m_size )
  232. {
  233. Error( "Wrong offset spec. Most probably you called an extra Write() before calling WriteOffset() - %s\n", szDescription );
  234. }
  235. LinkSource_t linkSource;
  236. linkSource.m_offset = offsetToOffset;
  237. LinkSourceDesc_t &lsd = m_mapSources[offsetToOffset];
  238. lsd.m_targetId = linkTargetId;
  239. lsd.m_type = type;
  240. lsd.m_pDescription = szDescription;
  241. return linkSource;
  242. }
  243. LinkSource_t Stream::WriteOffset( const char *szDescription )
  244. {
  245. return WriteOffset( LinkTarget_t(), szDescription );
  246. }
  247. LinkSource_t Stream::WriteOffset( LinkTarget_t linkTarget, const char *szDescription )
  248. {
  249. int offsetToOffset = m_size;
  250. Write<int32>();
  251. return NewLinkSource( offsetToOffset, kOtRelative32bit, linkTarget.m_id, szDescription );
  252. }
  253. LinkTarget_t Stream::NewTarget()// create new, unresolved target
  254. {
  255. LinkTarget_t linkTarget;
  256. linkTarget.m_id = ++m_lastTarget; // shouldn't be 0 or -1
  257. return linkTarget;
  258. }
  259. LinkTarget_t Stream::NewTarget( void *pWhere )
  260. {
  261. int offsetToTarget = GetOffsetTo( pWhere );
  262. if ( offsetToTarget < 0 )
  263. Error( "Invalid new target @%p\n", pWhere );
  264. LinkTarget_t linkTarget = NewTarget();
  265. SetTarget( linkTarget, offsetToTarget );
  266. return linkTarget;
  267. }
  268. LinkTarget_t Stream::NewTargetHere() // creates a target right here
  269. {
  270. LinkTarget_t linkTarget = NewTarget();
  271. SetTargetHere( linkTarget );
  272. return linkTarget;
  273. }
  274. void Stream::SetTarget( LinkTarget_t linkTarget, int offsetToTarget ) // sets the given target to point to offsetToTarget
  275. {
  276. LinkTargetDesc_t &target = m_mapTargets[linkTarget.m_id];
  277. target.m_type = kTargetResolved;
  278. target.m_resolvedOffset = offsetToTarget;
  279. }
  280. void Stream::SetTargetHere( LinkTarget_t linkTarget ) // sets the given target to point to right here
  281. {
  282. if ( linkTarget.m_id > 0 && linkTarget.m_id <= m_lastTarget )
  283. {
  284. SetTarget( linkTarget, m_size );
  285. }
  286. else
  287. {
  288. Warning( "Trying to set invalid target %d to here (absolute offset %d)\n", linkTarget.m_id, m_size );
  289. }
  290. }
  291. void Stream::SetTargetNull( LinkTarget_t linkTarget ) // set this target to point to NULL
  292. {
  293. if ( linkTarget.m_id > 0 && linkTarget.m_id <= m_lastTarget )
  294. {
  295. m_mapTargets[linkTarget.m_id].m_type = kTargetNull;
  296. }
  297. else
  298. {
  299. Warning( "Trying to set invalid target %d to null\n", linkTarget.m_id );
  300. }
  301. }
  302. bool Stream::IsDeclared( LinkTarget_t linkTarget )const
  303. {
  304. return m_mapTargets.find( linkTarget.m_id ) != m_mapTargets.end();
  305. }
  306. bool Stream::IsSet( LinkTarget_t linkTarget )const
  307. {
  308. LinkTargetMap::const_iterator itFind = m_mapTargets.find( linkTarget.m_id );
  309. if ( itFind == m_mapTargets.end() )
  310. return false; // it can't be set when it hasn't been declared
  311. return itFind->second.m_resolvedOffset >= 0;
  312. }
  313. bool Stream::IsDefined( LinkSource_t linkSource )const
  314. {
  315. LinkSourceMap::const_iterator itFind = m_mapSources.find( linkSource.m_offset );
  316. return itFind != m_mapSources.end();
  317. }
  318. bool Stream::IsLinked( LinkSource_t linkSource )const
  319. {
  320. LinkSourceMap::const_iterator itFind = m_mapSources.find( linkSource.m_offset );
  321. if ( itFind == m_mapSources.end() )
  322. return false;
  323. return itFind->second.m_targetId >= 0;
  324. }
  325. void Stream::Begin( const char *szName, uint flags )
  326. {
  327. Block_t newBlock;
  328. if ( !m_stackBlocks.empty() )
  329. newBlock.m_name = m_stackBlocks.back().m_name + ":" + szName;
  330. else
  331. newBlock.m_name = szName;
  332. newBlock.m_tell = Tell();
  333. m_stackBlocks.push_back( newBlock );
  334. }
  335. void Stream::End()
  336. {
  337. if ( !m_stackBlocks.empty() )
  338. {
  339. const Block_t &curBlock = m_stackBlocks.back();
  340. m_mapBlockStats[curBlock.m_name].m_size += Tell() - curBlock.m_tell;
  341. m_stackBlocks.pop_back();
  342. }
  343. }
  344. void Stream::PrintStats()
  345. {
  346. for ( BlockStatsMap::const_iterator it = m_mapBlockStats.begin(); it != m_mapBlockStats.end(); ++it )
  347. Msg( "%-60s %7.1f KiB\n", it->first.c_str(), it->second.m_size / 1024. );
  348. Msg( "%-60s -----------\n", "" );
  349. Msg( "%-60s %7.1f KiB\n", "DataLinker total stream size", m_size / 1024. );
  350. }
  351. void Stream::ClearStats()
  352. {
  353. m_mapBlockStats.clear();
  354. }
  355. const char* Stream::WriteAndLinkString( Offset_t<char> *pOffset, const char *pString )
  356. {
  357. if ( pString )
  358. {
  359. StringTableElement_t &ste = m_stringTable[pString];
  360. if ( !ste.m_pString )
  361. {
  362. int nLen = Q_strlen( pString );
  363. ste.m_nOffset = Tell();
  364. ste.m_pString = ( char* )this->WriteBytes( nLen + 1 );
  365. Q_memcpy( ste.m_pString, pString, nLen + 1 );
  366. }
  367. Assert( !Q_strcmp( ste.m_pString, pString ) );
  368. int offsetToOffset = GetOffsetTo( pOffset );
  369. pOffset->offset = ste.m_nOffset - offsetToOffset;
  370. return ste.m_pString;
  371. }
  372. else
  373. {
  374. pOffset->offset = 0; // make the offset NULL
  375. return NULL;
  376. }
  377. }
  378. }