blob: 3f7e3f583d286ed708270ca4236ae06335cdd3af [file] [log] [blame]
// Copyright 2011 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVTOOLS_GOMA_LIB_COMPRESS_UTIL_H_
#define DEVTOOLS_GOMA_LIB_COMPRESS_UTIL_H_
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#ifdef ENABLE_LZMA
# ifdef _WIN32
# define LZMA_API_STATIC
# endif // _WIN32
#include "lzma.h"
#endif // ENABLE_LZMA
namespace devtools_goma {
using google::protobuf::int64;
using google::protobuf::io::ArrayInputStream;
using google::protobuf::io::ConcatenatingInputStream;
using google::protobuf::io::ZeroCopyInputStream;
using google::protobuf::io::ZeroCopyOutputStream;
using std::string;
enum class EncodingType {
NO_ENCODING,
DEFLATE,
GZIP,
LZMA2,
};
const char* GetEncodingName(EncodingType type);
// Parse encoding name.
// Note: it ignores weight.
EncodingType ParseEncodingName(absl::string_view s);
// Parse encoding in header field value.
// Note: it ignores weight, and can't handle '*'.
std::vector<EncodingType> ParseAcceptEncoding(absl::string_view field);
// Pick preferred encodings from accepts.
EncodingType PickEncoding(const std::vector<EncodingType>& accepts,
const std::vector<EncodingType>& prefs);
// Gets encoding type from |header| field value.
// If multiple encodings are found,
// this function returns the preferred one.
ABSL_DEPRECATED("Use ParseEncodingName, ParseAcceptEncoding and PickEncoding")
EncodingType GetEncodingFromHeader(absl::string_view header);
#ifdef ENABLE_LZMA
class LZMAInputStream : public ZeroCopyInputStream {
public:
explicit LZMAInputStream(std::unique_ptr<ZeroCopyInputStream> sub_stream);
~LZMAInputStream() override;
LZMAInputStream(LZMAInputStream&&) = delete;
LZMAInputStream(const LZMAInputStream&) = delete;
LZMAInputStream& operator=(const LZMAInputStream&) = delete;
LZMAInputStream& operator=(LZMAInputStream&&) = delete;
// implements ZeroCopyInputStream ---
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int size) override;
int64 ByteCount() const override;
private:
lzma_ret Decode();
void DoNextOutput(const void** data, int* size);
std::unique_ptr<ZeroCopyInputStream> sub_stream_;
// This code use lzma_context_ and lzma_error_ like GzipInputStream
// in protobuf library.
// lzma_context_ is used like zcontext_ in GzipInputStream, and
// lzma_error_ is used like zerror_ in GzipInputStream.
// lzma_context_ has following members:
// - next_out: an address to be written by lzma_code in the next time.
// - avail_out: size of next_out lzma_code can write in the next time.
// - next_in: an address to be read by lzma_code in the next time.
// - avail_in: size of next_in lzma_code can read in the next time.
// Note that when lzma_code is called, above values are updated for the next
// lzma_code. i.e. next_out increase and avail_out decrease with the size
// of decompressed data.
//
// output_buffer_ is a buffer dynamically allocated for writing uncompressed
// data. output_buffer_size_ represents its size.
// TODO: allow to change buffer size.
//
// output_position_ is a cursor in output_buffer_ to be read with Next method.
// If BackUp is called, output_position_ decrease.
lzma_stream lzma_context_;
lzma_ret lzma_error_;
std::unique_ptr<uint8_t[]> output_buffer_;
size_t output_buffer_size_;
uint8_t* output_position_;
int64 byte_count_;
};
// LZMAOutputStream is an ZeroCopyOutputStream that compresses data to
// an underlying ZeroCopyOutputStream.
class LZMAOutputStream : public ZeroCopyOutputStream {
public:
struct Options {
Options();
uint32_t preset;
lzma_check check;
size_t buffer_size;
};
explicit LZMAOutputStream(std::unique_ptr<ZeroCopyOutputStream> sub_stream);
LZMAOutputStream(std::unique_ptr<ZeroCopyOutputStream> sub_stream,
const Options& options);
~LZMAOutputStream() override;
LZMAOutputStream(LZMAOutputStream&&) = delete;
LZMAOutputStream(const LZMAOutputStream&) = delete;
LZMAOutputStream& operator=(const LZMAOutputStream&) = delete;
LZMAOutputStream& operator=(LZMAOutputStream&&) = delete;
// Writes out all data and close the LZMA stream.
// It is the caller's responsibility to close the underlying stream if
// necessary.
// Returns true if no error.
bool Close();
int ErrorCode() const {
return lzma_error_;
}
// implements ZeroCopyOutputStream ---
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64 ByteCount() const override;
private:
void Init(std::unique_ptr<ZeroCopyOutputStream> sub_stream,
const Options& options);
lzma_ret Encode(lzma_action action);
void DoNextOutput(const void** data, int* size);
std::unique_ptr<ZeroCopyOutputStream> sub_stream_;
// Result from calling Next() on sub_stream_
void* sub_data_;
int sub_data_size_;
// This code use lzma_context_ and lzma_error_ like GzipOutputStream
// in protobuf library.
// lzma_context_ is used like zcontext_ in GzipOutputStream, and
// lzma_error_ is used like zerror_ in GzipOutputStream.
// lzma_context_ has following members:
// - next_out: an address to be written by lzma_code in the next time.
// - avail_out: size of next_out lzma_code can write in the next time.
// - next_in: an address to be read by lzma_code in the next time.
// - avail_in: size of next_in lzma_code can read in the next time.
// Note that when lzma_code is called, above values are updated for the next
// lzma_code. i.e. next_out increase and avail_out decrease with the size
// of decompressed data.
lzma_stream lzma_context_;
lzma_ret lzma_error_;
// input_buffer_ is a buffer dynamically allocated for getting uncompressed
// data. input_buffer_size_ represents its size.
std::unique_ptr<uint8_t[]> input_buffer_;
size_t input_buffer_length_;
};
#endif
// InflateInputStream assumes sub_stream as deflate compressed stream.
// It automatically inserts zlib header to make sub_stream handled by
// GzipInputStream.
// TODO: insert zlib header only if needed.
class InflateInputStream : public ZeroCopyInputStream {
public:
explicit InflateInputStream(std::unique_ptr<ZeroCopyInputStream> sub_stream);
~InflateInputStream() override = default;
InflateInputStream(InflateInputStream&&) = delete;
InflateInputStream(const InflateInputStream&) = delete;
InflateInputStream& operator=(const InflateInputStream&) = delete;
InflateInputStream& operator=(InflateInputStream&&) = delete;
// implements ZeroCopyInputStream ---
bool Next(const void** data, int* size) override {
return zlib_stream_->Next(data, size);
}
void BackUp(int count) override {
zlib_stream_->BackUp(count);
}
bool Skip(int size) override {
return zlib_stream_->Skip(size);
}
int64 ByteCount() const override {
return zlib_stream_->ByteCount();
}
private:
std::unique_ptr<ZeroCopyInputStream> zlib_stream_;
std::unique_ptr<ZeroCopyInputStream> sub_stream_;
std::vector<ZeroCopyInputStream*> sub_stream_inputs_;
std::unique_ptr<ZeroCopyInputStream> zlib_header_;
std::unique_ptr<ZeroCopyInputStream> zlib_content_;
};
} // namespace devtools_goma
#endif // DEVTOOLS_GOMA_LIB_COMPRESS_UTIL_H_