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