deflate.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
  2. //
  3. // This file is part of libzipper.
  4. //
  5. // libzipper is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // libzipper is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with libzipper. If not, see <http://www.gnu.org/licenses/>.
  17. #include "zipper.hh"
  18. #include "deflate.hh"
  19. #include "util.hh"
  20. #include <zlib.h>
  21. #include <cassert>
  22. #include <iostream>
  23. using namespace zipper;
  24. namespace
  25. {
  26. struct DeflateDeleter
  27. {
  28. public:
  29. DeflateDeleter(z_stream* stream) : m_stream(stream) {}
  30. ~DeflateDeleter()
  31. {
  32. deflateEnd(m_stream);
  33. }
  34. private:
  35. z_stream* m_stream;
  36. };
  37. struct InflateDeleter
  38. {
  39. public:
  40. InflateDeleter(z_stream* stream) : m_stream(stream) {}
  41. ~InflateDeleter()
  42. {
  43. inflateEnd(m_stream);
  44. }
  45. private:
  46. z_stream* m_stream;
  47. };
  48. enum Constants
  49. {
  50. ChunkSize = 64*1024,
  51. WindowBits = 15
  52. };
  53. }
  54. void
  55. zipper::deflate(
  56. const Reader& reader,
  57. const WriterPtr& writer,
  58. zsize_t& writeOffset,
  59. zsize_t& uncompressedSize,
  60. zsize_t& compressedSize,
  61. uint32_t& crc)
  62. {
  63. uint8_t inChunk[ChunkSize];
  64. uint8_t outChunk[ChunkSize];
  65. uncompressedSize = 0;
  66. compressedSize = 0;
  67. z_stream stream;
  68. stream.zalloc = NULL;
  69. stream.zfree = NULL;
  70. stream.opaque = NULL;
  71. int zlibErr(
  72. deflateInit2(
  73. &stream,
  74. Z_DEFAULT_COMPRESSION,
  75. Z_DEFLATED,
  76. -WindowBits,
  77. MAX_MEM_LEVEL,
  78. Z_DEFAULT_STRATEGY)
  79. );
  80. assert(zlibErr == Z_OK);
  81. DeflateDeleter deleter(&stream);
  82. stream.next_in = NULL;
  83. stream.avail_in = 0;
  84. bool finished(false);
  85. zsize_t pos(0);
  86. zsize_t end(reader.getSize());
  87. crc = crc32(0, NULL, 0);
  88. while (!finished)
  89. {
  90. if ((stream.avail_in == 0) && (pos < end))
  91. {
  92. stream.avail_in =
  93. std::min(zsize_t(ChunkSize), end - pos);
  94. reader.readData(
  95. pos, stream.avail_in, &inChunk[0]);
  96. stream.next_in = reinterpret_cast<Bytef*>(&inChunk);
  97. pos += stream.avail_in;
  98. uncompressedSize += stream.avail_in;
  99. crc = crc32(crc, stream.next_in, stream.avail_in);
  100. }
  101. stream.next_out = reinterpret_cast<Bytef*>(&outChunk);
  102. stream.avail_out = sizeof(outChunk);
  103. finished = false;
  104. zlibErr = deflate(&stream, (pos < end) ? Z_NO_FLUSH : Z_FINISH);
  105. if (zlibErr == Z_STREAM_END)
  106. {
  107. if (pos < end)
  108. {
  109. assert(!"zlib buffer unexpectedly empty");
  110. std::terminate();
  111. }
  112. finished = true;
  113. }
  114. else if (zlibErr != Z_OK)
  115. {
  116. throw FormatException("Corrupt Data");
  117. }
  118. zsize_t bytesToWrite(sizeof(outChunk) - stream.avail_out);
  119. writer->writeData(writeOffset, bytesToWrite, &outChunk[0]);
  120. writeOffset += bytesToWrite;
  121. compressedSize += bytesToWrite;
  122. }
  123. }
  124. void
  125. zipper::inflate(
  126. const ReaderPtr& reader,
  127. Writer& writer,
  128. zsize_t& readOffset,
  129. zsize_t readEnd,
  130. zsize_t& writeOffset,
  131. uint32_t& crc)
  132. {
  133. uint8_t inChunk[ChunkSize];
  134. uint8_t outChunk[ChunkSize];
  135. z_stream stream;
  136. stream.zalloc = NULL;
  137. stream.zfree = NULL;
  138. stream.opaque = NULL;
  139. int zlibErr(inflateInit2(&stream, -WindowBits));
  140. assert(zlibErr == Z_OK);
  141. InflateDeleter deleter(&stream);
  142. stream.next_in = NULL;
  143. stream.avail_in = 0;
  144. bool finished(false);
  145. zsize_t pos(readOffset);
  146. crc = crc32(0, NULL, 0);
  147. while (!finished)
  148. {
  149. if (stream.avail_in == 0)
  150. {
  151. stream.avail_in = std::min(zsize_t(ChunkSize), readEnd - pos);
  152. if (stream.avail_in == 0)
  153. {
  154. break;
  155. }
  156. reader->readData(pos, stream.avail_in, &inChunk[0]);
  157. stream.next_in = reinterpret_cast<Bytef*>(&inChunk);
  158. pos += stream.avail_in;
  159. }
  160. stream.next_out = reinterpret_cast<Bytef*>(&outChunk);
  161. stream.avail_out = sizeof(outChunk);
  162. zlibErr = inflate(&stream, Z_SYNC_FLUSH);
  163. finished = false;
  164. if (zlibErr == Z_STREAM_END)
  165. {
  166. finished = true;
  167. }
  168. else if (zlibErr != Z_OK)
  169. {
  170. throw FormatException("Corrupt Data");
  171. }
  172. zsize_t bytesToWrite(sizeof(outChunk) - stream.avail_out);
  173. writer.writeData(writeOffset, bytesToWrite, &outChunk[0]);
  174. writeOffset += bytesToWrite;
  175. crc = crc32(crc, &outChunk[0], bytesToWrite);
  176. }
  177. if (!finished)
  178. {
  179. // Ran out of data to process
  180. throw FormatException("Corrupt Data");
  181. }
  182. // We've read data that wasn't consumed!
  183. readOffset = pos - stream.avail_in;
  184. }