BsCompression.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Utility/BsCompression.h"
  4. #include "FileSystem/BsDataStream.h"
  5. // Third party
  6. #include "snappy.h"
  7. #include "snappy-sinksource.h"
  8. #include "Debug/BsDebug.h"
  9. namespace bs
  10. {
  11. /** Source accepting a data stream. Used for Snappy compression library. */
  12. class DataStreamSource : public snappy::Source
  13. {
  14. public:
  15. DataStreamSource(const SPtr<DataStream>& stream)
  16. : mStream(stream), mReadBuffer(nullptr), mReadBufferContentSize(0), mBufferOffset(0)
  17. {
  18. mRemaining = mStream->size() - mStream->tell();
  19. if (mStream->isFile())
  20. mReadBuffer = (char*)bs_alloc(2048);
  21. }
  22. virtual ~DataStreamSource()
  23. {
  24. if (mReadBuffer != nullptr)
  25. bs_free(mReadBuffer);
  26. }
  27. size_t Available() const override
  28. {
  29. return mRemaining;
  30. }
  31. const char* Peek(size_t* len) override
  32. {
  33. if (!mStream->isFile())
  34. {
  35. SPtr<MemoryDataStream> memStream = std::static_pointer_cast<MemoryDataStream>(mStream);
  36. *len = Available();
  37. return (char*)memStream->getPtr() + mBufferOffset;
  38. }
  39. else
  40. {
  41. while (mBufferOffset >= mReadBufferContentSize)
  42. {
  43. mBufferOffset -= mReadBufferContentSize;
  44. mReadBufferContentSize = mStream->read(mReadBuffer, 2048);
  45. if (mReadBufferContentSize == 0)
  46. break;
  47. }
  48. *len = mReadBufferContentSize - mBufferOffset;
  49. return (char*)(mReadBuffer + mBufferOffset);
  50. }
  51. }
  52. void Skip(size_t n) override
  53. {
  54. mBufferOffset += n;
  55. mRemaining -= n;
  56. }
  57. private:
  58. SPtr<DataStream> mStream;
  59. // File streams only
  60. char* mReadBuffer;
  61. size_t mReadBufferContentSize;
  62. size_t mRemaining;
  63. size_t mBufferOffset;
  64. };
  65. /** Sink (destination) accepting a data stream. Used for Snappy compression library. */
  66. class DataStreamSink : public snappy::Sink
  67. {
  68. struct BufferPiece
  69. {
  70. char* buffer;
  71. size_t size;
  72. };
  73. public:
  74. DataStreamSink() { }
  75. virtual ~DataStreamSink()
  76. {
  77. for (auto& entry : mBufferPieces)
  78. bs_free(entry.buffer);
  79. }
  80. void Append(const char* data, size_t n) override
  81. {
  82. if(mBufferPieces.size() == 0 || mBufferPieces.back().buffer != data)
  83. {
  84. BufferPiece piece;
  85. piece.buffer = (char*)bs_alloc((UINT32)n);
  86. piece.size = n;
  87. memcpy(piece.buffer, data, n);
  88. mBufferPieces.push_back(piece);
  89. }
  90. else
  91. {
  92. BufferPiece& piece = mBufferPieces.back();
  93. assert(piece.buffer == data);
  94. piece.size = n;
  95. }
  96. }
  97. char* GetAppendBuffer(size_t len, char* scratch) override
  98. {
  99. BufferPiece piece;
  100. piece.buffer = (char*)bs_alloc((UINT32)len);
  101. piece.size = 0;
  102. mBufferPieces.push_back(piece);
  103. return piece.buffer;
  104. }
  105. char* GetAppendBufferVariable(size_t min_size, size_t desired_size_hint, char* scratch, size_t scratch_size,
  106. size_t* allocated_size) override
  107. {
  108. BufferPiece piece;
  109. piece.buffer = (char*)bs_alloc((UINT32)desired_size_hint);
  110. piece.size = 0;
  111. mBufferPieces.push_back(piece);
  112. *allocated_size = desired_size_hint;
  113. return piece.buffer;
  114. }
  115. void AppendAndTakeOwnership(char* bytes, size_t n, void(*deleter)(void*, const char*, size_t),
  116. void *deleter_arg) override
  117. {
  118. BufferPiece& piece = mBufferPieces.back();
  119. if (piece.buffer != bytes)
  120. {
  121. memcpy(piece.buffer, bytes, n);
  122. (*deleter)(deleter_arg, bytes, n);
  123. }
  124. piece.size = n;
  125. }
  126. SPtr<MemoryDataStream> GetOutput()
  127. {
  128. size_t totalSize = 0;
  129. for (auto& entry : mBufferPieces)
  130. totalSize += entry.size;
  131. SPtr<MemoryDataStream> ds = bs_shared_ptr_new<MemoryDataStream>(totalSize);
  132. for (auto& entry : mBufferPieces)
  133. ds->write(entry.buffer, entry.size);
  134. ds->seek(0);
  135. return ds;
  136. }
  137. private:
  138. Vector<BufferPiece> mBufferPieces;
  139. };
  140. SPtr<MemoryDataStream> Compression::compress(SPtr<DataStream>& input)
  141. {
  142. DataStreamSource src(input);
  143. DataStreamSink dst;
  144. size_t bytesWritten = snappy::Compress(&src, &dst);
  145. SPtr<MemoryDataStream> output = dst.GetOutput();
  146. assert(output->size() == bytesWritten);
  147. return output;
  148. }
  149. SPtr<MemoryDataStream> Compression::decompress(SPtr<DataStream>& input)
  150. {
  151. DataStreamSource src(input);
  152. DataStreamSink dst;
  153. if (!snappy::Uncompress(&src, &dst))
  154. {
  155. LOGERR("Decompression failed, corrupt data.");
  156. return nullptr;
  157. }
  158. return dst.GetOutput();
  159. }
  160. }