diff options
author | Rumou Duan <rduan@google.com> | 2016-09-21 21:59:01 +0000 |
---|---|---|
committer | Laszlo Csomor <laszlocsomor@google.com> | 2016-09-22 09:55:50 +0000 |
commit | a518f63e6a9f42996b1707dd6bb9a9287eb5b675 (patch) | |
tree | 0dc35c1f3a1dd9a7b6f2297a23b32a82e35ede4f /third_party/ijar | |
parent | d7886f0589c217f90dca42cb5269d004ed3abbd1 (diff) |
Move zlib-interfacing code from third_party/ijar/zip.cc into a separate class. And add a dummy zlib client.
--
MOS_MIGRATED_REVID=133879880
Diffstat (limited to 'third_party/ijar')
-rw-r--r-- | third_party/ijar/BUILD | 10 | ||||
-rw-r--r-- | third_party/ijar/dummy_zlib_client.cc | 37 | ||||
-rw-r--r-- | third_party/ijar/zip.cc | 146 | ||||
-rw-r--r-- | third_party/ijar/zip.h | 3 | ||||
-rw-r--r-- | third_party/ijar/zlib_client.cc | 161 | ||||
-rw-r--r-- | third_party/ijar/zlib_client.h | 68 |
6 files changed, 311 insertions, 114 deletions
diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD index 85245de548..9abfd4d46c 100644 --- a/third_party/ijar/BUILD +++ b/third_party/ijar/BUILD @@ -24,6 +24,16 @@ cc_library( "mapped_file.h", "zip.h", ], + deps = [":zlib_client"], +) + +cc_library( + name = "zlib_client", + srcs = ["zlib_client.cc"], + hdrs = [ + "common.h", + "zlib_client.h", + ], deps = ["//third_party/zlib"], ) diff --git a/third_party/ijar/dummy_zlib_client.cc b/third_party/ijar/dummy_zlib_client.cc new file mode 100644 index 0000000000..fe1498770a --- /dev/null +++ b/third_party/ijar/dummy_zlib_client.cc @@ -0,0 +1,37 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <algorithm> + +#include "third_party/ijar/common.h" +#include "third_party/ijar/zlib_client.h" + +namespace devtools_ijar { + +u4 ComputeCrcChecksum(u1* buf, size_t length) { return 0; } + +size_t TryDeflate(u1* buf, size_t length) { return 0; } + +Decompressor::Decompressor() {} +Decompressor::~Decompressor() {} + +DecompressedFile* Decompressor::UncompressFile(const u1* buffer, + size_t bytes_avail) { + return NULL; +} + +char* Decompressor::GetError() { return NULL; } + +int Decompressor::error(const char* fmt, ...) { return 0; } +} // namespace devtools_ijar diff --git a/third_party/ijar/zip.cc b/third_party/ijar/zip.cc index a3d8c53831..3a56103eae 100644 --- a/third_party/ijar/zip.cc +++ b/third_party/ijar/zip.cc @@ -38,7 +38,7 @@ #include "third_party/ijar/mapped_file.h" #include "third_party/ijar/zip.h" -#include <zlib.h> +#include "third_party/ijar/zlib_client.h" #define LOCAL_FILE_HEADER_SIGNATURE 0x04034b50 #define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50 @@ -160,6 +160,8 @@ class InputZipFile : public ZipExtractor { // last error char errmsg[4*PATH_MAX]; + Decompressor *decompressor_; + int error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -458,73 +460,20 @@ int InputZipFile::SkipFile(const bool compressed) { u1* InputZipFile::UncompressFile() { size_t in_offset = p - zipdata_in_; size_t remaining = input_file_->Length() - in_offset; - z_stream stream; - - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - stream.avail_in = remaining; - stream.next_in = (Bytef *) p; - - int ret = inflateInit2(&stream, -MAX_WBITS); - if (ret != Z_OK) { - error("inflateInit: %d\n", ret); - return NULL; - } - - int uncompressed_until_now = 0; - - while (true) { - stream.avail_out = uncompressed_data_allocated_ - uncompressed_until_now; - stream.next_out = uncompressed_data_ + uncompressed_until_now; - int old_avail_out = stream.avail_out; - - ret = inflate(&stream, Z_SYNC_FLUSH); - int uncompressed_now = old_avail_out - stream.avail_out; - uncompressed_until_now += uncompressed_now; - - switch (ret) { - case Z_STREAM_END: { - // zlib said that there is no more data to decompress. - - u1 *new_p = reinterpret_cast<u1*>(stream.next_in); - compressed_size_ = new_p - p; - uncompressed_size_ = uncompressed_until_now; - p = new_p; - inflateEnd(&stream); - return uncompressed_data_; - } - - case Z_OK: { - // zlib said that there is no more room in the buffer allocated for - // the decompressed data. Enlarge that buffer and try again. - - if (uncompressed_data_allocated_ == MAX_BUFFER_SIZE) { - error("ijar does not support decompressing files " - "larger than %dMB.\n", - (int) (MAX_BUFFER_SIZE/(1024*1024))); - return NULL; - } - - uncompressed_data_allocated_ *= 2; - if (uncompressed_data_allocated_ > MAX_BUFFER_SIZE) { - uncompressed_data_allocated_ = MAX_BUFFER_SIZE; - } - - uncompressed_data_ = reinterpret_cast<u1*>( - realloc(uncompressed_data_, uncompressed_data_allocated_)); - break; - } - - case Z_DATA_ERROR: - case Z_BUF_ERROR: - case Z_STREAM_ERROR: - case Z_NEED_DICT: - default: { - error("zlib returned error code %d during inflate.\n", ret); - return NULL; - } + DecompressedFile *decompressed_file = + decompressor_->UncompressFile(p, remaining); + if (decompressed_file == NULL) { + if (decompressor_->GetError() != NULL) { + error(decompressor_->GetError()); } + return NULL; + } else { + compressed_size_ = decompressed_file->compressed_size; + uncompressed_size_ = decompressed_file->uncompressed_size; + u1 *uncompressed_data = decompressed_file->uncompressed_data; + free(decompressed_file); + p += compressed_size_; + return uncompressed_data; } } @@ -859,9 +808,7 @@ InputZipFile::InputZipFile(ZipExtractorProcessor *processor, const char* filename) : processor(processor), filename_(filename), input_file_(NULL), bytes_unmapped_(0) { - uncompressed_data_allocated_ = INITIAL_BUFFER_SIZE; - uncompressed_data_ = - reinterpret_cast<u1*>(malloc(uncompressed_data_allocated_)); + decompressor_ = new Decompressor(); errmsg[0] = 0; } @@ -900,7 +847,7 @@ bool InputZipFile::Open() { } InputZipFile::~InputZipFile() { - free(uncompressed_data_); + delete decompressor_; if (input_file_ != NULL) { input_file_->Close(); delete input_file_; @@ -1064,46 +1011,6 @@ u1* OutputZipFile::WriteLocalFileHeader(const char* filename, const u4 attr) { return header_ptr; } -// Try to compress a file entry in memory using the deflate algorithm. -// It will compress buf (of size length) unless the compressed size is bigger -// than the input size. The result will overwrite the content of buf and the -// final size is returned. -size_t TryDeflate(u1 *buf, size_t length) { - u1 *outbuf = reinterpret_cast<u1 *>(malloc(length)); - z_stream stream; - - // Initialize the z_stream strcut for reading from buf and wrinting in outbuf. - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - stream.total_in = length; - stream.avail_in = length; - stream.total_out = length; - stream.avail_out = length; - stream.next_in = buf; - stream.next_out = outbuf; - - // deflateInit2 negative windows size prevent the zlib wrapper to be used. - if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, - -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) { - // Failure to compress => return the buffer uncompressed - free(outbuf); - return length; - } - - if (deflate(&stream, Z_FINISH) == Z_STREAM_END) { - // Compression successful and fits in outbuf, let's copy the result in buf. - length = stream.total_out; - memcpy(buf, outbuf, length); - } - - deflateEnd(&stream); - free(outbuf); - - // Return the length of the resulting buffer - return length; -} - size_t OutputZipFile::WriteFileSizeInLocalFileHeader(u1 *header_ptr, size_t out_length, bool compress, @@ -1149,10 +1056,21 @@ int OutputZipFile::FinishFile(size_t filelength, bool compress, bool compute_crc) { u4 crc = 0; if (compute_crc) { - crc = crc32(crc, q, filelength); + crc = ComputeCrcChecksum(q, filelength); + + if (filelength > 0 && crc == 0) { + fprintf(stderr, "Error calculating CRC32 checksum.\n"); + return -1; + } } size_t compressed_size = WriteFileSizeInLocalFileHeader(header_ptr, filelength, compress, crc); + + if (compressed_size == 0 && filelength > 0) { + fprintf(stderr, "Error compressing files.\n"); + return -1; + } + entries_.back()->crc32 = crc; entries_.back()->compressed_length = compressed_size; entries_.back()->uncompressed_length = filelength; @@ -1200,7 +1118,9 @@ ZipBuilder* ZipBuilder::Create(const char* zip_file, u8 estimated_size) { return result; } -u8 ZipBuilder::EstimateSize(char **files, char **zip_paths, int nb_entries) { +u8 ZipBuilder::EstimateSize(char const* const* files, + char const* const* zip_paths, + int nb_entries) { struct stat statst; // Digital signature field size = 6, End of central directory = 22, Total = 28 u8 size = 28; diff --git a/third_party/ijar/zip.h b/third_party/ijar/zip.h index 6ca2e40f88..15b0198bb2 100644 --- a/third_party/ijar/zip.h +++ b/third_party/ijar/zip.h @@ -103,7 +103,8 @@ class ZipBuilder { // Estimate the maximum size of the ZIP files containing files in the "files" // null-terminated array. // Returns 0 on error. - static u8 EstimateSize(char** files, char** zip_paths, int nb_entries); + static u8 EstimateSize(char const* const* files, char const* const* zip_paths, + int nb_entries); }; // diff --git a/third_party/ijar/zlib_client.cc b/third_party/ijar/zlib_client.cc new file mode 100644 index 0000000000..1738a05465 --- /dev/null +++ b/third_party/ijar/zlib_client.cc @@ -0,0 +1,161 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <stdlib.h> +#include <algorithm> + +#include "third_party/ijar/common.h" +#include "third_party/ijar/zlib_client.h" +#include <zlib.h> + +namespace devtools_ijar { + +u4 ComputeCrcChecksum(u1 *buf, size_t length) { + return crc32(0, buf, length); +} + +size_t TryDeflate(u1 *buf, size_t length) { + u1 *outbuf = reinterpret_cast<u1 *>(malloc(length)); + z_stream stream; + + // Initialize the z_stream strcut for reading from buf and wrinting in outbuf. + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.total_in = length; + stream.avail_in = length; + stream.total_out = length; + stream.avail_out = length; + stream.next_in = buf; + stream.next_out = outbuf; + + // deflateInit2 negative windows size prevent the zlib wrapper to be used. + if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, + Z_DEFAULT_STRATEGY) != Z_OK) { + // Failure to compress => return the buffer uncompressed + free(outbuf); + return length; + } + + if (deflate(&stream, Z_FINISH) == Z_STREAM_END) { + // Compression successful and fits in outbuf, let's copy the result in buf. + length = stream.total_out; + memcpy(buf, outbuf, length); + } + + deflateEnd(&stream); + free(outbuf); + + // Return the length of the resulting buffer + return length; +} + +Decompressor::Decompressor() { + uncompressed_data_allocated_ = INITIAL_BUFFER_SIZE; + uncompressed_data_ = + reinterpret_cast<u1 *>(malloc(uncompressed_data_allocated_)); +} + +Decompressor::~Decompressor() { free(uncompressed_data_); } + +DecompressedFile *Decompressor::UncompressFile(const u1 *buffer, + size_t bytes_avail) { + z_stream stream; + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = bytes_avail; + stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(buffer)); + + int ret = inflateInit2(&stream, -MAX_WBITS); + if (ret != Z_OK) { + error("inflateInit: %d\n", ret); + return NULL; + } + + int uncompressed_until_now = 0; + + while (true) { + stream.avail_out = uncompressed_data_allocated_ - uncompressed_until_now; + stream.next_out = uncompressed_data_ + uncompressed_until_now; + int old_avail_out = stream.avail_out; + + ret = inflate(&stream, Z_SYNC_FLUSH); + int uncompressed_now = old_avail_out - stream.avail_out; + uncompressed_until_now += uncompressed_now; + + switch (ret) { + case Z_STREAM_END: { + struct DecompressedFile *decompressedFile = + reinterpret_cast<DecompressedFile *>( + malloc(sizeof(DecompressedFile))); + // zlib said that there is no more data to decompress. + u1 *new_p = reinterpret_cast<u1 *>(stream.next_in); + decompressedFile->compressed_size = new_p - buffer; + decompressedFile->uncompressed_size = uncompressed_until_now; + decompressedFile->uncompressed_data = uncompressed_data_; + inflateEnd(&stream); + return decompressedFile; + } + + case Z_OK: { + // zlib said that there is no more room in the buffer allocated for + // the decompressed data. Enlarge that buffer and try again. + + if (uncompressed_data_allocated_ == MAX_BUFFER_SIZE) { + error( + "ijar does not support decompressing files " + "larger than %dMB.\n", + static_cast<int>((MAX_BUFFER_SIZE / (1024 * 1024)))); + return NULL; + } + + uncompressed_data_allocated_ *= 2; + if (uncompressed_data_allocated_ > MAX_BUFFER_SIZE) { + uncompressed_data_allocated_ = MAX_BUFFER_SIZE; + } + + uncompressed_data_ = reinterpret_cast<u1 *>( + realloc(uncompressed_data_, uncompressed_data_allocated_)); + break; + } + + case Z_DATA_ERROR: + case Z_BUF_ERROR: + case Z_STREAM_ERROR: + case Z_NEED_DICT: + default: { + error("zlib returned error code %d during inflate.\n", ret); + return NULL; + } + } + } +} + +char *Decompressor::GetError() { + if (errmsg[0] == 0) { + return NULL; + } + return errmsg; +} + +int Decompressor::error(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vsnprintf(errmsg, 4 * PATH_MAX, fmt, ap); + va_end(ap); + return -1; +} +} // namespace devtools_ijar diff --git a/third_party/ijar/zlib_client.h b/third_party/ijar/zlib_client.h new file mode 100644 index 0000000000..ed6616362f --- /dev/null +++ b/third_party/ijar/zlib_client.h @@ -0,0 +1,68 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_IJAR_ZLIB_CLIENT_H_ +#define THIRD_PARTY_IJAR_ZLIB_CLIENT_H_ + +#include <limits.h> + +#include "third_party/ijar/common.h" + +namespace devtools_ijar { +// Try to compress a file entry in memory using the deflate algorithm. +// It will compress buf (of size length) unless the compressed size is bigger +// than the input size. The result will overwrite the content of buf and the +// final size is returned. +size_t TryDeflate(u1* buf, size_t length); + +u4 ComputeCrcChecksum(u1* buf, size_t length); + +struct DecompressedFile { + u1* uncompressed_data; + u4 uncompressed_size; + u4 compressed_size; +}; + +class Decompressor { + public: + Decompressor(); + ~Decompressor(); + DecompressedFile* UncompressFile(const u1* buffer, size_t bytes_avail); + char* GetError(); + + private: + // Administration of memory reserved for decompressed data. We use the same + // buffer for each file to avoid some malloc()/free() calls and free the + // memory only in the dtor. C-style memory management is used so that we + // can call realloc. + u1* uncompressed_data_; + size_t uncompressed_data_allocated_; + // last error + char errmsg[4 * PATH_MAX]; + + int error(const char* fmt, ...); + + // Buffer size is initially INITIAL_BUFFER_SIZE. It doubles in size every + // time it is found too small, until it reaches MAX_BUFFER_SIZE. If that is + // not enough, we bail out. We only decompress class files, so they should + // be smaller than 64K anyway, but we give a little leeway. + // MAX_BUFFER_SIZE must be bigger than the size of the biggest file in the + // ZIP. It is set to 2GB here because no one has audited the code for 64-bit + // cleanliness. + static const size_t INITIAL_BUFFER_SIZE = 256 * 1024; // 256K + static const size_t MAX_BUFFER_SIZE = std::numeric_limits<int32_t>::max(); +}; +} // namespace devtools_ijar + +#endif // THIRD_PARTY_IJAR_ZLIB_CLIENT_H_ |