compressor.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* Copyright 2016 Google Inc. All Rights Reserved.
  2. Distributed under MIT license.
  3. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  4. */
  5. /* Brotli compressor API C++ wrapper and utilities. */
  6. #include "./compressor.h"
  7. #include <cstdlib> /* exit */
  8. namespace brotli {
  9. static void SetParams(const BrotliParams* from, BrotliEncoderState* to) {
  10. BrotliEncoderMode mode = BROTLI_MODE_GENERIC;
  11. if (from->mode == BrotliParams::MODE_TEXT) {
  12. mode = BROTLI_MODE_TEXT;
  13. } else if (from->mode == BrotliParams::MODE_FONT) {
  14. mode = BROTLI_MODE_FONT;
  15. }
  16. BrotliEncoderSetParameter(to, BROTLI_PARAM_MODE, (uint32_t)mode);
  17. BrotliEncoderSetParameter(to, BROTLI_PARAM_QUALITY, (uint32_t)from->quality);
  18. BrotliEncoderSetParameter(to, BROTLI_PARAM_LGWIN, (uint32_t)from->lgwin);
  19. BrotliEncoderSetParameter(to, BROTLI_PARAM_LGBLOCK, (uint32_t)from->lgblock);
  20. }
  21. BrotliCompressor::BrotliCompressor(BrotliParams params) {
  22. state_ = BrotliEncoderCreateInstance(0, 0, 0);
  23. if (state_ == 0) std::exit(EXIT_FAILURE); /* OOM */
  24. SetParams(&params, state_);
  25. }
  26. BrotliCompressor::~BrotliCompressor(void) {
  27. BrotliEncoderDestroyInstance(state_);
  28. }
  29. bool BrotliCompressor::WriteMetaBlock(const size_t input_size,
  30. const uint8_t* input_buffer,
  31. const bool is_last, size_t* encoded_size,
  32. uint8_t* encoded_buffer) {
  33. return !!BrotliEncoderWriteMetaBlock(state_, input_size, input_buffer,
  34. is_last ? 1 : 0, encoded_size,
  35. encoded_buffer);
  36. }
  37. bool BrotliCompressor::WriteMetadata(const size_t input_size,
  38. const uint8_t* input_buffer,
  39. const bool is_last, size_t* encoded_size,
  40. uint8_t* encoded_buffer) {
  41. return !!BrotliEncoderWriteMetadata(state_, input_size, input_buffer,
  42. is_last ? 1 : 0, encoded_size,
  43. encoded_buffer);
  44. }
  45. bool BrotliCompressor::FinishStream(size_t* encoded_size,
  46. uint8_t* encoded_buffer) {
  47. return !!BrotliEncoderFinishStream(state_, encoded_size, encoded_buffer);
  48. }
  49. void BrotliCompressor::CopyInputToRingBuffer(const size_t input_size,
  50. const uint8_t* input_buffer) {
  51. BrotliEncoderCopyInputToRingBuffer(state_, input_size, input_buffer);
  52. }
  53. bool BrotliCompressor::WriteBrotliData(const bool is_last,
  54. const bool force_flush, size_t* out_size,
  55. uint8_t** output) {
  56. return !!BrotliEncoderWriteData(
  57. state_, is_last ? 1 : 0, force_flush ? 1 : 0, out_size, output);
  58. }
  59. void BrotliCompressor::BrotliSetCustomDictionary(size_t size,
  60. const uint8_t* dict) {
  61. BrotliEncoderSetCustomDictionary(state_, size, dict);
  62. }
  63. int BrotliCompressBuffer(BrotliParams params, size_t input_size,
  64. const uint8_t* input_buffer, size_t* encoded_size,
  65. uint8_t* encoded_buffer) {
  66. return BrotliEncoderCompress(params.quality, params.lgwin,
  67. (BrotliEncoderMode)params.mode, input_size, input_buffer,
  68. encoded_size, encoded_buffer);
  69. }
  70. int BrotliCompress(BrotliParams params, BrotliIn* in, BrotliOut* out) {
  71. return BrotliCompressWithCustomDictionary(0, 0, params, in, out);
  72. }
  73. int BrotliCompressWithCustomDictionary(size_t dictsize, const uint8_t* dict,
  74. BrotliParams params, BrotliIn* in,
  75. BrotliOut* out) {
  76. const size_t kOutputBufferSize = 65536;
  77. uint8_t* output_buffer;
  78. bool result = true;
  79. size_t available_in = 0;
  80. const uint8_t* next_in = NULL;
  81. size_t total_out = 0;
  82. bool end_of_input = false;
  83. BrotliEncoderState* s;
  84. s = BrotliEncoderCreateInstance(0, 0, 0);
  85. if (!s) return 0;
  86. SetParams(&params, s);
  87. BrotliEncoderSetCustomDictionary(s, dictsize, dict);
  88. output_buffer = new uint8_t[kOutputBufferSize];
  89. while (true) {
  90. if (available_in == 0 && !end_of_input) {
  91. next_in = reinterpret_cast<const uint8_t*>(
  92. in->Read(BrotliEncoderInputBlockSize(s), &available_in));
  93. if (!next_in) {
  94. end_of_input = true;
  95. available_in = 0;
  96. } else if (available_in == 0) {
  97. continue;
  98. }
  99. }
  100. size_t available_out = kOutputBufferSize;
  101. uint8_t* next_out = output_buffer;
  102. result = !!BrotliEncoderCompressStream(
  103. s, end_of_input ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,
  104. &available_in, &next_in, &available_out, &next_out, &total_out);
  105. if (!result) break;
  106. size_t used_output = kOutputBufferSize - available_out;
  107. if (used_output != 0) {
  108. result = out->Write(output_buffer, used_output);
  109. if (!result) break;
  110. }
  111. if (BrotliEncoderIsFinished(s)) break;
  112. }
  113. delete[] output_buffer;
  114. BrotliEncoderDestroyInstance(s);
  115. return result ? 1 : 0;
  116. }
  117. } /* namespace brotli */