Chunk.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define CC4_CHUNK CC4('C','H','N','K')
  6. /******************************************************************************/
  7. // WRITER
  8. /******************************************************************************/
  9. ChunkWriter::~ChunkWriter()
  10. {
  11. endChunk(); // end current chunk if any, but not the list, in case we want to append to it later
  12. _f=null;
  13. _chunk_size_pos=0;
  14. }
  15. ChunkWriter::ChunkWriter()
  16. {
  17. _f=null;
  18. _chunk_size_pos=0;
  19. }
  20. ChunkWriter::ChunkWriter(const_mem_addr File &f) : ChunkWriter() {beginChunkList(f);}
  21. /******************************************************************************/
  22. void ChunkWriter::appendChunkList(File &f)
  23. {
  24. endChunk(); // end current chunk if any, but not the list, because we're appending it now (if it exists)
  25. _chunk_size_pos=0;
  26. _f=&f;
  27. if(!f.pos())f.putUInt(CC4_CHUNK); // automatically add marker only when the file is at start
  28. }
  29. /******************************************************************************/
  30. void ChunkWriter::beginChunkList(File &f)
  31. {
  32. endChunkList(); // end current chunk list if any
  33. _chunk_size_pos=0;
  34. _f=&f;
  35. f.putUInt(CC4_CHUNK); // add chunk marker
  36. }
  37. /******************************************************************************/
  38. File* ChunkWriter::beginChunk(C Str &name, UInt version)
  39. {
  40. if(_f)
  41. {
  42. endChunk(); // finish current chunk if any
  43. _f->cmpUIntV(3 ); // internal chunk container version
  44. _f->putStr (name ); // chunk name
  45. _f->cmpUIntV(version); // chunk version
  46. _chunk_size_pos=_f->pos(); _f->putUInt (0 ); // remember position of chunk size just before writing it, to update it later, keep as fixed UInt size because we don't know it yet
  47. }
  48. return _f;
  49. }
  50. /******************************************************************************/
  51. void ChunkWriter::endChunk()
  52. {
  53. if(_chunk_size_pos) // we can end a chunk only if we started one
  54. {
  55. // update size of last written chunk
  56. ULong cur_pos=_f->pos(); // remember current position
  57. _f->pos (_chunk_size_pos);
  58. _f->putUInt(cur_pos-_chunk_size_pos-SIZE(UInt));
  59. _f->pos (cur_pos); // restore last position
  60. _chunk_size_pos=0; // clear chunk size pos as it's now ended
  61. }
  62. }
  63. /******************************************************************************/
  64. void ChunkWriter::endChunkList()
  65. {
  66. if(_f)
  67. {
  68. endChunk(); // end current chunk if any
  69. _f->cmpUIntV(0); // end of list, normally this is the place for chunk container version, setting 0 means that there are no more chunks, this is also compatible with 0 always being returned at the end of file
  70. _f=null;
  71. }
  72. }
  73. /******************************************************************************/
  74. // READER
  75. /******************************************************************************/
  76. void ChunkReader::zero()
  77. {
  78. _ver=0; _next_chunk_pos=0; _full_size=0; _offset_delta=0; _f=null;
  79. }
  80. ChunkReader::~ChunkReader() {restore();} // restore in case not all chunks were processed
  81. ChunkReader:: ChunkReader() {zero ();}
  82. ChunkReader:: ChunkReader(const_mem_addr File &f) : ChunkReader() {read(f);}
  83. void ChunkReader::restore()
  84. {
  85. if(_f)_f->unlimit(_full_size, _offset_delta); // restore original file values
  86. }
  87. /******************************************************************************/
  88. Bool ChunkReader::read(File &f)
  89. {
  90. restore();
  91. zero();
  92. _name.clear();
  93. if(f.getUInt()==CC4_CHUNK)
  94. {
  95. T._f =&f;
  96. T._full_size = f.size();
  97. T._next_chunk_pos= f.pos (); return true;
  98. }
  99. return false;
  100. }
  101. /******************************************************************************/
  102. File* ChunkReader::operator()()
  103. {
  104. if(_f)
  105. {
  106. restore(); // restore so that we can read the chunk container
  107. // go to next chunk
  108. _f->pos(_next_chunk_pos);
  109. if(!_f->end()) // don't read more at the end of file because that would trigger an error (f.ok=false), this is because chunks are normally processed in this way: "for(ChunkReader cr(f); File *f=cr(); )", keep reading as long as they exist
  110. switch(_f->decUIntV()) // read internal chunk container version
  111. {
  112. //default: _f->_ok=false; break; // unsupported version
  113. case 3:
  114. {
  115. // load chunk info
  116. _f->getStr (_name);
  117. _f->decUIntV(_ver );
  118. UInt chunk_size=_f->getUInt();
  119. if(_f->ok())
  120. {
  121. _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
  122. _f->limit(_full_size, _offset_delta, chunk_size);
  123. return _f;
  124. }
  125. }break;
  126. case 2:
  127. {
  128. // load chunk info
  129. _f->_getStr2 (_name);
  130. _f-> decUIntV(_ver );
  131. UInt chunk_size=_f->getUInt();
  132. if(_f->ok())
  133. {
  134. _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
  135. _f->limit(_full_size, _offset_delta, chunk_size);
  136. return _f;
  137. }
  138. }break;
  139. case 1:
  140. {
  141. // load chunk info
  142. _f->_getStr(_name);
  143. (*_f)>>_ver;
  144. UInt chunk_size=_f->getUInt();
  145. if(_f->ok())
  146. {
  147. _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
  148. _f->limit(_full_size, _offset_delta, chunk_size);
  149. return _f;
  150. }
  151. }break;
  152. case 0: break; // end of list
  153. }
  154. }
  155. _name.clear();
  156. _ver =0;
  157. return null;
  158. }
  159. /******************************************************************************/
  160. }
  161. /******************************************************************************/