blob: f349697dd84e69ee75169616388b5cad450ad36e [file] [log] [blame]
Josh Gao939fc192020-03-04 19:34:08 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
Josh Gao49ba5582020-03-26 19:33:25 -070019#include <algorithm>
20#include <memory>
Josh Gao939fc192020-03-04 19:34:08 -080021#include <span>
22
Josh Gao49ba5582020-03-26 19:33:25 -070023#include <android-base/logging.h>
24
Josh Gao939fc192020-03-04 19:34:08 -080025#include <brotli/decode.h>
26#include <brotli/encode.h>
27
28#include "types.h"
29
Josh Gao6e697f22020-03-26 14:06:55 -070030enum class DecodeResult {
31 Error,
32 Done,
33 NeedInput,
34 MoreOutput,
35};
36
37enum class EncodeResult {
Josh Gao939fc192020-03-04 19:34:08 -080038 Error,
39 Done,
40 NeedInput,
41 MoreOutput,
42};
43
Josh Gao49ba5582020-03-26 19:33:25 -070044struct Decoder {
45 void Append(Block&& block) { input_buffer_.append(std::move(block)); }
46 bool Finish() {
47 bool old = std::exchange(finished_, true);
48 if (old) {
49 LOG(FATAL) << "Decoder::Finish called while already finished?";
50 return false;
51 }
52 return true;
53 }
54
55 virtual DecodeResult Decode(std::span<char>* output) = 0;
56
57 protected:
58 Decoder(std::span<char> output_buffer) : output_buffer_(output_buffer) {}
59 ~Decoder() = default;
60
61 bool finished_ = false;
62 IOVector input_buffer_;
63 std::span<char> output_buffer_;
64};
65
66struct Encoder {
67 void Append(Block input) { input_buffer_.append(std::move(input)); }
68 bool Finish() {
69 bool old = std::exchange(finished_, true);
70 if (old) {
71 LOG(FATAL) << "Decoder::Finish called while already finished?";
72 return false;
73 }
74 return true;
75 }
76
77 virtual EncodeResult Encode(Block* output) = 0;
78
79 protected:
80 explicit Encoder(size_t output_block_size) : output_block_size_(output_block_size) {}
81 ~Encoder() = default;
82
83 const size_t output_block_size_;
84 bool finished_ = false;
85 IOVector input_buffer_;
86};
87
88struct NullDecoder final : public Decoder {
89 explicit NullDecoder(std::span<char> output_buffer) : Decoder(output_buffer) {}
90
91 DecodeResult Decode(std::span<char>* output) final {
92 size_t available_out = output_buffer_.size();
93 void* p = output_buffer_.data();
94 while (available_out > 0 && !input_buffer_.empty()) {
95 size_t len = std::min(available_out, input_buffer_.front_size());
96 p = mempcpy(p, input_buffer_.front_data(), len);
97 available_out -= len;
98 input_buffer_.drop_front(len);
99 }
100 *output = std::span(output_buffer_.data(), static_cast<char*>(p));
101 if (input_buffer_.empty()) {
102 return finished_ ? DecodeResult::Done : DecodeResult::NeedInput;
103 }
104 return DecodeResult::MoreOutput;
105 }
106};
107
108struct NullEncoder final : public Encoder {
109 explicit NullEncoder(size_t output_block_size) : Encoder(output_block_size) {}
110
111 EncodeResult Encode(Block* output) final {
112 output->clear();
113 output->resize(output_block_size_);
114
115 size_t available_out = output->size();
116 void* p = output->data();
117
118 while (available_out > 0 && !input_buffer_.empty()) {
119 size_t len = std::min(available_out, input_buffer_.front_size());
120 p = mempcpy(p, input_buffer_.front_data(), len);
121 available_out -= len;
122 input_buffer_.drop_front(len);
123 }
124
125 output->resize(output->size() - available_out);
126
127 if (input_buffer_.empty()) {
128 return finished_ ? EncodeResult::Done : EncodeResult::NeedInput;
129 }
130 return EncodeResult::MoreOutput;
131 }
132};
133
134struct BrotliDecoder final : public Decoder {
Josh Gao939fc192020-03-04 19:34:08 -0800135 explicit BrotliDecoder(std::span<char> output_buffer)
Josh Gao49ba5582020-03-26 19:33:25 -0700136 : Decoder(output_buffer),
Josh Gao939fc192020-03-04 19:34:08 -0800137 decoder_(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
138 BrotliDecoderDestroyInstance) {}
139
Josh Gao49ba5582020-03-26 19:33:25 -0700140 DecodeResult Decode(std::span<char>* output) final {
Josh Gao939fc192020-03-04 19:34:08 -0800141 size_t available_in = input_buffer_.front_size();
142 const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
143
144 size_t available_out = output_buffer_.size();
145 uint8_t* next_out = reinterpret_cast<uint8_t*>(output_buffer_.data());
146
147 BrotliDecoderResult r = BrotliDecoderDecompressStream(
148 decoder_.get(), &available_in, &next_in, &available_out, &next_out, nullptr);
149
150 size_t bytes_consumed = input_buffer_.front_size() - available_in;
151 input_buffer_.drop_front(bytes_consumed);
152
153 size_t bytes_emitted = output_buffer_.size() - available_out;
154 *output = std::span<char>(output_buffer_.data(), bytes_emitted);
155
156 switch (r) {
157 case BROTLI_DECODER_RESULT_SUCCESS:
Josh Gao49ba5582020-03-26 19:33:25 -0700158 // We need to wait for ID_DONE from the other end.
159 return finished_ ? DecodeResult::Done : DecodeResult::NeedInput;
Josh Gao939fc192020-03-04 19:34:08 -0800160 case BROTLI_DECODER_RESULT_ERROR:
Josh Gao6e697f22020-03-26 14:06:55 -0700161 return DecodeResult::Error;
Josh Gao939fc192020-03-04 19:34:08 -0800162 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
163 // Brotli guarantees as one of its invariants that if it returns NEEDS_MORE_INPUT,
164 // it will consume the entire input buffer passed in, so we don't have to worry
165 // about bytes left over in the front block with more input remaining.
Josh Gao6e697f22020-03-26 14:06:55 -0700166 return DecodeResult::NeedInput;
Josh Gao939fc192020-03-04 19:34:08 -0800167 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
Josh Gao6e697f22020-03-26 14:06:55 -0700168 return DecodeResult::MoreOutput;
Josh Gao939fc192020-03-04 19:34:08 -0800169 }
170 }
171
172 private:
Josh Gao939fc192020-03-04 19:34:08 -0800173 std::unique_ptr<BrotliDecoderState, void (*)(BrotliDecoderState*)> decoder_;
174};
175
Josh Gao49ba5582020-03-26 19:33:25 -0700176struct BrotliEncoder final : public Encoder {
177 explicit BrotliEncoder(size_t output_block_size)
178 : Encoder(output_block_size),
179 output_block_(output_block_size_),
180 output_bytes_left_(output_block_size_),
Josh Gao939fc192020-03-04 19:34:08 -0800181 encoder_(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr),
182 BrotliEncoderDestroyInstance) {
183 BrotliEncoderSetParameter(encoder_.get(), BROTLI_PARAM_QUALITY, 1);
184 }
185
Josh Gao49ba5582020-03-26 19:33:25 -0700186 EncodeResult Encode(Block* output) final {
Josh Gao939fc192020-03-04 19:34:08 -0800187 output->clear();
Josh Gao49ba5582020-03-26 19:33:25 -0700188
Josh Gao939fc192020-03-04 19:34:08 -0800189 while (true) {
190 size_t available_in = input_buffer_.front_size();
191 const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
192
193 size_t available_out = output_bytes_left_;
Josh Gao49ba5582020-03-26 19:33:25 -0700194 uint8_t* next_out = reinterpret_cast<uint8_t*>(
195 output_block_.data() + (output_block_size_ - output_bytes_left_));
Josh Gao939fc192020-03-04 19:34:08 -0800196
197 BrotliEncoderOperation op = BROTLI_OPERATION_PROCESS;
198 if (finished_) {
199 op = BROTLI_OPERATION_FINISH;
200 }
201
202 if (!BrotliEncoderCompressStream(encoder_.get(), op, &available_in, &next_in,
203 &available_out, &next_out, nullptr)) {
Josh Gao6e697f22020-03-26 14:06:55 -0700204 return EncodeResult::Error;
Josh Gao939fc192020-03-04 19:34:08 -0800205 }
206
207 size_t bytes_consumed = input_buffer_.front_size() - available_in;
208 input_buffer_.drop_front(bytes_consumed);
209
210 output_bytes_left_ = available_out;
211
212 if (BrotliEncoderIsFinished(encoder_.get())) {
Josh Gao49ba5582020-03-26 19:33:25 -0700213 output_block_.resize(output_block_size_ - output_bytes_left_);
Josh Gao939fc192020-03-04 19:34:08 -0800214 *output = std::move(output_block_);
Josh Gao6e697f22020-03-26 14:06:55 -0700215 return EncodeResult::Done;
Josh Gao939fc192020-03-04 19:34:08 -0800216 } else if (output_bytes_left_ == 0) {
217 *output = std::move(output_block_);
Josh Gao49ba5582020-03-26 19:33:25 -0700218 output_block_.resize(output_block_size_);
219 output_bytes_left_ = output_block_size_;
Josh Gao6e697f22020-03-26 14:06:55 -0700220 return EncodeResult::MoreOutput;
Josh Gao939fc192020-03-04 19:34:08 -0800221 } else if (input_buffer_.empty()) {
Josh Gao6e697f22020-03-26 14:06:55 -0700222 return EncodeResult::NeedInput;
Josh Gao939fc192020-03-04 19:34:08 -0800223 }
224 }
225 }
226
227 private:
Josh Gao939fc192020-03-04 19:34:08 -0800228 Block output_block_;
229 size_t output_bytes_left_;
230 std::unique_ptr<BrotliEncoderState, void (*)(BrotliEncoderState*)> encoder_;
231};