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