Index: net/filter/brotli_filter.cc |
diff --git a/net/filter/brotli_filter.cc b/net/filter/brotli_filter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..74b3c767aac1c145ad6d486d3c8f336df3bc17ea |
--- /dev/null |
+++ b/net/filter/brotli_filter.cc |
@@ -0,0 +1,96 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/filter/brotli_filter.h" |
+ |
+#include "base/logging.h" |
+#include "third_party/brotli/dec/decode.h" |
+ |
+namespace net { |
+ |
+BrotliFilter::BrotliFilter(FilterType type) |
+ : Filter(type), decoding_status_(DECODING_UNINITIALIZED) {} |
+ |
+BrotliFilter::~BrotliFilter() { |
+ if (decoding_status_ != DECODING_UNINITIALIZED) |
+ BrotliStateCleanup(brotli_state_.get()); |
+} |
+ |
+bool BrotliFilter::InitDecoding() { |
+ if (decoding_status_ != DECODING_UNINITIALIZED) |
+ return false; |
+ |
+ brotli_state_.reset(new BrotliState); |
+ if (!brotli_state_.get()) |
+ return false; |
+ |
+ BrotliStateInit(brotli_state_.get()); |
+ |
+ decoding_status_ = DECODING_IN_PROGRESS; |
+ return true; |
+} |
+ |
+Filter::FilterStatus BrotliFilter::ReadFilteredData(char* dest_buffer, |
+ int* dest_len) { |
+ if (!dest_buffer || !dest_len || *dest_len <= 0) |
+ return Filter::FILTER_ERROR; |
+ |
+ if (decoding_status_ == DECODING_DONE) { |
+ *dest_len = 0; |
+ return Filter::FILTER_DONE; |
+ } |
+ |
+ if (decoding_status_ != DECODING_IN_PROGRESS) |
+ return Filter::FILTER_ERROR; |
+ |
+ size_t available_in = stream_data_len_; |
+ const uint8_t* next_in = bit_cast<uint8_t*>(next_stream_data_); |
+ size_t available_out = *dest_len; |
+ uint8_t* next_out = bit_cast<uint8_t*>(dest_buffer); |
+ size_t total_out; |
+ BrotliResult result = |
+ BrotliDecompressStream(&available_in, &next_in, &available_out, &next_out, |
+ &total_out, brotli_state_.get()); |
+ int bytes_written = *dest_len - available_out; |
+ |
+ Filter::FilterStatus status; |
+ switch (result) { |
+ case BROTLI_RESULT_ERROR: { |
+ status = Filter::FILTER_ERROR; |
+ break; |
+ } |
+ // Fall through. |
+ case BROTLI_RESULT_NEEDS_MORE_OUTPUT: |
+ case BROTLI_RESULT_SUCCESS: { |
+ status = Filter::FILTER_OK; |
+ *dest_len = bytes_written; |
+ stream_data_len_ = available_in; |
+ next_stream_data_ = bit_cast<char*>(next_in); |
+ if (result == BROTLI_RESULT_SUCCESS) |
+ status = Filter::FILTER_DONE; |
+ break; |
+ } |
+ case BROTLI_RESULT_NEEDS_MORE_INPUT: { |
+ status = Filter::FILTER_NEED_MORE_DATA; |
+ *dest_len = bytes_written; |
+ stream_data_len_ = 0; |
+ next_stream_data_ = NULL; |
+ break; |
+ } |
+ default: { |
+ status = Filter::FILTER_ERROR; |
+ break; |
+ } |
+ } |
+ |
+ if (status == Filter::FILTER_DONE) { |
+ decoding_status_ = DECODING_DONE; |
+ } else if (status == Filter::FILTER_ERROR) { |
+ decoding_status_ = DECODING_ERROR; |
+ } |
+ |
+ return status; |
+} |
+ |
+} // namespace net |