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.

310 lines
7.5 KiB

  1. //====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "platform.h"
  9. #include "utlvector.h"
  10. #include "utlbuffer.h"
  11. #include "chunkfile.h"
  12. #include "utlencode.h"
  13. #include "fgdlib/wckeyvalues.h"
  14. #include "vmfmeshdatasupport.h"
  15. CVmfMeshDataSupport_SaveLoadHandler::CVmfMeshDataSupport_SaveLoadHandler()
  16. {
  17. }
  18. CVmfMeshDataSupport_SaveLoadHandler::~CVmfMeshDataSupport_SaveLoadHandler()
  19. {
  20. NULL;
  21. }
  22. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::WriteDataChunk( CChunkFile *pFile, char const *szHash )
  23. {
  24. ChunkFileResult_t eResult;
  25. eResult = pFile->BeginChunk( GetCustomSectionName() );
  26. if ( eResult != ChunkFile_Ok )
  27. return eResult;
  28. // Write out our data version
  29. char szModelDataVer[ 16 ] = {0};
  30. sprintf( szModelDataVer, "%d", GetCustomSectionVer() );
  31. eResult = pFile->WriteKeyValue( "version", szModelDataVer );
  32. if ( eResult != ChunkFile_Ok )
  33. return eResult;
  34. // Write our hash
  35. eResult = pFile->WriteKeyValue( "hash", szHash );
  36. if ( eResult != ChunkFile_Ok )
  37. return eResult;
  38. // Write out additional data
  39. eResult = OnFileDataWriting( pFile, szHash );
  40. if ( eResult != ChunkFile_Ok )
  41. return eResult;
  42. return pFile->EndChunk();
  43. }
  44. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::OnFileDataWriting( CChunkFile *pFile, char const *szHash )
  45. {
  46. return ChunkFile_Ok;
  47. }
  48. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::WriteBufferData( CChunkFile *pFile, CUtlBuffer &bufData, char const *szPrefix )
  49. {
  50. int numEncBytes = KvEncoder::GuessEncodedLength( bufData.TellPut() );
  51. CUtlBuffer bufEncoded;
  52. bufEncoded.EnsureCapacity( numEncBytes );
  53. if ( !KvEncoder::Encode( bufData, bufEncoded ) )
  54. return ChunkFile_Fail;
  55. numEncBytes = bufEncoded.TellPut();
  56. // Now we have the encoded data, split it into blocks
  57. int numBytesPerLine = KEYVALUE_MAX_VALUE_LENGTH - 2;
  58. int numLines = (numEncBytes + numBytesPerLine - 1 ) / numBytesPerLine;
  59. int numLastLineBytes = numEncBytes % numBytesPerLine;
  60. if ( !numLastLineBytes )
  61. numLastLineBytes = numBytesPerLine;
  62. // Key buffer
  63. char chKeyBuf[ KEYVALUE_MAX_KEY_LENGTH ] = {0};
  64. char chKeyValue[ KEYVALUE_MAX_VALUE_LENGTH ] = {0};
  65. // Write the data
  66. ChunkFileResult_t eResult;
  67. sprintf( chKeyBuf, "%s_ebytes", szPrefix );
  68. eResult = pFile->WriteKeyValueInt( chKeyBuf, numEncBytes );
  69. if ( eResult != ChunkFile_Ok )
  70. return eResult;
  71. sprintf( chKeyBuf, "%s_rbytes", szPrefix );
  72. eResult = pFile->WriteKeyValueInt( chKeyBuf, bufData.TellPut() );
  73. if ( eResult != ChunkFile_Ok )
  74. return eResult;
  75. sprintf( chKeyBuf, "%s_lines", szPrefix );
  76. eResult = pFile->WriteKeyValueInt( chKeyBuf, numLines );
  77. if ( eResult != ChunkFile_Ok )
  78. return eResult;
  79. for ( int ln = 0; ln < numLines; ++ ln )
  80. {
  81. int lnLen = ( ln < (numLines - 1) ) ? numBytesPerLine : numLastLineBytes;
  82. sprintf( chKeyBuf, "%s_ln_%d", szPrefix, ln );
  83. sprintf( chKeyValue, "%.*s", lnLen, ( char * ) bufEncoded.Base() + ln * numBytesPerLine );
  84. eResult = pFile->WriteKeyValue( chKeyBuf, chKeyValue );
  85. if ( eResult != ChunkFile_Ok )
  86. return eResult;
  87. }
  88. return ChunkFile_Ok;
  89. }
  90. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadKeyValueBegin( CChunkFile *pFile )
  91. {
  92. m_eLoadState = LOAD_VERSION;
  93. m_iLoadVer = 0;
  94. m_hLoadHeader.sHash[0] = 0;
  95. LoadInitHeader();
  96. return ChunkFile_Ok;
  97. }
  98. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadKeyValue( const char *szKey, const char *szValue )
  99. {
  100. switch ( m_eLoadState )
  101. {
  102. case LOAD_VERSION:
  103. return LoadKeyValue_Hdr( szKey, szValue );
  104. default:
  105. switch ( m_iLoadVer )
  106. {
  107. case 1:
  108. return LoadKeyValue_Ver1( szKey, szValue );
  109. default:
  110. return ChunkFile_Fail;
  111. }
  112. }
  113. }
  114. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadKeyValue_Hdr( const char *szKey, const char *szValue )
  115. {
  116. switch ( m_eLoadState )
  117. {
  118. case LOAD_VERSION:
  119. if ( stricmp( szKey, "version" ) )
  120. return ChunkFile_Fail;
  121. m_iLoadVer = atoi( szValue );
  122. switch ( m_iLoadVer )
  123. {
  124. case 1:
  125. m_eLoadState = LOAD_HASH;
  126. return ChunkFile_Ok;
  127. default:
  128. return ChunkFile_Fail;
  129. }
  130. default:
  131. return ChunkFile_Fail;
  132. }
  133. }
  134. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadKeyValue_Ver1( const char *szKey, const char *szValue )
  135. {
  136. const char *szKeyName = szKey;
  137. const int nPrefixLen = 3;
  138. switch ( m_eLoadState )
  139. {
  140. case LOAD_HASH:
  141. if ( stricmp( szKey, "hash" ) )
  142. return ChunkFile_Fail;
  143. strncpy( m_hLoadHeader.sHash, szValue, sizeof( m_hLoadHeader.sHash ) );
  144. m_eLoadState = LOAD_PREFIX;
  145. break;
  146. case LOAD_PREFIX:
  147. sprintf( m_hLoadHeader.sPrefix, "%.*s", nPrefixLen, szKey );
  148. if ( strlen( szKey ) < 4 )
  149. return ChunkFile_Fail;
  150. if ( szKey[3] != '_' )
  151. return ChunkFile_Fail;
  152. m_eLoadState = LOAD_HEADER;
  153. // fall-through
  154. case LOAD_HEADER:
  155. if ( strnicmp( m_hLoadHeader.sPrefix, szKey, nPrefixLen ) )
  156. return ChunkFile_Fail;
  157. if ( szKey[3] != '_' )
  158. return ChunkFile_Fail;
  159. szKeyName = szKey + 4;
  160. if ( !stricmp( szKeyName, "ebytes" ) )
  161. m_hLoadHeader.numEncBytes = atoi( szValue );
  162. else if ( !stricmp( szKeyName, "rbytes" ) )
  163. m_hLoadHeader.numBytes = atoi( szValue );
  164. else if ( !stricmp( szKeyName, "lines" ) )
  165. m_hLoadHeader.numLines = atoi( szValue );
  166. else
  167. return ChunkFile_Fail;
  168. if ( !LoadHaveHeader() )
  169. break;
  170. m_eLoadState = LOAD_DATA;
  171. return LoadHaveLines( 0 );
  172. case LOAD_DATA:
  173. if ( strnicmp( m_hLoadHeader.sPrefix, szKey, nPrefixLen ) )
  174. return ChunkFile_Fail;
  175. if ( szKey[3] != '_' )
  176. return ChunkFile_Fail;
  177. szKeyName = szKey + 4;
  178. if ( strnicmp( szKeyName, "ln", 2 ) || szKeyName[2] != '_' )
  179. return ChunkFile_Fail;
  180. szKeyName += 3;
  181. {
  182. int iLineNum = atoi( szKeyName );
  183. if ( iLineNum != m_hLoadHeader.numHaveLines )
  184. return ChunkFile_Fail;
  185. m_bufLoadData.Put( szValue, strlen( szValue ) );
  186. return LoadHaveLines( iLineNum + 1 );
  187. }
  188. default:
  189. return ChunkFile_Fail;
  190. }
  191. return ChunkFile_Ok;
  192. }
  193. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadKeyValueEnd( CChunkFile *pFile, ChunkFileResult_t eLoadResult )
  194. {
  195. if ( eLoadResult != ChunkFile_Ok )
  196. return eLoadResult;
  197. if ( m_eLoadState == LOAD_VERSION )
  198. return ChunkFile_Ok;
  199. switch ( m_iLoadVer )
  200. {
  201. case 1:
  202. switch ( m_eLoadState )
  203. {
  204. case LOAD_HASH:
  205. case LOAD_PREFIX:
  206. return ChunkFile_Ok;
  207. default:
  208. return ChunkFile_Fail;
  209. }
  210. default:
  211. return ChunkFile_Fail;
  212. }
  213. }
  214. void CVmfMeshDataSupport_SaveLoadHandler::LoadInitHeader()
  215. {
  216. m_hLoadHeader.sPrefix[0] = 0;
  217. m_hLoadHeader.numLines = -1;
  218. m_hLoadHeader.numBytes = -1;
  219. m_hLoadHeader.numEncBytes = -1;
  220. m_hLoadHeader.numHaveLines = 0;
  221. }
  222. bool CVmfMeshDataSupport_SaveLoadHandler::LoadHaveHeader()
  223. {
  224. return m_hLoadHeader.numLines >= 0 && m_hLoadHeader.numBytes >= 0 && m_hLoadHeader.numEncBytes >= 0;
  225. }
  226. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadHaveLines( int numHaveLines )
  227. {
  228. if ( !numHaveLines )
  229. {
  230. m_bufLoadData.EnsureCapacity( m_hLoadHeader.numEncBytes );
  231. m_bufLoadData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  232. }
  233. m_hLoadHeader.numHaveLines = numHaveLines;
  234. if ( m_hLoadHeader.numHaveLines < m_hLoadHeader.numLines )
  235. return ChunkFile_Ok;
  236. if ( m_hLoadHeader.numHaveLines > m_hLoadHeader.numLines )
  237. return ChunkFile_Fail;
  238. ChunkFileResult_t eRes = LoadSaveFullData();
  239. if ( eRes != ChunkFile_Ok )
  240. return eRes;
  241. LoadInitHeader();
  242. m_eLoadState = LOAD_PREFIX;
  243. return ChunkFile_Ok;
  244. }
  245. ChunkFileResult_t CVmfMeshDataSupport_SaveLoadHandler::LoadSaveFullData()
  246. {
  247. // The filename
  248. CUtlBuffer bufBytes;
  249. bufBytes.EnsureCapacity( m_hLoadHeader.numBytes + 0x10 );
  250. if ( !KvEncoder::Decode( m_bufLoadData, bufBytes ) )
  251. return ChunkFile_Fail;
  252. return OnFileDataLoaded( bufBytes );
  253. }