ISimpleResourceLoader.cpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "StdInc.h"
  2. #include "ISimpleResourceLoader.h"
  3. #include <zlib.h>
  4. std::pair<ui8*, size_t> ISimpleResourceLoader::decompressFile(ui8 * in, size_t size, size_t realSize)
  5. {
  6. std::pair<ui8*, size_t> retError(nullptr, 0);
  7. if (realSize == 0)
  8. realSize = 16 * 1024;
  9. std::unique_ptr<ui8[]> out(new ui8[realSize]);
  10. const int WBITS = 15;
  11. const int FCHUNK = 50000;
  12. int ret;
  13. z_stream strm;
  14. int lastPosOut = 0;
  15. // Allocate inflate state
  16. strm.zalloc = Z_NULL;
  17. strm.zfree = Z_NULL;
  18. strm.opaque = Z_NULL;
  19. strm.avail_in = 0;
  20. strm.next_in = Z_NULL;
  21. ret = inflateInit2(&strm, WBITS);
  22. if (ret != Z_OK)
  23. return retError;
  24. int chunkNumber = 0;
  25. do
  26. {
  27. if(size < chunkNumber * FCHUNK)
  28. break;
  29. strm.avail_in = std::min<size_t>(FCHUNK, size - chunkNumber * FCHUNK);
  30. if (strm.avail_in == 0)
  31. break;
  32. strm.next_in = in + chunkNumber * FCHUNK;
  33. // Run inflate() on input until output buffer not full
  34. do
  35. {
  36. strm.avail_out = realSize - lastPosOut;
  37. strm.next_out = out.get() + lastPosOut;
  38. ret = inflate(&strm, Z_NO_FLUSH);
  39. bool breakLoop = false;
  40. switch (ret)
  41. {
  42. case Z_STREAM_END:
  43. breakLoop = true;
  44. break;
  45. case Z_NEED_DICT:
  46. ret = Z_DATA_ERROR;
  47. case Z_DATA_ERROR:
  48. inflateEnd(&strm);
  49. return retError;
  50. case Z_MEM_ERROR:
  51. {
  52. //not enough memory. Allocate bigger buffer and try again
  53. realSize *= 2;
  54. std::unique_ptr<ui8[]> newOut(new ui8[realSize]);
  55. std::copy(out.get(), out.get() + strm.total_out, newOut.get());
  56. out.reset(newOut.release());
  57. }
  58. }
  59. if(breakLoop)
  60. break;
  61. lastPosOut = realSize - strm.avail_out;
  62. }
  63. while (strm.avail_out == 0);
  64. ++chunkNumber;
  65. }
  66. while (ret != Z_STREAM_END);
  67. // Clean up and return
  68. while (1)
  69. {
  70. ret = inflateEnd(&strm);
  71. switch (ret)
  72. {
  73. case Z_STREAM_END:
  74. //TODO: trim buffer? may be too time consuming
  75. return std::make_pair(out.release(), realSize - strm.avail_out);
  76. case Z_BUF_ERROR:
  77. {
  78. //not enough memory. Allocate bigger buffer and try again
  79. realSize *= 2;
  80. std::unique_ptr<ui8[]> newOut(new ui8[realSize]);
  81. std::copy(out.get(), out.get() + strm.total_out, newOut.get());
  82. out.reset(newOut.release());
  83. }
  84. default:
  85. return retError;
  86. }
  87. }
  88. }