1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 The Android Open Source Project
4a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org */
8a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
10314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com#include "SkData.h"
11a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#include "SkFlate.h"
12a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#include "SkStream.h"
13a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
14fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com#ifndef SK_HAS_ZLIB
15a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.orgbool SkFlate::HaveFlate() { return false; }
167453d0e450917209871c7ea54132bb5c18c7e2d3reed@google.combool SkFlate::Deflate(SkStream*, SkWStream*) { return false; }
17b14ef7315afafc5082791b7c49213ef99f3275cbepoger@google.combool SkFlate::Deflate(const void*, size_t, SkWStream*) { return false; }
18b14ef7315afafc5082791b7c49213ef99f3275cbepoger@google.combool SkFlate::Deflate(const SkData*, SkWStream*) { return false; }
197453d0e450917209871c7ea54132bb5c18c7e2d3reed@google.combool SkFlate::Inflate(SkStream*, SkWStream*) { return false; }
20a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#else
21a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
22a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org// static
23a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.orgbool SkFlate::HaveFlate() {
24a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    return true;
25a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org}
26a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
27a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.orgnamespace {
28a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
29fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com#ifdef SK_SYSTEM_ZLIB
30fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com#include <zlib.h>
31fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com#else
32a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#include SK_ZLIB_INCLUDE
33fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com#endif
34a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
35c7a38f38c938a9828af0a53040e3f27079c67da5vandebo@chromium.org// static
36c7a38f38c938a9828af0a53040e3f27079c67da5vandebo@chromium.orgconst size_t kBufferSize = 1024;
37c7a38f38c938a9828af0a53040e3f27079c67da5vandebo@chromium.org
387453d0e450917209871c7ea54132bb5c18c7e2d3reed@google.combool doFlate(bool compress, SkStream* src, SkWStream* dst) {
39a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    uint8_t inputBuffer[kBufferSize];
40a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    uint8_t outputBuffer[kBufferSize];
41a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    z_stream flateData;
42a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.zalloc = NULL;
43a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.zfree = NULL;
44a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.next_in = NULL;
45a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.avail_in = 0;
46a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.next_out = outputBuffer;
47a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    flateData.avail_out = kBufferSize;
48a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    int rc;
49a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    if (compress)
50a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        rc = deflateInit(&flateData, Z_DEFAULT_COMPRESSION);
51a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    else
52a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        rc = inflateInit(&flateData);
53a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    if (rc != Z_OK)
54a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        return false;
55a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
56a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    uint8_t* input = (uint8_t*)src->getMemoryBase();
57a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    size_t inputLength = src->getLength();
58ee34e35c8cefb5b384b34e4eb5ef8cb82774e5a0vandebo@chromium.org    if (input == NULL || inputLength == 0) {
59a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        input = NULL;
60a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        flateData.next_in = inputBuffer;
61a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        flateData.avail_in = 0;
62a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    } else {
63a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        flateData.next_in = input;
647fa2a65c0cfc714364490cb715171461143024e0reed@google.com        flateData.avail_in = SkToUInt(inputLength);
65a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    }
66a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
67a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    rc = Z_OK;
68a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    while (true) {
69a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        if (flateData.avail_out < kBufferSize) {
70a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) {
71a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org                rc = Z_BUF_ERROR;
72a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org                break;
73a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            }
74a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            flateData.next_out = outputBuffer;
75a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            flateData.avail_out = kBufferSize;
76a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        }
77ee34e35c8cefb5b384b34e4eb5ef8cb82774e5a0vandebo@chromium.org        if (rc != Z_OK)
78ee34e35c8cefb5b384b34e4eb5ef8cb82774e5a0vandebo@chromium.org            break;
79a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        if (flateData.avail_in == 0) {
80a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            if (input != NULL)
81a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org                break;
82a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            size_t read = src->read(&inputBuffer, kBufferSize);
83a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            if (read == 0)
84a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org                break;
85a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            flateData.next_in = inputBuffer;
867fa2a65c0cfc714364490cb715171461143024e0reed@google.com            flateData.avail_in = SkToUInt(read);
87a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        }
88a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        if (compress)
89a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            rc = deflate(&flateData, Z_NO_FLUSH);
90a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        else
91a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            rc = inflate(&flateData, Z_NO_FLUSH);
92a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    }
93a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    while (rc == Z_OK) {
94a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        if (compress)
95a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            rc = deflate(&flateData, Z_FINISH);
96a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        else
97a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            rc = inflate(&flateData, Z_FINISH);
98ee34e35c8cefb5b384b34e4eb5ef8cb82774e5a0vandebo@chromium.org        if (flateData.avail_out < kBufferSize) {
99a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out))
100a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org                return false;
101a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            flateData.next_out = outputBuffer;
102a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org            flateData.avail_out = kBufferSize;
103a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        }
104a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    }
105a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
106a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    if (compress)
107a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        deflateEnd(&flateData);
108a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    else
109a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        inflateEnd(&flateData);
110a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    if (rc == Z_STREAM_END)
111a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org        return true;
112a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org    return false;
113a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org}
114a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
115a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org}
116a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
117a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org// static
1187453d0e450917209871c7ea54132bb5c18c7e2d3reed@google.combool SkFlate::Deflate(SkStream* src, SkWStream* dst) {
119c7a38f38c938a9828af0a53040e3f27079c67da5vandebo@chromium.org    return doFlate(true, src, dst);
120a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org}
121a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
122314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.combool SkFlate::Deflate(const void* ptr, size_t len, SkWStream* dst) {
123314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com    SkMemoryStream stream(ptr, len);
124314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com    return doFlate(true, &stream, dst);
125314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com}
126314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com
127314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.combool SkFlate::Deflate(const SkData* data, SkWStream* dst) {
128314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com    if (data) {
129314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com        SkMemoryStream stream(data->data(), data->size());
130314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com        return doFlate(true, &stream, dst);
131314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com    }
132314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com    return false;
133314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com}
134314e9b3ba0b950b99e4d11e3302933014c35c3edreed@google.com
135a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org// static
1367453d0e450917209871c7ea54132bb5c18c7e2d3reed@google.combool SkFlate::Inflate(SkStream* src, SkWStream* dst) {
137c7a38f38c938a9828af0a53040e3f27079c67da5vandebo@chromium.org    return doFlate(false, src, dst);
138a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org}
139a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org
140a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#endif
141