• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 "utils/zlib/zlib.h"
18 
19 #include "utils/flatbuffers.h"
20 
21 namespace libtextclassifier3 {
22 
Instance(const unsigned char * dictionary,const unsigned int dictionary_size)23 std::unique_ptr<ZlibDecompressor> ZlibDecompressor::Instance(
24     const unsigned char* dictionary, const unsigned int dictionary_size) {
25   std::unique_ptr<ZlibDecompressor> result(
26       new ZlibDecompressor(dictionary, dictionary_size));
27   if (!result->initialized_) {
28     result.reset();
29   }
30   return result;
31 }
32 
ZlibDecompressor(const unsigned char * dictionary,const unsigned int dictionary_size)33 ZlibDecompressor::ZlibDecompressor(const unsigned char* dictionary,
34                                    const unsigned int dictionary_size) {
35   memset(&stream_, 0, sizeof(stream_));
36   stream_.zalloc = Z_NULL;
37   stream_.zfree = Z_NULL;
38   initialized_ = false;
39   if (inflateInit(&stream_) != Z_OK) {
40     TC3_LOG(ERROR) << "Could not initialize decompressor.";
41     return;
42   }
43   if (dictionary != nullptr &&
44       inflateSetDictionary(&stream_, dictionary, dictionary_size) != Z_OK) {
45     TC3_LOG(ERROR) << "Could not set dictionary.";
46     return;
47   }
48   initialized_ = true;
49 }
50 
~ZlibDecompressor()51 ZlibDecompressor::~ZlibDecompressor() {
52   if (initialized_) {
53     inflateEnd(&stream_);
54   }
55 }
56 
Decompress(const uint8 * buffer,const int buffer_size,const int uncompressed_size,std::string * out)57 bool ZlibDecompressor::Decompress(const uint8* buffer, const int buffer_size,
58                                   const int uncompressed_size,
59                                   std::string* out) {
60   if (out == nullptr) {
61     return false;
62   }
63   out->resize(uncompressed_size);
64   stream_.next_in = reinterpret_cast<const Bytef*>(buffer);
65   stream_.avail_in = buffer_size;
66   stream_.next_out = reinterpret_cast<Bytef*>(const_cast<char*>(out->c_str()));
67   stream_.avail_out = uncompressed_size;
68   return (inflate(&stream_, Z_SYNC_FLUSH) == Z_OK);
69 }
70 
MaybeDecompress(const CompressedBuffer * compressed_buffer,std::string * out)71 bool ZlibDecompressor::MaybeDecompress(
72     const CompressedBuffer* compressed_buffer, std::string* out) {
73   if (!compressed_buffer) {
74     return true;
75   }
76   return Decompress(compressed_buffer->buffer()->Data(),
77                     compressed_buffer->buffer()->size(),
78                     compressed_buffer->uncompressed_size(), out);
79 }
80 
MaybeDecompress(const CompressedBufferT * compressed_buffer,std::string * out)81 bool ZlibDecompressor::MaybeDecompress(
82     const CompressedBufferT* compressed_buffer, std::string* out) {
83   if (!compressed_buffer) {
84     return true;
85   }
86   return Decompress(compressed_buffer->buffer.data(),
87                     compressed_buffer->buffer.size(),
88                     compressed_buffer->uncompressed_size, out);
89 }
90 
MaybeDecompressOptionallyCompressedBuffer(const flatbuffers::String * uncompressed_buffer,const CompressedBuffer * compressed_buffer,std::string * out)91 bool ZlibDecompressor::MaybeDecompressOptionallyCompressedBuffer(
92     const flatbuffers::String* uncompressed_buffer,
93     const CompressedBuffer* compressed_buffer, std::string* out) {
94   if (uncompressed_buffer != nullptr) {
95     *out = uncompressed_buffer->str();
96     return true;
97   }
98   return MaybeDecompress(compressed_buffer, out);
99 }
100 
MaybeDecompressOptionallyCompressedBuffer(const flatbuffers::Vector<uint8> * uncompressed_buffer,const CompressedBuffer * compressed_buffer,std::string * out)101 bool ZlibDecompressor::MaybeDecompressOptionallyCompressedBuffer(
102     const flatbuffers::Vector<uint8>* uncompressed_buffer,
103     const CompressedBuffer* compressed_buffer, std::string* out) {
104   if (uncompressed_buffer != nullptr) {
105     *out =
106         std::string(reinterpret_cast<const char*>(uncompressed_buffer->data()),
107                     uncompressed_buffer->size());
108     return true;
109   }
110   return MaybeDecompress(compressed_buffer, out);
111 }
112 
Instance(const unsigned char * dictionary,const unsigned int dictionary_size)113 std::unique_ptr<ZlibCompressor> ZlibCompressor::Instance(
114     const unsigned char* dictionary, const unsigned int dictionary_size) {
115   std::unique_ptr<ZlibCompressor> result(
116       new ZlibCompressor(dictionary, dictionary_size));
117   if (!result->initialized_) {
118     result.reset();
119   }
120   return result;
121 }
122 
ZlibCompressor(const unsigned char * dictionary,const unsigned int dictionary_size,const int level,const int tmp_buffer_size)123 ZlibCompressor::ZlibCompressor(const unsigned char* dictionary,
124                                const unsigned int dictionary_size,
125                                const int level, const int tmp_buffer_size) {
126   memset(&stream_, 0, sizeof(stream_));
127   stream_.zalloc = Z_NULL;
128   stream_.zfree = Z_NULL;
129   buffer_size_ = tmp_buffer_size;
130   buffer_.reset(new Bytef[buffer_size_]);
131   initialized_ = false;
132   if (deflateInit(&stream_, level) != Z_OK) {
133     TC3_LOG(ERROR) << "Could not initialize compressor.";
134     return;
135   }
136   if (dictionary != nullptr &&
137       deflateSetDictionary(&stream_, dictionary, dictionary_size) != Z_OK) {
138     TC3_LOG(ERROR) << "Could not set dictionary.";
139     return;
140   }
141   initialized_ = true;
142 }
143 
~ZlibCompressor()144 ZlibCompressor::~ZlibCompressor() { deflateEnd(&stream_); }
145 
Compress(const std::string & uncompressed_content,CompressedBufferT * out)146 void ZlibCompressor::Compress(const std::string& uncompressed_content,
147                               CompressedBufferT* out) {
148   out->uncompressed_size = uncompressed_content.size();
149   out->buffer.clear();
150   stream_.next_in =
151       reinterpret_cast<const Bytef*>(uncompressed_content.c_str());
152   stream_.avail_in = uncompressed_content.size();
153   stream_.next_out = buffer_.get();
154   stream_.avail_out = buffer_size_;
155   unsigned char* buffer_deflate_start_position =
156       reinterpret_cast<unsigned char*>(buffer_.get());
157   int status;
158   do {
159     // Deflate chunk-wise.
160     // Z_SYNC_FLUSH causes all pending output to be flushed, but doesn't
161     // reset the compression state.
162     // As we do not know how big the compressed buffer will be, we compress
163     // chunk wise and append the flushed content to the output string buffer.
164     // As we store the uncompressed size, we do not have to do this during
165     // decompression.
166     status = deflate(&stream_, Z_SYNC_FLUSH);
167     unsigned char* buffer_deflate_end_position =
168         reinterpret_cast<unsigned char*>(stream_.next_out);
169     if (buffer_deflate_end_position != buffer_deflate_start_position) {
170       out->buffer.insert(out->buffer.end(), buffer_deflate_start_position,
171                          buffer_deflate_end_position);
172       stream_.next_out = buffer_deflate_start_position;
173       stream_.avail_out = buffer_size_;
174     } else {
175       break;
176     }
177   } while (status == Z_OK);
178 }
179 
GetDictionary(std::vector<unsigned char> * dictionary)180 bool ZlibCompressor::GetDictionary(std::vector<unsigned char>* dictionary) {
181   // Retrieve first the size of the dictionary.
182   unsigned int size;
183   if (deflateGetDictionary(&stream_, /*dictionary=*/Z_NULL, &size) != Z_OK) {
184     return false;
185   }
186   dictionary->resize(size);
187   return deflateGetDictionary(&stream_, dictionary->data(), &size) == Z_OK;
188 }
189 
190 }  // namespace libtextclassifier3
191