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.

505 lines
12 KiB

  1. //========= Copyright 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. return;
  74. }
  75. riff = ReadInt();
  76. if ( riff != RIFF_ID )
  77. {
  78. printf( "Not a RIFF File [%s]\n", pFileName );
  79. m_riffSize = 0;
  80. }
  81. else
  82. {
  83. // we store size as size of all chunks
  84. // subtract off the RIFF form type (e.g. 'WAVE', 4 bytes)
  85. m_riffSize = ReadInt() - 4;
  86. m_riffName = ReadInt();
  87. // HACKHACK: LWV files don't obey the RIFF format!!!
  88. // Do this or miss the linguistic chunks at the end. Lame!
  89. // subtract off 12 bytes for (RIFF, size, WAVE)
  90. m_riffSize = m_io.size( m_file ) - 12;
  91. }
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose: Close the file
  95. //-----------------------------------------------------------------------------
  96. InFileRIFF::~InFileRIFF( void )
  97. {
  98. m_io.close( m_file );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: read a 4-byte int out of the stream
  102. // Output : int = read value, default is zero
  103. //-----------------------------------------------------------------------------
  104. int InFileRIFF::ReadInt( void )
  105. {
  106. int tmp = 0;
  107. m_io.read( &tmp, sizeof(int), m_file );
  108. tmp = LittleLong( tmp );
  109. return tmp;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose: Read a block of binary data
  113. // Input : *pOutput - pointer to destination memory
  114. // dataSize - size of block to read
  115. // Output : int - number of bytes read
  116. //-----------------------------------------------------------------------------
  117. int InFileRIFF::ReadData( void *pOutput, int dataSize )
  118. {
  119. int count = m_io.read( pOutput, dataSize, m_file );
  120. return count;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Gets the file position
  124. // Output : int (bytes from start of file)
  125. //-----------------------------------------------------------------------------
  126. int InFileRIFF::PositionGet( void )
  127. {
  128. return m_io.tell( m_file );
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose: Seek to file position
  132. // Input : position - bytes from start of file
  133. //-----------------------------------------------------------------------------
  134. void InFileRIFF::PositionSet( int position )
  135. {
  136. m_io.seek( m_file, position );
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose: Used to write a RIFF format file
  140. //-----------------------------------------------------------------------------
  141. OutFileRIFF::OutFileRIFF( const char *pFileName, IFileWriteBinary &io ) : m_io( io )
  142. {
  143. m_file = m_io.create( pFileName );
  144. if ( !m_file )
  145. return;
  146. int riff = RIFF_ID;
  147. m_io.write( &riff, 4, m_file );
  148. m_riffSize = 0;
  149. m_nNamePos = m_io.tell( m_file );
  150. // Save room for the size and name now
  151. WriteInt( 0 );
  152. // Write out the name
  153. WriteInt( RIFF_WAVE );
  154. m_bUseIncorrectLISETLength = false;
  155. m_nLISETSize = 0;
  156. }
  157. OutFileRIFF::~OutFileRIFF( void )
  158. {
  159. if ( !IsValid() )
  160. return;
  161. unsigned int size = m_io.tell( m_file ) -8;
  162. m_io.seek( m_file, m_nNamePos );
  163. if ( m_bUseIncorrectLISETLength )
  164. {
  165. size = m_nLISETSize - 8;
  166. }
  167. WriteInt( size );
  168. m_io.close( m_file );
  169. }
  170. void OutFileRIFF::HasLISETData( int position )
  171. {
  172. m_bUseIncorrectLISETLength = true;
  173. m_nLISETSize = position;
  174. }
  175. bool OutFileRIFF::WriteInt( int number )
  176. {
  177. if ( !IsValid() )
  178. return false;
  179. m_io.write( &number, sizeof( int ), m_file );
  180. return true;
  181. }
  182. bool OutFileRIFF::WriteData( void *pOutput, int dataSize )
  183. {
  184. if ( !IsValid() )
  185. return false;
  186. m_io.write( pOutput, dataSize, m_file );
  187. return true;
  188. }
  189. int OutFileRIFF::PositionGet( void )
  190. {
  191. if ( !IsValid() )
  192. return 0;
  193. return m_io.tell( m_file );
  194. }
  195. void OutFileRIFF::PositionSet( int position )
  196. {
  197. if ( !IsValid() )
  198. return;
  199. m_io.seek( m_file, position );
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: Create an iterator for the given file
  203. // Input : &riff - riff file
  204. // size - size of file or sub-chunk
  205. //-----------------------------------------------------------------------------
  206. IterateRIFF::IterateRIFF( InFileRIFF &riff, int size )
  207. : m_riff(riff), m_size(size)
  208. {
  209. if ( !m_riff.RIFFSize() )
  210. {
  211. // bad file, just be an empty iterator
  212. ChunkClear();
  213. return;
  214. }
  215. // get the position and parse a chunk
  216. m_start = riff.PositionGet();
  217. ChunkSetup();
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose: Set up a sub-chunk iterator
  221. // Input : &parent - parent iterator
  222. //-----------------------------------------------------------------------------
  223. IterateRIFF::IterateRIFF( IterateRIFF &parent )
  224. : m_riff(parent.m_riff), m_size(parent.ChunkSize())
  225. {
  226. m_start = parent.ChunkFilePosition();
  227. ChunkSetup();
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose: Parse the chunk at the current file position
  231. // This object will iterate over the sub-chunks of this chunk.
  232. // This makes for easy hierarchical parsing
  233. //-----------------------------------------------------------------------------
  234. void IterateRIFF::ChunkSetup( void )
  235. {
  236. m_chunkPosition = m_riff.PositionGet();
  237. m_chunkName = m_riff.ReadInt();
  238. m_chunkSize = m_riff.ReadInt();
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose: clear chunk setup, ChunkAvailable will return false
  242. //-----------------------------------------------------------------------------
  243. void IterateRIFF::ChunkClear( void )
  244. {
  245. m_chunkSize = -1;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose: If there are chunks left to read beyond this one, return true
  249. //-----------------------------------------------------------------------------
  250. bool IterateRIFF::ChunkAvailable( void )
  251. {
  252. if ( m_chunkSize != -1 && m_chunkSize < 0x10000000 )
  253. return true;
  254. return false;
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose: Go to the next chunk in the file, return true if there is one.
  258. //-----------------------------------------------------------------------------
  259. bool IterateRIFF::ChunkNext( void )
  260. {
  261. if ( !ChunkAvailable() )
  262. return false;
  263. int nextPos = m_chunkPosition + 8 + m_chunkSize;
  264. // chunks are aligned
  265. nextPos += m_chunkSize & 1;
  266. if ( nextPos >= (m_start + m_size) )
  267. {
  268. ChunkClear();
  269. return false;
  270. }
  271. m_riff.PositionSet( nextPos );
  272. ChunkSetup();
  273. return ChunkAvailable();
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose: get the chunk FOURCC as an int
  277. // Output : unsigned int
  278. //-----------------------------------------------------------------------------
  279. unsigned int IterateRIFF::ChunkName( void )
  280. {
  281. return m_chunkName;
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose: get the size of this chunk
  285. // Output : unsigned int
  286. //-----------------------------------------------------------------------------
  287. unsigned int IterateRIFF::ChunkSize( void )
  288. {
  289. return m_chunkSize;
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose: Read the entire chunk into a buffer
  293. // Input : *pOutput - dest buffer
  294. // Output : int bytes read
  295. //-----------------------------------------------------------------------------
  296. int IterateRIFF::ChunkRead( void *pOutput )
  297. {
  298. return m_riff.ReadData( pOutput, ChunkSize() );
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: Read a partial chunk (updates file position for subsequent partial reads).
  302. // Input : *pOutput - dest buffer
  303. // dataSize - partial size
  304. // Output : int - bytes read
  305. //-----------------------------------------------------------------------------
  306. int IterateRIFF::ChunkReadPartial( void *pOutput, int dataSize )
  307. {
  308. return m_riff.ReadData( pOutput, dataSize );
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: Read a 4-byte int
  312. // Output : int - read int
  313. //-----------------------------------------------------------------------------
  314. int IterateRIFF::ChunkReadInt( void )
  315. {
  316. return m_riff.ReadInt();
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Used to iterate over an InFileRIFF
  320. //-----------------------------------------------------------------------------
  321. IterateOutputRIFF::IterateOutputRIFF( OutFileRIFF &riff )
  322. : m_riff( riff )
  323. {
  324. if ( !m_riff.IsValid() )
  325. return;
  326. m_start = m_riff.PositionGet();
  327. m_chunkPosition = m_start;
  328. m_chunkStart = -1;
  329. }
  330. IterateOutputRIFF::IterateOutputRIFF( IterateOutputRIFF &parent )
  331. : m_riff(parent.m_riff)
  332. {
  333. m_start = parent.ChunkFilePosition();
  334. m_chunkPosition = m_start;
  335. m_chunkStart = -1;
  336. }
  337. void IterateOutputRIFF::ChunkWrite( unsigned int chunkname, void *pOutput, int size )
  338. {
  339. m_chunkPosition = m_riff.PositionGet();
  340. m_chunkName = chunkname;
  341. m_chunkSize = size;
  342. m_riff.WriteInt( chunkname );
  343. m_riff.WriteInt( size );
  344. m_riff.WriteData( pOutput, size );
  345. m_chunkPosition = m_riff.PositionGet();
  346. m_chunkPosition += m_chunkPosition & 1;
  347. m_riff.PositionSet( m_chunkPosition );
  348. m_chunkStart = -1;
  349. }
  350. void IterateOutputRIFF::ChunkWriteInt( int number )
  351. {
  352. m_riff.WriteInt( number );
  353. }
  354. void IterateOutputRIFF::ChunkWriteData( void *pOutput, int size )
  355. {
  356. m_riff.WriteData( pOutput, size );
  357. }
  358. void IterateOutputRIFF::ChunkFinish( void )
  359. {
  360. Assert( m_chunkStart != -1 );
  361. m_chunkPosition = m_riff.PositionGet();
  362. int size = m_chunkPosition - m_chunkStart - 8;
  363. m_chunkPosition += m_chunkPosition & 1;
  364. m_riff.PositionSet( m_chunkStart + sizeof( int ) );
  365. m_riff.WriteInt( size );
  366. m_riff.PositionSet( m_chunkPosition );
  367. m_chunkStart = -1;
  368. }
  369. void IterateOutputRIFF::ChunkStart( unsigned int chunkname )
  370. {
  371. Assert( m_chunkStart == -1 );
  372. m_chunkStart = m_riff.PositionGet();
  373. m_riff.WriteInt( chunkname );
  374. m_riff.WriteInt( 0 );
  375. }
  376. void IterateOutputRIFF::ChunkSetPosition( int position )
  377. {
  378. m_riff.PositionSet( position );
  379. }
  380. unsigned int IterateOutputRIFF::ChunkGetPosition( void )
  381. {
  382. return m_riff.PositionGet();
  383. }
  384. void IterateOutputRIFF::CopyChunkData( IterateRIFF& input )
  385. {
  386. if ( input.ChunkSize() > 0 )
  387. {
  388. char *buffer = new char[ input.ChunkSize() ];
  389. Assert( buffer );
  390. input.ChunkRead( buffer );
  391. // Don't copy/write the name or size, just the data itself
  392. ChunkWriteData( buffer, input.ChunkSize() );
  393. delete[] buffer;
  394. }
  395. }
  396. void IterateOutputRIFF::SetLISETData( int position )
  397. {
  398. m_riff.HasLISETData( position );
  399. }