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