1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/util/zip_reader.h"
18
19 #include <time.h>
20
21 #include "perfetto/base/build_config.h"
22 #include "perfetto/ext/base/file_utils.h"
23 #include "perfetto/ext/base/string_utils.h"
24
25 #include "test/gtest_and_gmock.h"
26
27 namespace perfetto {
28 namespace trace_processor {
29 namespace util {
30 namespace {
31
32 // This zip file contains the following:
33 // Zip file size: 386 bytes, number of entries: 2
34 // -rw-r--r-- 3.0 unx 4 tx stor 22-Jul-25 16:43 stored_file
35 // -rw-r--r-- 3.0 unx 89 tx defN 22-Jul-25 18:34 dir/deflated_file
36 // 2 files, 92 bytes uncompressed, 52 bytes compressed: 43.5%
37 //
38 // /stored_file content: "foo"
39 // dir/deflated_file content: 2x "The quick brown fox jumps over the lazy dog\n"
40 const uint8_t kTestZip[] = {
41 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85,
42 0xf9, 0x54, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
43 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64,
44 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x09, 0x00, 0x03, 0x17, 0xba,
45 0xde, 0x62, 0x44, 0xba, 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04,
46 0xce, 0x69, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f,
47 0x0a, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x47,
48 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, 0x3c, 0x34, 0x00, 0x00, 0x00, 0x59,
49 0x00, 0x00, 0x00, 0x11, 0x00, 0x1c, 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64,
50 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65,
51 0x55, 0x54, 0x09, 0x00, 0x03, 0x15, 0xd4, 0xde, 0x62, 0xf4, 0xba, 0xde,
52 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce, 0x69, 0x02, 0x00, 0x04,
53 0x00, 0x00, 0x00, 0x00, 0x0b, 0xc9, 0x48, 0x55, 0x28, 0x2c, 0xcd, 0x4c,
54 0xce, 0x56, 0x48, 0x2a, 0xca, 0x2f, 0xcf, 0x53, 0x48, 0xcb, 0xaf, 0x50,
55 0xc8, 0x2a, 0xcd, 0x2d, 0x28, 0x56, 0xc8, 0x2f, 0x4b, 0x2d, 0x52, 0x28,
56 0x01, 0x4a, 0xe7, 0x24, 0x56, 0x55, 0x2a, 0xa4, 0xe4, 0xa7, 0x73, 0x85,
57 0x10, 0xa9, 0x36, 0xad, 0x08, 0xa8, 0x18, 0x00, 0x50, 0x4b, 0x01, 0x02,
58 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85, 0xf9, 0x54,
59 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
60 0x0b, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
61 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64,
62 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x05, 0x00, 0x03, 0x17, 0xba,
63 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce, 0x69, 0x02, 0x00,
64 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x14,
65 0x00, 0x00, 0x00, 0x08, 0x00, 0x47, 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92,
66 0x3c, 0x34, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x11, 0x00, 0x18,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x49,
68 0x00, 0x00, 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64, 0x65, 0x66, 0x6c, 0x61,
69 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x05, 0x00,
70 0x03, 0x15, 0xd4, 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce,
71 0x69, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06,
72 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00,
73 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00};
74
vec2str(const std::vector<uint8_t> & vec)75 std::string vec2str(const std::vector<uint8_t>& vec) {
76 return std::string(reinterpret_cast<const char*>(vec.data()), vec.size());
77 }
78
ValidateTestZip(ZipReader & zr)79 void ValidateTestZip(ZipReader& zr) {
80 ASSERT_EQ(zr.files().size(), 2u);
81
82 std::vector<uint8_t> dec;
83 ASSERT_EQ(zr.files()[0].name(), "stored_file");
84 ASSERT_EQ(zr.files()[0].GetDatetimeStr(), "2022-07-25 16:43:20");
85
86 ASSERT_EQ(zr.files()[1].name(), "dir/deflated_file");
87 ASSERT_EQ(zr.files()[1].GetDatetimeStr(), "2022-07-25 18:34:14");
88
89 // This file is STORE-d and doesn't require any decompression.
90 auto res = zr.files()[0].Decompress(&dec);
91 ASSERT_TRUE(res.ok()) << res.message();
92 ASSERT_EQ(dec.size(), 4u);
93 ASSERT_EQ(vec2str(dec), "foo\n");
94
95 // This file is DEFLATE-d and requires zlib.
96 #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
97 res = zr.files()[1].Decompress(&dec);
98 ASSERT_TRUE(res.ok()) << res.message();
99 ASSERT_EQ(dec.size(), 89u);
100 ASSERT_EQ(vec2str(dec),
101 "The quick brown fox jumps over the lazy dog\n"
102 "The quick brown fox jumps over the lazy frog\n");
103 #endif
104 }
105
TEST(ZipReaderTest,ValidZip_OneShotParse)106 TEST(ZipReaderTest, ValidZip_OneShotParse) {
107 ZipReader zr;
108 base::Status res = zr.Parse(kTestZip, sizeof(kTestZip));
109 ASSERT_TRUE(res.ok()) << res.message();
110 ValidateTestZip(zr);
111 }
112
TEST(ZipReaderTest,ValidZip_OneByteChunks)113 TEST(ZipReaderTest, ValidZip_OneByteChunks) {
114 ZipReader zr;
115 for (size_t i = 0; i < sizeof(kTestZip); i++) {
116 base::Status res = zr.Parse(&kTestZip[i], 1);
117 ASSERT_TRUE(res.ok()) << res.message();
118 }
119 ValidateTestZip(zr);
120 }
121
TEST(ZipReaderTest,MalformedZip_InvalidSignature)122 TEST(ZipReaderTest, MalformedZip_InvalidSignature) {
123 ZipReader zr;
124 uint8_t content[sizeof(kTestZip)];
125 memcpy(content, kTestZip, sizeof(kTestZip));
126 content[0] = 0xff; // Invalid signature
127 base::Status res = zr.Parse(content, sizeof(kTestZip));
128 ASSERT_FALSE(res.ok());
129 ASSERT_EQ(zr.files().size(), 0u);
130 }
131
TEST(ZipReaderTest,MalformedZip_VersionTooHigh)132 TEST(ZipReaderTest, MalformedZip_VersionTooHigh) {
133 ZipReader zr;
134 uint8_t content[sizeof(kTestZip)];
135 memcpy(content, kTestZip, sizeof(kTestZip));
136 content[5] = 9; // Version: 9.0
137 base::Status res = zr.Parse(content, sizeof(kTestZip));
138 ASSERT_FALSE(res.ok());
139 ASSERT_EQ(zr.files().size(), 0u);
140 }
141
TEST(ZipReaderTest,TruncatedZip)142 TEST(ZipReaderTest, TruncatedZip) {
143 ZipReader zr;
144 base::Status res = zr.Parse(kTestZip, 40);
145 ASSERT_EQ(zr.files().size(), 0u);
146 }
147
TEST(ZipReaderTest,Find)148 TEST(ZipReaderTest, Find) {
149 ZipReader zr;
150 base::Status res = zr.Parse(kTestZip, sizeof(kTestZip));
151 ASSERT_TRUE(res.ok()) << res.message();
152 ASSERT_EQ(zr.Find("stored_file")->name(), "stored_file");
153 ASSERT_EQ(zr.Find("dir/deflated_file")->name(), "dir/deflated_file");
154 ASSERT_EQ(nullptr, zr.Find("stored_f"));
155 ASSERT_EQ(nullptr, zr.Find("_file*"));
156 ASSERT_EQ(nullptr, zr.Find("dirz/deflated_file"));
157 }
158
159 // All the tests below require zlib.
160 #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
161
TEST(ZipReaderTest,ValidZip_DecompressLines)162 TEST(ZipReaderTest, ValidZip_DecompressLines) {
163 ZipReader zr;
164 base::Status res = zr.Parse(kTestZip, sizeof(kTestZip));
165 ASSERT_TRUE(res.ok()) << res.message();
166 ValidateTestZip(zr);
167 int num_callbacks = 0;
168 zr.files()[1].DecompressLines(
169 [&](const std::vector<base::StringView>& lines) {
170 ASSERT_EQ(num_callbacks++, 0);
171 ASSERT_TRUE(lines.size() == 2);
172 ASSERT_EQ(lines[0].ToStdString(),
173 "The quick brown fox jumps over the lazy dog");
174 ASSERT_EQ(lines[1].ToStdString(),
175 "The quick brown fox jumps over the lazy frog");
176 });
177
178 ASSERT_EQ(num_callbacks, 1);
179 }
180
TEST(ZipReaderTest,MalformedZip_DecomprError)181 TEST(ZipReaderTest, MalformedZip_DecomprError) {
182 ZipReader zr;
183 uint8_t content[sizeof(kTestZip)];
184 memcpy(content, kTestZip, sizeof(kTestZip));
185
186 // The 2nd file header starts at 103, the payload at 30 (header) + 17 (fname)
187 // bytes later. We start clobbering at offset=150, so the header is intanct
188 // but decompression fails.
189 memset(&content[150], 0, 40);
190 base::Status res = zr.Parse(content, sizeof(kTestZip));
191 ASSERT_TRUE(res.ok());
192 ASSERT_EQ(zr.files().size(), 2u);
193 std::vector<uint8_t> ignored;
194 ASSERT_TRUE(zr.files()[0].Decompress(&ignored).ok());
195 ASSERT_FALSE(zr.files()[1].Decompress(&ignored).ok());
196 }
197
198 #endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
199
200 } // namespace
201 } // namespace util
202 } // namespace trace_processor
203 } // namespace perfetto
204