Team Fortress 2 Source Code as on 22/4/2020
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.

436 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "keyvaluescompiler.h"
  7. #include "filesystem.h"
  8. #include "tier1/KeyValues.h"
  9. extern IFileSystem *g_pFullFileSystem;
  10. bool CRunTimeKeyValuesStringTable::ReadStringTable( int numStrings, CUtlBuffer& buf )
  11. {
  12. Assert( m_Strings.Count() == 0 );
  13. CUtlVector< int > offsets;
  14. offsets.EnsureCapacity( numStrings );
  15. offsets.CopyArray( (int *)( buf.PeekGet() ), numStrings );
  16. // Skip over data
  17. buf.SeekGet( CUtlBuffer::SEEK_HEAD, buf.TellGet() + numStrings * sizeof( int ) );
  18. int stringSize = buf.GetInt();
  19. // Read in the string table
  20. m_Strings.EnsureCapacity( numStrings );
  21. int i;
  22. for ( i = 0 ; i < numStrings; ++i )
  23. {
  24. m_Strings.AddToTail( (const char *)buf.PeekGet( offsets[ i ] ) );
  25. }
  26. buf.SeekGet( CUtlBuffer::SEEK_HEAD, buf.TellGet() + stringSize );
  27. return true;
  28. }
  29. void CCompiledKeyValuesWriter::BuildKVData_R( KeyValues *kv, int parent )
  30. {
  31. // Add self
  32. KVInfo_t info;
  33. info.key = m_StringTable.AddString( kv->GetName() );
  34. info.value = m_StringTable.AddString( kv->GetString() );
  35. info.SetSubTree( kv->GetFirstSubKey() != NULL ? true : false );
  36. info.SetParent( parent );
  37. int newParent = m_Data.AddToTail( info );
  38. // Then add children
  39. for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
  40. {
  41. BuildKVData_R( sub, newParent );
  42. }
  43. // Then add peers
  44. if ( parent == -1 )
  45. {
  46. if ( kv->GetNextKey() )
  47. {
  48. BuildKVData_R( kv->GetNextKey(), parent );
  49. }
  50. }
  51. }
  52. void CCompiledKeyValuesWriter::Describe( const KVFile_t& file )
  53. {
  54. Msg( "file( %s )\n", m_StringTable.String( file.filename ) );
  55. int c = file.numElements;
  56. for ( int i = 0; i < c; ++i )
  57. {
  58. KVInfo_t &info = m_Data[ file.firstElement + i ];
  59. if ( info.IsSubTree() )
  60. {
  61. Msg( "%d: %s -> subtree at parent %i\n",
  62. file.firstElement + i,
  63. m_StringTable.String( info.key ),
  64. info.GetParent() );
  65. }
  66. else
  67. {
  68. Msg( "%d: %s -> %s at parent %i\n",
  69. file.firstElement + i,
  70. m_StringTable.String( info.key ),
  71. m_StringTable.String( info.value ),
  72. info.GetParent() );
  73. }
  74. }
  75. }
  76. void CCompiledKeyValuesWriter::AppendKeyValuesFile( char const *filename )
  77. {
  78. KVFile_t kvf;
  79. kvf.filename = m_StringTable.AddString( filename );
  80. kvf.firstElement = m_Data.Count();
  81. KeyValues *kv = new KeyValues( filename );
  82. if ( kv->LoadFromFile( g_pFullFileSystem, filename ) )
  83. {
  84. // Add to dictionary
  85. // do a depth first traversal of the keyvalues
  86. BuildKVData_R( kv, -1 );
  87. }
  88. kv->deleteThis();
  89. kvf.numElements = m_Data.Count() - kvf.firstElement;
  90. // Describe( kvf );
  91. m_Files.AddToTail( kvf );
  92. }
  93. void CCompiledKeyValuesWriter::WriteData( CUtlBuffer& buf )
  94. {
  95. int c = m_Data.Count();
  96. buf.PutInt( c );
  97. for ( int i = 0; i < c; ++i )
  98. {
  99. KVInfo_t &info = m_Data[ i ];
  100. buf.PutShort( info.key );
  101. buf.PutShort( info.value );
  102. buf.PutShort( info.GetParent() );
  103. buf.PutChar( info.IsSubTree() ? 1 : 0 );
  104. }
  105. }
  106. void CCompiledKeyValuesWriter::WriteFiles( CUtlBuffer &buf )
  107. {
  108. int c = m_Files.Count();
  109. buf.PutInt( c );
  110. for ( int i = 0; i < c; ++i )
  111. {
  112. KVFile_t &file = m_Files[ i ];
  113. buf.PutShort( file.filename );
  114. buf.PutShort( file.firstElement );
  115. buf.PutShort( file.numElements );
  116. }
  117. }
  118. void CCompiledKeyValuesWriter::WriteStringTable( CUtlBuffer& buf )
  119. {
  120. int i;
  121. CUtlVector< int > offsets;
  122. CUtlBuffer stringBuffer;
  123. offsets.AddToTail( stringBuffer.TellPut() );
  124. stringBuffer.PutString( "" );
  125. // save all the rest
  126. int c = m_StringTable.GetNumStrings();
  127. for ( i = 1; i < c; i++)
  128. {
  129. offsets.AddToTail( stringBuffer.TellPut() );
  130. stringBuffer.PutString( m_StringTable.String( i ) );
  131. }
  132. buf.Put( offsets.Base(), offsets.Count() * sizeof( int ) );
  133. buf.PutInt( stringBuffer.TellPut() );
  134. buf.Put( stringBuffer.Base(), stringBuffer.TellPut() );
  135. }
  136. void CCompiledKeyValuesWriter::WriteFile( char const *outfile )
  137. {
  138. CUtlBuffer buf;
  139. // Write the data file out
  140. KVHeader_t header;
  141. header.fileid = COMPILED_KEYVALUES_ID;
  142. header.version = COMPILED_KEYVALUES_VERSION;
  143. header.numStrings = m_StringTable.GetNumStrings();
  144. buf.Put( &header, sizeof( header ) );
  145. WriteStringTable( buf );
  146. WriteData( buf );
  147. WriteFiles( buf );
  148. g_pFullFileSystem->WriteFile( outfile, NULL, buf );
  149. }
  150. CCompiledKeyValuesReader::CCompiledKeyValuesReader()
  151. : m_Dict( 0, 0, FileInfo_t::Less )
  152. {
  153. }
  154. int CCompiledKeyValuesReader::First() const
  155. {
  156. return m_Dict.FirstInorder();
  157. }
  158. int CCompiledKeyValuesReader::Next( int i ) const
  159. {
  160. return m_Dict.NextInorder( i );
  161. }
  162. int CCompiledKeyValuesReader::InvalidIndex() const
  163. {
  164. return m_Dict.InvalidIndex();
  165. }
  166. void CCompiledKeyValuesReader::GetFileName( int index, char *buf, size_t bufsize )
  167. {
  168. Assert( buf );
  169. buf[ 0 ] = 0;
  170. FileNameHandle_t& handle = m_Dict[ index ].hFile;
  171. g_pFullFileSystem->String( handle, buf, bufsize );
  172. }
  173. bool CCompiledKeyValuesReader::LoadFile( char const *filename )
  174. {
  175. int i;
  176. m_LoadBuffer.Purge();
  177. g_pFullFileSystem->ReadFile( filename, NULL, m_LoadBuffer );
  178. KVHeader_t header;
  179. m_LoadBuffer.Get( &header, sizeof( header ) );
  180. if ( header.fileid != COMPILED_KEYVALUES_ID )
  181. {
  182. return false;
  183. }
  184. if ( header.version != COMPILED_KEYVALUES_VERSION )
  185. {
  186. return false;
  187. }
  188. if ( !m_StringTable.ReadStringTable( header.numStrings, m_LoadBuffer ) )
  189. {
  190. return false;
  191. }
  192. // Now parse the data
  193. int dataCount = m_LoadBuffer.GetInt();
  194. m_Data.EnsureCapacity( dataCount );
  195. for ( i = 0; i < dataCount; ++i )
  196. {
  197. KVInfo_t info;
  198. info.key = m_LoadBuffer.GetShort();
  199. info.value = m_LoadBuffer.GetShort();
  200. info.SetParent( m_LoadBuffer.GetShort() );
  201. info.SetSubTree( m_LoadBuffer.GetChar() == 1 ? true : false );
  202. m_Data.AddToTail( info );
  203. }
  204. int fileCount = m_LoadBuffer.GetInt();
  205. for ( i = 0; i < fileCount; ++i )
  206. {
  207. FileInfo_t kvf;
  208. short fileNameString = m_LoadBuffer.GetShort();
  209. kvf.hFile = g_pFullFileSystem->FindOrAddFileName( m_StringTable.Lookup( fileNameString ) );
  210. kvf.nFirstIndex = m_LoadBuffer.GetShort();
  211. kvf.nCount = m_LoadBuffer.GetShort();
  212. m_Dict.Insert( kvf );
  213. }
  214. return true;
  215. }
  216. struct CreateHelper_t
  217. {
  218. int index;
  219. KeyValues *kv;
  220. KeyValues *tail;
  221. static bool Less( const CreateHelper_t& lhs, const CreateHelper_t& rhs )
  222. {
  223. return lhs.index < rhs.index;
  224. }
  225. };
  226. KeyValues *CCompiledKeyValuesReader::CreateFromData( const FileInfo_t& info )
  227. {
  228. KeyValues *head = new KeyValues( "" );
  229. if ( CreateInPlaceFromData( *head, info ) )
  230. {
  231. return head;
  232. }
  233. else
  234. {
  235. head->deleteThis();
  236. return NULL;
  237. }
  238. }
  239. bool CCompiledKeyValuesReader::CreateInPlaceFromData( KeyValues& head, const FileInfo_t& info )
  240. {
  241. int first = info.nFirstIndex;
  242. int num = info.nCount;
  243. KeyValues *root = NULL;
  244. KeyValues *tail = NULL;
  245. CUtlRBTree< CreateHelper_t, int > helper( 0, 0, CreateHelper_t::Less );
  246. for ( int i = 0; i < num; ++i )
  247. {
  248. int offset = first + i;
  249. KVInfo_t& info = m_Data[ offset ];
  250. if ( info.GetParent() != -1 )
  251. {
  252. CreateHelper_t search;
  253. search.index = info.GetParent();
  254. int idx = helper.Find( search );
  255. if ( idx == helper.InvalidIndex() )
  256. {
  257. return NULL;
  258. }
  259. KeyValues *parent = helper[ idx ].kv;
  260. Assert( parent );
  261. KeyValues *sub = new KeyValues( m_StringTable.Lookup( info.key ) );
  262. if ( !info.IsSubTree() )
  263. {
  264. sub->SetStringValue(m_StringTable.Lookup( info.value ) );
  265. }
  266. if ( !parent->GetFirstSubKey() )
  267. {
  268. parent->AddSubKey( sub );
  269. }
  270. else
  271. {
  272. KeyValues *last = helper[ idx ].tail;
  273. last->SetNextKey( sub );
  274. }
  275. helper[ idx ].tail = sub;
  276. CreateHelper_t insert;
  277. insert.index = offset;
  278. insert.kv = sub;
  279. insert.tail = NULL;
  280. helper.Insert( insert );
  281. }
  282. else
  283. {
  284. if ( !root )
  285. {
  286. root = &head;
  287. root->SetName( m_StringTable.Lookup( info.key ) );
  288. tail = root;
  289. CreateHelper_t insert;
  290. insert.index = offset;
  291. insert.kv = root;
  292. insert.tail = NULL;
  293. helper.Insert( insert );
  294. }
  295. else
  296. {
  297. CreateHelper_t insert;
  298. insert.index = offset;
  299. insert.kv = new KeyValues( m_StringTable.Lookup( info.key ) );
  300. insert.tail = NULL;
  301. helper.Insert( insert );
  302. tail->SetNextKey( insert.kv );
  303. tail = insert.kv;
  304. }
  305. }
  306. }
  307. return true;
  308. }
  309. bool CCompiledKeyValuesReader::InstanceInPlace( KeyValues& head, char const *kvfilename )
  310. {
  311. char sz[ 512 ];
  312. Q_strncpy( sz, kvfilename, sizeof( sz ) );
  313. Q_FixSlashes( sz );
  314. FileInfo_t search;
  315. search.hFile = g_pFullFileSystem->FindOrAddFileName( sz );
  316. int idx = m_Dict.Find( search );
  317. if ( idx == m_Dict.InvalidIndex() )
  318. {
  319. return false;
  320. }
  321. const FileInfo_t& info = m_Dict[ idx ];
  322. return CreateInPlaceFromData( head, info );
  323. }
  324. KeyValues *CCompiledKeyValuesReader::Instance( char const *kvfilename )
  325. {
  326. char sz[ 512 ];
  327. Q_strncpy( sz, kvfilename, sizeof( sz ) );
  328. Q_FixSlashes( sz );
  329. FileInfo_t search;
  330. search.hFile = g_pFullFileSystem->FindOrAddFileName( sz );
  331. int idx = m_Dict.Find( search );
  332. if ( idx == m_Dict.InvalidIndex() )
  333. {
  334. return NULL;
  335. }
  336. const FileInfo_t& info = m_Dict[ idx ];
  337. return CreateFromData( info );
  338. }
  339. bool CCompiledKeyValuesReader::LookupKeyValuesRootKeyName( char const *kvfilename, char *outbuf, size_t bufsize )
  340. {
  341. char sz[ 512 ];
  342. Q_strncpy( sz, kvfilename, sizeof( sz ) );
  343. Q_FixSlashes( sz );
  344. FileInfo_t search;
  345. search.hFile = g_pFullFileSystem->FindOrAddFileName( sz );
  346. int idx = m_Dict.Find( search );
  347. if ( idx == m_Dict.InvalidIndex() )
  348. {
  349. return false;
  350. }
  351. const FileInfo_t& info = m_Dict[ idx ];
  352. Q_strncpy( outbuf, m_StringTable.Lookup( m_Data[ info.nFirstIndex ].key ), bufsize );
  353. return true;
  354. }