Index: src/platform/update_engine/gzip.cc |
diff --git a/src/platform/update_engine/gzip.cc b/src/platform/update_engine/gzip.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..96437248a8934c5bd15d6355a5558773aa13700d |
--- /dev/null |
+++ b/src/platform/update_engine/gzip.cc |
@@ -0,0 +1,185 @@ |
+// Copyright (c) 2009 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 <zlib.h> |
+#include "chromeos/obsolete_logging.h" |
+#include "update_engine/utils.h" |
+ |
+using std::max; |
+using std::string; |
+using std::vector; |
+ |
+namespace chromeos_update_engine { |
+ |
+bool GzipDecompressData(const char* const in, const size_t in_size, |
+ char** out, size_t* out_size) { |
+ if (in_size == 0) { |
+ // malloc(0) may legally return NULL, so do malloc(1) |
+ *out = reinterpret_cast<char*>(malloc(1)); |
+ *out_size = 0; |
+ return true; |
+ } |
+ TEST_AND_RETURN_FALSE(out); |
+ TEST_AND_RETURN_FALSE(out_size); |
+ z_stream stream; |
+ memset(&stream, 0, sizeof(stream)); |
+ TEST_AND_RETURN_FALSE(inflateInit2(&stream, 16 + MAX_WBITS) == Z_OK); |
+ |
+ // guess that output will be roughly double the input size |
+ *out_size = in_size * 2; |
+ *out = reinterpret_cast<char*>(malloc(*out_size)); |
+ TEST_AND_RETURN_FALSE(*out); |
+ |
+ // TODO(adlr): ensure that this const_cast is safe. |
+ stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(in)); |
+ stream.avail_in = in_size; |
+ stream.next_out = reinterpret_cast<Bytef*>(*out); |
+ stream.avail_out = *out_size; |
+ for (;;) { |
+ int rc = inflate(&stream, Z_FINISH); |
+ switch (rc) { |
+ case Z_STREAM_END: { |
+ *out_size = reinterpret_cast<char*>(stream.next_out) - (*out); |
+ TEST_AND_RETURN_FALSE(inflateEnd(&stream) == Z_OK); |
+ return true; |
+ } |
+ case Z_OK: // fall through |
+ case Z_BUF_ERROR: { |
+ // allocate more space |
+ ptrdiff_t out_length = |
+ reinterpret_cast<char*>(stream.next_out) - (*out); |
+ *out_size *= 2; |
+ char* new_out = reinterpret_cast<char*>(realloc(*out, *out_size)); |
+ if (!new_out) { |
+ free(*out); |
+ return false; |
+ } |
+ *out = new_out; |
+ stream.next_out = reinterpret_cast<Bytef*>((*out) + out_length); |
+ stream.avail_out = (*out_size) - out_length; |
+ break; |
+ } |
+ default: |
+ LOG(INFO) << "Unknown inflate() return value: " << rc; |
+ if (stream.msg) |
+ LOG(INFO) << " message: " << stream.msg; |
+ free(*out); |
+ return false; |
+ } |
+ } |
+} |
+ |
+bool GzipCompressData(const char* const in, const size_t in_size, |
+ char** out, size_t* out_size) { |
+ if (in_size == 0) { |
+ // malloc(0) may legally return NULL, so do malloc(1) |
+ *out = reinterpret_cast<char*>(malloc(1)); |
+ *out_size = 0; |
+ return true; |
+ } |
+ TEST_AND_RETURN_FALSE(out); |
+ TEST_AND_RETURN_FALSE(out_size); |
+ z_stream stream; |
+ memset(&stream, 0, sizeof(stream)); |
+ TEST_AND_RETURN_FALSE(deflateInit2(&stream, |
+ Z_BEST_COMPRESSION, |
+ Z_DEFLATED, |
+ 16 + MAX_WBITS, |
+ 9, // most memory used/best compression |
+ Z_DEFAULT_STRATEGY) == Z_OK); |
+ |
+ // guess that output will be roughly half the input size |
+ *out_size = max(1U, in_size / 2); |
+ *out = reinterpret_cast<char*>(malloc(*out_size)); |
+ TEST_AND_RETURN_FALSE(*out); |
+ |
+ // TODO(adlr): ensure that this const_cast is safe. |
+ stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(in)); |
+ stream.avail_in = in_size; |
+ stream.next_out = reinterpret_cast<Bytef*>(*out); |
+ stream.avail_out = *out_size; |
+ for (;;) { |
+ int rc = deflate(&stream, Z_FINISH); |
+ switch (rc) { |
+ case Z_STREAM_END: { |
+ *out_size = reinterpret_cast<char*>(stream.next_out) - (*out); |
+ TEST_AND_RETURN_FALSE(deflateEnd(&stream) == Z_OK); |
+ return true; |
+ } |
+ case Z_OK: // fall through |
+ case Z_BUF_ERROR: { |
+ // allocate more space |
+ ptrdiff_t out_length = |
+ reinterpret_cast<char*>(stream.next_out) - (*out); |
+ *out_size *= 2; |
+ char* new_out = reinterpret_cast<char*>(realloc(*out, *out_size)); |
+ if (!new_out) { |
+ free(*out); |
+ return false; |
+ } |
+ *out = new_out; |
+ stream.next_out = reinterpret_cast<Bytef*>((*out) + out_length); |
+ stream.avail_out = (*out_size) - out_length; |
+ break; |
+ } |
+ default: |
+ LOG(INFO) << "Unknown defalate() return value: " << rc; |
+ if (stream.msg) |
+ LOG(INFO) << " message: " << stream.msg; |
+ free(*out); |
+ return false; |
+ } |
+ } |
+} |
+ |
+bool GzipDecompress(const std::vector<char>& in, std::vector<char>* out) { |
+ TEST_AND_RETURN_FALSE(out); |
+ char* out_buf; |
+ size_t out_size; |
+ TEST_AND_RETURN_FALSE(GzipDecompressData(&in[0], in.size(), |
+ &out_buf, &out_size)); |
+ out->insert(out->end(), out_buf, out_buf + out_size); |
+ free(out_buf); |
+ return true; |
+} |
+ |
+bool GzipCompress(const std::vector<char>& in, std::vector<char>* out) { |
+ TEST_AND_RETURN_FALSE(out); |
+ char* out_buf; |
+ size_t out_size; |
+ TEST_AND_RETURN_FALSE(GzipCompressData(&in[0], in.size(), |
+ &out_buf, &out_size)); |
+ out->insert(out->end(), out_buf, out_buf + out_size); |
+ free(out_buf); |
+ return true; |
+} |
+ |
+bool GzipCompressString(const std::string& str, |
+ std::vector<char>* out) { |
+ TEST_AND_RETURN_FALSE(out); |
+ char* out_buf; |
+ size_t out_size; |
+ TEST_AND_RETURN_FALSE(GzipCompressData(str.data(), str.size(), |
+ &out_buf, &out_size)); |
+ out->insert(out->end(), out_buf, out_buf + out_size); |
+ free(out_buf); |
+ return true; |
+} |
+ |
+bool GzipDecompressString(const std::string& str, |
+ std::vector<char>* out) { |
+ TEST_AND_RETURN_FALSE(out); |
+ char* out_buf; |
+ size_t out_size; |
+ TEST_AND_RETURN_FALSE(GzipDecompressData(str.data(), str.size(), |
+ &out_buf, &out_size)); |
+ out->insert(out->end(), out_buf, out_buf + out_size); |
+ free(out_buf); |
+ return true; |
+} |
+ |
+} // namespace chromeos_update_engine |