adb: add interfaces for Encoder/Decoder.

More groundwork to support more compression algorithms.

Bug: https://issuetracker.google.com/150827486
Test: python3 -m unittest test_device.FileOperationsTest{Uncompressed,Brotli}
Change-Id: I638493083b83e3f6c6854b631471e9d6b50bd79f
diff --git a/adb/compression_utils.h b/adb/compression_utils.h
index c445095..f349697 100644
--- a/adb/compression_utils.h
+++ b/adb/compression_utils.h
@@ -16,8 +16,12 @@
 
 #pragma once
 
+#include <algorithm>
+#include <memory>
 #include <span>
 
+#include <android-base/logging.h>
+
 #include <brotli/decode.h>
 #include <brotli/encode.h>
 
@@ -37,15 +41,103 @@
     MoreOutput,
 };
 
-struct BrotliDecoder {
+struct Decoder {
+    void Append(Block&& block) { input_buffer_.append(std::move(block)); }
+    bool Finish() {
+        bool old = std::exchange(finished_, true);
+        if (old) {
+            LOG(FATAL) << "Decoder::Finish called while already finished?";
+            return false;
+        }
+        return true;
+    }
+
+    virtual DecodeResult Decode(std::span<char>* output) = 0;
+
+  protected:
+    Decoder(std::span<char> output_buffer) : output_buffer_(output_buffer) {}
+    ~Decoder() = default;
+
+    bool finished_ = false;
+    IOVector input_buffer_;
+    std::span<char> output_buffer_;
+};
+
+struct Encoder {
+    void Append(Block input) { input_buffer_.append(std::move(input)); }
+    bool Finish() {
+        bool old = std::exchange(finished_, true);
+        if (old) {
+            LOG(FATAL) << "Decoder::Finish called while already finished?";
+            return false;
+        }
+        return true;
+    }
+
+    virtual EncodeResult Encode(Block* output) = 0;
+
+  protected:
+    explicit Encoder(size_t output_block_size) : output_block_size_(output_block_size) {}
+    ~Encoder() = default;
+
+    const size_t output_block_size_;
+    bool finished_ = false;
+    IOVector input_buffer_;
+};
+
+struct NullDecoder final : public Decoder {
+    explicit NullDecoder(std::span<char> output_buffer) : Decoder(output_buffer) {}
+
+    DecodeResult Decode(std::span<char>* output) final {
+        size_t available_out = output_buffer_.size();
+        void* p = output_buffer_.data();
+        while (available_out > 0 && !input_buffer_.empty()) {
+            size_t len = std::min(available_out, input_buffer_.front_size());
+            p = mempcpy(p, input_buffer_.front_data(), len);
+            available_out -= len;
+            input_buffer_.drop_front(len);
+        }
+        *output = std::span(output_buffer_.data(), static_cast<char*>(p));
+        if (input_buffer_.empty()) {
+            return finished_ ? DecodeResult::Done : DecodeResult::NeedInput;
+        }
+        return DecodeResult::MoreOutput;
+    }
+};
+
+struct NullEncoder final : public Encoder {
+    explicit NullEncoder(size_t output_block_size) : Encoder(output_block_size) {}
+
+    EncodeResult Encode(Block* output) final {
+        output->clear();
+        output->resize(output_block_size_);
+
+        size_t available_out = output->size();
+        void* p = output->data();
+
+        while (available_out > 0 && !input_buffer_.empty()) {
+            size_t len = std::min(available_out, input_buffer_.front_size());
+            p = mempcpy(p, input_buffer_.front_data(), len);
+            available_out -= len;
+            input_buffer_.drop_front(len);
+        }
+
+        output->resize(output->size() - available_out);
+
+        if (input_buffer_.empty()) {
+            return finished_ ? EncodeResult::Done : EncodeResult::NeedInput;
+        }
+        return EncodeResult::MoreOutput;
+    }
+};
+
+struct BrotliDecoder final : public Decoder {
     explicit BrotliDecoder(std::span<char> output_buffer)
-        : output_buffer_(output_buffer),
+        : Decoder(output_buffer),
           decoder_(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
                    BrotliDecoderDestroyInstance) {}
 
-    void Append(Block&& block) { input_buffer_.append(std::move(block)); }
-
-    DecodeResult Decode(std::span<char>* output) {
+    DecodeResult Decode(std::span<char>* output) final {
         size_t available_in = input_buffer_.front_size();
         const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
 
@@ -63,7 +155,8 @@
 
         switch (r) {
             case BROTLI_DECODER_RESULT_SUCCESS:
-                return DecodeResult::Done;
+                // We need to wait for ID_DONE from the other end.
+                return finished_ ? DecodeResult::Done : DecodeResult::NeedInput;
             case BROTLI_DECODER_RESULT_ERROR:
                 return DecodeResult::Error;
             case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
@@ -77,33 +170,29 @@
     }
 
   private:
-    IOVector input_buffer_;
-    std::span<char> output_buffer_;
     std::unique_ptr<BrotliDecoderState, void (*)(BrotliDecoderState*)> decoder_;
 };
 
-template <size_t OutputBlockSize>
-struct BrotliEncoder {
-    explicit BrotliEncoder()
-        : output_block_(OutputBlockSize),
-          output_bytes_left_(OutputBlockSize),
+struct BrotliEncoder final : public Encoder {
+    explicit BrotliEncoder(size_t output_block_size)
+        : Encoder(output_block_size),
+          output_block_(output_block_size_),
+          output_bytes_left_(output_block_size_),
           encoder_(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr),
                    BrotliEncoderDestroyInstance) {
         BrotliEncoderSetParameter(encoder_.get(), BROTLI_PARAM_QUALITY, 1);
     }
 
-    void Append(Block input) { input_buffer_.append(std::move(input)); }
-    void Finish() { finished_ = true; }
-
-    EncodeResult Encode(Block* output) {
+    EncodeResult Encode(Block* output) final {
         output->clear();
+
         while (true) {
             size_t available_in = input_buffer_.front_size();
             const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
 
             size_t available_out = output_bytes_left_;
-            uint8_t* next_out = reinterpret_cast<uint8_t*>(output_block_.data() +
-                                                           (OutputBlockSize - output_bytes_left_));
+            uint8_t* next_out = reinterpret_cast<uint8_t*>(
+                    output_block_.data() + (output_block_size_ - output_bytes_left_));
 
             BrotliEncoderOperation op = BROTLI_OPERATION_PROCESS;
             if (finished_) {
@@ -121,13 +210,13 @@
             output_bytes_left_ = available_out;
 
             if (BrotliEncoderIsFinished(encoder_.get())) {
-                output_block_.resize(OutputBlockSize - output_bytes_left_);
+                output_block_.resize(output_block_size_ - output_bytes_left_);
                 *output = std::move(output_block_);
                 return EncodeResult::Done;
             } else if (output_bytes_left_ == 0) {
                 *output = std::move(output_block_);
-                output_block_.resize(OutputBlockSize);
-                output_bytes_left_ = OutputBlockSize;
+                output_block_.resize(output_block_size_);
+                output_bytes_left_ = output_block_size_;
                 return EncodeResult::MoreOutput;
             } else if (input_buffer_.empty()) {
                 return EncodeResult::NeedInput;
@@ -136,8 +225,6 @@
     }
 
   private:
-    bool finished_ = false;
-    IOVector input_buffer_;
     Block output_block_;
     size_t output_bytes_left_;
     std::unique_ptr<BrotliEncoderState, void (*)(BrotliEncoderState*)> encoder_;