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 #ifndef SRC_TRACE_PROCESSOR_UTIL_GZIP_UTILS_H_ 18 #define SRC_TRACE_PROCESSOR_UTIL_GZIP_UTILS_H_ 19 20 #include <memory> 21 #include <vector> 22 23 struct z_stream_s; 24 25 namespace perfetto { 26 namespace trace_processor { 27 namespace util { 28 29 // Returns whether gzip related functioanlity is supported with the current 30 // build flags. 31 bool IsGzipSupported(); 32 33 // Usage: To decompress in a streaming way, there are two ways of using it: 34 // 1. [Commonly used] - Feed the sequence of mem-blocks in 'FeedAndExtract' one 35 // by one. Output will be produced in given output_consumer, which is simply 36 // a callback. On each 'FeedAndExtract', output_consumer could get invoked 37 // any number of times, based on how much partial output is available. 38 39 // 2. [Uncommon ; Discouraged] - Feed the sequence of mem-blocks one by one, by 40 // calling 'Feed'. For each time 'Feed' is called, client should call 41 // 'ExtractOutput' again and again to extrat the partially available output, 42 // until there in no more output to extract. Also see 'ResultCode' enum. 43 class GzipDecompressor { 44 public: 45 enum class ResultCode { 46 // 'kOk' means nothing bad happened so far, but continue doing what you 47 // were doing. 48 kOk, 49 // While calling 'ExtractOutput' repeatedly, if we get 'kEof', it means 50 // we have extracted all the partially available data and we are also 51 // done, i.e. there is no need to feed more input. 52 kEof, 53 // Some error. Possibly invalid compressed stream or corrupted data. 54 kError, 55 // While calling 'ExtractOutput' repeatedly, if we get 'kNeedsMoreInput', 56 // it means we have extracted all the partially available data, but we are 57 // not done yet. We need to call the 'Feed' to feed the next input 58 // mem-block and go through the ExtractOutput loop again. 59 kNeedsMoreInput, 60 }; 61 struct Result { 62 // The return code of the decompression. 63 ResultCode ret; 64 65 // The amount of bytes written to output. 66 // Valid in all cases except |ResultCode::kError|. 67 size_t bytes_written; 68 }; 69 70 GzipDecompressor(); 71 ~GzipDecompressor(); 72 GzipDecompressor(const GzipDecompressor&) = delete; 73 GzipDecompressor& operator=(const GzipDecompressor&) = delete; 74 75 // Feed the next mem-block. 76 void Feed(const uint8_t* data, size_t size); 77 78 // Feed the next mem-block and extract output in the callback consumer. 79 // callback can get invoked multiple times if there are multiple 80 // mem-blocks to output. 81 template <typename Callback = void(const uint8_t* ptr, size_t size)> FeedAndExtract(const uint8_t * data,size_t size,const Callback & output_consumer)82 ResultCode FeedAndExtract(const uint8_t* data, 83 size_t size, 84 const Callback& output_consumer) { 85 Feed(data, size); 86 uint8_t buffer[4096]; 87 Result result; 88 do { 89 result = ExtractOutput(buffer, sizeof(buffer)); 90 if (result.ret != ResultCode::kError && result.bytes_written > 0) { 91 output_consumer(buffer, result.bytes_written); 92 } 93 } while (result.ret == ResultCode::kOk); 94 return result.ret; 95 } 96 97 // Extract the newly available partial output. On each 'Feed', this method 98 // should be called repeatedly until there is no more data to output 99 // i.e. (either 'kEof' or 'kNeedsMoreInput'). 100 Result ExtractOutput(uint8_t* out, size_t out_capacity); 101 102 // Sets the state of the decompressor to reuse with other gzip streams. 103 // This is almost like constructing a new 'GzipDecompressor' object 104 // but without paying the cost of internal memory allocation. 105 void Reset(); 106 107 // Decompress the entire mem-block and return decompressed mem-block. 108 // This is used for decompressing small strings or small files 109 // which doesn't require streaming decompression. 110 static std::vector<uint8_t> DecompressFully(const uint8_t* data, size_t len); 111 112 private: 113 std::unique_ptr<z_stream_s> z_stream_; 114 }; 115 116 } // namespace util 117 } // namespace trace_processor 118 } // namespace perfetto 119 120 #endif // SRC_TRACE_PROCESSOR_UTIL_GZIP_UTILS_H_ 121