// 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(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(1234, lh->compressed_file_size32()); EXPECT_EQ(1234, lh->compressed_file_size()); lh->uncompressed_file_size32(3421); EXPECT_EQ(3421, lh->uncompressed_file_size32()); EXPECT_EQ(3421, lh->uncompressed_file_size()); lh->file_name("foobar", 6); EXPECT_EQ(6, 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(0, lh->extra_fields_length()); EXPECT_EQ(30 + 6, 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(5000000000, zip64_field->attr64(0)); EXPECT_EQ(3000000, 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(3000000, lh->compressed_file_size()); EXPECT_EQ(5000000000, lh->uncompressed_file_size()); EXPECT_EQ(3000000, 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(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(1234, cdh->compressed_file_size32()); EXPECT_EQ(1234, cdh->compressed_file_size()); cdh->uncompressed_file_size32(3421); EXPECT_EQ(3421, cdh->uncompressed_file_size32()); EXPECT_EQ(3421, 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(1234567, cdh->external_attributes()); cdh->local_header_offset32(76234); EXPECT_EQ(76234, cdh->local_header_offset32()); EXPECT_EQ(76234, cdh->local_header_offset()); // Only one variable field (filename) is present: EXPECT_EQ(46 + 6, 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(5000000000, zip64_field->attr64(0)); EXPECT_EQ(3000000, 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(0x57910A85, 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(3000000, cdh->compressed_file_size()); EXPECT_EQ(5000000000, 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(1234, cdh->compressed_file_size()); EXPECT_EQ(5000000000, cdh->uncompressed_file_size()); EXPECT_EQ(6000000000, 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(123, cdh->compressed_file_size()); EXPECT_EQ(6000000000, cdh->uncompressed_file_size()); EXPECT_EQ(42, cdh->local_header_offset()); } TEST(ZipHeadersTest, ECD64Locator) { uint8_t bytes[256]; memset(bytes, kPoison, sizeof(bytes)); ECD64Locator *ecd64loc = reinterpret_cast(bytes); ecd64loc->signature(); EXPECT_TRUE(ecd64loc->is()); ecd64loc->ecd64_disk_nr(123456); EXPECT_EQ(123456, ecd64loc->ecd64_disk_nr()); ecd64loc->ecd64_offset(6000000000); EXPECT_EQ(6000000000, ecd64loc->ecd64_offset()); ecd64loc->total_disks(213456); EXPECT_EQ(213456, ecd64loc->total_disks()); } TEST(ZipHeadersTest, Zip64EndOfCentralDirectory) { uint8_t bytes[256]; memset(bytes, kPoison, sizeof(bytes)); ECD64 *ecd64 = reinterpret_cast(bytes); ecd64->signature(); EXPECT_TRUE(ecd64->is()); ecd64->remaining_size(44); EXPECT_EQ(44, ecd64->remaining_size()); ecd64->version(56); EXPECT_EQ(56, ecd64->version()); ecd64->version_to_extract(754); EXPECT_EQ(754, ecd64->version_to_extract()); ecd64->this_disk_nr(75123); EXPECT_EQ(75123, ecd64->this_disk_nr()); ecd64->cen_disk_nr(87654); EXPECT_EQ(87654, ecd64->cen_disk_nr()); ecd64->this_disk_entries(9000000000); EXPECT_EQ(9000000000, ecd64->this_disk_entries()); ecd64->total_entries(8000000000); EXPECT_EQ(8000000000, ecd64->total_entries()); ecd64->cen_size(19000000000); EXPECT_EQ(19000000000, ecd64->cen_size()); ecd64->cen_offset(11000000000); EXPECT_EQ(11000000000, ecd64->cen_offset()); } TEST(ZipHeadersTest, EndOfCentralDirectory) { uint8_t bytes[256]; memset(bytes, kPoison, sizeof(bytes)); ECD64Locator *ecd64loc = reinterpret_cast(bytes); ECD *ecd = reinterpret_cast(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(123400, ecd->cen_size32()); ecd->cen_offset32(123000); EXPECT_EQ(123000, 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(9876543210, ecd->ecd64_offset()); } TEST(ZipHeadersTest, Zip64ExtraFieldTest) { uint8_t bytes[256]; memset(bytes, kPoison, sizeof(bytes)); Zip64ExtraField *z64 = reinterpret_cast(bytes); z64->signature(); EXPECT_TRUE(z64->is()); z64->payload_size(16); z64->attr64(0, 9876543210); EXPECT_EQ(9876543210, z64->attr64(0)); z64->attr64(1, 8976543210); EXPECT_EQ(8976543210, z64->attr64(1)); EXPECT_EQ(kPoison, bytes[z64->size()]); } } // namespace