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