| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- /******************************************************************************/
- #define CC4_CHUNK CC4('C','H','N','K')
- /******************************************************************************/
- // WRITER
- /******************************************************************************/
- ChunkWriter::~ChunkWriter()
- {
- endChunk(); // end current chunk if any, but not the list, in case we want to append to it later
- _f=null;
- _chunk_size_pos=0;
- }
- ChunkWriter::ChunkWriter()
- {
- _f=null;
- _chunk_size_pos=0;
- }
- ChunkWriter::ChunkWriter(const_mem_addr File &f) : ChunkWriter() {beginChunkList(f);}
- /******************************************************************************/
- void ChunkWriter::appendChunkList(File &f)
- {
- endChunk(); // end current chunk if any, but not the list, because we're appending it now (if it exists)
- _chunk_size_pos=0;
- _f=&f;
- if(!f.pos())f.putUInt(CC4_CHUNK); // automatically add marker only when the file is at start
- }
- /******************************************************************************/
- void ChunkWriter::beginChunkList(File &f)
- {
- endChunkList(); // end current chunk list if any
- _chunk_size_pos=0;
- _f=&f;
- f.putUInt(CC4_CHUNK); // add chunk marker
- }
- /******************************************************************************/
- File* ChunkWriter::beginChunk(C Str &name, UInt version)
- {
- if(_f)
- {
- endChunk(); // finish current chunk if any
- _f->cmpUIntV(3 ); // internal chunk container version
- _f->putStr (name ); // chunk name
- _f->cmpUIntV(version); // chunk version
- _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
- }
- return _f;
- }
- /******************************************************************************/
- void ChunkWriter::endChunk()
- {
- if(_chunk_size_pos) // we can end a chunk only if we started one
- {
- // update size of last written chunk
- ULong cur_pos=_f->pos(); // remember current position
- _f->pos (_chunk_size_pos);
- _f->putUInt(cur_pos-_chunk_size_pos-SIZE(UInt));
- _f->pos (cur_pos); // restore last position
- _chunk_size_pos=0; // clear chunk size pos as it's now ended
- }
- }
- /******************************************************************************/
- void ChunkWriter::endChunkList()
- {
- if(_f)
- {
- endChunk(); // end current chunk if any
- _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
- _f=null;
- }
- }
- /******************************************************************************/
- // READER
- /******************************************************************************/
- void ChunkReader::zero()
- {
- _ver=0; _next_chunk_pos=0; _full_size=0; _offset_delta=0; _f=null;
- }
- ChunkReader::~ChunkReader() {restore();} // restore in case not all chunks were processed
- ChunkReader:: ChunkReader() {zero ();}
- ChunkReader:: ChunkReader(const_mem_addr File &f) : ChunkReader() {read(f);}
- void ChunkReader::restore()
- {
- if(_f)_f->unlimit(_full_size, _offset_delta); // restore original file values
- }
- /******************************************************************************/
- Bool ChunkReader::read(File &f)
- {
- restore();
- zero();
- _name.clear();
- if(f.getUInt()==CC4_CHUNK)
- {
- T._f =&f;
- T._full_size = f.size();
- T._next_chunk_pos= f.pos (); return true;
- }
- return false;
- }
- /******************************************************************************/
- File* ChunkReader::operator()()
- {
- if(_f)
- {
- restore(); // restore so that we can read the chunk container
- // go to next chunk
- _f->pos(_next_chunk_pos);
- 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
- switch(_f->decUIntV()) // read internal chunk container version
- {
- //default: _f->_ok=false; break; // unsupported version
- case 3:
- {
- // load chunk info
- _f->getStr (_name);
- _f->decUIntV(_ver );
- UInt chunk_size=_f->getUInt();
- if(_f->ok())
- {
- _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
- _f->limit(_full_size, _offset_delta, chunk_size);
- return _f;
- }
- }break;
- case 2:
- {
- // load chunk info
- _f->_getStr2 (_name);
- _f-> decUIntV(_ver );
- UInt chunk_size=_f->getUInt();
- if(_f->ok())
- {
- _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
- _f->limit(_full_size, _offset_delta, chunk_size);
- return _f;
- }
- }break;
- case 1:
- {
- // load chunk info
- _f->_getStr(_name);
- (*_f)>>_ver;
- UInt chunk_size=_f->getUInt();
- if(_f->ok())
- {
- _next_chunk_pos=_f->pos()+chunk_size; // current position + chunk size
- _f->limit(_full_size, _offset_delta, chunk_size);
- return _f;
- }
- }break;
- case 0: break; // end of list
- }
- }
- _name.clear();
- _ver =0;
- return null;
- }
- /******************************************************************************/
- }
- /******************************************************************************/
|