1 /*
2 * Copyright 2011 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 "Resources.h"
9 #include "SkAutoMalloc.h"
10 #include "SkData.h"
11 #include "SkFrontBufferedStream.h"
12 #include "SkOSFile.h"
13 #include "SkOSPath.h"
14 #include "SkRandom.h"
15 #include "SkStream.h"
16 #include "SkStreamPriv.h"
17 #include "Test.h"
18
19 #ifndef SK_BUILD_FOR_WIN
20 #include <unistd.h>
21 #include <fcntl.h>
22 #endif
23
24 #define MAX_SIZE (256 * 1024)
25
test_loop_stream(skiatest::Reporter * reporter,SkStream * stream,const void * src,size_t len,int repeat)26 static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
27 const void* src, size_t len, int repeat) {
28 SkAutoSMalloc<256> storage(len);
29 void* tmp = storage.get();
30
31 for (int i = 0; i < repeat; ++i) {
32 size_t bytes = stream->read(tmp, len);
33 REPORTER_ASSERT(reporter, bytes == len);
34 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
35 }
36
37 // expect EOF
38 size_t bytes = stream->read(tmp, 1);
39 REPORTER_ASSERT(reporter, 0 == bytes);
40 // isAtEnd might not return true until after the first failing read.
41 REPORTER_ASSERT(reporter, stream->isAtEnd());
42 }
43
test_filestreams(skiatest::Reporter * reporter,const char * tmpDir)44 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
45 SkString path = SkOSPath::Join(tmpDir, "wstream_test");
46
47 const char s[] = "abcdefghijklmnopqrstuvwxyz";
48
49 {
50 SkFILEWStream writer(path.c_str());
51 if (!writer.isValid()) {
52 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
53 return;
54 }
55
56 for (int i = 0; i < 100; ++i) {
57 writer.write(s, 26);
58 }
59 }
60
61 {
62 SkFILEStream stream(path.c_str());
63 REPORTER_ASSERT(reporter, stream.isValid());
64 test_loop_stream(reporter, &stream, s, 26, 100);
65
66 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
67 test_loop_stream(reporter, stream2.get(), s, 26, 100);
68 }
69
70 {
71 FILE* file = ::fopen(path.c_str(), "rb");
72 SkFILEStream stream(file);
73 REPORTER_ASSERT(reporter, stream.isValid());
74 test_loop_stream(reporter, &stream, s, 26, 100);
75
76 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
77 test_loop_stream(reporter, stream2.get(), s, 26, 100);
78 }
79 }
80
TestWStream(skiatest::Reporter * reporter)81 static void TestWStream(skiatest::Reporter* reporter) {
82 SkDynamicMemoryWStream ds;
83 const char s[] = "abcdefghijklmnopqrstuvwxyz";
84 int i;
85 for (i = 0; i < 100; i++) {
86 REPORTER_ASSERT(reporter, ds.write(s, 26));
87 }
88 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
89
90 char* dst = new char[100 * 26 + 1];
91 dst[100*26] = '*';
92 ds.copyTo(dst);
93 REPORTER_ASSERT(reporter, dst[100*26] == '*');
94 for (i = 0; i < 100; i++) {
95 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
96 }
97
98 {
99 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
100 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
101 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
102 test_loop_stream(reporter, stream.get(), s, 26, 100);
103
104 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
105 test_loop_stream(reporter, stream2.get(), s, 26, 100);
106
107 std::unique_ptr<SkStreamAsset> stream3(stream->fork());
108 REPORTER_ASSERT(reporter, stream3->isAtEnd());
109 char tmp;
110 size_t bytes = stream->read(&tmp, 1);
111 REPORTER_ASSERT(reporter, 0 == bytes);
112 stream3->rewind();
113 test_loop_stream(reporter, stream3.get(), s, 26, 100);
114 }
115
116 for (i = 0; i < 100; i++) {
117 REPORTER_ASSERT(reporter, ds.write(s, 26));
118 }
119 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
120
121 {
122 // Test that this works after a snapshot.
123 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
124 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
125 test_loop_stream(reporter, stream.get(), s, 26, 100);
126
127 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
128 test_loop_stream(reporter, stream2.get(), s, 26, 100);
129 }
130 delete[] dst;
131
132 SkString tmpDir = skiatest::GetTmpDir();
133 if (!tmpDir.isEmpty()) {
134 test_filestreams(reporter, tmpDir.c_str());
135 }
136 }
137
TestPackedUInt(skiatest::Reporter * reporter)138 static void TestPackedUInt(skiatest::Reporter* reporter) {
139 // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
140 // so we test values around each of those transitions (and a few others)
141 const size_t sizes[] = {
142 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
143 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
144 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
145 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
146 };
147
148
149 size_t i;
150 SkDynamicMemoryWStream wstream;
151
152 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
153 bool success = wstream.writePackedUInt(sizes[i]);
154 REPORTER_ASSERT(reporter, success);
155 }
156
157 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
158 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
159 size_t n = rstream->readPackedUInt();
160 if (sizes[i] != n) {
161 ERRORF(reporter, "sizes:%x != n:%x\n", i, sizes[i], n);
162 }
163 }
164 }
165
166 // Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling
167 // methods that access fData.
TestDereferencingData(SkMemoryStream * memStream)168 static void TestDereferencingData(SkMemoryStream* memStream) {
169 memStream->read(nullptr, 0);
170 memStream->getMemoryBase();
171 (void)memStream->asData();
172 }
173
TestNullData()174 static void TestNullData() {
175 SkMemoryStream memStream(nullptr);
176 TestDereferencingData(&memStream);
177
178 memStream.setData(nullptr);
179 TestDereferencingData(&memStream);
180
181 }
182
DEF_TEST(Stream,reporter)183 DEF_TEST(Stream, reporter) {
184 TestWStream(reporter);
185 TestPackedUInt(reporter);
186 TestNullData();
187 }
188
189 #ifndef SK_BUILD_FOR_IOS
190 /**
191 * Tests peeking and then reading the same amount. The two should provide the
192 * same results.
193 * Returns the amount successfully read minus the amount successfully peeked.
194 */
compare_peek_to_read(skiatest::Reporter * reporter,SkStream * stream,size_t bytesToPeek)195 static size_t compare_peek_to_read(skiatest::Reporter* reporter,
196 SkStream* stream, size_t bytesToPeek) {
197 // The rest of our tests won't be very interesting if bytesToPeek is zero.
198 REPORTER_ASSERT(reporter, bytesToPeek > 0);
199 SkAutoMalloc peekStorage(bytesToPeek);
200 SkAutoMalloc readStorage(bytesToPeek);
201 void* peekPtr = peekStorage.get();
202 void* readPtr = peekStorage.get();
203
204 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
205 const size_t bytesRead = stream->read(readPtr, bytesToPeek);
206
207 // bytesRead should only be less than attempted if the stream is at the
208 // end.
209 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
210
211 // peek and read should behave the same, except peek returned to the
212 // original position, so they read the same data.
213 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
214
215 // A stream should never be able to peek more than it can read.
216 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
217
218 return bytesRead - bytesPeeked;
219 }
220
test_fully_peekable_stream(skiatest::Reporter * r,SkStream * stream,size_t limit)221 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
222 for (size_t i = 1; !stream->isAtEnd(); i++) {
223 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
224 }
225 }
226
test_peeking_front_buffered_stream(skiatest::Reporter * r,const SkStream & original,size_t bufferSize)227 static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
228 const SkStream& original,
229 size_t bufferSize) {
230 SkStream* dupe = original.duplicate();
231 REPORTER_ASSERT(r, dupe != nullptr);
232 std::unique_ptr<SkStream> bufferedStream(SkFrontBufferedStream::Create(dupe, bufferSize));
233 REPORTER_ASSERT(r, bufferedStream != nullptr);
234
235 size_t peeked = 0;
236 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
237 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
238 if (unpeekableBytes > 0) {
239 // This could not have returned a number greater than i.
240 REPORTER_ASSERT(r, unpeekableBytes <= i);
241
242 // We have reached the end of the buffer. Verify that it was at least
243 // bufferSize.
244 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
245 // No more peeking is supported.
246 break;
247 }
248 peeked += i;
249 }
250
251 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
252 bufferedStream.reset(SkFrontBufferedStream::Create(original.duplicate(), bufferSize));
253 REPORTER_ASSERT(r, bufferedStream != nullptr);
254
255 const size_t bytesToPeek = bufferSize + 1;
256 SkAutoMalloc peekStorage(bytesToPeek);
257 SkAutoMalloc readStorage(bytesToPeek);
258
259 for (size_t start = 0; start <= bufferSize; start++) {
260 // Skip to the starting point
261 REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
262
263 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
264 if (0 == bytesPeeked) {
265 // Peeking should only fail completely if we have read/skipped beyond the buffer.
266 REPORTER_ASSERT(r, start >= bufferSize);
267 break;
268 }
269
270 // Only read the amount that was successfully peeked.
271 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
272 REPORTER_ASSERT(r, bytesRead == bytesPeeked);
273 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
274
275 // This should be safe to rewind.
276 REPORTER_ASSERT(r, bufferedStream->rewind());
277 }
278 }
279
280 // This test uses file system operations that don't work out of the
281 // box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
282 // TODO(stephana): Re-evaluate if we need this in the future.
DEF_TEST(StreamPeek,reporter)283 DEF_TEST(StreamPeek, reporter) {
284 // Test a memory stream.
285 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
286 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
287 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
288
289 // Test an arbitrary file stream. file streams do not support peeking.
290 SkFILEStream fileStream(GetResourcePath("baby_tux.webp").c_str());
291 REPORTER_ASSERT(reporter, fileStream.isValid());
292 if (!fileStream.isValid()) {
293 return;
294 }
295 SkAutoMalloc storage(fileStream.getLength());
296 for (size_t i = 1; i < fileStream.getLength(); i++) {
297 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
298 }
299
300 // Now test some FrontBufferedStreams
301 for (size_t i = 1; i < memStream.getLength(); i++) {
302 test_peeking_front_buffered_stream(reporter, memStream, i);
303 }
304 }
305 #endif
306
307 // Asserts that asset == expected and is peekable.
stream_peek_test(skiatest::Reporter * rep,SkStreamAsset * asset,const SkData * expected)308 static void stream_peek_test(skiatest::Reporter* rep,
309 SkStreamAsset* asset,
310 const SkData* expected) {
311 if (asset->getLength() != expected->size()) {
312 ERRORF(rep, "Unexpected length.");
313 return;
314 }
315 SkRandom rand;
316 uint8_t buffer[4096];
317 const uint8_t* expect = expected->bytes();
318 for (size_t i = 0; i < asset->getLength(); ++i) {
319 uint32_t maxSize =
320 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i));
321 size_t size = rand.nextRangeU(1, maxSize);
322 SkASSERT(size >= 1);
323 SkASSERT(size <= sizeof(buffer));
324 SkASSERT(size + i <= asset->getLength());
325 if (asset->peek(buffer, size) < size) {
326 ERRORF(rep, "Peek Failed!");
327 return;
328 }
329 if (0 != memcmp(buffer, &expect[i], size)) {
330 ERRORF(rep, "Peek returned wrong bytes!");
331 return;
332 }
333 uint8_t value;
334 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
335 if (value != expect[i]) {
336 ERRORF(rep, "Read Failed!");
337 return;
338 }
339 }
340 }
341
DEF_TEST(StreamPeek_BlockMemoryStream,rep)342 DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
343 const static int kSeed = 1234;
344 SkRandom valueSource(kSeed);
345 SkRandom rand(kSeed << 1);
346 uint8_t buffer[4096];
347 SkDynamicMemoryWStream dynamicMemoryWStream;
348 size_t totalWritten = 0;
349 for (int i = 0; i < 32; ++i) {
350 // Randomize the length of the blocks.
351 size_t size = rand.nextRangeU(1, sizeof(buffer));
352 for (size_t j = 0; j < size; ++j) {
353 buffer[j] = valueSource.nextU() & 0xFF;
354 }
355 dynamicMemoryWStream.write(buffer, size);
356 totalWritten += size;
357 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
358 }
359 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
360 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
361 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
362 valueSource.setSeed(kSeed); // reseed.
363 // We want the exact same same "random" string of numbers to put
364 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
365 // correctly while we are testing SkDynamicMemoryStream.
366 for (size_t i = 0; i < asset->getLength(); ++i) {
367 expectedPtr[i] = valueSource.nextU() & 0xFF;
368 }
369 stream_peek_test(rep, asset.get(), expected.get());
370 }
371
372 namespace {
373 class DumbStream : public SkStream {
374 public:
DumbStream(const uint8_t * data,size_t n)375 DumbStream(const uint8_t* data, size_t n)
376 : fData(data), fCount(n), fIdx(0) {}
read(void * buffer,size_t size)377 size_t read(void* buffer, size_t size) override {
378 size_t copyCount = SkTMin(fCount - fIdx, size);
379 if (copyCount) {
380 memcpy(buffer, &fData[fIdx], copyCount);
381 fIdx += copyCount;
382 }
383 return copyCount;
384 }
isAtEnd() const385 bool isAtEnd() const override {
386 return fCount == fIdx;
387 }
388 private:
389 const uint8_t* fData;
390 size_t fCount, fIdx;
391 };
392 } // namespace
393
stream_copy_test(skiatest::Reporter * reporter,const void * srcData,size_t N,SkStream * stream)394 static void stream_copy_test(skiatest::Reporter* reporter,
395 const void* srcData,
396 size_t N,
397 SkStream* stream) {
398 SkDynamicMemoryWStream tgt;
399 if (!SkStreamCopy(&tgt, stream)) {
400 ERRORF(reporter, "SkStreamCopy failed");
401 return;
402 }
403 sk_sp<SkData> data(tgt.detachAsData());
404 if (data->size() != N) {
405 ERRORF(reporter, "SkStreamCopy incorrect size");
406 return;
407 }
408 if (0 != memcmp(data->data(), srcData, N)) {
409 ERRORF(reporter, "SkStreamCopy bad copy");
410 }
411 }
412
DEF_TEST(DynamicMemoryWStream_detachAsData,r)413 DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
414 const char az[] = "abcdefghijklmnopqrstuvwxyz";
415 const unsigned N = 40000;
416 SkDynamicMemoryWStream dmws;
417 for (unsigned i = 0; i < N; ++i) {
418 dmws.writeText(az);
419 }
420 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
421 auto data = dmws.detachAsData();
422 REPORTER_ASSERT(r, data->size() == N * strlen(az));
423 const uint8_t* ptr = data->bytes();
424 for (unsigned i = 0; i < N; ++i) {
425 if (0 != memcmp(ptr, az, strlen(az))) {
426 ERRORF(r, "detachAsData() memcmp failed");
427 return;
428 }
429 ptr += strlen(az);
430 }
431 }
432
DEF_TEST(StreamCopy,reporter)433 DEF_TEST(StreamCopy, reporter) {
434 SkRandom random(123456);
435 static const int N = 10000;
436 SkAutoTMalloc<uint8_t> src((size_t)N);
437 for (int j = 0; j < N; ++j) {
438 src[j] = random.nextU() & 0xff;
439 }
440 // SkStreamCopy had two code paths; this test both.
441 DumbStream dumbStream(src.get(), (size_t)N);
442 stream_copy_test(reporter, src, N, &dumbStream);
443 SkMemoryStream smartStream(src.get(), (size_t)N);
444 stream_copy_test(reporter, src, N, &smartStream);
445 }
446
DEF_TEST(StreamEmptyStreamMemoryBase,r)447 DEF_TEST(StreamEmptyStreamMemoryBase, r) {
448 SkDynamicMemoryWStream tmp;
449 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
450 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
451 }
452
453 #include "SkBuffer.h"
454
DEF_TEST(RBuffer,reporter)455 DEF_TEST(RBuffer, reporter) {
456 int32_t value = 0;
457 SkRBuffer buffer(&value, 4);
458 REPORTER_ASSERT(reporter, buffer.isValid());
459
460 int32_t tmp;
461 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
462 REPORTER_ASSERT(reporter, buffer.isValid());
463
464 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
465 REPORTER_ASSERT(reporter, !buffer.isValid());
466 }
467