• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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