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
14namespace {
15
16#ifdef ZLIB_INCLUDE
17    #include ZLIB_INCLUDE
18#else
19    #include "zlib.h"
20#endif
21
22// static
23const size_t kBufferSize = 1024;
24
25// Different zlib implementations use different T.
26// We've seen size_t and unsigned.
27template <typename T> void* skia_alloc_func(void*, T items, T size) {
28    return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
29}
30
31static void skia_free_func(void*, void* address) { sk_free(address); }
32
33bool 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
114bool SkFlate::Deflate(SkStream* src, SkWStream* dst) {
115    return doFlate(true, src, dst);
116}
117
118bool SkFlate::Deflate(const void* ptr, size_t len, SkWStream* dst) {
119    SkMemoryStream stream(ptr, len);
120    return doFlate(true, &stream, dst);
121}
122
123bool 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
132bool 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()
143static 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.
166struct SkDeflateWStream::Impl {
167    SkWStream* fOut;
168    unsigned char fInBuffer[SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE];
169    size_t fInBufferIndex;
170    z_stream fZStream;
171};
172
173SkDeflateWStream::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
187SkDeflateWStream::~SkDeflateWStream() { this->finalize(); }
188
189void 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
199bool 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
223size_t SkDeflateWStream::bytesWritten() const {
224    return fImpl->fZStream.total_in + fImpl->fInBufferIndex;
225}
226