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.

508 lines
12 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // Avoid these warnings:
  9. #pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated
  10. #pragma warning(disable : 4514) // warning C4514: 'RIFFName' : unreferenced inline function has been removed
  11. #include "riff.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include "tier0/dbg.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #if 0
  18. //-----------------------------------------------------------------------------
  19. // Purpose: Test code that implements the interface on stdio
  20. //-----------------------------------------------------------------------------
  21. class StdIOReadBinary : public IFileReadBinary
  22. {
  23. public:
  24. int open( const char *pFileName )
  25. {
  26. return (int)fopen( pFileName, "rb" );
  27. }
  28. int read( void *pOutput, int size, int file )
  29. {
  30. FILE *fp = (FILE *)file;
  31. return fread( pOutput, size, 1, fp );
  32. }
  33. void seek( int file, int pos )
  34. {
  35. fseek( (FILE *)file, pos, SEEK_SET );
  36. }
  37. unsigned int tell( int file )
  38. {
  39. return ftell( (FILE *)file );
  40. }
  41. unsigned int size( int file )
  42. {
  43. FILE *fp = (FILE *)file;
  44. if ( !fp )
  45. return 0;
  46. unsigned int pos = ftell( fp );
  47. fseek( fp, 0, SEEK_END );
  48. unsigned int size = ftell( fp );
  49. fseek( fp, pos, SEEK_SET );
  50. return size;
  51. }
  52. void close( int file )
  53. {
  54. FILE *fp = (FILE *)file;
  55. fclose( fp );
  56. }
  57. };
  58. #endif
  59. #define RIFF_ID MAKEID('R','I','F','F')
  60. //-----------------------------------------------------------------------------
  61. // Purpose: Opens a RIFF file using the given I/O mechanism
  62. // Input : *pFileName
  63. // &io - I/O interface
  64. //-----------------------------------------------------------------------------
  65. InFileRIFF::InFileRIFF( const char *pFileName, IFileReadBinary &io ) : m_io(io)
  66. {
  67. m_file = m_io.open( pFileName );
  68. int riff = 0;
  69. if ( !m_file )
  70. {
  71. m_riffSize = 0;
  72. m_riffName = 0;
  73. m_nFileSize = 0;
  74. return;
  75. }
  76. m_nFileSize = m_io.size( m_file );
  77. riff = ReadInt();
  78. if ( riff != RIFF_ID )
  79. {
  80. printf( "Not a RIFF File [%s]\n", pFileName );
  81. m_riffSize = 0;
  82. }
  83. else
  84. {
  85. // we store size as size of all chunks
  86. // subtract off the RIFF form type (e.g. 'WAVE', 4 bytes)
  87. m_riffSize = ReadInt() - 4;
  88. m_riffName = ReadInt();
  89. // HACKHACK: LWV files don't obey the RIFF format!!!
  90. // Do this or miss the linguistic chunks at the end. Lame!
  91. // subtract off 12 bytes for (RIFF, size, WAVE)
  92. m_riffSize = m_nFileSize - 12;
  93. }
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Close the file
  97. //-----------------------------------------------------------------------------
  98. InFileRIFF::~InFileRIFF( void )
  99. {
  100. m_io.close( m_file );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose: read a 4-byte int out of the stream
  104. // Output : int = read value, default is zero
  105. //-----------------------------------------------------------------------------
  106. int InFileRIFF::ReadInt( void )
  107. {
  108. int tmp = 0;
  109. m_io.read( &tmp, sizeof(int), m_file );
  110. tmp = LittleLong( tmp );
  111. return tmp;
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: Read a block of binary data
  115. // Input : *pOutput - pointer to destination memory
  116. // dataSize - size of block to read
  117. // Output : int - number of bytes read
  118. //-----------------------------------------------------------------------------
  119. int InFileRIFF::ReadData( void *pOutput, int dataSize )
  120. {
  121. int count = m_io.read( pOutput, dataSize, m_file );
  122. return count;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose: Gets the file position
  126. // Output : int (bytes from start of file)
  127. //-----------------------------------------------------------------------------
  128. int InFileRIFF::PositionGet( void )
  129. {
  130. return m_io.tell( m_file );
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose: Seek to file position
  134. // Input : position - bytes from start of file
  135. //-----------------------------------------------------------------------------
  136. void InFileRIFF::PositionSet( int position )
  137. {
  138. m_io.seek( m_file, position );
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Used to write a RIFF format file
  142. //-----------------------------------------------------------------------------
  143. OutFileRIFF::OutFileRIFF( const char *pFileName, IFileWriteBinary &io ) : m_io( io )
  144. {
  145. m_file = m_io.create( pFileName );
  146. if ( !m_file )
  147. return;
  148. int riff = RIFF_ID;
  149. m_io.write( &riff, 4, m_file );
  150. m_riffSize = 0;
  151. m_nNamePos = m_io.tell( m_file );
  152. // Save room for the size and name now
  153. WriteInt( 0 );
  154. // Write out the name
  155. WriteInt( RIFF_WAVE );
  156. m_bUseIncorrectLISETLength = false;
  157. m_nLISETSize = 0;
  158. }
  159. OutFileRIFF::~OutFileRIFF( void )
  160. {
  161. if ( !IsValid() )
  162. return;
  163. unsigned int size = m_io.tell( m_file ) -8;
  164. m_io.seek( m_file, m_nNamePos );
  165. if ( m_bUseIncorrectLISETLength )
  166. {
  167. size = m_nLISETSize - 8;
  168. }
  169. WriteInt( size );
  170. m_io.close( m_file );
  171. }
  172. void OutFileRIFF::HasLISETData( int position )
  173. {
  174. m_bUseIncorrectLISETLength = true;
  175. m_nLISETSize = position;
  176. }
  177. bool OutFileRIFF::WriteInt( int number )
  178. {
  179. if ( !IsValid() )
  180. return false;
  181. m_io.write( &number, sizeof( int ), m_file );
  182. return true;
  183. }
  184. bool OutFileRIFF::WriteData( void *pOutput, int dataSize )
  185. {
  186. if ( !IsValid() )
  187. return false;
  188. m_io.write( pOutput, dataSize, m_file );
  189. return true;
  190. }
  191. int OutFileRIFF::PositionGet( void )
  192. {
  193. if ( !IsValid() )
  194. return 0;
  195. return m_io.tell( m_file );
  196. }
  197. void OutFileRIFF::PositionSet( int position )
  198. {
  199. if ( !IsValid() )
  200. return;
  201. m_io.seek( m_file, position );
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose: Create an iterator for the given file
  205. // Input : &riff - riff file
  206. // size - size of file or sub-chunk
  207. //-----------------------------------------------------------------------------
  208. IterateRIFF::IterateRIFF( InFileRIFF &riff, int size )
  209. : m_riff(riff), m_size(size)
  210. {
  211. if ( !m_riff.RIFFSize() )
  212. {
  213. // bad file, just be an empty iterator
  214. ChunkClear();
  215. return;
  216. }
  217. // get the position and parse a chunk
  218. m_start = riff.PositionGet();
  219. ChunkSetup();
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose: Set up a sub-chunk iterator
  223. // Input : &parent - parent iterator
  224. //-----------------------------------------------------------------------------
  225. IterateRIFF::IterateRIFF( IterateRIFF &parent )
  226. : m_riff(parent.m_riff), m_size(parent.ChunkSize())
  227. {
  228. m_start = parent.ChunkFilePosition();
  229. ChunkSetup();
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: Parse the chunk at the current file position
  233. // This object will iterate over the sub-chunks of this chunk.
  234. // This makes for easy hierarchical parsing
  235. //-----------------------------------------------------------------------------
  236. void IterateRIFF::ChunkSetup( void )
  237. {
  238. m_chunkPosition = m_riff.PositionGet();
  239. m_chunkName = m_riff.ReadInt();
  240. m_chunkSize = m_riff.ReadInt();
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose: clear chunk setup, ChunkAvailable will return false
  244. //-----------------------------------------------------------------------------
  245. void IterateRIFF::ChunkClear( void )
  246. {
  247. m_chunkSize = -1;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: If there are chunks left to read beyond this one, return true
  251. //-----------------------------------------------------------------------------
  252. bool IterateRIFF::ChunkAvailable( void )
  253. {
  254. if ( m_chunkSize != -1 && m_chunkSize < 0x10000000 )
  255. return true;
  256. return false;
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose: Go to the next chunk in the file, return true if there is one.
  260. //-----------------------------------------------------------------------------
  261. bool IterateRIFF::ChunkNext( void )
  262. {
  263. if ( !ChunkAvailable() )
  264. return false;
  265. int nextPos = m_chunkPosition + 8 + m_chunkSize;
  266. // chunks are aligned
  267. nextPos += m_chunkSize & 1;
  268. if ( nextPos >= (m_start + m_size) )
  269. {
  270. ChunkClear();
  271. return false;
  272. }
  273. m_riff.PositionSet( nextPos );
  274. ChunkSetup();
  275. return ChunkAvailable();
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: get the chunk FOURCC as an int
  279. // Output : unsigned int
  280. //-----------------------------------------------------------------------------
  281. unsigned int IterateRIFF::ChunkName( void )
  282. {
  283. return m_chunkName;
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose: get the size of this chunk
  287. // Output : unsigned int
  288. //-----------------------------------------------------------------------------
  289. unsigned int IterateRIFF::ChunkSize( void )
  290. {
  291. return m_chunkSize;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Purpose: Read the entire chunk into a buffer
  295. // Input : *pOutput - dest buffer
  296. // Output : int bytes read
  297. //-----------------------------------------------------------------------------
  298. int IterateRIFF::ChunkRead( void *pOutput )
  299. {
  300. return m_riff.ReadData( pOutput, ChunkSize() );
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Purpose: Read a partial chunk (updates file position for subsequent partial reads).
  304. // Input : *pOutput - dest buffer
  305. // dataSize - partial size
  306. // Output : int - bytes read
  307. //-----------------------------------------------------------------------------
  308. int IterateRIFF::ChunkReadPartial( void *pOutput, int dataSize )
  309. {
  310. return m_riff.ReadData( pOutput, dataSize );
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose: Read a 4-byte int
  314. // Output : int - read int
  315. //-----------------------------------------------------------------------------
  316. int IterateRIFF::ChunkReadInt( void )
  317. {
  318. return m_riff.ReadInt();
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: Used to iterate over an InFileRIFF
  322. //-----------------------------------------------------------------------------
  323. IterateOutputRIFF::IterateOutputRIFF( OutFileRIFF &riff )
  324. : m_riff( riff )
  325. {
  326. if ( !m_riff.IsValid() )
  327. return;
  328. m_start = m_riff.PositionGet();
  329. m_chunkPosition = m_start;
  330. m_chunkStart = -1;
  331. }
  332. IterateOutputRIFF::IterateOutputRIFF( IterateOutputRIFF &parent )
  333. : m_riff(parent.m_riff)
  334. {
  335. m_start = parent.ChunkFilePosition();
  336. m_chunkPosition = m_start;
  337. m_chunkStart = -1;
  338. }
  339. void IterateOutputRIFF::ChunkWrite( unsigned int chunkname, void *pOutput, int size )
  340. {
  341. m_chunkPosition = m_riff.PositionGet();
  342. m_chunkName = chunkname;
  343. m_chunkSize = size;
  344. m_riff.WriteInt( chunkname );
  345. m_riff.WriteInt( size );
  346. m_riff.WriteData( pOutput, size );
  347. m_chunkPosition = m_riff.PositionGet();
  348. m_chunkPosition += m_chunkPosition & 1;
  349. m_riff.PositionSet( m_chunkPosition );
  350. m_chunkStart = -1;
  351. }
  352. void IterateOutputRIFF::ChunkWriteInt( int number )
  353. {
  354. m_riff.WriteInt( number );
  355. }
  356. void IterateOutputRIFF::ChunkWriteData( void *pOutput, int size )
  357. {
  358. m_riff.WriteData( pOutput, size );
  359. }
  360. void IterateOutputRIFF::ChunkFinish( void )
  361. {
  362. Assert( m_chunkStart != -1 );
  363. m_chunkPosition = m_riff.PositionGet();
  364. int size = m_chunkPosition - m_chunkStart - 8;
  365. m_chunkPosition += m_chunkPosition & 1;
  366. m_riff.PositionSet( m_chunkStart + sizeof( int ) );
  367. m_riff.WriteInt( size );
  368. m_riff.PositionSet( m_chunkPosition );
  369. m_chunkStart = -1;
  370. }
  371. void IterateOutputRIFF::ChunkStart( unsigned int chunkname )
  372. {
  373. Assert( m_chunkStart == -1 );
  374. m_chunkStart = m_riff.PositionGet();
  375. m_riff.WriteInt( chunkname );
  376. m_riff.WriteInt( 0 );
  377. }
  378. void IterateOutputRIFF::ChunkSetPosition( int position )
  379. {
  380. m_riff.PositionSet( position );
  381. }
  382. unsigned int IterateOutputRIFF::ChunkGetPosition( void )
  383. {
  384. return m_riff.PositionGet();
  385. }
  386. void IterateOutputRIFF::CopyChunkData( IterateRIFF& input )
  387. {
  388. if ( input.ChunkSize() > 0 )
  389. {
  390. char *buffer = new char[ input.ChunkSize() ];
  391. Assert( buffer );
  392. input.ChunkRead( buffer );
  393. // Don't copy/write the name or size, just the data itself
  394. ChunkWriteData( buffer, input.ChunkSize() );
  395. delete[] buffer;
  396. }
  397. }
  398. void IterateOutputRIFF::SetLISETData( int position )
  399. {
  400. m_riff.HasLISETData( position );
  401. }