Merge "Remove cyclic symlink"
diff --git a/BUILD.gn b/BUILD.gn
index 24d9c06..100c4c4 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -16,15 +16,24 @@
     deps += [ ":puffin_test" ]
   }
   if (use.fuzzer) {
-    deps += [ ":puffin_fuzzer" ]
+    deps += [
+      ":puffin_huff_fuzzer",
+      ":puffin_puff_fuzzer",
+      ":puffin_puffpatch_fuzzer",
+    ]
   }
 }
 
 pkg_config("target_defaults") {
   pkg_deps = [
     "libchrome-${libbase_ver}",
-    "protobuf-lite",
   ]
+  if (use.fuzzer) {
+    # Link against protobuf for fuzzers so we can use libprotobuf-mutator.
+    pkg_deps += [ "protobuf" ]
+  } else {
+    pkg_deps += [ "protobuf-lite" ]
+  }
   cflags = [ "-Wextra" ]
   cflags_cc = [ "-Wnon-virtual-dtor" ]
   include_dirs = [ "src/include" ]
@@ -95,7 +104,7 @@
 
 pkg_config("libbrillo") {
   pkg_deps = [
-    "libbrillo-${libbase_ver}",
+    "libbrillo",
   ]
 }
 
@@ -138,7 +147,33 @@
 }
 
 if (use.fuzzer) {
-  executable("puffin_fuzzer") {
+  executable("puffin_huff_fuzzer") {
+    configs += [
+      "//common-mk/common_fuzzer",
+      ":libbrillo",
+      ":target_defaults",
+    ]
+    deps = [
+      ":libpuffpatch",
+    ]
+    sources = [
+      "src/fuzzer_huff.cc",
+    ]
+  }
+  executable("puffin_puff_fuzzer") {
+    configs += [
+      "//common-mk/common_fuzzer",
+      ":libbrillo",
+      ":target_defaults",
+    ]
+    deps = [
+      ":libpuffpatch",
+    ]
+    sources = [
+      "src/fuzzer_puff.cc",
+    ]
+  }
+  executable("puffin_puffpatch_fuzzer") {
     configs += [
       "//common-mk/common_fuzzer",
       ":libbrillo",
@@ -148,7 +183,7 @@
       ":libpuffdiff",
     ]
     sources = [
-      "src/fuzzer.cc",
+      "src/fuzzer_puffpatch.cc",
     ]
   }
 }
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..ee8f0ca
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "puffin_unittest"
+    }
+  ]
+}
diff --git a/src/fuzzer_huff.cc b/src/fuzzer_huff.cc
new file mode 100644
index 0000000..4002aa0
--- /dev/null
+++ b/src/fuzzer_huff.cc
@@ -0,0 +1,43 @@
+// Copyright 2019 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 "base/logging.h"
+#include "brillo/test_helpers.h"
+
+#include "puffin/src/bit_writer.h"
+#include "puffin/src/include/puffin/common.h"
+#include "puffin/src/include/puffin/huffer.h"
+#include "puffin/src/puff_reader.h"
+
+using puffin::Buffer;
+using puffin::BufferBitWriter;
+using puffin::BufferPuffReader;
+using puffin::ByteExtent;
+using puffin::Huffer;
+
+namespace {
+void FuzzHuff(const uint8_t* data, size_t size) {
+  BufferPuffReader puff_reader(data, size);
+  Buffer deflate_buffer(size);
+  BufferBitWriter bit_writer(deflate_buffer.data(), deflate_buffer.size());
+  Huffer huffer;
+  huffer.HuffDeflate(&puff_reader, &bit_writer);
+}
+
+class Environment {
+ public:
+  Environment() {
+    // To turn off the logging.
+    logging::SetMinLogLevel(logging::LOG_FATAL);
+  }
+};
+
+}  // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static Environment env;
+
+  FuzzHuff(data, size);
+  return 0;
+}
diff --git a/src/fuzzer_puff.cc b/src/fuzzer_puff.cc
new file mode 100644
index 0000000..c4d26f6
--- /dev/null
+++ b/src/fuzzer_puff.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 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 <vector>
+
+#include "base/logging.h"
+#include "brillo/test_helpers.h"
+
+#include "puffin/src/bit_reader.h"
+#include "puffin/src/include/puffin/common.h"
+#include "puffin/src/include/puffin/puffer.h"
+#include "puffin/src/puff_writer.h"
+
+using puffin::BitExtent;
+using puffin::Buffer;
+using puffin::BufferBitReader;
+using puffin::BufferPuffWriter;
+using puffin::Puffer;
+using std::vector;
+
+namespace {
+void FuzzPuff(const uint8_t* data, size_t size) {
+  BufferBitReader bit_reader(data, size);
+  Buffer puff_buffer(size * 2);
+  BufferPuffWriter puff_writer(puff_buffer.data(), puff_buffer.size());
+  vector<BitExtent> bit_extents;
+  Puffer puffer;
+  puffer.PuffDeflate(&bit_reader, &puff_writer, &bit_extents);
+}
+
+class Environment {
+ public:
+  Environment() {
+    // To turn off the logging.
+    logging::SetMinLogLevel(logging::LOG_FATAL);
+  }
+};
+
+}  // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static Environment env;
+
+  FuzzPuff(data, size);
+  return 0;
+}
diff --git a/src/fuzzer.cc b/src/fuzzer_puffpatch.cc
similarity index 73%
rename from src/fuzzer.cc
rename to src/fuzzer_puffpatch.cc
index b870ac4..28ee5bc 100644
--- a/src/fuzzer.cc
+++ b/src/fuzzer_puffpatch.cc
@@ -7,27 +7,14 @@
 #include "base/logging.h"
 #include "brillo/test_helpers.h"
 
-#include "puffin/src/bit_reader.h"
-#include "puffin/src/bit_writer.h"
 #include "puffin/src/include/puffin/common.h"
-#include "puffin/src/include/puffin/huffer.h"
-#include "puffin/src/include/puffin/puffer.h"
 #include "puffin/src/include/puffin/puffpatch.h"
 #include "puffin/src/memory_stream.h"
-#include "puffin/src/puff_reader.h"
-#include "puffin/src/puff_writer.h"
 
 using puffin::BitExtent;
 using puffin::Buffer;
-using puffin::BufferBitReader;
-using puffin::BufferBitWriter;
-using puffin::BufferPuffReader;
-using puffin::BufferPuffWriter;
 using puffin::ByteExtent;
-using puffin::Huffer;
 using puffin::MemoryStream;
-using puffin::Puffer;
-using puffin::UniqueStreamPtr;
 using std::vector;
 
 namespace puffin {
@@ -45,23 +32,6 @@
 }  // namespace puffin
 
 namespace {
-void FuzzPuff(const uint8_t* data, size_t size) {
-  BufferBitReader bit_reader(data, size);
-  Buffer puff_buffer(size * 2);
-  BufferPuffWriter puff_writer(puff_buffer.data(), puff_buffer.size());
-  vector<BitExtent> bit_extents;
-  Puffer puffer;
-  puffer.PuffDeflate(&bit_reader, &puff_writer, &bit_extents);
-}
-
-void FuzzHuff(const uint8_t* data, size_t size) {
-  BufferPuffReader puff_reader(data, size);
-  Buffer deflate_buffer(size);
-  BufferBitWriter bit_writer(deflate_buffer.data(), deflate_buffer.size());
-  Huffer huffer;
-  huffer.HuffDeflate(&puff_reader, &bit_writer);
-}
-
 template <typename T>
 bool TestExtentsArrayForFuzzer(const vector<T>& extents) {
   const size_t kMaxArraySize = 100;
@@ -114,7 +84,8 @@
   }
 }
 
-struct Environment {
+class Environment {
+ public:
   Environment() {
     // To turn off the logging.
     logging::SetMinLogLevel(logging::LOG_FATAL);
@@ -123,13 +94,12 @@
     std::cerr.setstate(std::ios_base::failbit);
   }
 };
-Environment* env = new Environment();
 
 }  // namespace
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  FuzzPuff(data, size);
-  FuzzHuff(data, size);
+  static Environment env;
+
   FuzzPuffPatch(data, size);
   return 0;
 }
diff --git a/src/puffdiff.cc b/src/puffdiff.cc
index 9e3de72..15d0fa6 100644
--- a/src/puffdiff.cc
+++ b/src/puffdiff.cc
@@ -68,7 +68,9 @@
   header.mutable_src()->set_puff_length(src_puff_size);
   header.mutable_dst()->set_puff_length(dst_puff_size);
 
-  const uint32_t header_size = header.ByteSize();
+  const size_t header_size_long = header.ByteSizeLong();
+  TEST_AND_RETURN_FALSE(header_size_long <= UINT32_MAX);
+  const uint32_t header_size = header_size_long;
 
   uint64_t offset = 0;
   patch->resize(kMagicLength + sizeof(header_size) + header_size +
diff --git a/src/utils.cc b/src/utils.cc
index 708684d..b9b06c1 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -7,6 +7,7 @@
 #include <inttypes.h>
 
 #include <algorithm>
+#include <iterator>
 #include <set>
 #include <string>
 #include <vector>
@@ -176,16 +177,24 @@
   return true;
 }
 
+namespace {
 // For more information about gzip format, refer to RFC 1952 located at:
 // https://www.ietf.org/rfc/rfc1952.txt
+bool IsValidGzipHeader(const uint8_t* header, size_t size) {
+  // Each gzip entry has the following format magic header:
+  // 0      1     0x1F
+  // 1      1     0x8B
+  // 2      1     compression method (8 denotes deflate)
+  static const uint8_t magic[] = {0x1F, 0x8B, 8};
+  return size >= 10 && std::equal(std::begin(magic), std::end(magic), header);
+}
+}  // namespace
+
 bool LocateDeflatesInGzip(const Buffer& data, vector<BitExtent>* deflates) {
+  TEST_AND_RETURN_FALSE(IsValidGzipHeader(data.data(), data.size()));
   uint64_t member_start = 0;
-  while (member_start + 10 <= data.size() && data[member_start + 0] == 0x1F &&
-         data[member_start + 1] == 0x8B && data[member_start + 2] == 8) {
-    // Each member entry has the following format
-    // 0      1     0x1F
-    // 1      1     0x8B
-    // 2      1     compression method (8 denotes deflate)
+  do {
+    // After the magic header, the gzip contains:
     // 3      1     set of flags
     // 4      4     modification time
     // 8      1     extra flags
@@ -234,9 +243,8 @@
     TEST_AND_RETURN_FALSE(offset + 8 <= data.size());
     offset += 8;
     member_start = offset;
-  }
-  // Return true if we've successfully parsed at least one gzip.
-  return member_start != 0;
+  } while (IsValidGzipHeader(&data[member_start], data.size() - member_start));
+  return true;
 }
 
 // For more information about the zip format, refer to
@@ -244,7 +252,7 @@
 bool LocateDeflatesInZipArchive(const Buffer& data,
                                 vector<BitExtent>* deflates) {
   uint64_t pos = 0;
-  while (pos <= data.size() - 30) {
+  while (pos + 30 <= data.size()) {
     // TODO(xunchang) add support for big endian system when searching for
     // magic numbers.
     if (get_unaligned<uint32_t>(data.data() + pos) != 0x04034b50) {