1 
2 /*
3  * Copyright 2010 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkData.h"
11 #include "SkFlate.h"
12 #include "SkStream.h"
13 
14 namespace {
15 
16 #ifdef ZLIB_INCLUDE
17     #include ZLIB_INCLUDE
18 #else
19     #include "zlib.h"
20 #endif
21 
22 // static
23 const size_t kBufferSize = 1024;
24 
25 // Different zlib implementations use different T.
26 // We've seen size_t and unsigned.
skia_alloc_func(void *,T items,T size)27 template <typename T> void* skia_alloc_func(void*, T items, T size) {
28     return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
29 }
30 
skia_free_func(void *,void * address)31 static void skia_free_func(void*, void* address) { sk_free(address); }
32 
doFlate(bool compress,SkStream * src,SkWStream * dst)33 bool doFlate(bool compress, SkStream* src, SkWStream* dst) {
34     uint8_t inputBuffer[kBufferSize];
35     uint8_t outputBuffer[kBufferSize];
36     z_stream flateData;
37     flateData.zalloc = &skia_alloc_func;
38     flateData.zfree = &skia_free_func;
39     flateData.opaque = NULL;
40     flateData.next_in = NULL;
41     flateData.avail_in = 0;
42     flateData.next_out = outputBuffer;
43     flateData.avail_out = kBufferSize;
44     int rc;
45     if (compress)
46         rc = deflateInit(&flateData, Z_DEFAULT_COMPRESSION);
47     else
48         rc = inflateInit(&flateData);
49     if (rc != Z_OK)
50         return false;
51 
52     uint8_t* input = (uint8_t*)src->getMemoryBase();
53     size_t inputLength = src->getLength();
54     if (input == NULL || inputLength == 0) {
55         input = NULL;
56         flateData.next_in = inputBuffer;
57         flateData.avail_in = 0;
58     } else {
59         flateData.next_in = input;
60         flateData.avail_in = SkToUInt(inputLength);
61     }
62 
63     rc = Z_OK;
64     while (true) {
65         if (flateData.avail_out < kBufferSize) {
66             if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) {
67                 rc = Z_BUF_ERROR;
68                 break;
69             }
70             flateData.next_out = outputBuffer;
71             flateData.avail_out = kBufferSize;
72         }
73         if (rc != Z_OK)
74             break;
75         if (flateData.avail_in == 0) {
76             if (input != NULL)
77                 break;
78             size_t read = src->read(&inputBuffer, kBufferSize);
79             if (read == 0)
80                 break;
81             flateData.next_in = inputBuffer;
82             flateData.avail_in = SkToUInt(read);
83         }
84         if (compress)
85             rc = deflate(&flateData, Z_NO_FLUSH);
86         else
87             rc = inflate(&flateData, Z_NO_FLUSH);
88     }
89     while (rc == Z_OK) {
90         if (compress)
91             rc = deflate(&flateData, Z_FINISH);
92         else
93             rc = inflate(&flateData, Z_FINISH);
94         if (flateData.avail_out < kBufferSize) {
95             if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out))
96                 return false;
97             flateData.next_out = outputBuffer;
98             flateData.avail_out = kBufferSize;
99         }
100     }
101 
102     if (compress)
103         deflateEnd(&flateData);
104     else
105         inflateEnd(&flateData);
106     if (rc == Z_STREAM_END)
107         return true;
108     return false;
109 }
110 
111 }
112 
113 // static
Deflate(SkStream * src,SkWStream * dst)114 bool SkFlate::Deflate(SkStream* src, SkWStream* dst) {
115     return doFlate(true, src, dst);
116 }
117 
Deflate(const void * ptr,size_t len,SkWStream * dst)118 bool SkFlate::Deflate(const void* ptr, size_t len, SkWStream* dst) {
119     SkMemoryStream stream(ptr, len);
120     return doFlate(true, &stream, dst);
121 }
122 
Deflate(const SkData * data,SkWStream * dst)123 bool SkFlate::Deflate(const SkData* data, SkWStream* dst) {
124     if (data) {
125         SkMemoryStream stream(data->data(), data->size());
126         return doFlate(true, &stream, dst);
127     }
128     return false;
129 }
130 
131 // static
Inflate(SkStream * src,SkWStream * dst)132 bool SkFlate::Inflate(SkStream* src, SkWStream* dst) {
133     return doFlate(false, src, dst);
134 }
135 
136 
137 #define SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE 4096
138 #define SKDEFLATEWSTREAM_OUTPUT_BUFFER_SIZE 4224  // 4096 + 128, usually big
139                                                   // enough to always do a
140                                                   // single loop.
141 
142 // called by both write() and finalize()
do_deflate(int flush,z_stream * zStream,SkWStream * out,unsigned char * inBuffer,size_t inBufferSize)143 static void do_deflate(int flush,
144                        z_stream* zStream,
145                        SkWStream* out,
146                        unsigned char* inBuffer,
147                        size_t inBufferSize) {
148     zStream->next_in = inBuffer;
149     zStream->avail_in = SkToInt(inBufferSize);
150     unsigned char outBuffer[SKDEFLATEWSTREAM_OUTPUT_BUFFER_SIZE];
151     SkDEBUGCODE(int returnValue;)
152     do {
153         zStream->next_out = outBuffer;
154         zStream->avail_out = sizeof(outBuffer);
155         SkDEBUGCODE(returnValue =) deflate(zStream, flush);
156         SkASSERT(!zStream->msg);
157 
158         out->write(outBuffer, sizeof(outBuffer) - zStream->avail_out);
159     } while (zStream->avail_in || !zStream->avail_out);
160     SkASSERT(flush == Z_FINISH
161                  ? returnValue == Z_STREAM_END
162                  : returnValue == Z_OK);
163 }
164 
165 // Hide all zlib impl details.
166 struct SkDeflateWStream::Impl {
167     SkWStream* fOut;
168     unsigned char fInBuffer[SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE];
169     size_t fInBufferIndex;
170     z_stream fZStream;
171 };
172 
SkDeflateWStream(SkWStream * out)173 SkDeflateWStream::SkDeflateWStream(SkWStream* out)
174     : fImpl(SkNEW(SkDeflateWStream::Impl)) {
175     fImpl->fOut = out;
176     fImpl->fInBufferIndex = 0;
177     if (!fImpl->fOut) {
178         return;
179     }
180     fImpl->fZStream.zalloc = &skia_alloc_func;
181     fImpl->fZStream.zfree = &skia_free_func;
182     fImpl->fZStream.opaque = NULL;
183     SkDEBUGCODE(int r =) deflateInit(&fImpl->fZStream, Z_DEFAULT_COMPRESSION);
184     SkASSERT(Z_OK == r);
185 }
186 
~SkDeflateWStream()187 SkDeflateWStream::~SkDeflateWStream() { this->finalize(); }
188 
finalize()189 void SkDeflateWStream::finalize() {
190     if (!fImpl->fOut) {
191         return;
192     }
193     do_deflate(Z_FINISH, &fImpl->fZStream, fImpl->fOut, fImpl->fInBuffer,
194                fImpl->fInBufferIndex);
195     (void)deflateEnd(&fImpl->fZStream);
196     fImpl->fOut = NULL;
197 }
198 
write(const void * void_buffer,size_t len)199 bool SkDeflateWStream::write(const void* void_buffer, size_t len) {
200     if (!fImpl->fOut) {
201         return false;
202     }
203     const char* buffer = (const char*)void_buffer;
204     while (len > 0) {
205         size_t tocopy =
206                 SkTMin(len, sizeof(fImpl->fInBuffer) - fImpl->fInBufferIndex);
207         memcpy(fImpl->fInBuffer + fImpl->fInBufferIndex, buffer, tocopy);
208         len -= tocopy;
209         buffer += tocopy;
210         fImpl->fInBufferIndex += tocopy;
211         SkASSERT(fImpl->fInBufferIndex <= sizeof(fImpl->fInBuffer));
212 
213         // if the buffer isn't filled, don't call into zlib yet.
214         if (sizeof(fImpl->fInBuffer) == fImpl->fInBufferIndex) {
215             do_deflate(Z_NO_FLUSH, &fImpl->fZStream, fImpl->fOut,
216                        fImpl->fInBuffer, fImpl->fInBufferIndex);
217             fImpl->fInBufferIndex = 0;
218         }
219     }
220     return true;
221 }
222 
bytesWritten() const223 size_t SkDeflateWStream::bytesWritten() const {
224     return fImpl->fZStream.total_in + fImpl->fInBufferIndex;
225 }
226