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