1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2010 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/pdf/SkDeflate.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkData.h"
11cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
13cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include "zlib.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include <algorithm>
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cinamespace {
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci// Different zlib implementations use different T.
22cb93a386Sopenharmony_ci// We've seen size_t and unsigned.
23cb93a386Sopenharmony_citemplate <typename T> void* skia_alloc_func(void*, T items, T size) {
24cb93a386Sopenharmony_ci    return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
25cb93a386Sopenharmony_ci}
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_civoid skia_free_func(void*, void* address) { sk_free(address); }
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci}  // namespace
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci#define SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE 4096
32cb93a386Sopenharmony_ci#define SKDEFLATEWSTREAM_OUTPUT_BUFFER_SIZE 4224  // 4096 + 128, usually big
33cb93a386Sopenharmony_ci                                                  // enough to always do a
34cb93a386Sopenharmony_ci                                                  // single loop.
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci// called by both write() and finalize()
37cb93a386Sopenharmony_cistatic void do_deflate(int flush,
38cb93a386Sopenharmony_ci                       z_stream* zStream,
39cb93a386Sopenharmony_ci                       SkWStream* out,
40cb93a386Sopenharmony_ci                       unsigned char* inBuffer,
41cb93a386Sopenharmony_ci                       size_t inBufferSize) {
42cb93a386Sopenharmony_ci    zStream->next_in = inBuffer;
43cb93a386Sopenharmony_ci    zStream->avail_in = SkToInt(inBufferSize);
44cb93a386Sopenharmony_ci    unsigned char outBuffer[SKDEFLATEWSTREAM_OUTPUT_BUFFER_SIZE];
45cb93a386Sopenharmony_ci    SkDEBUGCODE(int returnValue;)
46cb93a386Sopenharmony_ci    do {
47cb93a386Sopenharmony_ci        zStream->next_out = outBuffer;
48cb93a386Sopenharmony_ci        zStream->avail_out = sizeof(outBuffer);
49cb93a386Sopenharmony_ci        SkDEBUGCODE(returnValue =) deflate(zStream, flush);
50cb93a386Sopenharmony_ci        SkASSERT(!zStream->msg);
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci        out->write(outBuffer, sizeof(outBuffer) - zStream->avail_out);
53cb93a386Sopenharmony_ci    } while (zStream->avail_in || !zStream->avail_out);
54cb93a386Sopenharmony_ci    SkASSERT(flush == Z_FINISH
55cb93a386Sopenharmony_ci                 ? returnValue == Z_STREAM_END
56cb93a386Sopenharmony_ci                 : returnValue == Z_OK);
57cb93a386Sopenharmony_ci}
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci// Hide all zlib impl details.
60cb93a386Sopenharmony_cistruct SkDeflateWStream::Impl {
61cb93a386Sopenharmony_ci    SkWStream* fOut;
62cb93a386Sopenharmony_ci    unsigned char fInBuffer[SKDEFLATEWSTREAM_INPUT_BUFFER_SIZE];
63cb93a386Sopenharmony_ci    size_t fInBufferIndex;
64cb93a386Sopenharmony_ci    z_stream fZStream;
65cb93a386Sopenharmony_ci};
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ciSkDeflateWStream::SkDeflateWStream(SkWStream* out,
68cb93a386Sopenharmony_ci                                   int compressionLevel,
69cb93a386Sopenharmony_ci                                   bool gzip)
70cb93a386Sopenharmony_ci    : fImpl(std::make_unique<SkDeflateWStream::Impl>()) {
71cb93a386Sopenharmony_ci    fImpl->fOut = out;
72cb93a386Sopenharmony_ci    fImpl->fInBufferIndex = 0;
73cb93a386Sopenharmony_ci    if (!fImpl->fOut) {
74cb93a386Sopenharmony_ci        return;
75cb93a386Sopenharmony_ci    }
76cb93a386Sopenharmony_ci    fImpl->fZStream.next_in = nullptr;
77cb93a386Sopenharmony_ci    fImpl->fZStream.zalloc = &skia_alloc_func;
78cb93a386Sopenharmony_ci    fImpl->fZStream.zfree = &skia_free_func;
79cb93a386Sopenharmony_ci    fImpl->fZStream.opaque = nullptr;
80cb93a386Sopenharmony_ci    SkASSERT(compressionLevel <= 9 && compressionLevel >= -1);
81cb93a386Sopenharmony_ci    SkDEBUGCODE(int r =) deflateInit2(&fImpl->fZStream, compressionLevel,
82cb93a386Sopenharmony_ci                                      Z_DEFLATED, gzip ? 0x1F : 0x0F,
83cb93a386Sopenharmony_ci                                      8, Z_DEFAULT_STRATEGY);
84cb93a386Sopenharmony_ci    SkASSERT(Z_OK == r);
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ciSkDeflateWStream::~SkDeflateWStream() { this->finalize(); }
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_civoid SkDeflateWStream::finalize() {
90cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
91cb93a386Sopenharmony_ci    if (!fImpl->fOut) {
92cb93a386Sopenharmony_ci        return;
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci    do_deflate(Z_FINISH, &fImpl->fZStream, fImpl->fOut, fImpl->fInBuffer,
95cb93a386Sopenharmony_ci               fImpl->fInBufferIndex);
96cb93a386Sopenharmony_ci    (void)deflateEnd(&fImpl->fZStream);
97cb93a386Sopenharmony_ci    fImpl->fOut = nullptr;
98cb93a386Sopenharmony_ci}
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_cibool SkDeflateWStream::write(const void* void_buffer, size_t len) {
101cb93a386Sopenharmony_ci    TRACE_EVENT0("skia", TRACE_FUNC);
102cb93a386Sopenharmony_ci    if (!fImpl->fOut) {
103cb93a386Sopenharmony_ci        return false;
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci    const char* buffer = (const char*)void_buffer;
106cb93a386Sopenharmony_ci    while (len > 0) {
107cb93a386Sopenharmony_ci        size_t tocopy =
108cb93a386Sopenharmony_ci                std::min(len, sizeof(fImpl->fInBuffer) - fImpl->fInBufferIndex);
109cb93a386Sopenharmony_ci        memcpy(fImpl->fInBuffer + fImpl->fInBufferIndex, buffer, tocopy);
110cb93a386Sopenharmony_ci        len -= tocopy;
111cb93a386Sopenharmony_ci        buffer += tocopy;
112cb93a386Sopenharmony_ci        fImpl->fInBufferIndex += tocopy;
113cb93a386Sopenharmony_ci        SkASSERT(fImpl->fInBufferIndex <= sizeof(fImpl->fInBuffer));
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci        // if the buffer isn't filled, don't call into zlib yet.
116cb93a386Sopenharmony_ci        if (sizeof(fImpl->fInBuffer) == fImpl->fInBufferIndex) {
117cb93a386Sopenharmony_ci            do_deflate(Z_NO_FLUSH, &fImpl->fZStream, fImpl->fOut,
118cb93a386Sopenharmony_ci                       fImpl->fInBuffer, fImpl->fInBufferIndex);
119cb93a386Sopenharmony_ci            fImpl->fInBufferIndex = 0;
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci    }
122cb93a386Sopenharmony_ci    return true;
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_cisize_t SkDeflateWStream::bytesWritten() const {
126cb93a386Sopenharmony_ci    return fImpl->fZStream.total_in + fImpl->fInBufferIndex;
127cb93a386Sopenharmony_ci}
128