123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- #include "StdInc.h"
- #include "CLodStream.h"
- #include "CLodArchiveLoader.h"
- #include "CFileInputStream.h"
- #include <zlib.h>
- CLodStream::CLodStream()
- {
- }
- CLodStream::CLodStream(const CLodArchiveLoader * loader, const std::string & resourceName)
- {
- open(loader, resourceName);
- }
- void CLodStream::open(const CLodArchiveLoader * loader, const std::string & resourceName)
- {
- close();
- const ArchiveEntry * archiveEntry = loader->getArchiveEntry(resourceName);
- if(archiveEntry == nullptr)
- {
- throw std::runtime_error("Archive entry " + resourceName + " wasn't found in the archive " + loader->getOrigin());
- }
- this->archiveEntry = archiveEntry;
- // Open the archive and set the read pointer to the correct position
- fileStream.open(loader->getOrigin());
- fileStream.seek(this->archiveEntry->offset);
- }
- si64 CLodStream::read(ui8 * data, si64 size)
- {
- // Test whether the file has to be decompressed
- if(archiveEntry->size == 0)
- {
- // No decompression
- return fileStream.read(data, size);
- }
- else
- {
- // Decompress file
- // We can't decompress partially, so the size of the output buffer has to be minimum the
- // size of the decompressed lod entry. If this isn't the case, it is a programming fault.
- assert(size >= archiveEntry->realSize);
- // Read the compressed data into a buffer
- ui8 * comp = new ui8[archiveEntry->size];
- fileStream.read(comp, archiveEntry->size);
- // Decompress the file
- if(!decompressFile(comp, archiveEntry->size, archiveEntry->realSize, data))
- {
- throw std::runtime_error("File decompression wasn't successful. Resource name: " + archiveEntry->name);
- }
- delete[] comp;
- // We're reading the total size always
- return archiveEntry->realSize;
- }
- }
- bool CLodStream::decompressFile(ui8 * in, int size, int realSize, ui8 * out)
- {
- const int WBITS = 15;
- const int FCHUNK = 50000;
- int ret;
- unsigned have;
- z_stream strm;
- int latPosOut = 0;
- // Allocate inflate state
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
- ret = inflateInit2(&strm, WBITS);
- if (ret != Z_OK)
- return false;
- int chunkNumber = 0;
- do
- {
- if(size < chunkNumber * FCHUNK)
- break;
- strm.avail_in = std::min(FCHUNK, size - chunkNumber * FCHUNK);
- if (strm.avail_in == 0)
- break;
- strm.next_in = in + chunkNumber * FCHUNK;
- // Run inflate() on input until output buffer not full
- do
- {
- strm.avail_out = realSize - latPosOut;
- strm.next_out = out + latPosOut;
- ret = inflate(&strm, Z_NO_FLUSH);
- bool breakLoop = false;
- switch (ret)
- {
- case Z_STREAM_END:
- breakLoop = true;
- break;
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR;
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- (void)inflateEnd(&strm);
- return false;
- }
- if(breakLoop)
- break;
- have = realSize - latPosOut - strm.avail_out;
- latPosOut += have;
- } while (strm.avail_out == 0);
- ++chunkNumber;
- } while (ret != Z_STREAM_END);
- // Clean up and return
- (void)inflateEnd(&strm);
- return ret == Z_STREAM_END ? true : false;
- }
- si64 CLodStream::seek(si64 position)
- {
- return fileStream.seek(archiveEntry->offset + position);
- }
- si64 CLodStream::tell()
- {
- return fileStream.tell() - archiveEntry->offset;
- }
- si64 CLodStream::skip(si64 delta)
- {
- return fileStream.skip(delta);
- }
- si64 CLodStream::getSize()
- {
- return archiveEntry->realSize;
- }
- void CLodStream::close()
- {
- fileStream.close();
- }
|