mirror of
https://github.com/expo/bsdiff.git
synced 2026-11-14 17:49:03 -10:00
Merge "Add a brotli decompressor in bsdiff"
This commit is contained in:
commit
2ac5778d43
13 files changed
+170
-17
No files matched your search
@@ -35,9 +35,11 @@ cc_library_static {
|
||||
defaults: ["bsdiff_defaults"],
|
||||
|
||||
srcs: [
|
||||
"brotli_decompressor.cc",
|
||||
"bspatch.cc",
|
||||
"bz2_decompressor.cc",
|
||||
"buffer_file.cc",
|
||||
"decompressor_interface.cc",
|
||||
"extents.cc",
|
||||
"extents_file.cc",
|
||||
"file.cc",
|
||||
|
||||
@@ -47,9 +47,11 @@ bsdiff_src_files := \
|
||||
|
||||
# "bspatch" program.
|
||||
bspatch_src_files := \
|
||||
brotli_decompressor.cc \
|
||||
bspatch.cc \
|
||||
bz2_decompressor.cc \
|
||||
buffer_file.cc \
|
||||
decompressor_interface.cc \
|
||||
extents.cc \
|
||||
extents_file.cc \
|
||||
file.cc \
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "bsdiff/brotli_decompressor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const uint8_t kHelloWorld[] = {
|
||||
constexpr uint8_t kHelloWorld[] = {
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a,
|
||||
};
|
||||
} // namespace
|
||||
@@ -22,8 +24,17 @@ TEST(BrotliCompressorTest, BrotliCompressorSmoke) {
|
||||
std::vector<uint8_t> compressed_data = brotli_compressor.GetCompressedData();
|
||||
EXPECT_GT(compressed_data.size(), static_cast<size_t>(0));
|
||||
|
||||
// TODO(xunchang) run brotli decompressor and check we can get back
|
||||
// kHelloWorld.
|
||||
// Run decompressor and check we can get the exact same data as kHelloWorld.
|
||||
std::vector<uint8_t> decompressed_data(sizeof(kHelloWorld));
|
||||
BrotliDecompressor brotli_decompressor;
|
||||
EXPECT_TRUE(brotli_decompressor.SetInputData(compressed_data.data(),
|
||||
compressed_data.size()));
|
||||
EXPECT_TRUE(
|
||||
brotli_decompressor.Read(decompressed_data.data(), sizeof(kHelloWorld)));
|
||||
EXPECT_TRUE(brotli_decompressor.Close());
|
||||
EXPECT_EQ(
|
||||
std::vector<uint8_t>(kHelloWorld, kHelloWorld + sizeof(kHelloWorld)),
|
||||
decompressed_data);
|
||||
}
|
||||
|
||||
} // namespace bsdiff
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2017 The Chromium OS 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 "bsdiff/brotli_decompressor.h"
|
||||
|
||||
#include "bsdiff/logging.h"
|
||||
|
||||
using std::endl;
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
bool BrotliDecompressor::SetInputData(const uint8_t* input_data, size_t size) {
|
||||
brotli_decoder_state_ =
|
||||
BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
|
||||
if (brotli_decoder_state_ == nullptr) {
|
||||
LOG(ERROR) << "Failed to initialize brotli decoder." << endl;
|
||||
return false;
|
||||
}
|
||||
next_in_ = input_data;
|
||||
available_in_ = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BrotliDecompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
|
||||
auto next_out = output_data;
|
||||
size_t available_out = bytes_to_output;
|
||||
|
||||
while (available_out > 0) {
|
||||
// The brotli decoder will update |available_in_|, |available_in_|,
|
||||
// |next_out| and |available_out|.
|
||||
BrotliDecoderResult result = BrotliDecoderDecompressStream(
|
||||
brotli_decoder_state_, &available_in_, &next_in_, &available_out,
|
||||
&next_out, nullptr);
|
||||
|
||||
if (result == BROTLI_DECODER_RESULT_ERROR) {
|
||||
LOG(ERROR) << "Decompression failed with "
|
||||
<< BrotliDecoderErrorString(
|
||||
BrotliDecoderGetErrorCode(brotli_decoder_state_))
|
||||
<< endl;
|
||||
return false;
|
||||
} else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||||
LOG(ERROR) << "Decompressor reached EOF while reading from input stream."
|
||||
<< endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BrotliDecompressor::Close() {
|
||||
if (!BrotliDecoderIsFinished(brotli_decoder_state_)) {
|
||||
LOG(ERROR) << "Unfinished brotli decoder." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
BrotliDecoderDestroyInstance(brotli_decoder_state_);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace bsdiff
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2017 The Chromium OS 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 _BSDIFF_BROTLI_DECOMPRESSOR_H_
|
||||
#define _BSDIFF_BROTLI_DECOMPRESSOR_H_
|
||||
|
||||
#include <brotli/decode.h>
|
||||
|
||||
#include "bsdiff/decompressor_interface.h"
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
class BrotliDecompressor : public DecompressorInterface {
|
||||
public:
|
||||
BrotliDecompressor()
|
||||
: brotli_decoder_state_(nullptr), next_in_(nullptr), available_in_(0) {}
|
||||
|
||||
// DecompressorInterface overrides.
|
||||
bool SetInputData(const uint8_t* input_data, size_t size) override;
|
||||
bool Read(uint8_t* output_data, size_t bytes_to_output) override;
|
||||
bool Close() override;
|
||||
|
||||
private:
|
||||
BrotliDecoderState* brotli_decoder_state_;
|
||||
const uint8_t* next_in_;
|
||||
size_t available_in_;
|
||||
};
|
||||
|
||||
} // namespace bsdiff
|
||||
|
||||
#endif // _BSDIFF_BROTLI_DECOMPRESSOR_H_
|
||||
@@ -93,9 +93,11 @@
|
||||
},
|
||||
},
|
||||
'sources': [
|
||||
'brotli_decompressor.cc',
|
||||
'bspatch.cc',
|
||||
'buffer_file.cc',
|
||||
'bz2_decompressor.cc',
|
||||
'decompressor_interface.cc',
|
||||
'extents.cc',
|
||||
'extents_file.cc',
|
||||
'file.cc',
|
||||
|
||||
@@ -11,12 +11,9 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace bsdiff {
|
||||
#include "bsdiff/constants.h"
|
||||
|
||||
enum class CompressorType {
|
||||
kBrotli,
|
||||
kBZ2,
|
||||
};
|
||||
namespace bsdiff {
|
||||
|
||||
class CompressorInterface {
|
||||
public:
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017 The Chromium OS 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 _BSDIFF_CONSTANTS_H_
|
||||
#define _BSDIFF_CONSTANTS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
enum class CompressorType {
|
||||
kBrotli,
|
||||
kBZ2,
|
||||
};
|
||||
|
||||
// The header of the upstream's "BSDIFF40" format using BZ2 as compressor.
|
||||
constexpr uint8_t kMagicHeader[] = "BSDIFF40";
|
||||
|
||||
} // namespace bsdiff
|
||||
|
||||
|
||||
#endif // _BSDIFF_CONSTANTS_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017 The Chromium OS 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 "bsdiff/decompressor_interface.h"
|
||||
|
||||
#include "bsdiff/brotli_decompressor.h"
|
||||
#include "bsdiff/bz2_decompressor.h"
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
std::unique_ptr<DecompressorInterface> CreateDecompressor(CompressorType type) {
|
||||
if (type == CompressorType::kBrotli) {
|
||||
return std::unique_ptr<DecompressorInterface>(new BrotliDecompressor());
|
||||
}
|
||||
// Use BZ2 as a default decompressor.
|
||||
return std::unique_ptr<DecompressorInterface>(new BZ2Decompressor());
|
||||
}
|
||||
|
||||
} // namespace bsdiff
|
||||
@@ -8,6 +8,10 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "bsdiff/constants.h"
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
class DecompressorInterface {
|
||||
@@ -28,5 +32,7 @@ class DecompressorInterface {
|
||||
virtual bool Close() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<DecompressorInterface> CreateDecompressor(CompressorType type);
|
||||
|
||||
} // namespace bsdiff
|
||||
#endif // _BSDIFF_DECOMPRESSOR_INTERFACE_H_
|
||||
+5
-5
@@ -8,8 +8,10 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "bsdiff/brotli_decompressor.h"
|
||||
#include "bsdiff/bspatch.h"
|
||||
#include "bsdiff/bz2_decompressor.h"
|
||||
#include "bsdiff/constants.h"
|
||||
#include "bsdiff/logging.h"
|
||||
#include "bsdiff/utils.h"
|
||||
|
||||
@@ -17,8 +19,6 @@ using std::endl;
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
const uint8_t kMagicHeader[] = "BSDIFF40";
|
||||
|
||||
bool BsdiffPatchReader::Init(const uint8_t* patch_data, size_t patch_size) {
|
||||
// File format:
|
||||
// 0 8 "BSDIFF40"
|
||||
@@ -54,9 +54,9 @@ bool BsdiffPatchReader::Init(const uint8_t* patch_data, size_t patch_size) {
|
||||
|
||||
// TODO(xunchang) set the correct decompressor based on the info in the
|
||||
// header.
|
||||
ctrl_stream_.reset(new BZ2Decompressor());
|
||||
diff_stream_.reset(new BZ2Decompressor());
|
||||
extra_stream_.reset(new BZ2Decompressor());
|
||||
ctrl_stream_ = CreateDecompressor(CompressorType::kBZ2);
|
||||
diff_stream_ = CreateDecompressor(CompressorType::kBZ2);
|
||||
extra_stream_ = CreateDecompressor(CompressorType::kBZ2);
|
||||
|
||||
int64_t offset = 32;
|
||||
if (!ctrl_stream_->SetInputData(const_cast<uint8_t*>(patch_data) + offset,
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
namespace bsdiff {
|
||||
|
||||
extern const uint8_t kMagicHeader[];
|
||||
|
||||
// A wrapper class to read and parse the data in a bsdiff patch. The reader
|
||||
// class contains the concatenated streams of control, diff, and extra data.
|
||||
// After initialization, this class provides the function to read the metadata
|
||||
|
||||
+1
-2
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "bsdiff/brotli_compressor.h"
|
||||
#include "bsdiff/bz2_compressor.h"
|
||||
#include "bsdiff/constants.h"
|
||||
#include "bsdiff/control_entry.h"
|
||||
#include "bsdiff/logging.h"
|
||||
|
||||
@@ -15,8 +16,6 @@ using std::endl;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint8_t kMagicHeader[] = "BSDIFF40";
|
||||
|
||||
void EncodeInt64(int64_t x, uint8_t* buf) {
|
||||
uint64_t y = x < 0 ? (1ULL << 63ULL) - x : x;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
|
||||
Reference in new issue
Block a user