diff options
author | Sasha Smundak <asmundak@google.com> | 2016-07-15 17:35:51 +0000 |
---|---|---|
committer | Yun Peng <pcloudy@google.com> | 2016-07-18 10:43:29 +0000 |
commit | 06a12e561268f67de6a417315944f8e4d05afc0f (patch) | |
tree | a9fe559e7f307d0a132c59def9fa309c8710465a /src/tools/singlejar/zip_headers.h | |
parent | 5ea55cbab969820da346d16c4998e957b8c3f60e (diff) |
C++ reimplementation of singlejar tool: first checkin, take two: fix the problem that caused the rollback.
*** Original change description ***
Automated [] rollback of commit f667aa54f4fcc2c04182de9bc267a7ee469f6445.
*** Reason for rollback ***
Breaks CI, see, e.g., http://ci.bazel.io/job/bazel-tests/BAZEL_VERSION=HEAD,PLATFORM_NAME=ubuntu_15.10-x86_64/92/console
*** Original change description ***
C++ reimplementation of singlejar tool: first checkin.
--
MOS_MIGRATED_REVID=127554239
Diffstat (limited to 'src/tools/singlejar/zip_headers.h')
-rw-r--r-- | src/tools/singlejar/zip_headers.h | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/src/tools/singlejar/zip_headers.h b/src/tools/singlejar/zip_headers.h new file mode 100644 index 0000000000..d1018d3553 --- /dev/null +++ b/src/tools/singlejar/zip_headers.h @@ -0,0 +1,485 @@ +// 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 BAZEL_SRC_TOOLS_SINGLEJAR_ZIP_HEADERS_H_ +#define BAZEL_SRC_TOOLS_SINGLEJAR_ZIP_HEADERS_H_ + +/* + * Zip file headers, as described in .ZIP File Format Specification + * http://www.pkware.com/documents/casestudies/APPNOTE.TXT + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__linux) +#include <endian.h> +#elif defined(__APPLE__) +// Hopefully OSX will keep running solely on little endian CPUs, so: +#define le16toh(x) (x) +#define le32toh(x) (x) +#define le64toh(x) (x) +#define htole16(x) (x) +#define htole32(x) (x) +#define htole64(x) (x) +#else +#error "This platform is not supported." +#endif + +#include <type_traits> + +static const uint8_t *byte_ptr(const void *ptr) { + return reinterpret_cast<const uint8_t *>(ptr); +} + +/* Overall .ZIP file format (section 4.3.6), and the corresponding classes + * [local file header 1] class LH + * [encryption header 1] + * [file data 1] + * [data descriptor 1] + * . + * . + * . + * [local file header n] + * [encryption header n] + * [file data n] + * [data descriptor n] + * [archive decryption header] + * [archive extra data record] + * [central directory header 1] class CDH + * . + * . + * . + * [central directory header n] + * [zip64 end of central directory record] class ECD64 + * [zip64 end of central directory locator] class ECDLocator + * [end of central directory record] class ECD + */ + +/* Zip64 Extra Field (section 4.5.3 of the .ZIP format spec) + * + * It is present if a value of a uncompressed_size/compressed_size/file_offset + * exceeds 32 bits. It consists of a 4-byte header followed by + * [64-bit uncompressed_size] [64-bit compressed_size] [64-bit file_offset] + * Only the entities whose value exceed 32 bits are present, and the present + * ones are always in the order shown above. The originating 32-bit field + * contains 0xFFFFFFFF to indicate that the value is 64-bit and is in + * Zip64 Extra Field. + */ +class Zip64ExtraField { + public: + static const Zip64ExtraField *find(const uint8_t *start, const uint8_t *end) { + while (start < end) { + const Zip64ExtraField *z64 = + reinterpret_cast<const Zip64ExtraField *>(start); + if (z64->is()) { + return z64; + } + start = byte_ptr(start) + z64->size(); + } + return nullptr; + } + + bool is() const { return 1 == le16toh(tag_); } + void signature() { tag_ = htole16(1); } + + uint16_t payload_size() const { return le16toh(payload_size_); } + void payload_size(uint16_t v) { payload_size_ = htole16(v); } + + uint16_t size() const { return sizeof(Zip64ExtraField) + payload_size(); } + + // The value of i-th attribute + uint64_t attr64(int index) const { return le64toh(attr_[index]); } + + private: + uint16_t tag_; + uint16_t payload_size_; + uint64_t attr_[]; +} __attribute__((packed)); +static_assert(4 == sizeof(Zip64ExtraField), + "Zip64ExtraField class fields layout is incorrect."); + +/* Local Header precedes each archive file data (section 4.3.7). */ +class LH { + public: + bool is() const { return 0x04034b50 == le32toh(signature_); } + void signature() { signature_ = htole32(0x04034b50); } + + uint16_t version() const { return le16toh(version_); } + void version(uint16_t v) { version_ = htole16(v); } + + void bit_flag(uint16_t v) { bit_flag_ = htole16(v); } + uint16_t bit_flag() const { return le16toh(bit_flag_); } + + uint16_t compression_method() const { return le16toh(compression_method_); } + void compression_method(uint16_t v) { compression_method_ = htole16(v); } + + uint16_t last_mod_file_time() const { return le16toh(last_mod_file_time_); } + void last_mod_file_time(uint16_t v) { last_mod_file_time_ = htole16(v); } + + uint16_t last_mod_file_date() const { return le16toh(last_mod_file_date_); } + void last_mod_file_date(uint16_t v) { last_mod_file_date_ = htole16(v); } + + uint32_t crc32() const { return le32toh(crc32_); } + void crc32(uint32_t v) { crc32_ = htole32(v); } + + size_t compressed_file_size() const { + size_t size32 = compressed_file_size32(); + if (size32 != 0xFFFFFFFF) { + return size32; + } + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr + ? 0xFFFFFFFF + : z64->attr64(uncompressed_file_size32() == 0xFFFFFFFF ? 1 : 0); + } + size_t compressed_file_size32() const { + return le32toh(compressed_file_size32_); + } + void compressed_file_size32(uint32_t v) { + compressed_file_size32_ = htole32(v); + } + + size_t uncompressed_file_size() const { + size_t size32 = uncompressed_file_size32(); + if (size32 != 0xFFFFFFFF) { + return size32; + } + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); + } + size_t uncompressed_file_size32() const { + return le32toh(uncompressed_file_size32_); + } + void uncompressed_file_size32(uint32_t v) { + uncompressed_file_size32_ = htole32(v); + } + + uint16_t file_name_length() const { return le16toh(file_name_length_); } + const char *file_name() const { return file_name_; } + void file_name(const char *filename, uint16_t len) { + file_name_length_ = htole16(len); + if (len) { + memcpy(file_name_, filename, file_name_length_); + } + } + bool file_name_is(const char *name) const { + size_t name_len = strlen(name); + return file_name_length() == name_len && + 0 == strncmp(file_name(), name, name_len); + } + + uint16_t extra_fields_length() const { return le16toh(extra_fields_length_); } + void extra_fields_length(uint16_t v) { + extra_fields_length_ = htole16(extra_fields_length_); + } + const uint8_t *extra_fields() const { + return byte_ptr(file_name_ + file_name_length_); + } + + size_t size() const { + return sizeof(LH) + file_name_length() + extra_fields_length(); + } + const uint8_t *data() const { return extra_fields() + extra_fields_length(); } + size_t in_zip_size() const { + return compression_method() ? compressed_file_size() + : uncompressed_file_size(); + } + + const Zip64ExtraField *zip64_extra_field() const { + return Zip64ExtraField::find(extra_fields(), + extra_fields() + extra_fields_length()); + } + + private: + uint32_t signature_; + uint16_t version_; + uint16_t bit_flag_; + uint16_t compression_method_; + uint16_t last_mod_file_time_; + uint16_t last_mod_file_date_; + uint32_t crc32_; + uint32_t compressed_file_size32_; + uint32_t uncompressed_file_size32_; + uint16_t file_name_length_; + uint16_t extra_fields_length_; + char file_name_[0]; + // Followed by extra_fields. +} __attribute__((packed)); +static_assert(30 == sizeof(LH), "The fields layout for class LH is incorrect"); + +/* Central Directory Header. */ +class CDH { + public: + void signature() { signature_ = htole32(0x02014b50); } + bool is() const { return 0x02014b50 == le32toh(signature_); } + + void version(uint16_t v) { version_ = htole16(v); } + + void version_to_extract(uint16_t v) { version_to_extract_ = htole16(v); } + + void bit_flag(uint16_t v) { bit_flag_ = htole16(v); } + uint16_t bit_flag() const { return le16toh(bit_flag_); } + + void compression_method(uint16_t v) { compression_method_ = htole16(v); } + + void last_mod_file_time(uint16_t v) { last_mod_file_time_ = htole16(v); } + + void last_mod_file_date(uint16_t v) { last_mod_file_date_ = htole16(v); } + + void crc32(uint32_t v) { crc32_ = htole32(v); } + + size_t compressed_file_size() const { + size_t size32 = compressed_file_size32(); + if (size32 != 0xFFFFFFFF) { + return size32; + } + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr + ? 0xFFFFFFFF + : z64->attr64(uncompressed_file_size32() == 0xFFFFFFFF ? 1 : 0); + } + size_t compressed_file_size32() const { + return le32toh(compressed_file_size32_); + } + void compressed_file_size32(uint32_t v) { + compressed_file_size32_ = htole32(v); + } + + size_t uncompressed_file_size() const { + uint32_t size32 = uncompressed_file_size32(); + if (size32 != 0xFFFFFFFF) { + return size32; + } + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); + } + size_t uncompressed_file_size32() const { + return le32toh(uncompressed_file_size32_); + } + + void uncompressed_file_size32(uint32_t v) { + uncompressed_file_size32_ = htole32(v); + } + + uint16_t file_name_length() const { return le16toh(file_name_length_); } + const char *file_name() const { return file_name_; } + void file_name(const char *filename, uint16_t filename_len) { + file_name_length_ = htole16(filename_len); + if (filename_len) { + memcpy(file_name_, filename, filename_len); + } + } + bool file_name_is(const char *name) const { + size_t name_len = strlen(name); + return file_name_length() == name_len && + 0 == strncmp(file_name(), name, name_len); + } + + uint16_t extra_fields_length() const { return le16toh(extra_fields_length_); } + const uint8_t *extra_fields() const { + return byte_ptr(file_name_ + file_name_length_); + } + void extra_fields_length(uint16_t v) { extra_fields_length_ = htole16(v); } + + uint16_t comment_length() const { return le16toh(comment_length_); } + void comment_length(uint16_t v) { comment_length_ = htole16(v); } + + uint16_t start_disk_nr() const { return le16toh(start_disk_nr_); } + void disk_number(uint16_t v) { start_disk_nr_ = htole16(v); } + + uint16_t internal_attributes() const { return le16toh(internal_attributes_); } + void internal_attributes(uint16_t v) { internal_attributes_ = htole16(v); } + + uint32_t external_attribute() const { return le32toh(external_attributes_); } + void external_attribute(uint32_t v) { external_attributes_ = htole32(v); } + + uint64_t local_header_offset() const { + uint32_t size32 = local_header_offset32(); + if (size32 != 0xFFFFFFFF) { + return size32; + } + const Zip64ExtraField *z64 = zip64_extra_field(); + int attr_no = uncompressed_file_size32() == 0xFFFFFFFF ? 1 : 0; + if (compressed_file_size32() == 0xFFFFFFFF) { + ++attr_no; + } + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(attr_no); + } + + uint32_t local_header_offset32() const { + return le32toh(local_header_offset32_); + } + void local_header_offset32(uint32_t v) { + local_header_offset32_ = htole32(v); + } + bool no_size_in_local_header() const { return bit_flag() & 0x08; } + size_t size() const { + return sizeof(*this) + file_name_length() + extra_fields_length() + + comment_length(); + } + + const Zip64ExtraField *zip64_extra_field() const { + return Zip64ExtraField::find(extra_fields(), + extra_fields() + extra_fields_length()); + } + + private: + uint32_t signature_; + uint16_t version_; + uint16_t version_to_extract_; + uint16_t bit_flag_; + uint16_t compression_method_; + uint16_t last_mod_file_time_; + uint16_t last_mod_file_date_; + uint32_t crc32_; + uint32_t compressed_file_size32_; + uint32_t uncompressed_file_size32_; + uint16_t file_name_length_; + uint16_t extra_fields_length_; + uint16_t comment_length_; + uint16_t start_disk_nr_; + uint16_t internal_attributes_; + uint32_t external_attributes_; + uint32_t local_header_offset32_; + char file_name_[0]; + // Followed by extra fields and then comment. +} __attribute__((packed)); +static_assert(46 == sizeof(CDH), "Class CDH fields layout is incorrect."); + +/* Zip64 End of Central Directory Locator. */ +class ECD64Locator { + public: + void signature() { signature_ = htole32(0x07064b50); } + bool is() const { return 0x07064b50 == le32toh(signature_); } + + void ecd64_disk_nr(uint32_t nr) { ecd64_disk_nr_ = htole32(nr); } + uint32_t ecd4_disk_nr() const { return le32toh(ecd64_disk_nr_); } + + void ecd64_offset(uint64_t v) { ecd64_offset_ = htole64(v); } + uint64_t ecd64_offset() const { return le64toh(ecd64_offset_); } + + void total_disks(uint32_t v) { total_disks_ = htole32(v); } + uint32_t total_disks() const { return le32toh(total_disks_); } + + private: + uint32_t signature_; + uint32_t ecd64_disk_nr_; + uint64_t ecd64_offset_; + uint32_t total_disks_; +} __attribute__((packed)); +static_assert(20 == sizeof(ECD64Locator), + "ECD64Locator class fields layout is incorrect."); + +/* End of Central Directory. */ +class ECD { + public: + void signature() { signature_ = htole32(0x06054b50); } + bool is() const { return 0x06054b50 == le32toh(signature_); } + + void this_disk_nr(uint16_t v) { this_disk_nr_ = htole16(v); } + uint16_t this_disk_nr() const { return le16toh(this_disk_nr_); } + + void cen_disk_nr(uint16_t v) { cen_disk_nr_ = htole16(v); } + uint16_t cen_disk_nr() const { return le16toh(cen_disk_nr_); } + + void this_disk_entries16(uint16_t v) { this_disk_entries16_ = htole16(v); } + uint16_t this_disk_entries16() const { return le16toh(this_disk_entries16_); } + + void total_entries16(uint16_t v) { total_entries16_ = htole16(v); } + uint16_t total_entries16() const { return le16toh(total_entries16_); } + + void cen_size32(uint32_t v) { cen_size32_ = htole32(v); } + uint32_t cen_size32() const { return le32toh(cen_size32_); } + + void cen_offset32(uint32_t v) { cen_offset32_ = htole32(v); } + uint32_t cen_offset32() const { return le32toh(cen_offset32_); } + + void comment(uint8_t *data, uint16_t data_size) { + comment_length_ = htole16(data_size); + if (data_size) { + memcpy(comment_, data, data_size); + } + } + uint16_t comment_length() const { return le16toh(comment_length_); } + const uint8_t *comment() const { return comment_; } + + uint64_t ecd64_offset() const { + const ECD64Locator *locator = reinterpret_cast<const ECD64Locator *>( + byte_ptr(this) - sizeof(ECD64Locator)); + return locator->is() ? locator->ecd64_offset() : 0xFFFFFFFFFFFFFFFF; + } + + private: + uint32_t signature_; + uint16_t this_disk_nr_; + uint16_t cen_disk_nr_; + uint16_t this_disk_entries16_; + uint16_t total_entries16_; + uint32_t cen_size32_; + uint32_t cen_offset32_; + uint16_t comment_length_; + uint8_t comment_[0]; +} __attribute__((packed)); +static_assert(22 == sizeof(ECD), "ECD class fields layout is incorrect."); + +/* Zip64 end of central directory. */ +class ECD64 { + public: + bool is() const { return 0x06064b50 == le32toh(signature_); } + void signature() { signature_ = htole32(0x06064b50); } + + void remaining_size(uint64_t v) { remaining_size_ = htole64(v); } + uint64_t remaining_size() const { return le64toh(remaining_size_); } + + void version(uint16_t v) { version_ = htole16(v); } + uint16_t version() const { return le16toh(version_); } + + void version_to_extract(uint16_t v) { version_to_extract_ = htole16(v); } + uint16_t version_to_extract() const { return le16toh(version_to_extract_); } + + void this_disk_nr(uint32_t v) { this_disk_nr_ = htole32(v); } + uint32_t this_disk_nr() const { return le32toh(this_disk_nr_); } + + void cen_disk_nr(uint32_t v) { cen_disk_nr_ = htole32(v); } + uint32_t cen_disk_nr() const { return le32toh(cen_disk_nr_); } + + void this_disk_entries(uint64_t v) { this_disk_entries_ = htole64(v); } + uint64_t this_disk_entries() const { return le64toh(this_disk_entries_); } + + void total_entries(uint64_t v) { total_entries_ = htole64(v); } + uint64_t total_entries() const { return le64toh(total_entries_); } + + void cen_size(uint64_t v) { cen_size_ = htole64(v); } + uint64_t cen_size() const { return le64toh(cen_size_); } + + void cen_offset(uint64_t v) { cen_offset_ = htole64(v); } + uint64_t cen_offset() const { return le64toh(cen_offset_); } + + private: + uint32_t signature_; + uint64_t remaining_size_; + uint16_t version_; + uint16_t version_to_extract_; + uint32_t this_disk_nr_; + uint32_t cen_disk_nr_; + uint64_t this_disk_entries_; + uint64_t total_entries_; + uint64_t cen_size_; + uint64_t cen_offset_; +} __attribute__((packed)); +static_assert(56 == sizeof(ECD64), "ECD64 class fields layout is incorrect."); + +#endif // BAZEL_SRC_TOOLS_SINGLEJAR_ZIP_HEADERS_H_ |