|  | // 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 "googletest/include/gtest/gtest.h" | 
|  |  | 
|  | #include "src/tools/singlejar/zip_headers.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const uint8_t kPoison = 0xFB; | 
|  |  | 
|  | TEST(ZipHeadersTest, LocalHeader) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  | LH *lh = reinterpret_cast<LH *>(bytes); | 
|  |  | 
|  | // Simple fields. | 
|  | lh->signature(); | 
|  | EXPECT_TRUE(lh->is()); | 
|  | lh->version(123); | 
|  | EXPECT_EQ(123, lh->version()); | 
|  | lh->bit_flag(0xCAFE); | 
|  | EXPECT_EQ(0xCAFE, lh->bit_flag()); | 
|  | lh->compression_method(8); | 
|  | EXPECT_EQ(8, lh->compression_method()); | 
|  | lh->last_mod_file_time(0xBACD); | 
|  | EXPECT_EQ(0xBACD, lh->last_mod_file_time()); | 
|  | lh->last_mod_file_date(0xCDEF); | 
|  | EXPECT_EQ(0xCDEF, lh->last_mod_file_date()); | 
|  | lh->crc32(0xEF015423); | 
|  | EXPECT_EQ(0xEF015423, lh->crc32()); | 
|  | lh->compressed_file_size32(1234); | 
|  | EXPECT_EQ(1234UL, lh->compressed_file_size32()); | 
|  | EXPECT_EQ(1234UL, lh->compressed_file_size()); | 
|  | lh->uncompressed_file_size32(3421); | 
|  | EXPECT_EQ(3421UL, lh->uncompressed_file_size32()); | 
|  | EXPECT_EQ(3421UL, lh->uncompressed_file_size()); | 
|  | lh->file_name("foobar", 6); | 
|  | EXPECT_EQ(6UL, lh->file_name_length()); | 
|  | EXPECT_EQ(0, strncmp("foobar", lh->file_name(), 6)); | 
|  | EXPECT_EQ("foobar", lh->file_name_string()); | 
|  | EXPECT_TRUE(lh->file_name_is("foobar")); | 
|  | lh->extra_fields(nullptr, 0); | 
|  | EXPECT_EQ(0UL, lh->extra_fields_length()); | 
|  | EXPECT_EQ(30UL + 6UL, lh->size()); | 
|  |  | 
|  | // Extra fields should not be written yet | 
|  | EXPECT_EQ(kPoison, *lh->extra_fields()); | 
|  |  | 
|  | // Now copy extra fields and check we can locate them. | 
|  | // The array extra_data contains two extra fields: a 'UT' field with Unix time | 
|  | // attributes, and a Zip64 extension with two uint64 values: uncompressed file | 
|  | // size 5000000000 (0x12A05F200) and compressed file size 3000000(0x2DC6C0). | 
|  | uint8_t extra_data[] = { | 
|  | // 'UT' field: 9 bytes of payload. | 
|  | 'U', 'T', 9, 0,    // tag 0x5455, length 0x0009 | 
|  | 0x03, 0x85, 0x0a, 0x91, 0x57, 0x7d, 0x0a, 0x91, 0x57, | 
|  | // Zip64 extension: 16 bytes of payload. | 
|  | 1, 0, 16, 0,       // tag 0x0001, length 0x0010 | 
|  | 0, 0xf2, 0x5, 0x2a, 1, 0, 0, 0, | 
|  | 0xc0, 0xc6, 0x2d, 0, 0, 0, 0, 0, | 
|  | }; | 
|  | lh->extra_fields(extra_data, sizeof(extra_data)); | 
|  | EXPECT_EQ(sizeof(extra_data), lh->extra_fields_length()); | 
|  | EXPECT_EQ(36 + sizeof(extra_data), lh->size()); | 
|  | const Zip64ExtraField *zip64_field = lh->zip64_extra_field(); | 
|  | ASSERT_NE(nullptr, zip64_field); | 
|  | EXPECT_EQ(16, zip64_field->payload_size()); | 
|  | EXPECT_EQ(20, zip64_field->size()); | 
|  | EXPECT_EQ(5000000000UL, zip64_field->attr64(0)); | 
|  | EXPECT_EQ(3000000UL, zip64_field->attr64(1)); | 
|  |  | 
|  | const UnixTimeExtraField *ut_extra_field = lh->unix_time_extra_field(); | 
|  | ASSERT_NE(nullptr, ut_extra_field); | 
|  | EXPECT_EQ(9, ut_extra_field->payload_size()); | 
|  | EXPECT_EQ(13, ut_extra_field->size()); | 
|  | EXPECT_EQ(2, ut_extra_field->timestamp_count()); | 
|  | EXPECT_TRUE(ut_extra_field->has_modification_time()); | 
|  | EXPECT_TRUE(ut_extra_field->has_access_time()); | 
|  | EXPECT_FALSE(ut_extra_field->has_creation_time()); | 
|  |  | 
|  | // Check that 64-bit sizes are returned correctly. | 
|  | lh->compressed_file_size32(0xFFFFFFFF); | 
|  | lh->uncompressed_file_size32(0xFFFFFFFF); | 
|  | EXPECT_EQ(3000000UL, lh->compressed_file_size()); | 
|  | EXPECT_EQ(5000000000UL, lh->uncompressed_file_size()); | 
|  | EXPECT_EQ(3000000UL, lh->in_zip_size()); | 
|  |  | 
|  | // Data hasn't been written: | 
|  | EXPECT_EQ(kPoison, *lh->data()); | 
|  | } | 
|  |  | 
|  | TEST(ZipHeadersTest, CentralDirectoryHeader) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  | CDH *cdh = reinterpret_cast<CDH *>(bytes); | 
|  |  | 
|  | // Simple fields. | 
|  | cdh->signature(); | 
|  | EXPECT_TRUE(cdh->is()); | 
|  | cdh->version(123); | 
|  | EXPECT_EQ(123, cdh->version()); | 
|  | cdh->version_to_extract(321); | 
|  | EXPECT_EQ(321, cdh->version_to_extract()); | 
|  | cdh->bit_flag(0xCAFE); | 
|  | EXPECT_EQ(0xCAFE, cdh->bit_flag()); | 
|  | cdh->compression_method(8); | 
|  | EXPECT_EQ(8, cdh->compression_method()); | 
|  | cdh->last_mod_file_time(0xBACD); | 
|  | EXPECT_EQ(0xBACD, cdh->last_mod_file_time()); | 
|  | cdh->last_mod_file_date(0xCDEF); | 
|  | EXPECT_EQ(0xCDEF, cdh->last_mod_file_date()); | 
|  | cdh->crc32(0xEF015423); | 
|  | EXPECT_EQ(0xEF015423, cdh->crc32()); | 
|  | cdh->compressed_file_size32(1234); | 
|  | EXPECT_EQ(1234U, cdh->compressed_file_size32()); | 
|  | EXPECT_EQ(1234UL, cdh->compressed_file_size()); | 
|  | cdh->uncompressed_file_size32(3421); | 
|  | EXPECT_EQ(3421U, cdh->uncompressed_file_size32()); | 
|  | EXPECT_EQ(3421UL, cdh->uncompressed_file_size()); | 
|  | cdh->file_name("foobar", 6); | 
|  | EXPECT_EQ(6, cdh->file_name_length()); | 
|  | EXPECT_EQ(0, strncmp("foobar", cdh->file_name(), 6)); | 
|  | EXPECT_EQ("foobar", cdh->file_name_string()); | 
|  | EXPECT_TRUE(cdh->file_name_is("foobar")); | 
|  | cdh->extra_fields(nullptr, 0); | 
|  | EXPECT_EQ(0, cdh->extra_fields_length()); | 
|  | cdh->comment_length(0); | 
|  | EXPECT_EQ(0, cdh->comment_length()); | 
|  | cdh->start_disk_nr(42); | 
|  | EXPECT_EQ(42, cdh->start_disk_nr()); | 
|  | cdh->internal_attributes(1932); | 
|  | EXPECT_EQ(1932, cdh->internal_attributes()); | 
|  | cdh->external_attributes(1234567); | 
|  | EXPECT_EQ(1234567UL, cdh->external_attributes()); | 
|  | cdh->local_header_offset32(76234); | 
|  | EXPECT_EQ(76234U, cdh->local_header_offset32()); | 
|  | EXPECT_EQ(76234UL, cdh->local_header_offset()); | 
|  |  | 
|  | // Only one variable field (filename) is present: | 
|  | EXPECT_EQ(46UL + 6UL, cdh->size()); | 
|  |  | 
|  | // Extra fields should not be written yet | 
|  | EXPECT_EQ(kPoison, *cdh->extra_fields()); | 
|  |  | 
|  | // Now copy extra fields and check we can locate them. | 
|  | // The array extra_data contains two extra fields: a 'UT' field with Unix time | 
|  | // attributes, and a Zip64 extension with two uint64 values: original file | 
|  | // size 5000000000 (0x12A05F200) and compressed file size 3000000(0x2DC6C0). | 
|  | uint8_t extra_data[] = { | 
|  | // 'UT' field: 5 bytes of payload (only mod time, reagrdless of flag bits) | 
|  | 'U', 'T', 5, 0, 0x03, 0x85, 0x0a, 0x91, 0x57, | 
|  | // Zip64 extension: 16 bytes of payload. | 
|  | 1, 0, 16, 0,    // tag 0x0001, length 0x0010 | 
|  | 0, 0xf2, 0x5, 0x2a, 1, 0, 0, 0,   // 0x12a05f200 = 5000000000 | 
|  | 0xc0, 0xc6, 0x2d, 0, 0, 0, 0, 0,  // 0x2dc6c0 = 3000000 | 
|  | }; | 
|  | cdh->extra_fields(extra_data, sizeof(extra_data)); | 
|  | EXPECT_EQ(sizeof(extra_data), cdh->extra_fields_length()); | 
|  | EXPECT_EQ(52 + sizeof(extra_data), cdh->size()); | 
|  | const Zip64ExtraField *zip64_field = cdh->zip64_extra_field(); | 
|  | ASSERT_NE(nullptr, zip64_field); | 
|  | EXPECT_EQ(16, zip64_field->payload_size()); | 
|  | EXPECT_EQ(20, zip64_field->size()); | 
|  | EXPECT_EQ(5000000000UL, zip64_field->attr64(0)); | 
|  | EXPECT_EQ(3000000UL, zip64_field->attr64(1)); | 
|  | const UnixTimeExtraField *ut_extra_field = cdh->unix_time_extra_field(); | 
|  | ASSERT_NE(nullptr, ut_extra_field); | 
|  | EXPECT_EQ(5, ut_extra_field->payload_size()); | 
|  | EXPECT_EQ(9, ut_extra_field->size()); | 
|  | EXPECT_EQ(1, ut_extra_field->timestamp_count()); | 
|  | EXPECT_TRUE(ut_extra_field->has_modification_time()); | 
|  | EXPECT_EQ(0x57910A85UL, ut_extra_field->timestamp(0)); | 
|  |  | 
|  | // Check that 64-bit sizes are returned correctly. | 
|  | cdh->compressed_file_size32(0xFFFFFFFF); | 
|  | cdh->uncompressed_file_size32(0xFFFFFFFF); | 
|  | EXPECT_EQ(3000000UL, cdh->compressed_file_size()); | 
|  | EXPECT_EQ(5000000000UL, cdh->uncompressed_file_size()); | 
|  |  | 
|  | // Check that a file with 32-bit compressed size, 64-bit original size | 
|  | // and 64-bit local header offset is handled correctly. Zip64 extension | 
|  | // field is this case contains two 64-bit quantities, original file size | 
|  | // and offset. | 
|  | uint8_t extra_data2[] = { | 
|  | 1, 0, 16, 0,    // tag 0x0001, length 0x0010 | 
|  | 0, 0xf2, 0x5, 0x2a, 1, 0, 0, 0,   // 0x12a05f200 = 5000000000 | 
|  | 0, 0xbc, 0xa0, 0x65, 1, 0, 0, 0,  // 0x165A0BC00 = 6000000000 | 
|  | }; | 
|  | cdh->extra_fields(extra_data2, sizeof(extra_data2)); | 
|  | EXPECT_EQ(sizeof(extra_data2), cdh->extra_fields_length()); | 
|  | cdh->compressed_file_size32(1234); | 
|  | cdh->uncompressed_file_size32(0xFFFFFFFF); | 
|  | cdh->local_header_offset32(0xFFFFFFFF); | 
|  | EXPECT_EQ(1234UL, cdh->compressed_file_size()); | 
|  | EXPECT_EQ(5000000000UL, cdh->uncompressed_file_size()); | 
|  | EXPECT_EQ(6000000000UL, cdh->local_header_offset()); | 
|  |  | 
|  | // Only uncompressed file size is 64-bit quantity. | 
|  | uint8_t extra_data3[] = { | 
|  | 1, 0, 8, 0,    // tag 0x0001, length 0x0008 | 
|  | 0, 0xbc, 0xa0, 0x65, 1, 0, 0, 0,  // 0x165A0BC00 = 6000000000 | 
|  | }; | 
|  | cdh->extra_fields(extra_data3, sizeof(extra_data3)); | 
|  | EXPECT_EQ(sizeof(extra_data3), cdh->extra_fields_length()); | 
|  | cdh->compressed_file_size32(123); | 
|  | cdh->uncompressed_file_size32(0xFFFFFFFF); | 
|  | cdh->local_header_offset32(42); | 
|  | EXPECT_EQ(123UL, cdh->compressed_file_size()); | 
|  | EXPECT_EQ(6000000000UL, cdh->uncompressed_file_size()); | 
|  | EXPECT_EQ(42UL, cdh->local_header_offset()); | 
|  | } | 
|  |  | 
|  | TEST(ZipHeadersTest, ECD64Locator) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  | ECD64Locator *ecd64loc = reinterpret_cast<ECD64Locator *>(bytes); | 
|  |  | 
|  | ecd64loc->signature(); | 
|  | EXPECT_TRUE(ecd64loc->is()); | 
|  | ecd64loc->ecd64_disk_nr(123456); | 
|  | EXPECT_EQ(123456UL, ecd64loc->ecd64_disk_nr()); | 
|  | ecd64loc->ecd64_offset(6000000000); | 
|  | EXPECT_EQ(6000000000UL, ecd64loc->ecd64_offset()); | 
|  | ecd64loc->total_disks(213456); | 
|  | EXPECT_EQ(213456UL, ecd64loc->total_disks()); | 
|  | } | 
|  |  | 
|  | TEST(ZipHeadersTest, Zip64EndOfCentralDirectory) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  |  | 
|  | ECD64 *ecd64 = reinterpret_cast<ECD64 *>(bytes); | 
|  | ecd64->signature(); | 
|  | EXPECT_TRUE(ecd64->is()); | 
|  | ecd64->remaining_size(44); | 
|  | EXPECT_EQ(44UL, ecd64->remaining_size()); | 
|  | ecd64->version(56); | 
|  | EXPECT_EQ(56UL, ecd64->version()); | 
|  | ecd64->version_to_extract(754); | 
|  | EXPECT_EQ(754UL, ecd64->version_to_extract()); | 
|  | ecd64->this_disk_nr(75123); | 
|  | EXPECT_EQ(75123UL, ecd64->this_disk_nr()); | 
|  | ecd64->cen_disk_nr(87654); | 
|  | EXPECT_EQ(87654UL, ecd64->cen_disk_nr()); | 
|  | ecd64->this_disk_entries(9000000000); | 
|  | EXPECT_EQ(9000000000UL, ecd64->this_disk_entries()); | 
|  | ecd64->total_entries(8000000000); | 
|  | EXPECT_EQ(8000000000UL, ecd64->total_entries()); | 
|  | ecd64->cen_size(19000000000); | 
|  | EXPECT_EQ(19000000000UL, ecd64->cen_size()); | 
|  | ecd64->cen_offset(11000000000); | 
|  | EXPECT_EQ(11000000000UL, ecd64->cen_offset()); | 
|  | } | 
|  |  | 
|  | TEST(ZipHeadersTest, EndOfCentralDirectory) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  | ECD64Locator *ecd64loc = reinterpret_cast<ECD64Locator *>(bytes); | 
|  | ECD *ecd = reinterpret_cast<ECD *>(bytes + sizeof(ECD64Locator)); | 
|  |  | 
|  | ecd->signature(); | 
|  | EXPECT_TRUE(ecd->is()); | 
|  | ecd->this_disk_nr(123); | 
|  | EXPECT_EQ(123, ecd->this_disk_nr()); | 
|  | ecd->cen_disk_nr(4123); | 
|  | EXPECT_EQ(4123, ecd->cen_disk_nr()); | 
|  | ecd->this_disk_entries16(23); | 
|  | EXPECT_EQ(23, ecd->this_disk_entries16()); | 
|  | ecd->total_entries16(23); | 
|  | EXPECT_EQ(23, ecd->total_entries16()); | 
|  | ecd->cen_size32(123400); | 
|  | EXPECT_EQ(123400U, ecd->cen_size32()); | 
|  | ecd->cen_offset32(123000); | 
|  | EXPECT_EQ(123000U, ecd->cen_offset32()); | 
|  | uint8_t comment_bytes[] = {0xCA, 0xFE}; | 
|  | ecd->comment(comment_bytes, sizeof(comment_bytes)); | 
|  | EXPECT_EQ(sizeof(comment_bytes), ecd->comment_length()); | 
|  | EXPECT_EQ(comment_bytes[0], ecd->comment()[0]); | 
|  | EXPECT_EQ(comment_bytes[1], ecd->comment()[1]); | 
|  |  | 
|  | // ECD64 locator has not been constructed yet, so: | 
|  | EXPECT_EQ(0xFFFFFFFFFFFFFFFFLL, ecd->ecd64_offset()); | 
|  |  | 
|  | // Now construct it and see it used: | 
|  | ecd64loc->signature(); | 
|  | ecd64loc->ecd64_offset(9876543210); | 
|  | EXPECT_EQ(9876543210UL, ecd->ecd64_offset()); | 
|  | } | 
|  |  | 
|  | TEST(ZipHeadersTest, Zip64ExtraFieldTest) { | 
|  | uint8_t bytes[256]; | 
|  | memset(bytes, kPoison, sizeof(bytes)); | 
|  | Zip64ExtraField *z64 = reinterpret_cast<Zip64ExtraField *>(bytes); | 
|  |  | 
|  | z64->signature(); | 
|  | EXPECT_TRUE(z64->is()); | 
|  | z64->payload_size(16); | 
|  | z64->attr64(0, 9876543210); | 
|  | EXPECT_EQ(9876543210UL, z64->attr64(0)); | 
|  | z64->attr64(1, 8976543210); | 
|  | EXPECT_EQ(8976543210UL, z64->attr64(1)); | 
|  | EXPECT_EQ(kPoison, bytes[z64->size()]); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  |