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.

571 lines
13 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // $Header: $
  4. // $NoKeywords: $
  5. //
  6. // Serialization buffer
  7. //===========================================================================//
  8. #pragma warning (disable : 4514)
  9. #include "tier1/utlbufferutil.h"
  10. #include "tier1/utlbuffer.h"
  11. #include "mathlib/vector.h"
  12. #include "mathlib/vector2d.h"
  13. #include "mathlib/vector4d.h"
  14. #include "mathlib/vmatrix.h"
  15. #include "color.h"
  16. #include <stdio.h>
  17. #include <stdarg.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <limits.h>
  21. #include "tier1/utlstring.h"
  22. #include "tier1/strtools.h"
  23. #include "tier1/characterset.h"
  24. #include "tier1/utlsymbollarge.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. //-----------------------------------------------------------------------------
  28. // For serialization, set the delimiter rules
  29. //-----------------------------------------------------------------------------
  30. CUtlCharConversion *s_pConv = NULL;
  31. const char *s_pUtlBufferUtilArrayDelim = NULL;
  32. void SetSerializationDelimiter( CUtlCharConversion *pConv )
  33. {
  34. s_pConv = pConv;
  35. }
  36. void SetSerializationArrayDelimiter( const char *pDelimiter )
  37. {
  38. s_pUtlBufferUtilArrayDelim = pDelimiter;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Serialize a floating point number in text mode in a readably friendly fashion
  42. //-----------------------------------------------------------------------------
  43. static void SerializeFloat( CUtlBuffer &buf, float f )
  44. {
  45. Assert( buf.IsText() );
  46. // FIXME: Print this in a way that we never lose precision
  47. char pTemp[256];
  48. int nLen = Q_snprintf( pTemp, sizeof(pTemp), "%.10f", f );
  49. while ( nLen > 0 && pTemp[nLen-1] == '0' )
  50. {
  51. --nLen;
  52. pTemp[nLen] = 0;
  53. }
  54. if ( nLen > 0 && pTemp[nLen-1] == '.' )
  55. {
  56. --nLen;
  57. pTemp[nLen] = 0;
  58. }
  59. buf.PutString( pTemp );
  60. }
  61. static void SerializeFloats( CUtlBuffer &buf, int nCount, const float *pFloats )
  62. {
  63. for ( int i = 0; i < nCount; ++i )
  64. {
  65. SerializeFloat( buf, pFloats[i] );
  66. if ( i != nCount-1 )
  67. {
  68. buf.PutChar( ' ' );
  69. }
  70. }
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Serialization methods for basic types
  74. //-----------------------------------------------------------------------------
  75. bool Serialize( CUtlBuffer &buf, const bool &src )
  76. {
  77. if ( buf.IsText() )
  78. {
  79. buf.Printf( "%d", src );
  80. }
  81. else
  82. {
  83. buf.PutChar( src );
  84. }
  85. return buf.IsValid();
  86. }
  87. bool Unserialize( CUtlBuffer &buf, bool &dest )
  88. {
  89. if ( buf.IsText() )
  90. {
  91. int nValue = 0;
  92. int nRetVal = buf.Scanf( "%d", &nValue );
  93. dest = ( nValue != 0 );
  94. return (nRetVal == 1) && buf.IsValid();
  95. }
  96. dest = ( buf.GetChar( ) != 0 );
  97. return buf.IsValid();
  98. }
  99. bool Serialize( CUtlBuffer &buf, const int &src )
  100. {
  101. if ( buf.IsText() )
  102. {
  103. buf.Printf( "%d", src );
  104. }
  105. else
  106. {
  107. buf.PutInt( src );
  108. }
  109. return buf.IsValid();
  110. }
  111. bool Unserialize( CUtlBuffer &buf, int &dest )
  112. {
  113. if ( buf.IsText() )
  114. {
  115. int nRetVal = buf.Scanf( "%d", &dest );
  116. return (nRetVal == 1) && buf.IsValid();
  117. }
  118. dest = buf.GetInt( );
  119. return buf.IsValid();
  120. }
  121. bool Serialize( CUtlBuffer &buf, const float &src )
  122. {
  123. if ( buf.IsText() )
  124. {
  125. SerializeFloat( buf, src );
  126. }
  127. else
  128. {
  129. buf.PutFloat( src );
  130. }
  131. return buf.IsValid();
  132. }
  133. bool Unserialize( CUtlBuffer &buf, float &dest )
  134. {
  135. if ( buf.IsText() )
  136. {
  137. // FIXME: Print this in a way that we never lose precision
  138. int nRetVal = buf.Scanf( "%f", &dest );
  139. return (nRetVal == 1) && buf.IsValid();
  140. }
  141. dest = buf.GetFloat( );
  142. return buf.IsValid();
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Attribute types related to vector math
  146. //-----------------------------------------------------------------------------
  147. bool Serialize( CUtlBuffer &buf, const Vector2D &src )
  148. {
  149. if ( buf.IsText() )
  150. {
  151. SerializeFloats( buf, 2, src.Base() );
  152. }
  153. else
  154. {
  155. buf.PutFloat( src.x );
  156. buf.PutFloat( src.y );
  157. }
  158. return buf.IsValid();
  159. }
  160. bool Unserialize( CUtlBuffer &buf, Vector2D &dest )
  161. {
  162. if ( buf.IsText() )
  163. {
  164. // FIXME: Print this in a way that we never lose precision
  165. int nRetVal = buf.Scanf( "%f %f", &dest.x, &dest.y );
  166. return (nRetVal == 2) && buf.IsValid();
  167. }
  168. dest.x = buf.GetFloat( );
  169. dest.y = buf.GetFloat( );
  170. return buf.IsValid();
  171. }
  172. bool Serialize( CUtlBuffer &buf, const Vector &src )
  173. {
  174. if ( buf.IsText() )
  175. {
  176. SerializeFloats( buf, 3, src.Base() );
  177. }
  178. else
  179. {
  180. buf.PutFloat( src.x );
  181. buf.PutFloat( src.y );
  182. buf.PutFloat( src.z );
  183. }
  184. return buf.IsValid();
  185. }
  186. bool Unserialize( CUtlBuffer &buf, Vector &dest )
  187. {
  188. if ( buf.IsText() )
  189. {
  190. // FIXME: Print this in a way that we never lose precision
  191. int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
  192. return (nRetVal == 3) && buf.IsValid();
  193. }
  194. dest.x = buf.GetFloat( );
  195. dest.y = buf.GetFloat( );
  196. dest.z = buf.GetFloat( );
  197. return buf.IsValid();
  198. }
  199. bool Serialize( CUtlBuffer &buf, const Vector4D &src )
  200. {
  201. if ( buf.IsText() )
  202. {
  203. SerializeFloats( buf, 4, src.Base() );
  204. }
  205. else
  206. {
  207. buf.PutFloat( src.x );
  208. buf.PutFloat( src.y );
  209. buf.PutFloat( src.z );
  210. buf.PutFloat( src.w );
  211. }
  212. return buf.IsValid();
  213. }
  214. bool Unserialize( CUtlBuffer &buf, Vector4D &dest )
  215. {
  216. if ( buf.IsText() )
  217. {
  218. // FIXME: Print this in a way that we never lose precision
  219. int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
  220. return (nRetVal == 4) && buf.IsValid();
  221. }
  222. dest.x = buf.GetFloat( );
  223. dest.y = buf.GetFloat( );
  224. dest.z = buf.GetFloat( );
  225. dest.w = buf.GetFloat( );
  226. return buf.IsValid();
  227. }
  228. bool Serialize( CUtlBuffer &buf, const QAngle &src )
  229. {
  230. if ( buf.IsText() )
  231. {
  232. SerializeFloats( buf, 3, src.Base() );
  233. }
  234. else
  235. {
  236. buf.PutFloat( src.x );
  237. buf.PutFloat( src.y );
  238. buf.PutFloat( src.z );
  239. }
  240. return buf.IsValid();
  241. }
  242. bool Unserialize( CUtlBuffer &buf, QAngle &dest )
  243. {
  244. if ( buf.IsText() )
  245. {
  246. // FIXME: Print this in a way that we never lose precision
  247. int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
  248. return (nRetVal == 3) && buf.IsValid();
  249. }
  250. dest.x = buf.GetFloat( );
  251. dest.y = buf.GetFloat( );
  252. dest.z = buf.GetFloat( );
  253. return buf.IsValid();
  254. }
  255. bool Serialize( CUtlBuffer &buf, const Quaternion &src )
  256. {
  257. if ( buf.IsText() )
  258. {
  259. SerializeFloats( buf, 4, &src.x );
  260. }
  261. else
  262. {
  263. buf.PutFloat( src.x );
  264. buf.PutFloat( src.y );
  265. buf.PutFloat( src.z );
  266. buf.PutFloat( src.w );
  267. }
  268. return buf.IsValid();
  269. }
  270. bool Unserialize( CUtlBuffer &buf, Quaternion &dest )
  271. {
  272. if ( buf.IsText() )
  273. {
  274. // FIXME: Print this in a way that we never lose precision
  275. int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
  276. QuaternionNormalize( dest );
  277. return (nRetVal == 4) && buf.IsValid();
  278. }
  279. dest.x = buf.GetFloat( );
  280. dest.y = buf.GetFloat( );
  281. dest.z = buf.GetFloat( );
  282. dest.w = buf.GetFloat( );
  283. QuaternionNormalize( dest );
  284. return buf.IsValid();
  285. }
  286. bool Serialize( CUtlBuffer &buf, const VMatrix &src )
  287. {
  288. if ( buf.IsText() )
  289. {
  290. buf.Printf( "\n" );
  291. SerializeFloats( buf, 4, src[0] );
  292. buf.Printf( "\n" );
  293. SerializeFloats( buf, 4, src[1] );
  294. buf.Printf( "\n" );
  295. SerializeFloats( buf, 4, src[2] );
  296. buf.Printf( "\n" );
  297. SerializeFloats( buf, 4, src[3] );
  298. buf.Printf( "\n" );
  299. }
  300. else
  301. {
  302. buf.Put( &src, sizeof(VMatrix) );
  303. }
  304. return buf.IsValid();
  305. }
  306. bool Unserialize( CUtlBuffer &buf, VMatrix &dest )
  307. {
  308. if ( !buf.IsValid() )
  309. return false;
  310. if ( buf.IsText() )
  311. {
  312. int nRetVal = buf.Scanf( "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
  313. &dest[ 0 ][ 0 ], &dest[ 0 ][ 1 ], &dest[ 0 ][ 2 ], &dest[ 0 ][ 3 ],
  314. &dest[ 1 ][ 0 ], &dest[ 1 ][ 1 ], &dest[ 1 ][ 2 ], &dest[ 1 ][ 3 ],
  315. &dest[ 2 ][ 0 ], &dest[ 2 ][ 1 ], &dest[ 2 ][ 2 ], &dest[ 2 ][ 3 ],
  316. &dest[ 3 ][ 0 ], &dest[ 3 ][ 1 ], &dest[ 3 ][ 2 ], &dest[ 3 ][ 3 ] );
  317. return (nRetVal == 16);
  318. }
  319. buf.Get( &dest, sizeof(VMatrix) );
  320. return true;
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Color attribute
  324. //-----------------------------------------------------------------------------
  325. bool Serialize( CUtlBuffer &buf, const Color &src )
  326. {
  327. if ( buf.IsText() )
  328. {
  329. buf.Printf( "%d %d %d %d", src[0], src[1], src[2], src[3] );
  330. }
  331. else
  332. {
  333. buf.PutUnsignedChar( src[0] );
  334. buf.PutUnsignedChar( src[1] );
  335. buf.PutUnsignedChar( src[2] );
  336. buf.PutUnsignedChar( src[3] );
  337. }
  338. return buf.IsValid();
  339. }
  340. bool Unserialize( CUtlBuffer &buf, Color &dest )
  341. {
  342. if ( buf.IsText() )
  343. {
  344. int r = 0, g = 0, b = 0, a = 255;
  345. int nRetVal = buf.Scanf( "%d %d %d %d", &r, &g, &b, &a );
  346. dest.SetColor( r, g, b, a );
  347. return (nRetVal == 4) && buf.IsValid();
  348. }
  349. dest[0] = buf.GetUnsignedChar( );
  350. dest[1] = buf.GetUnsignedChar( );
  351. dest[2] = buf.GetUnsignedChar( );
  352. dest[3] = buf.GetUnsignedChar( );
  353. return buf.IsValid();
  354. }
  355. /*
  356. //-----------------------------------------------------------------------------
  357. // Object ID attribute
  358. //-----------------------------------------------------------------------------
  359. bool Serialize( CUtlBuffer &buf, const DmObjectId_t &src )
  360. {
  361. return g_pDataModel->Serialize( buf, src );
  362. }
  363. bool Unserialize( CUtlBuffer &buf, DmObjectId_t &dest )
  364. {
  365. return g_pDataModel->Unserialize( buf, &dest );
  366. }
  367. */
  368. //-----------------------------------------------------------------------------
  369. // Binary buffer attribute
  370. //-----------------------------------------------------------------------------
  371. bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src )
  372. {
  373. int nLength = src.Length();
  374. if ( !buf.IsText() )
  375. {
  376. buf.PutInt( nLength );
  377. if ( nLength != 0 )
  378. {
  379. buf.Put( src.Get(), nLength );
  380. }
  381. return buf.IsValid();
  382. }
  383. // Writes out uuencoded binaries
  384. for ( int i = 0; i < nLength; ++i )
  385. {
  386. if ( (i % 40) == 0 )
  387. {
  388. buf.PutChar( '\n' );
  389. }
  390. char b1 = src[i] & 0xF;
  391. char b2 = src[i] >> 4;
  392. char c1 = ( b1 <= 9 ) ? b1 + '0' : b1 - 10 + 'A';
  393. char c2 = ( b2 <= 9 ) ? b2 + '0' : b2 - 10 + 'A';
  394. buf.PutChar( c2 );
  395. buf.PutChar( c1 );
  396. }
  397. buf.PutChar( '\n' );
  398. return buf.IsValid();
  399. }
  400. static int CountBinaryBytes( CUtlBuffer &buf, int *pEndGet )
  401. {
  402. // This counts the number of bytes in the uuencoded text
  403. int nStartGet = buf.TellGet();
  404. buf.EatWhiteSpace();
  405. *pEndGet = buf.TellGet();
  406. int nByteCount = 0;
  407. while ( buf.IsValid() )
  408. {
  409. char c1 = buf.GetChar();
  410. char c2 = buf.GetChar();
  411. bool bIsNum1 = ( c1 >= '0' ) && ( c1 <= '9' );
  412. bool bIsNum2 = ( c2 >= '0' ) && ( c2 <= '9' );
  413. bool bIsAlpha1 = (( c1 >= 'A' ) && ( c1 <= 'F' )) || (( c1 >= 'a' ) && ( c1 <= 'f' ));
  414. bool bIsAlpha2 = (( c2 >= 'A' ) && ( c2 <= 'F' )) || (( c2 >= 'a' ) && ( c2 <= 'f' ));
  415. if ( !(bIsNum1 || bIsAlpha1) || !(bIsNum2 || bIsAlpha2) )
  416. break;
  417. buf.EatWhiteSpace();
  418. *pEndGet = buf.TellGet();
  419. ++nByteCount;
  420. }
  421. buf.SeekGet( CUtlBuffer::SEEK_HEAD, nStartGet );
  422. return nByteCount;
  423. }
  424. inline static unsigned char HexCharToInt( int c1 )
  425. {
  426. if (( c1 >= '0' ) && ( c1 <= '9' ))
  427. return c1 - '0';
  428. if (( c1 >= 'A' ) && ( c1 <= 'F' ))
  429. return 10 + c1 - 'A';
  430. if (( c1 >= 'a' ) && ( c1 <= 'f' ))
  431. return 10 + c1 - 'a';
  432. return 0xFF;
  433. }
  434. bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest )
  435. {
  436. if ( !buf.IsText() )
  437. {
  438. int nLen = buf.GetInt( );
  439. dest.SetLength( nLen );
  440. if ( dest.Length() != 0 )
  441. {
  442. buf.Get( dest.Get(), dest.Length() );
  443. }
  444. if ( nLen != dest.Length() )
  445. {
  446. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLen - dest.Length() );
  447. return false;
  448. }
  449. return buf.IsValid();
  450. }
  451. int nEndGet = 0;
  452. int nByteCount = CountBinaryBytes( buf, &nEndGet );
  453. if ( nByteCount < 0 )
  454. return false;
  455. buf.EatWhiteSpace();
  456. int nDest = 0;
  457. dest.SetLength( nByteCount );
  458. while( buf.TellGet() < nEndGet )
  459. {
  460. char c1 = buf.GetChar();
  461. char c2 = buf.GetChar();
  462. unsigned char b1 = HexCharToInt( c1 );
  463. unsigned char b2 = HexCharToInt( c2 );
  464. if ( b1 == 0xFF || b2 == 0xFF )
  465. return false;
  466. dest[ nDest++ ] = b2 | ( b1 << 4 );
  467. buf.EatWhiteSpace();
  468. }
  469. return true;
  470. }
  471. //-----------------------------------------------------------------------------
  472. // String attribute
  473. //-----------------------------------------------------------------------------
  474. bool Serialize( CUtlBuffer &buf, const CUtlString &src )
  475. {
  476. buf.PutDelimitedString( s_pConv, src.Get() );
  477. return buf.IsValid();
  478. }
  479. bool Unserialize( CUtlBuffer &buf, CUtlString &dest )
  480. {
  481. int nLen = buf.PeekDelimitedStringLength( s_pConv );
  482. dest.SetLength( nLen - 1 ); // -1 because the length returned includes space for \0
  483. buf.GetDelimitedString( s_pConv, dest.Get(), nLen );
  484. return buf.IsValid();
  485. }
  486. bool Serialize( CUtlBuffer &buf, const CUtlSymbolLarge &src )
  487. {
  488. // Serialization of symbols is allowed, but it writes that string of the symbol,
  489. // not the symbol index. This is done so that text serialization of symbols will write
  490. // the actual string and so that functions which rely on text serialization to convert
  491. // an attribute value to text will get the proper string for the symbol.
  492. buf.PutDelimitedString( s_pConv, src.String() );
  493. return buf.IsValid();
  494. }