diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-02-18 08:27:17 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-02-18 08:27:17 +0000 |
commit | f0c8211af44d092cf6cc816b1e9af72f14fe80f6 (patch) | |
tree | 11699d8101fe082b541a365de69b62f934a2fe47 | |
parent | 335d9aebe5923bdcb06e552257a91a9aa8f3c543 (diff) | |
parent | 359aa079d3dcff5f4aee11faf5a74239d0cbe64a (diff) | |
download | bsdiff-pie-cts-release.tar.gz |
Snap for 4610834 from 359aa079d3dcff5f4aee11faf5a74239d0cbe64a to pi-releaseandroid-wear-9.0.0_r9android-wear-9.0.0_r8android-wear-9.0.0_r7android-wear-9.0.0_r6android-wear-9.0.0_r5android-wear-9.0.0_r4android-wear-9.0.0_r34android-wear-9.0.0_r33android-wear-9.0.0_r32android-wear-9.0.0_r31android-wear-9.0.0_r30android-wear-9.0.0_r3android-wear-9.0.0_r29android-wear-9.0.0_r28android-wear-9.0.0_r27android-wear-9.0.0_r26android-wear-9.0.0_r25android-wear-9.0.0_r24android-wear-9.0.0_r23android-wear-9.0.0_r22android-wear-9.0.0_r21android-wear-9.0.0_r20android-wear-9.0.0_r2android-wear-9.0.0_r19android-wear-9.0.0_r18android-wear-9.0.0_r17android-wear-9.0.0_r16android-wear-9.0.0_r15android-wear-9.0.0_r14android-wear-9.0.0_r13android-wear-9.0.0_r12android-wear-9.0.0_r11android-wear-9.0.0_r10android-wear-9.0.0_r1android-vts-9.0_r9android-vts-9.0_r8android-vts-9.0_r7android-vts-9.0_r6android-vts-9.0_r5android-vts-9.0_r4android-vts-9.0_r19android-vts-9.0_r18android-vts-9.0_r17android-vts-9.0_r16android-vts-9.0_r15android-vts-9.0_r14android-vts-9.0_r13android-vts-9.0_r12android-vts-9.0_r11android-vts-9.0_r10android-security-9.0.0_r76android-security-9.0.0_r75android-security-9.0.0_r74android-security-9.0.0_r73android-security-9.0.0_r72android-security-9.0.0_r71android-security-9.0.0_r70android-security-9.0.0_r69android-security-9.0.0_r68android-security-9.0.0_r67android-security-9.0.0_r66android-security-9.0.0_r65android-security-9.0.0_r64android-security-9.0.0_r63android-security-9.0.0_r62android-cts-9.0_r9android-cts-9.0_r8android-cts-9.0_r7android-cts-9.0_r6android-cts-9.0_r5android-cts-9.0_r4android-cts-9.0_r3android-cts-9.0_r20android-cts-9.0_r2android-cts-9.0_r19android-cts-9.0_r18android-cts-9.0_r17android-cts-9.0_r16android-cts-9.0_r15android-cts-9.0_r14android-cts-9.0_r13android-cts-9.0_r12android-cts-9.0_r11android-cts-9.0_r10android-cts-9.0_r1android-9.0.0_r9android-9.0.0_r8android-9.0.0_r7android-9.0.0_r61android-9.0.0_r60android-9.0.0_r6android-9.0.0_r59android-9.0.0_r58android-9.0.0_r57android-9.0.0_r56android-9.0.0_r55android-9.0.0_r54android-9.0.0_r53android-9.0.0_r52android-9.0.0_r51android-9.0.0_r50android-9.0.0_r5android-9.0.0_r49android-9.0.0_r48android-9.0.0_r3android-9.0.0_r2android-9.0.0_r18android-9.0.0_r17android-9.0.0_r10android-9.0.0_r1security-pi-releasepie-vts-releasepie-security-releasepie-s2-releasepie-release-2pie-releasepie-r2-s2-releasepie-r2-s1-releasepie-r2-releasepie-platform-releasepie-gsipie-cuttlefish-testingpie-cts-release
Change-Id: I6382adadb4487efe07d1b274f06a6d4fb7b41dda
-rw-r--r-- | bsdiff_arguments.cc | 30 | ||||
-rw-r--r-- | bsdiff_arguments_unittest.cc | 3 | ||||
-rw-r--r-- | bsdiff_main.cc | 35 | ||||
-rw-r--r-- | endsley_patch_writer.cc | 45 | ||||
-rw-r--r-- | endsley_patch_writer.h | 17 | ||||
-rw-r--r-- | endsley_patch_writer_unittest.cc | 30 | ||||
-rw-r--r-- | include/bsdiff/patch_writer_factory.h | 16 | ||||
-rw-r--r-- | include/bsdiff/patch_writer_interface.h | 1 | ||||
-rw-r--r-- | patch_writer_factory.cc | 11 | ||||
-rw-r--r-- | utils.cc | 4 |
10 files changed, 161 insertions, 31 deletions
diff --git a/bsdiff_arguments.cc b/bsdiff_arguments.cc index f56c186..ebcddf1 100644 --- a/bsdiff_arguments.cc +++ b/bsdiff_arguments.cc @@ -1,3 +1,7 @@ +// 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/bsdiff_arguments.h" #include <getopt.h> @@ -21,6 +25,7 @@ constexpr char kBrotliString[] = "brotli"; constexpr char kLegacyString[] = "legacy"; constexpr char kBsdf2String[] = "bsdf2"; constexpr char kBsdiff40String[] = "bsdiff40"; +constexpr char kEndsleyString[] = "endsley"; const struct option OPTIONS[] = { {"format", required_argument, nullptr, 0}, @@ -37,16 +42,20 @@ const uint32_t kBrotliDefaultQuality = BROTLI_MAX_QUALITY; namespace bsdiff { bool BsdiffArguments::IsValid() const { + if (compressor_type_ == CompressorType::kBrotli && + (compression_quality_ < BROTLI_MIN_QUALITY || + compression_quality_ > BROTLI_MAX_QUALITY)) { + return false; + } + if (format_ == BsdiffFormat::kLegacy) { - return (compressor_type_ == CompressorType::kBZ2); + return compressor_type_ == CompressorType::kBZ2; } else if (format_ == BsdiffFormat::kBsdf2) { - if (compressor_type_ == CompressorType::kBZ2) { - return true; - } - if (compressor_type_ == CompressorType::kBrotli) { - return (compression_quality_ >= BROTLI_MIN_QUALITY && - compression_quality_ <= BROTLI_MAX_QUALITY); - } + return (compressor_type_ == CompressorType::kBZ2 || + compressor_type_ == CompressorType::kBrotli); + } else if (format_ == BsdiffFormat::kEndsley) { + // All compression options are valid for this format. + return true; } return false; } @@ -83,7 +92,7 @@ bool BsdiffArguments::ParseCommandLine(int argc, char** argv) { } // If quality is uninitialized for brotli, set it to default value. - if (format_ == BsdiffFormat::kBsdf2 && + if (format_ != BsdiffFormat::kLegacy && compressor_type_ == CompressorType::kBrotli && compression_quality_ == -1) { compression_quality_ = kBrotliDefaultQuality; @@ -144,6 +153,9 @@ bool BsdiffArguments::ParseBsdiffFormat(const string& str, } else if (format_string == kBsdf2String) { *format = BsdiffFormat::kBsdf2; return true; + } else if (format_string == kEndsleyString) { + *format = BsdiffFormat::kEndsley; + return true; } std::cerr << "Failed to parse bsdiff format in " << str << endl; return false; diff --git a/bsdiff_arguments_unittest.cc b/bsdiff_arguments_unittest.cc index 3f061c9..412b8e9 100644 --- a/bsdiff_arguments_unittest.cc +++ b/bsdiff_arguments_unittest.cc @@ -32,6 +32,9 @@ TEST(BsdiffArgumentsTest, ParseBsdiffFormatTest) { EXPECT_TRUE(BsdiffArguments::ParseBsdiffFormat("bsdiff40", &format)); EXPECT_EQ(BsdiffFormat::kLegacy, format); + EXPECT_TRUE(BsdiffArguments::ParseBsdiffFormat("endsley", &format)); + EXPECT_EQ(BsdiffFormat::kEndsley, format); + EXPECT_FALSE(BsdiffArguments::ParseBsdiffFormat("Other", &format)); } diff --git a/bsdiff_main.cc b/bsdiff_main.cc index 6747055..bed38b6 100644 --- a/bsdiff_main.cc +++ b/bsdiff_main.cc @@ -74,12 +74,18 @@ int GenerateBsdiffFromFiles(const char* old_filename, } std::unique_ptr<bsdiff::PatchWriterInterface> patch_writer; + std::vector<uint8_t> raw_data; + if (arguments.format() == bsdiff::BsdiffFormat::kLegacy) { patch_writer = bsdiff::CreateBsdiffPatchWriter(patch_filename); } else if (arguments.format() == bsdiff::BsdiffFormat::kBsdf2) { patch_writer = bsdiff::CreateBSDF2PatchWriter( patch_filename, arguments.compressor_type(), arguments.compression_quality()); + } else if (arguments.format() == bsdiff::BsdiffFormat::kEndsley) { + patch_writer = + bsdiff::CreateEndsleyPatchWriter(&raw_data, arguments.compressor_type(), + arguments.compression_quality()); } else { std::cerr << "unexpected bsdiff format." << std::endl; return 1; @@ -91,20 +97,33 @@ int GenerateBsdiffFromFiles(const char* old_filename, munmap(old_buf, oldsize); munmap(new_buf, newsize); + if (!ret && arguments.format() == bsdiff::BsdiffFormat::kEndsley) { + // Store the raw_data on disk. + FILE* fp = fopen(patch_filename, "wb"); + if (!fp) { + perror("Opening the patch file"); + return 1; + } + if (raw_data.size() != fwrite(raw_data.data(), 1, raw_data.size(), fp)) { + perror("Writing to the patch file"); + ret = 1; + } + fclose(fp); + } return ret; } void PrintUsage(const std::string& proc_name) { std::cerr << "usage: " << proc_name << " [options] oldfile newfile patchfile\n"; - std::cerr << " --format <legacy|bsdiff40|bsdf2> The format of the bsdiff" - " patch.\n" - << " --minlen LEN The minimum match length required " - "to consider a match in the algorithm.\n" - << " --type <bz2|brotli> The algorithm to compress the " - "patch, bsdf2 format only.\n" - << " --quality Quality of the patch compression," - " brotli only.\n"; + std::cerr << " --format <legacy|bsdiff40|bsdf2|endsley> The format of the" + " bsdiff patch.\n" + << " --minlen LEN The minimum match length " + "required to consider a match in the algorithm.\n" + << " --type <bz2|brotli|nocompression> The algorithm to compress " + "the patch, bsdf2 format only.\n" + << " --quality Quality of the patch " + "compression, brotli only.\n"; } } // namespace diff --git a/endsley_patch_writer.cc b/endsley_patch_writer.cc index cb23f46..e40406d 100644 --- a/endsley_patch_writer.cc +++ b/endsley_patch_writer.cc @@ -8,6 +8,8 @@ #include <algorithm> +#include "bsdiff/brotli_compressor.h" +#include "bsdiff/bz2_compressor.h" #include "bsdiff/logging.h" namespace { @@ -30,12 +32,30 @@ constexpr size_t kMinimumFlushSize = 1024 * 1024; // 1 MiB namespace bsdiff { bool EndsleyPatchWriter::Init(size_t new_size) { - // The patch is uncompressed and it will need exactly: - // new_size + 24 * len(control_entries) + sizeof(header) - // We don't know the length of the control entries yet, but we can reserve - // enough space to hold at least |new_size|. - patch_->clear(); - patch_->reserve(new_size); + switch (compressor_type_) { + case CompressorType::kNoCompression: + // The patch is uncompressed and it will need exactly: + // new_size + 24 * len(control_entries) + sizeof(header) + // We don't know the length of the control entries yet, but we can reserve + // enough space to hold at least |new_size|. + patch_->clear(); + patch_->reserve(new_size); + break; + case CompressorType::kBrotli: + compressor_.reset(new BrotliCompressor(quality_)); + if (!compressor_) { + LOG(ERROR) << "Error creating brotli compressor."; + return false; + } + break; + case CompressorType::kBZ2: + compressor_.reset(new BZ2Compressor()); + if (!compressor_) { + LOG(ERROR) << "Error creating BZ2 compressor."; + return false; + } + break; + } // Header is the magic followed by the new length. uint8_t header[24]; @@ -116,6 +136,13 @@ bool EndsleyPatchWriter::Close() { LOG(ERROR) << "Pending data to diff/extra not flushed out on Close()"; return false; } + + if (compressor_) { + if (!compressor_->Finish()) + return false; + *patch_ = compressor_->GetCompressedData(); + } + return true; } @@ -129,7 +156,11 @@ void EndsleyPatchWriter::EmitControlEntry(const ControlEntry& entry) { } void EndsleyPatchWriter::EmitBuffer(const uint8_t* data, size_t size) { - patch_->insert(patch_->end(), data, data + size); + if (compressor_) { + compressor_->Write(data, size); + } else { + patch_->insert(patch_->end(), data, data + size); + } } void EndsleyPatchWriter::Flush() { diff --git a/endsley_patch_writer.h b/endsley_patch_writer.h index 1840d8d..a3170f6 100644 --- a/endsley_patch_writer.h +++ b/endsley_patch_writer.h @@ -5,9 +5,12 @@ #ifndef _BSDIFF_ENDSLEY_PATCH_WRITER_H_ #define _BSDIFF_ENDSLEY_PATCH_WRITER_H_ +#include <memory> #include <string> #include <vector> +#include "bsdiff/compressor_interface.h" +#include "bsdiff/constants.h" #include "bsdiff/patch_writer_interface.h" namespace bsdiff { @@ -35,8 +38,12 @@ class EndsleyPatchWriter : public PatchWriterInterface { public: // Create the patch writer that will write the data to the passed vector // |patch|, resizing it as needed. The |patch| vector must be valid until - // Close() is called or this patch is destroyed. - explicit EndsleyPatchWriter(std::vector<uint8_t>* patch) : patch_(patch) {} + // Close() is called or this patch is destroyed. The data in |patch| will be + // compressed using the compressor type |type|. + EndsleyPatchWriter(std::vector<uint8_t>* patch, + CompressorType type, + int quality) + : patch_(patch), compressor_type_(type), quality_(quality) {} // PatchWriterInterface overrides. bool Init(size_t new_size) override; @@ -58,6 +65,12 @@ class EndsleyPatchWriter : public PatchWriterInterface { // The vector we are writing to, owned by the caller. std::vector<uint8_t>* patch_; + // The compressor type to use and its quality (if any). + CompressorType compressor_type_; + int quality_; + + std::unique_ptr<CompressorInterface> compressor_; + // The pending diff and extra data to be encoded in the file. These vectors // would not be used whenever is possible to the data directly to the patch_ // vector; namely when the control, diff and extra stream data are provided in diff --git a/endsley_patch_writer_unittest.cc b/endsley_patch_writer_unittest.cc index 29f404c..456209d 100644 --- a/endsley_patch_writer_unittest.cc +++ b/endsley_patch_writer_unittest.cc @@ -31,7 +31,7 @@ class EndsleyPatchWriterTest : public testing::Test { } std::vector<uint8_t> data_; - EndsleyPatchWriter patch_writer_{&data_}; + EndsleyPatchWriter patch_writer_{&data_, CompressorType::kNoCompression, 0}; }; // Smoke check that a patch includes the new_size and magic header. @@ -51,6 +51,34 @@ TEST_F(EndsleyPatchWriterTest, CreateEmptyPatchTest) { EXPECT_EQ(empty_patch, data_); } +TEST_F(EndsleyPatchWriterTest, CreateCompressedPatchTest) { + EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBZ2, 9); + + auto text = VectorFromString("HelloWorld"); + EXPECT_TRUE(compressed_writer.Init(text.size())); + + EXPECT_TRUE(compressed_writer.AddControlEntry(ControlEntry(5, 5, -2))); + EXPECT_TRUE(compressed_writer.WriteDiffStream(text.data(), 5)); + EXPECT_TRUE(compressed_writer.WriteExtraStream(text.data() + 5, 5)); + + // Check that the output patch had no data written to it before Close() is + // called, since we are still compressing it. + EXPECT_TRUE(data_.empty()); + + EXPECT_TRUE(compressed_writer.Close()); + + // Check that the whole file is compressed with BZ2 by looking at the header. + const auto bz2_header = VectorFromString("BZh9"); + data_.resize(4); + EXPECT_EQ(bz2_header, data_); +} + +TEST_F(EndsleyPatchWriterTest, CreateEmptyBrotliPatchTest) { + EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBrotli, 9); + EXPECT_TRUE(compressed_writer.Init(0)); + EXPECT_TRUE(compressed_writer.Close()); +} + // Test we generate the right patch when the control, diff and extra stream come // in the right order. TEST_F(EndsleyPatchWriterTest, DataInNiceOrderTest) { diff --git a/include/bsdiff/patch_writer_factory.h b/include/bsdiff/patch_writer_factory.h index 7c3613c..64ec4fa 100644 --- a/include/bsdiff/patch_writer_factory.h +++ b/include/bsdiff/patch_writer_factory.h @@ -29,13 +29,23 @@ std::unique_ptr<PatchWriterInterface> CreateBSDF2PatchWriter( CompressorType type, int quality); -// Create a patch writer compatible with Android Play Store bsdiff patches, -// uncompressed. The data will be written to the passed |patch| vector, which -// must be valid until Close() is called or this patch is destroyed. +// Create a patch writer compatible with Android Play Store bsdiff patches. +// The data will be written to the passed |patch| vector, which must be valid +// until Close() is called or this patch is destroyed. The data will be +// compressed using the compressor type |type|. To get an uncompressed patch, +// pass CompressortType::kNoCompression. +BSDIFF_EXPORT +std::unique_ptr<PatchWriterInterface> CreateEndsleyPatchWriter( + std::vector<uint8_t>* patch, + CompressorType type, + int quality); + +// Helper function to create an Endsley patch writer with no compression. BSDIFF_EXPORT std::unique_ptr<PatchWriterInterface> CreateEndsleyPatchWriter( std::vector<uint8_t>* patch); + } // namespace bsdiff #endif // _BSDIFF_PATCH_WRITER_FACTORY_H_ diff --git a/include/bsdiff/patch_writer_interface.h b/include/bsdiff/patch_writer_interface.h index 31fc3d8..bc59b36 100644 --- a/include/bsdiff/patch_writer_interface.h +++ b/include/bsdiff/patch_writer_interface.h @@ -15,6 +15,7 @@ namespace bsdiff { enum class BsdiffFormat { kLegacy, kBsdf2, + kEndsley, }; class PatchWriterInterface { diff --git a/patch_writer_factory.cc b/patch_writer_factory.cc index 95bfe32..8c29bf2 100644 --- a/patch_writer_factory.cc +++ b/patch_writer_factory.cc @@ -24,8 +24,17 @@ std::unique_ptr<PatchWriterInterface> CreateBSDF2PatchWriter( } std::unique_ptr<PatchWriterInterface> CreateEndsleyPatchWriter( + std::vector<uint8_t>* patch, + CompressorType type, + int quality) { + return std::unique_ptr<PatchWriterInterface>( + new EndsleyPatchWriter(patch, type, quality)); +} + +std::unique_ptr<PatchWriterInterface> CreateEndsleyPatchWriter( std::vector<uint8_t>* patch) { - return std::unique_ptr<PatchWriterInterface>(new EndsleyPatchWriter(patch)); + return std::unique_ptr<PatchWriterInterface>( + new EndsleyPatchWriter(patch, CompressorType::kNoCompression, 0)); } } // namespace bsdiff @@ -1,3 +1,7 @@ +// Copyright 2018 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/utils.h" namespace bsdiff { |