• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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