1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Test.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SUPPORT_PDF
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDeflate.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRandom.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace {
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "zlib.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Different zlib implementations use different T.
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// We've seen size_t and unsigned.
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> void* skia_alloc_func(void*, T items, T size) {
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size));
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid skia_free_func(void*, void* address) { sk_free(address); }
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Use the un-deflate compression algorithm to decompress the data in src,
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  returning the result.  Returns nullptr if an error occurs.
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstd::unique_ptr<SkStreamAsset> stream_inflate(skiatest::Reporter* reporter, SkStream* src) {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDynamicMemoryWStream decompressedDynamicMemoryWStream;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkWStream* dst = &decompressedDynamicMemoryWStream;
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const size_t kBufferSize = 1024;
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t inputBuffer[kBufferSize];
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t outputBuffer[kBufferSize];
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    z_stream flateData;
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.zalloc = &skia_alloc_func;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.zfree = &skia_free_func;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.opaque = nullptr;
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.next_in = nullptr;
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.avail_in = 0;
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.next_out = outputBuffer;
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flateData.avail_out = kBufferSize;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int rc;
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rc = inflateInit(&flateData);
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (rc != Z_OK) {
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ERRORF(reporter, "Zlib: inflateInit failed");
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* input = (uint8_t*)src->getMemoryBase();
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t inputLength = src->getLength();
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (input == nullptr || inputLength == 0) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        input = nullptr;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flateData.next_in = inputBuffer;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flateData.avail_in = 0;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flateData.next_in = input;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flateData.avail_in = SkToUInt(inputLength);
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rc = Z_OK;
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (true) {
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (flateData.avail_out < kBufferSize) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                rc = Z_BUF_ERROR;
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.next_out = outputBuffer;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.avail_out = kBufferSize;
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (rc != Z_OK)
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (flateData.avail_in == 0) {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (input != nullptr)
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t read = src->read(&inputBuffer, kBufferSize);
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (read == 0)
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.next_in = inputBuffer;
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.avail_in = SkToUInt(read);
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rc = inflate(&flateData, Z_NO_FLUSH);
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (rc == Z_OK) {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rc = inflate(&flateData, Z_FINISH);
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (flateData.avail_out < kBufferSize) {
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ERRORF(reporter, "write failed");
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return nullptr;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.next_out = outputBuffer;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flateData.avail_out = kBufferSize;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    inflateEnd(&flateData);
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (rc != Z_STREAM_END) {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ERRORF(reporter, "Zlib: inflateEnd failed");
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return decompressedDynamicMemoryWStream.detachAsStream();
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}  // namespace
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(SkPDF_DeflateWStream, r) {
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRandom random(123456);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < 50; ++i) {
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t size = random.nextULessThan(10000);
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkAutoTMalloc<uint8_t> buffer(size);
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (uint32_t j = 0; j < size; ++j) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            buffer[j] = random.nextU() & 0xff;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDynamicMemoryWStream dynamicMemoryWStream;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDeflateWStream deflateWStream(&dynamicMemoryWStream);
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint32_t j = 0;
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (j < size) {
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint32_t writeSize =
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        SkTMin(size - j, random.nextRangeU(1, 400));
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!deflateWStream.write(&buffer[j], writeSize)) {
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ERRORF(r, "something went wrong.");
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                j += writeSize;
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(r, deflateWStream.bytesWritten() == size);
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<SkStreamAsset> compressed(dynamicMemoryWStream.detachAsStream());
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<SkStreamAsset> decompressed(stream_inflate(r, compressed.get()));
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!decompressed) {
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(r, "Decompression failed.");
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (decompressed->getLength() != size) {
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(r, "Decompression failed to get right size [%d]."
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                   " %u != %u", i,  (unsigned)(decompressed->getLength()),
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                   (unsigned)size);
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkString s = SkStringPrintf("/tmp/deftst_compressed_%d", i);
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkFILEWStream o(s.c_str());
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            o.writeStream(compressed.get(), compressed->getLength());
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            compressed->rewind();
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            s = SkStringPrintf("/tmp/deftst_input_%d", i);
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkFILEWStream o2(s.c_str());
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            o2.write(&buffer[0], size);
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t minLength = SkTMin(size,
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                    (uint32_t)(decompressed->getLength()));
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (uint32_t i = 0; i < minLength; ++i) {
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint8_t c;
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDEBUGCODE(size_t rb =)decompressed->read(&c, sizeof(uint8_t));
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(sizeof(uint8_t) == rb);
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (buffer[i] != c) {
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ERRORF(r, "Decompression failed at byte %u.", (unsigned)i);
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDeflateWStream emptyDeflateWStream(nullptr);
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    REPORTER_ASSERT(r, !emptyDeflateWStream.writeText("FOO"));
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
170