Snap for 4610834 from 359aa079d3dcff5f4aee11faf5a74239d0cbe64a to pi-release

Change-Id: I6382adadb4487efe07d1b274f06a6d4fb7b41dda
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 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 @@
 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 @@
   }
 
   // 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 @@
   } 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 @@
   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 @@
   }
 
   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 @@
   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 @@
 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 @@
     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::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 @@
  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 @@
   // 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 @@
   }
 
   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 @@
   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 @@
     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 @@
 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> 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
diff --git a/utils.cc b/utils.cc
index bcaba65..c3e613e 100644
--- a/utils.cc
+++ b/utils.cc
@@ -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 {