CLodStream.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include "StdInc.h"
  2. #include "CLodStream.h"
  3. #include "CLodArchiveLoader.h"
  4. #include "CFileInputStream.h"
  5. #include <zlib.h>
  6. CLodStream::CLodStream()
  7. {
  8. }
  9. CLodStream::CLodStream(const CLodArchiveLoader * loader, const std::string & resourceName)
  10. {
  11. open(loader, resourceName);
  12. }
  13. void CLodStream::open(const CLodArchiveLoader * loader, const std::string & resourceName)
  14. {
  15. close();
  16. const ArchiveEntry * archiveEntry = loader->getArchiveEntry(resourceName);
  17. if(archiveEntry == nullptr)
  18. {
  19. throw std::runtime_error("Archive entry " + resourceName + " wasn't found in the archive " + loader->getOrigin());
  20. }
  21. this->archiveEntry = archiveEntry;
  22. // Open the archive and set the read pointer to the correct position
  23. fileStream.open(loader->getOrigin());
  24. fileStream.seek(this->archiveEntry->offset);
  25. }
  26. si64 CLodStream::read(ui8 * data, si64 size)
  27. {
  28. // Test whether the file has to be decompressed
  29. if(archiveEntry->size == 0)
  30. {
  31. // No decompression
  32. return fileStream.read(data, size);
  33. }
  34. else
  35. {
  36. // Decompress file
  37. // We can't decompress partially, so the size of the output buffer has to be minimum the
  38. // size of the decompressed lod entry. If this isn't the case, it is a programming fault.
  39. assert(size >= archiveEntry->realSize);
  40. // Read the compressed data into a buffer
  41. ui8 * comp = new ui8[archiveEntry->size];
  42. fileStream.read(comp, archiveEntry->size);
  43. // Decompress the file
  44. if(!decompressFile(comp, archiveEntry->size, archiveEntry->realSize, data))
  45. {
  46. throw std::runtime_error("File decompression wasn't successful. Resource name: " + archiveEntry->name);
  47. }
  48. delete[] comp;
  49. // We're reading the total size always
  50. return archiveEntry->realSize;
  51. }
  52. }
  53. bool CLodStream::decompressFile(ui8 * in, int size, int realSize, ui8 * out)
  54. {
  55. const int WBITS = 15;
  56. const int FCHUNK = 50000;
  57. int ret;
  58. unsigned have;
  59. z_stream strm;
  60. int latPosOut = 0;
  61. // Allocate inflate state
  62. strm.zalloc = Z_NULL;
  63. strm.zfree = Z_NULL;
  64. strm.opaque = Z_NULL;
  65. strm.avail_in = 0;
  66. strm.next_in = Z_NULL;
  67. ret = inflateInit2(&strm, WBITS);
  68. if (ret != Z_OK)
  69. return false;
  70. int chunkNumber = 0;
  71. do
  72. {
  73. if(size < chunkNumber * FCHUNK)
  74. break;
  75. strm.avail_in = std::min(FCHUNK, size - chunkNumber * FCHUNK);
  76. if (strm.avail_in == 0)
  77. break;
  78. strm.next_in = in + chunkNumber * FCHUNK;
  79. // Run inflate() on input until output buffer not full
  80. do
  81. {
  82. strm.avail_out = realSize - latPosOut;
  83. strm.next_out = out + latPosOut;
  84. ret = inflate(&strm, Z_NO_FLUSH);
  85. bool breakLoop = false;
  86. switch (ret)
  87. {
  88. case Z_STREAM_END:
  89. breakLoop = true;
  90. break;
  91. case Z_NEED_DICT:
  92. ret = Z_DATA_ERROR;
  93. case Z_DATA_ERROR:
  94. case Z_MEM_ERROR:
  95. (void)inflateEnd(&strm);
  96. return false;
  97. }
  98. if(breakLoop)
  99. break;
  100. have = realSize - latPosOut - strm.avail_out;
  101. latPosOut += have;
  102. } while (strm.avail_out == 0);
  103. ++chunkNumber;
  104. } while (ret != Z_STREAM_END);
  105. // Clean up and return
  106. (void)inflateEnd(&strm);
  107. return ret == Z_STREAM_END ? true : false;
  108. }
  109. si64 CLodStream::seek(si64 position)
  110. {
  111. return fileStream.seek(archiveEntry->offset + position);
  112. }
  113. si64 CLodStream::tell()
  114. {
  115. return fileStream.tell() - archiveEntry->offset;
  116. }
  117. si64 CLodStream::skip(si64 delta)
  118. {
  119. return fileStream.skip(delta);
  120. }
  121. si64 CLodStream::getSize()
  122. {
  123. return archiveEntry->realSize;
  124. }
  125. void CLodStream::close()
  126. {
  127. fileStream.close();
  128. }