Gzip.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (c) 2013-2017, The PurpleI2P Project
  3. *
  4. * This file is part of Purple i2pd project and licensed under BSD3
  5. *
  6. * See full license text in LICENSE file at top of project tree
  7. */
  8. #include <inttypes.h>
  9. #include <string.h> /* memset */
  10. #include <iostream>
  11. #include "Log.h"
  12. #include "Gzip.h"
  13. namespace i2p
  14. {
  15. namespace data
  16. {
  17. const size_t GZIP_CHUNK_SIZE = 16384;
  18. GzipInflator::GzipInflator (): m_IsDirty (false)
  19. {
  20. memset (&m_Inflator, 0, sizeof (m_Inflator));
  21. inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip
  22. }
  23. GzipInflator::~GzipInflator ()
  24. {
  25. inflateEnd (&m_Inflator);
  26. }
  27. size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen)
  28. {
  29. if (m_IsDirty) inflateReset (&m_Inflator);
  30. m_IsDirty = true;
  31. m_Inflator.next_in = const_cast<uint8_t *>(in);
  32. m_Inflator.avail_in = inLen;
  33. m_Inflator.next_out = out;
  34. m_Inflator.avail_out = outLen;
  35. int err;
  36. if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
  37. return outLen - m_Inflator.avail_out;
  38. // else
  39. LogPrint (eLogError, "Gzip: Inflate error ", err);
  40. return 0;
  41. }
  42. void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os)
  43. {
  44. m_IsDirty = true;
  45. uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE];
  46. m_Inflator.next_in = const_cast<uint8_t *>(in);
  47. m_Inflator.avail_in = inLen;
  48. int ret;
  49. do
  50. {
  51. m_Inflator.next_out = out;
  52. m_Inflator.avail_out = GZIP_CHUNK_SIZE;
  53. ret = inflate (&m_Inflator, Z_NO_FLUSH);
  54. if (ret < 0)
  55. {
  56. inflateEnd (&m_Inflator);
  57. os.setstate(std::ios_base::failbit);
  58. break;
  59. }
  60. os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
  61. }
  62. while (!m_Inflator.avail_out); // more data to read
  63. delete[] out;
  64. }
  65. void GzipInflator::Inflate (std::istream& in, std::ostream& out)
  66. {
  67. uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE];
  68. while (!in.eof ())
  69. {
  70. in.read ((char *) buf, GZIP_CHUNK_SIZE);
  71. Inflate (buf, in.gcount (), out);
  72. }
  73. delete[] buf;
  74. }
  75. GzipDeflator::GzipDeflator (): m_IsDirty (false)
  76. {
  77. memset (&m_Deflator, 0, sizeof (m_Deflator));
  78. deflateInit2 (&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip
  79. }
  80. GzipDeflator::~GzipDeflator ()
  81. {
  82. deflateEnd (&m_Deflator);
  83. }
  84. void GzipDeflator::SetCompressionLevel (int level)
  85. {
  86. deflateParams (&m_Deflator, level, Z_DEFAULT_STRATEGY);
  87. }
  88. size_t GzipDeflator::Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen)
  89. {
  90. if (m_IsDirty) deflateReset (&m_Deflator);
  91. m_IsDirty = true;
  92. m_Deflator.next_in = const_cast<uint8_t *>(in);
  93. m_Deflator.avail_in = inLen;
  94. m_Deflator.next_out = out;
  95. m_Deflator.avail_out = outLen;
  96. int err;
  97. if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END)
  98. return outLen - m_Deflator.avail_out;
  99. // else
  100. LogPrint (eLogError, "Gzip: Deflate error ", err);
  101. return 0;
  102. }
  103. } // data
  104. } // i2p