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.

285 lines
5.6 KiB

  1. //========= Copyright (c), Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Contains a branch-neutral binary packer for KeyValues trees.
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <keyvalues.h>
  9. #include "kvpacker.h"
  10. #include "tier0/dbg.h"
  11. #include "utlbuffer.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include <tier0/memdbgon.h>
  14. #define KEYVALUES_TOKEN_SIZE 1024
  15. // writes KeyValue as binary data to buffer
  16. bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
  17. {
  18. if ( buffer.IsText() ) // must be a binary buffer
  19. return false;
  20. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  21. return false;
  22. // Write subkeys:
  23. // loop through all our peers
  24. for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() )
  25. {
  26. // write type
  27. switch ( dat->GetDataType() )
  28. {
  29. case KeyValues::TYPE_NONE:
  30. {
  31. buffer.PutUnsignedChar( PACKTYPE_NONE );
  32. break;
  33. }
  34. case KeyValues::TYPE_STRING:
  35. {
  36. buffer.PutUnsignedChar( PACKTYPE_STRING );
  37. break;
  38. }
  39. case KeyValues::TYPE_WSTRING:
  40. {
  41. buffer.PutUnsignedChar( PACKTYPE_WSTRING );
  42. break;
  43. }
  44. case KeyValues::TYPE_INT:
  45. {
  46. buffer.PutUnsignedChar( PACKTYPE_INT );
  47. break;
  48. }
  49. case KeyValues::TYPE_UINT64:
  50. {
  51. buffer.PutUnsignedChar( PACKTYPE_UINT64 );
  52. break;
  53. }
  54. case KeyValues::TYPE_FLOAT:
  55. {
  56. buffer.PutUnsignedChar( PACKTYPE_FLOAT );
  57. break;
  58. }
  59. case KeyValues::TYPE_COLOR:
  60. {
  61. buffer.PutUnsignedChar( PACKTYPE_COLOR );
  62. break;
  63. }
  64. case KeyValues::TYPE_PTR:
  65. {
  66. buffer.PutUnsignedChar( PACKTYPE_PTR );
  67. break;
  68. }
  69. default:
  70. break;
  71. }
  72. // write name
  73. buffer.PutString( dat->GetName() );
  74. // write value
  75. switch ( dat->GetDataType() )
  76. {
  77. case KeyValues::TYPE_NONE:
  78. {
  79. if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) )
  80. return false;
  81. break;
  82. }
  83. case KeyValues::TYPE_STRING:
  84. {
  85. if (dat->GetString() && *(dat->GetString()))
  86. {
  87. buffer.PutString( dat->GetString() );
  88. }
  89. else
  90. {
  91. buffer.PutString( "" );
  92. }
  93. break;
  94. }
  95. case KeyValues::TYPE_WSTRING:
  96. {
  97. int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0;
  98. buffer.PutShort( nLength );
  99. for( int k = 0; k < nLength; ++ k )
  100. {
  101. buffer.PutShort( ( unsigned short ) dat->GetWString()[k] );
  102. }
  103. break;
  104. }
  105. case KeyValues::TYPE_INT:
  106. {
  107. buffer.PutInt( dat->GetInt() );
  108. break;
  109. }
  110. case KeyValues::TYPE_UINT64:
  111. {
  112. buffer.PutInt64( dat->GetUint64() );
  113. break;
  114. }
  115. case KeyValues::TYPE_FLOAT:
  116. {
  117. buffer.PutFloat( dat->GetFloat() );
  118. break;
  119. }
  120. case KeyValues::TYPE_COLOR:
  121. {
  122. Color color = dat->GetColor();
  123. buffer.PutUnsignedChar( color[0] );
  124. buffer.PutUnsignedChar( color[1] );
  125. buffer.PutUnsignedChar( color[2] );
  126. buffer.PutUnsignedChar( color[3] );
  127. break;
  128. }
  129. case KeyValues::TYPE_PTR:
  130. {
  131. buffer.PutPtr( dat->GetPtr() );
  132. break;
  133. }
  134. default:
  135. break;
  136. }
  137. }
  138. // write tail, marks end of peers
  139. buffer.PutUnsignedChar( PACKTYPE_NULLMARKER );
  140. return buffer.IsValid();
  141. }
  142. // read KeyValues from binary buffer, returns true if parsing was successful
  143. bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
  144. {
  145. if ( buffer.IsText() ) // must be a binary buffer
  146. return false;
  147. if ( !buffer.IsValid() ) // must be valid, no overflows etc
  148. return false;
  149. pNode->Clear();
  150. char token[KEYVALUES_TOKEN_SIZE];
  151. KeyValues *dat = pNode;
  152. EPackType ePackType = (EPackType)buffer.GetUnsignedChar();
  153. // loop through all our peers
  154. while ( true )
  155. {
  156. if ( ePackType == PACKTYPE_NULLMARKER )
  157. break; // no more peers
  158. buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
  159. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  160. dat->SetName( token );
  161. switch ( ePackType )
  162. {
  163. case PACKTYPE_NONE:
  164. {
  165. KeyValues *pNewNode = new KeyValues("");
  166. dat->AddSubKey( pNewNode );
  167. if( !ReadAsBinary( pNewNode, buffer ) )
  168. return false;
  169. break;
  170. }
  171. case PACKTYPE_STRING:
  172. {
  173. buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
  174. token[KEYVALUES_TOKEN_SIZE-1] = 0;
  175. dat->SetStringValue( token );
  176. break;
  177. }
  178. case PACKTYPE_WSTRING:
  179. {
  180. int nLength = buffer.GetShort();
  181. if ( nLength >= 0 && nLength*sizeof( uint16 ) <= (uint)buffer.GetBytesRemaining() )
  182. {
  183. if ( nLength > 0 )
  184. {
  185. wchar_t *pTemp = (wchar_t *)malloc( sizeof( wchar_t ) * (1 + nLength) );
  186. for ( int k = 0; k < nLength; ++k )
  187. {
  188. pTemp[k] = buffer.GetShort(); // ugly, but preserving existing behavior
  189. }
  190. pTemp[nLength] = 0;
  191. dat->SetWString( NULL, pTemp );
  192. free( pTemp );
  193. }
  194. else
  195. dat->SetWString( NULL, L"" );
  196. }
  197. break;
  198. }
  199. case PACKTYPE_INT:
  200. {
  201. dat->SetInt( NULL, buffer.GetInt() );
  202. break;
  203. }
  204. case PACKTYPE_UINT64:
  205. {
  206. dat->SetUint64( NULL, (uint64)buffer.GetInt64() );
  207. break;
  208. }
  209. case PACKTYPE_FLOAT:
  210. {
  211. dat->SetFloat( NULL, buffer.GetFloat() );
  212. break;
  213. }
  214. case PACKTYPE_COLOR:
  215. {
  216. Color color(
  217. buffer.GetUnsignedChar(),
  218. buffer.GetUnsignedChar(),
  219. buffer.GetUnsignedChar(),
  220. buffer.GetUnsignedChar() );
  221. dat->SetColor( NULL, color );
  222. break;
  223. }
  224. case PACKTYPE_PTR:
  225. {
  226. dat->SetPtr( NULL, buffer.GetPtr() );
  227. break;
  228. }
  229. default:
  230. break;
  231. }
  232. if ( !buffer.IsValid() ) // error occured
  233. return false;
  234. ePackType = (EPackType)buffer.GetUnsignedChar();
  235. if ( ePackType == PACKTYPE_NULLMARKER )
  236. break;
  237. // new peer follows
  238. KeyValues *pNewPeer = new KeyValues("");
  239. dat->SetNextKey( pNewPeer );
  240. dat = pNewPeer;
  241. }
  242. return buffer.IsValid();
  243. }