aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/singlejar/zip_headers.h
diff options
context:
space:
mode:
authorGravatar Sasha Smundak <asmundak@google.com>2016-07-15 17:35:51 +0000
committerGravatar Yun Peng <pcloudy@google.com>2016-07-18 10:43:29 +0000
commit06a12e561268f67de6a417315944f8e4d05afc0f (patch)
treea9fe559e7f307d0a132c59def9fa309c8710465a /src/tools/singlejar/zip_headers.h
parent5ea55cbab969820da346d16c4998e957b8c3f60e (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.h485
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_