xref: /aosp_15_r20/external/libtextclassifier/native/utils/zlib/zlib.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker #include "utils/zlib/zlib.h"
18*993b0882SAndroid Build Coastguard Worker 
19*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
20*993b0882SAndroid Build Coastguard Worker #include "utils/flatbuffers/flatbuffers.h"
21*993b0882SAndroid Build Coastguard Worker 
22*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
23*993b0882SAndroid Build Coastguard Worker 
Instance()24*993b0882SAndroid Build Coastguard Worker std::unique_ptr<ZlibDecompressor> ZlibDecompressor::Instance() {
25*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<ZlibDecompressor> result(new ZlibDecompressor());
26*993b0882SAndroid Build Coastguard Worker   if (!result->initialized_) {
27*993b0882SAndroid Build Coastguard Worker     result.reset();
28*993b0882SAndroid Build Coastguard Worker   }
29*993b0882SAndroid Build Coastguard Worker   return result;
30*993b0882SAndroid Build Coastguard Worker }
31*993b0882SAndroid Build Coastguard Worker 
ZlibDecompressor()32*993b0882SAndroid Build Coastguard Worker ZlibDecompressor::ZlibDecompressor() {
33*993b0882SAndroid Build Coastguard Worker   memset(&stream_, 0, sizeof(stream_));
34*993b0882SAndroid Build Coastguard Worker   stream_.zalloc = Z_NULL;
35*993b0882SAndroid Build Coastguard Worker   stream_.zfree = Z_NULL;
36*993b0882SAndroid Build Coastguard Worker   initialized_ = false;
37*993b0882SAndroid Build Coastguard Worker   if (inflateInit(&stream_) != Z_OK) {
38*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Could not initialize decompressor.";
39*993b0882SAndroid Build Coastguard Worker     return;
40*993b0882SAndroid Build Coastguard Worker   }
41*993b0882SAndroid Build Coastguard Worker   initialized_ = true;
42*993b0882SAndroid Build Coastguard Worker }
43*993b0882SAndroid Build Coastguard Worker 
~ZlibDecompressor()44*993b0882SAndroid Build Coastguard Worker ZlibDecompressor::~ZlibDecompressor() {
45*993b0882SAndroid Build Coastguard Worker   if (initialized_) {
46*993b0882SAndroid Build Coastguard Worker     inflateEnd(&stream_);
47*993b0882SAndroid Build Coastguard Worker   }
48*993b0882SAndroid Build Coastguard Worker }
49*993b0882SAndroid Build Coastguard Worker 
Decompress(const uint8 * buffer,const int buffer_size,const int uncompressed_size,std::string * out)50*993b0882SAndroid Build Coastguard Worker bool ZlibDecompressor::Decompress(const uint8* buffer, const int buffer_size,
51*993b0882SAndroid Build Coastguard Worker                                   const int uncompressed_size,
52*993b0882SAndroid Build Coastguard Worker                                   std::string* out) {
53*993b0882SAndroid Build Coastguard Worker   if (out == nullptr) {
54*993b0882SAndroid Build Coastguard Worker     return false;
55*993b0882SAndroid Build Coastguard Worker   }
56*993b0882SAndroid Build Coastguard Worker   out->resize(uncompressed_size);
57*993b0882SAndroid Build Coastguard Worker   stream_.next_in =
58*993b0882SAndroid Build Coastguard Worker       const_cast<z_const Bytef*>(reinterpret_cast<const Bytef*>(buffer));
59*993b0882SAndroid Build Coastguard Worker   stream_.avail_in = buffer_size;
60*993b0882SAndroid Build Coastguard Worker   stream_.next_out = reinterpret_cast<Bytef*>(const_cast<char*>(out->c_str()));
61*993b0882SAndroid Build Coastguard Worker   stream_.avail_out = uncompressed_size;
62*993b0882SAndroid Build Coastguard Worker   return (inflate(&stream_, Z_SYNC_FLUSH) == Z_OK);
63*993b0882SAndroid Build Coastguard Worker }
64*993b0882SAndroid Build Coastguard Worker 
MaybeDecompress(const CompressedBuffer * compressed_buffer,std::string * out)65*993b0882SAndroid Build Coastguard Worker bool ZlibDecompressor::MaybeDecompress(
66*993b0882SAndroid Build Coastguard Worker     const CompressedBuffer* compressed_buffer, std::string* out) {
67*993b0882SAndroid Build Coastguard Worker   if (!compressed_buffer) {
68*993b0882SAndroid Build Coastguard Worker     return true;
69*993b0882SAndroid Build Coastguard Worker   }
70*993b0882SAndroid Build Coastguard Worker   return Decompress(compressed_buffer->buffer()->Data(),
71*993b0882SAndroid Build Coastguard Worker                     compressed_buffer->buffer()->size(),
72*993b0882SAndroid Build Coastguard Worker                     compressed_buffer->uncompressed_size(), out);
73*993b0882SAndroid Build Coastguard Worker }
74*993b0882SAndroid Build Coastguard Worker 
MaybeDecompress(const CompressedBufferT * compressed_buffer,std::string * out)75*993b0882SAndroid Build Coastguard Worker bool ZlibDecompressor::MaybeDecompress(
76*993b0882SAndroid Build Coastguard Worker     const CompressedBufferT* compressed_buffer, std::string* out) {
77*993b0882SAndroid Build Coastguard Worker   if (!compressed_buffer) {
78*993b0882SAndroid Build Coastguard Worker     return true;
79*993b0882SAndroid Build Coastguard Worker   }
80*993b0882SAndroid Build Coastguard Worker   return Decompress(compressed_buffer->buffer.data(),
81*993b0882SAndroid Build Coastguard Worker                     compressed_buffer->buffer.size(),
82*993b0882SAndroid Build Coastguard Worker                     compressed_buffer->uncompressed_size, out);
83*993b0882SAndroid Build Coastguard Worker }
84*993b0882SAndroid Build Coastguard Worker 
MaybeDecompressOptionallyCompressedBuffer(const flatbuffers::String * uncompressed_buffer,const CompressedBuffer * compressed_buffer,std::string * out)85*993b0882SAndroid Build Coastguard Worker bool ZlibDecompressor::MaybeDecompressOptionallyCompressedBuffer(
86*993b0882SAndroid Build Coastguard Worker     const flatbuffers::String* uncompressed_buffer,
87*993b0882SAndroid Build Coastguard Worker     const CompressedBuffer* compressed_buffer, std::string* out) {
88*993b0882SAndroid Build Coastguard Worker   if (uncompressed_buffer != nullptr) {
89*993b0882SAndroid Build Coastguard Worker     *out = uncompressed_buffer->str();
90*993b0882SAndroid Build Coastguard Worker     return true;
91*993b0882SAndroid Build Coastguard Worker   }
92*993b0882SAndroid Build Coastguard Worker   return MaybeDecompress(compressed_buffer, out);
93*993b0882SAndroid Build Coastguard Worker }
94*993b0882SAndroid Build Coastguard Worker 
MaybeDecompressOptionallyCompressedBuffer(const flatbuffers::Vector<uint8> * uncompressed_buffer,const CompressedBuffer * compressed_buffer,std::string * out)95*993b0882SAndroid Build Coastguard Worker bool ZlibDecompressor::MaybeDecompressOptionallyCompressedBuffer(
96*993b0882SAndroid Build Coastguard Worker     const flatbuffers::Vector<uint8>* uncompressed_buffer,
97*993b0882SAndroid Build Coastguard Worker     const CompressedBuffer* compressed_buffer, std::string* out) {
98*993b0882SAndroid Build Coastguard Worker   if (uncompressed_buffer != nullptr) {
99*993b0882SAndroid Build Coastguard Worker     *out =
100*993b0882SAndroid Build Coastguard Worker         std::string(reinterpret_cast<const char*>(uncompressed_buffer->data()),
101*993b0882SAndroid Build Coastguard Worker                     uncompressed_buffer->size());
102*993b0882SAndroid Build Coastguard Worker     return true;
103*993b0882SAndroid Build Coastguard Worker   }
104*993b0882SAndroid Build Coastguard Worker   return MaybeDecompress(compressed_buffer, out);
105*993b0882SAndroid Build Coastguard Worker }
106*993b0882SAndroid Build Coastguard Worker 
Instance()107*993b0882SAndroid Build Coastguard Worker std::unique_ptr<ZlibCompressor> ZlibCompressor::Instance() {
108*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<ZlibCompressor> result(new ZlibCompressor());
109*993b0882SAndroid Build Coastguard Worker   if (!result->initialized_) {
110*993b0882SAndroid Build Coastguard Worker     result.reset();
111*993b0882SAndroid Build Coastguard Worker   }
112*993b0882SAndroid Build Coastguard Worker   return result;
113*993b0882SAndroid Build Coastguard Worker }
114*993b0882SAndroid Build Coastguard Worker 
ZlibCompressor(const int level,const int tmp_buffer_size)115*993b0882SAndroid Build Coastguard Worker ZlibCompressor::ZlibCompressor(const int level, const int tmp_buffer_size) {
116*993b0882SAndroid Build Coastguard Worker   memset(&stream_, 0, sizeof(stream_));
117*993b0882SAndroid Build Coastguard Worker   stream_.zalloc = Z_NULL;
118*993b0882SAndroid Build Coastguard Worker   stream_.zfree = Z_NULL;
119*993b0882SAndroid Build Coastguard Worker   buffer_size_ = tmp_buffer_size;
120*993b0882SAndroid Build Coastguard Worker   buffer_.reset(new Bytef[buffer_size_]);
121*993b0882SAndroid Build Coastguard Worker   initialized_ = false;
122*993b0882SAndroid Build Coastguard Worker   if (deflateInit(&stream_, level) != Z_OK) {
123*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Could not initialize compressor.";
124*993b0882SAndroid Build Coastguard Worker     return;
125*993b0882SAndroid Build Coastguard Worker   }
126*993b0882SAndroid Build Coastguard Worker   initialized_ = true;
127*993b0882SAndroid Build Coastguard Worker }
128*993b0882SAndroid Build Coastguard Worker 
~ZlibCompressor()129*993b0882SAndroid Build Coastguard Worker ZlibCompressor::~ZlibCompressor() { deflateEnd(&stream_); }
130*993b0882SAndroid Build Coastguard Worker 
Compress(const std::string & uncompressed_content,CompressedBufferT * out)131*993b0882SAndroid Build Coastguard Worker void ZlibCompressor::Compress(const std::string& uncompressed_content,
132*993b0882SAndroid Build Coastguard Worker                               CompressedBufferT* out) {
133*993b0882SAndroid Build Coastguard Worker   out->uncompressed_size = uncompressed_content.size();
134*993b0882SAndroid Build Coastguard Worker   out->buffer.clear();
135*993b0882SAndroid Build Coastguard Worker   stream_.next_in = const_cast<z_const Bytef*>(
136*993b0882SAndroid Build Coastguard Worker       reinterpret_cast<const Bytef*>(uncompressed_content.c_str()));
137*993b0882SAndroid Build Coastguard Worker   stream_.avail_in = uncompressed_content.size();
138*993b0882SAndroid Build Coastguard Worker   stream_.next_out = buffer_.get();
139*993b0882SAndroid Build Coastguard Worker   stream_.avail_out = buffer_size_;
140*993b0882SAndroid Build Coastguard Worker   unsigned char* buffer_deflate_start_position =
141*993b0882SAndroid Build Coastguard Worker       reinterpret_cast<unsigned char*>(buffer_.get());
142*993b0882SAndroid Build Coastguard Worker   int status;
143*993b0882SAndroid Build Coastguard Worker   do {
144*993b0882SAndroid Build Coastguard Worker     // Deflate chunk-wise.
145*993b0882SAndroid Build Coastguard Worker     // Z_SYNC_FLUSH causes all pending output to be flushed, but doesn't
146*993b0882SAndroid Build Coastguard Worker     // reset the compression state.
147*993b0882SAndroid Build Coastguard Worker     // As we do not know how big the compressed buffer will be, we compress
148*993b0882SAndroid Build Coastguard Worker     // chunk wise and append the flushed content to the output string buffer.
149*993b0882SAndroid Build Coastguard Worker     // As we store the uncompressed size, we do not have to do this during
150*993b0882SAndroid Build Coastguard Worker     // decompression.
151*993b0882SAndroid Build Coastguard Worker     status = deflate(&stream_, Z_SYNC_FLUSH);
152*993b0882SAndroid Build Coastguard Worker     unsigned char* buffer_deflate_end_position =
153*993b0882SAndroid Build Coastguard Worker         reinterpret_cast<unsigned char*>(stream_.next_out);
154*993b0882SAndroid Build Coastguard Worker     if (buffer_deflate_end_position != buffer_deflate_start_position) {
155*993b0882SAndroid Build Coastguard Worker       out->buffer.insert(out->buffer.end(), buffer_deflate_start_position,
156*993b0882SAndroid Build Coastguard Worker                          buffer_deflate_end_position);
157*993b0882SAndroid Build Coastguard Worker       stream_.next_out = buffer_deflate_start_position;
158*993b0882SAndroid Build Coastguard Worker       stream_.avail_out = buffer_size_;
159*993b0882SAndroid Build Coastguard Worker     } else {
160*993b0882SAndroid Build Coastguard Worker       break;
161*993b0882SAndroid Build Coastguard Worker     }
162*993b0882SAndroid Build Coastguard Worker   } while (status == Z_OK);
163*993b0882SAndroid Build Coastguard Worker }
164*993b0882SAndroid Build Coastguard Worker 
165*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
166