AU: Bzip2 utility functions that mirror Gzip utility functions.
Also, Convert the gzip_unittest into a typed test and use the same
test cases for bzip2.
Review URL: http://codereview.chromium.org/855002
diff --git a/SConstruct b/SConstruct
index e27871a..8854abc 100644
--- a/SConstruct
+++ b/SConstruct
@@ -85,6 +85,7 @@
sources = Split("""action_processor.cc
+ bzip.cc
bzip_extent_writer.cc
cycle_breaker.cc
decompressing_file_writer.cc
@@ -125,7 +126,6 @@
filesystem_copier_action_unittest.cc
filesystem_iterator_unittest.cc
graph_utils_unittest.cc
- gzip_unittest.cc
http_fetcher_unittest.cc
mock_http_fetcher.cc
omaha_hash_calculator_unittest.cc
@@ -138,7 +138,8 @@
test_utils.cc
topological_sort_unittest.cc
update_check_action_unittest.cc
- utils_unittest.cc""")
+ utils_unittest.cc
+ zip_unittest.cc""")
unittest_main = ['testrunner.cc']
delta_generator_sources = Split("""delta_diff_generator.cc""")
diff --git a/bzip.cc b/bzip.cc
new file mode 100644
index 0000000..4a41980
--- /dev/null
+++ b/bzip.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2010 The Chromium 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 "update_engine/gzip.h"
+#include <stdlib.h>
+#include <algorithm>
+#include <bzlib.h>
+#include "update_engine/utils.h"
+
+using std::max;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+namespace {
+
+// BzipData compresses or decompresses the input to the output.
+// Returns true on success.
+// Use one of BzipBuffToBuff*ompress as the template parameter to BzipData().
+int BzipBuffToBuffDecompress(char* out,
+ size_t* out_length,
+ const char* in,
+ size_t in_length) {
+ return BZ2_bzBuffToBuffDecompress(out,
+ out_length,
+ const_cast<char*>(in),
+ in_length,
+ 0, // Silent verbosity
+ 0); // Normal algorithm
+}
+
+int BzipBuffToBuffCompress(char* out,
+ size_t* out_length,
+ const char* in,
+ size_t in_length) {
+ return BZ2_bzBuffToBuffCompress(out,
+ out_length,
+ const_cast<char*>(in),
+ in_length,
+ 9, // Best compression
+ 0, // Silent verbosity
+ 0); // Default work factor
+}
+
+template<int F(char* out,
+ size_t* out_length,
+ const char* in,
+ size_t in_length)>
+bool BzipData(const char* const in,
+ const size_t in_size,
+ vector<char>* const out) {
+ TEST_AND_RETURN_FALSE(out);
+ out->clear();
+ if (in_size == 0) {
+ return true;
+ }
+ // Try increasing buffer size until it works
+ size_t buf_size = in_size;
+ out->resize(buf_size);
+
+ for (;;) {
+ size_t data_size = buf_size;
+ int rc = F(&(*out)[0], &data_size, in, in_size);
+ TEST_AND_RETURN_FALSE(rc == BZ_OUTBUFF_FULL || rc == BZ_OK);
+ if (rc == BZ_OK) {
+ // we're done!
+ out->resize(data_size);
+ return true;
+ }
+
+ // Data didn't fit; double the buffer size.
+ buf_size *= 2;
+ out->resize(buf_size);
+ }
+}
+
+} // namespace {}
+
+bool BzipDecompress(const std::vector<char>& in, std::vector<char>* out) {
+ return BzipData<BzipBuffToBuffDecompress>(&in[0], in.size(), out);
+}
+
+bool BzipCompress(const std::vector<char>& in, std::vector<char>* out) {
+ return BzipData<BzipBuffToBuffCompress>(&in[0], in.size(), out);
+}
+
+namespace {
+template<bool F(const char* const in,
+ const size_t in_size,
+ vector<char>* const out)>
+bool BzipString(const std::string& str,
+ std::vector<char>* out) {
+ TEST_AND_RETURN_FALSE(out);
+ vector<char> temp;
+ TEST_AND_RETURN_FALSE(F(str.data(),
+ str.size(),
+ &temp));
+ out->clear();
+ out->insert(out->end(), temp.begin(), temp.end());
+ return true;
+}
+} // namespace {}
+
+bool BzipCompressString(const std::string& str,
+ std::vector<char>* out) {
+ return BzipString<BzipData<BzipBuffToBuffCompress> >(str, out);
+}
+
+bool BzipDecompressString(const std::string& str,
+ std::vector<char>* out) {
+ return BzipString<BzipData<BzipBuffToBuffDecompress> >(str, out);
+}
+
+} // namespace chromeos_update_engine
diff --git a/bzip.h b/bzip.h
new file mode 100644
index 0000000..ca6e881
--- /dev/null
+++ b/bzip.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 The Chromium 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 <string>
+#include <vector>
+
+namespace chromeos_update_engine {
+
+// Bzip2 compresses or decompresses str/in to out.
+bool BzipDecompress(const std::vector<char>& in, std::vector<char>* out);
+bool BzipCompress(const std::vector<char>& in, std::vector<char>* out);
+bool BzipCompressString(const std::string& str, std::vector<char>* out);
+bool BzipDecompressString(const std::string& str, std::vector<char>* out);
+
+} // namespace chromeos_update_engine
diff --git a/gzip_unittest.cc b/gzip_unittest.cc
deleted file mode 100644
index 298ca9d..0000000
--- a/gzip_unittest.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2009 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 <string.h>
-#include <unistd.h>
-#include <string>
-#include <vector>
-#include <gtest/gtest.h>
-#include "update_engine/gzip.h"
-#include "update_engine/test_utils.h"
-#include "update_engine/utils.h"
-
-using std::string;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-class GzipTest : public ::testing::Test { };
-
-TEST(GzipTest, SimpleTest) {
- string in("this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
- vector<char> out;
- EXPECT_TRUE(GzipCompressString(in, &out));
- EXPECT_LT(out.size(), in.size());
- EXPECT_GT(out.size(), 0);
- vector<char> decompressed;
- EXPECT_TRUE(GzipDecompress(out, &decompressed));
- EXPECT_EQ(in.size(), decompressed.size());
- EXPECT_TRUE(!memcmp(in.data(), &decompressed[0], in.size()));
-}
-
-TEST(GzipTest, PoorCompressionTest) {
- string in(reinterpret_cast<const char*>(kRandomString),
- sizeof(kRandomString));
- vector<char> out;
- EXPECT_TRUE(GzipCompressString(in, &out));
- EXPECT_GT(out.size(), in.size());
- string out_string(&out[0], out.size());
- vector<char> decompressed;
- EXPECT_TRUE(GzipDecompressString(out_string, &decompressed));
- EXPECT_EQ(in.size(), decompressed.size());
- EXPECT_TRUE(!memcmp(in.data(), &decompressed[0], in.size()));
-}
-
-TEST(GzipTest, MalformedGzipTest) {
- string in(reinterpret_cast<const char*>(kRandomString),
- sizeof(kRandomString));
- vector<char> out;
- EXPECT_FALSE(GzipDecompressString(in, &out));
-}
-
-TEST(GzipTest, EmptyInputsTest) {
- string in;
- vector<char> out;
- EXPECT_TRUE(GzipDecompressString(in, &out));
- EXPECT_EQ(0, out.size());
-
- EXPECT_TRUE(GzipCompressString(in, &out));
- EXPECT_EQ(0, out.size());
-}
-
-} // namespace chromeos_update_engine
diff --git a/zip_unittest.cc b/zip_unittest.cc
new file mode 100644
index 0000000..72bd7f3
--- /dev/null
+++ b/zip_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2009 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 <string.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+#include <gtest/gtest.h>
+#include "update_engine/bzip.h"
+#include "update_engine/gzip.h"
+#include "update_engine/test_utils.h"
+#include "update_engine/utils.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+template <typename T>
+class ZipTest : public ::testing::Test {
+ public:
+ bool ZipDecompress(const std::vector<char>& in,
+ std::vector<char>* out) const = 0;
+ bool ZipCompress(const std::vector<char>& in,
+ std::vector<char>* out) const = 0;
+ bool ZipCompressString(const std::string& str,
+ std::vector<char>* out) const = 0;
+ bool ZipDecompressString(const std::string& str,
+ std::vector<char>* out) const = 0;
+};
+
+class GzipTest {};
+
+template <>
+class ZipTest<GzipTest> : public ::testing::Test {
+ public:
+ bool ZipDecompress(const std::vector<char>& in,
+ std::vector<char>* out) const {
+ return GzipDecompress(in, out);
+ }
+ bool ZipCompress(const std::vector<char>& in,
+ std::vector<char>* out) const {
+ return GzipCompress(in, out);
+ }
+ bool ZipCompressString(const std::string& str,
+ std::vector<char>* out) const {
+ return GzipCompressString(str, out);
+ }
+ bool ZipDecompressString(const std::string& str,
+ std::vector<char>* out) const {
+ return GzipDecompressString(str, out);
+ }
+};
+
+class BzipTest {};
+
+template <>
+class ZipTest<BzipTest> : public ::testing::Test {
+ public:
+ bool ZipDecompress(const std::vector<char>& in,
+ std::vector<char>* out) const {
+ return BzipDecompress(in, out);
+ }
+ bool ZipCompress(const std::vector<char>& in,
+ std::vector<char>* out) const {
+ return BzipCompress(in, out);
+ }
+ bool ZipCompressString(const std::string& str,
+ std::vector<char>* out) const {
+ return BzipCompressString(str, out);
+ }
+ bool ZipDecompressString(const std::string& str,
+ std::vector<char>* out) const {
+ return BzipDecompressString(str, out);
+ }
+};
+
+typedef ::testing::Types<GzipTest, BzipTest>
+ ZipTestTypes;
+TYPED_TEST_CASE(ZipTest, ZipTestTypes);
+
+
+
+TYPED_TEST(ZipTest, SimpleTest) {
+ string in("this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ vector<char> out;
+ EXPECT_TRUE(this->ZipCompressString(in, &out));
+ EXPECT_LT(out.size(), in.size());
+ EXPECT_GT(out.size(), 0);
+ vector<char> decompressed;
+ EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
+ EXPECT_EQ(in.size(), decompressed.size());
+ EXPECT_TRUE(!memcmp(in.data(), &decompressed[0], in.size()));
+}
+
+TYPED_TEST(ZipTest, PoorCompressionTest) {
+ string in(reinterpret_cast<const char*>(kRandomString),
+ sizeof(kRandomString));
+ vector<char> out;
+ EXPECT_TRUE(this->ZipCompressString(in, &out));
+ EXPECT_GT(out.size(), in.size());
+ string out_string(&out[0], out.size());
+ vector<char> decompressed;
+ EXPECT_TRUE(this->ZipDecompressString(out_string, &decompressed));
+ EXPECT_EQ(in.size(), decompressed.size());
+ EXPECT_TRUE(!memcmp(in.data(), &decompressed[0], in.size()));
+}
+
+TYPED_TEST(ZipTest, MalformedZipTest) {
+ string in(reinterpret_cast<const char*>(kRandomString),
+ sizeof(kRandomString));
+ vector<char> out;
+ EXPECT_FALSE(this->ZipDecompressString(in, &out));
+}
+
+TYPED_TEST(ZipTest, EmptyInputsTest) {
+ string in;
+ vector<char> out;
+ EXPECT_TRUE(this->ZipDecompressString(in, &out));
+ EXPECT_EQ(0, out.size());
+
+ EXPECT_TRUE(this->ZipCompressString(in, &out));
+ EXPECT_EQ(0, out.size());
+}
+
+} // namespace chromeos_update_engine