xref: /aosp_15_r20/external/perfetto/src/trace_processor/util/gzip_utils.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 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/gzip_utils.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <memory>
22 #include <vector>
23 
24 #include "perfetto/base/build_config.h"
25 
26 #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
27 #include <zconf.h>
28 #include <zlib.h>
29 #else
30 struct z_stream_s {};
31 #endif
32 
33 namespace perfetto::trace_processor::util {
34 
35 #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)  // Real Implementation
36 
GzipDecompressor(InputMode mode)37 GzipDecompressor::GzipDecompressor(InputMode mode)
38     : z_stream_(new z_stream_s()) {
39   z_stream_->zalloc = nullptr;
40   z_stream_->zfree = nullptr;
41   z_stream_->opaque = nullptr;
42   // zlib uses a window size of -15..-8 to indicate it's a raw inflate stream
43   // (i.e. there's no zlib or gzip header).
44   int wbits = (mode == InputMode::kRawDeflate) ? -15 : 32 + MAX_WBITS;
45   inflateInit2(z_stream_.get(), wbits);
46 }
47 
Reset()48 void GzipDecompressor::Reset() {
49   inflateReset(z_stream_.get());
50 }
51 
Feed(const uint8_t * data,size_t size)52 void GzipDecompressor::Feed(const uint8_t* data, size_t size) {
53   // This const_cast is not harmfull as zlib will not modify the data in this
54   // pointer. This is only necessary because of the build flags we use to be
55   // compatible with other embedders.
56   z_stream_->next_in = const_cast<uint8_t*>(data);
57   z_stream_->avail_in = static_cast<uInt>(size);
58 }
59 
ExtractOutput(uint8_t * out,size_t out_size)60 GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t* out,
61                                                          size_t out_size) {
62   if (z_stream_->avail_in == 0)
63     return Result{ResultCode::kNeedsMoreInput, 0};
64 
65   z_stream_->next_out = out;
66   z_stream_->avail_out = static_cast<uInt>(out_size);
67 
68   int ret = inflate(z_stream_.get(), Z_NO_FLUSH);
69   switch (ret) {
70     case Z_NEED_DICT:
71     case Z_DATA_ERROR:
72     case Z_MEM_ERROR:
73       // Ignore inflateEnd error as we will error out anyway.
74       inflateEnd(z_stream_.get());
75       return Result{ResultCode::kError, 0};
76     case Z_STREAM_END:
77       return Result{ResultCode::kEof, out_size - z_stream_->avail_out};
78     case Z_BUF_ERROR:
79       return Result{ResultCode::kNeedsMoreInput, 0};
80     default:
81       return Result{ResultCode::kOk, out_size - z_stream_->avail_out};
82   }
83 }
84 
AvailIn() const85 size_t GzipDecompressor::AvailIn() const {
86   return z_stream_->avail_in;
87 }
88 
operator ()(z_stream_s * stream) const89 void GzipDecompressor::Deleter::operator()(z_stream_s* stream) const {
90   inflateEnd(stream);
91   delete stream;
92 }
93 
94 #else  // Dummy Implementation
95 
96 GzipDecompressor::GzipDecompressor(InputMode) {}
97 void GzipDecompressor::Reset() {}
98 void GzipDecompressor::Feed(const uint8_t*, size_t) {}
99 GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t*, size_t) {
100   return Result{ResultCode::kError, 0};
101 }
102 size_t GzipDecompressor::AvailIn() const {
103   return 0;
104 }
105 void GzipDecompressor::Deleter::operator()(z_stream_s*) const {}
106 
107 #endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
108 
109 // static
DecompressFully(const uint8_t * data,size_t len)110 std::vector<uint8_t> GzipDecompressor::DecompressFully(const uint8_t* data,
111                                                        size_t len) {
112   std::vector<uint8_t> whole_data;
113   GzipDecompressor decompressor;
114   auto decom_output_consumer = [&](const uint8_t* buf, size_t buf_len) {
115     whole_data.insert(whole_data.end(), buf, buf + buf_len);
116   };
117   decompressor.FeedAndExtract(data, len, decom_output_consumer);
118   return whole_data;
119 }
120 
121 }  // namespace perfetto::trace_processor::util
122