blob: b199a1b94440daa8a5e38c4f2b8fefdd916b2803 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/images/SkStream.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkStream.h"
19#include "SkFixed.h"
20#include "SkString.h"
21#include "SkOSFile.h"
22
23SkStream::~SkStream() {}
24
25const char* SkStream::getFileName()
26{
27 // override in subclass if you represent a file
28 return NULL;
29}
30
31const void* SkStream::getMemoryBase()
32{
33 // override in subclass if you represent a memory block
34 return NULL;
35}
36
37size_t SkStream::skip(size_t size)
38{
39 /* Check for size == 0, and just return 0. If we passed that
40 to read(), it would interpret it as a request for the entire
41 size of the stream.
42 */
43 return size ? this->read(NULL, size) : 0;
44}
45
46int8_t SkStream::readS8() {
47 int8_t value;
48 size_t len = this->read(&value, 1);
49 SkASSERT(1 == len);
50 return value;
51}
52
53int16_t SkStream::readS16() {
54 int16_t value;
55 size_t len = this->read(&value, 2);
56 SkASSERT(2 == len);
57 return value;
58}
59
60int32_t SkStream::readS32() {
61 int32_t value;
62 size_t len = this->read(&value, 4);
63 SkASSERT(4 == len);
64 return value;
65}
66
67SkScalar SkStream::readScalar() {
68 SkScalar value;
69 size_t len = this->read(&value, sizeof(SkScalar));
70 SkASSERT(sizeof(SkScalar) == len);
71 return value;
72}
73
74size_t SkStream::readPackedUInt() {
75 uint8_t byte;
76 if (!this->read(&byte, 1)) {
77 return 0;
78 }
79 if (byte != 0xFF) {
80 return byte;
81 }
82
83 uint16_t word;
84 if (!this->read(&word, 2)) {
85 return 0;
86 }
87 if (word != 0xFFFF) {
88 return word;
89 }
90
91 uint32_t quad;
92 if (!this->read(&quad, 4)) {
93 return 0;
94 }
95 return quad;
96}
97
98//////////////////////////////////////////////////////////////////////////////////////
99
100SkWStream::~SkWStream()
101{
102}
103
104void SkWStream::newline()
105{
106 this->write("\n", 1);
107}
108
109void SkWStream::flush()
110{
111}
112
113bool SkWStream::writeText(const char text[])
114{
115 SkASSERT(text);
116 return this->write(text, strlen(text));
117}
118
119bool SkWStream::writeDecAsText(int32_t dec)
120{
121 SkString tmp;
122 tmp.appendS32(dec);
123 return this->write(tmp.c_str(), tmp.size());
124}
125
126bool SkWStream::writeHexAsText(uint32_t hex, int digits)
127{
128 SkString tmp;
129 tmp.appendHex(hex, digits);
130 return this->write(tmp.c_str(), tmp.size());
131}
132
133bool SkWStream::writeScalarAsText(SkScalar value)
134{
135 SkString tmp;
136 tmp.appendScalar(value);
137 return this->write(tmp.c_str(), tmp.size());
138}
139
140bool SkWStream::write8(U8CPU value) {
141 uint8_t v = SkToU8(value);
142 return this->write(&v, 1);
143}
144
145bool SkWStream::write16(U16CPU value) {
146 uint16_t v = SkToU16(value);
147 return this->write(&v, 2);
148}
149
150bool SkWStream::write32(uint32_t value) {
151 return this->write(&value, 4);
152}
153
154bool SkWStream::writeScalar(SkScalar value) {
155 return this->write(&value, sizeof(value));
156}
157
158bool SkWStream::writePackedUInt(size_t value) {
159 if (value < 0xFF) {
160 return this->write8(value);
161 } else if (value < 0xFFFF) {
162 return this->write8(0xFF) && this->write16(value);
163 } else {
164 return this->write16(0xFFFF) && this->write32(value);
165 }
166}
167
168bool SkWStream::writeStream(SkStream* stream, size_t length) {
169 char scratch[1024];
170 const size_t MAX = sizeof(scratch);
171
172 while (length != 0) {
173 size_t n = length;
174 if (n > MAX) {
175 n = MAX;
176 }
177 stream->read(scratch, n);
178 if (!this->write(scratch, n)) {
179 return false;
180 }
181 length -= n;
182 }
183 return true;
184}
185
186////////////////////////////////////////////////////////////////////////////
187
188SkFILEStream::SkFILEStream(const char file[]) : fName(file)
189{
190#ifdef SK_BUILD_FOR_BREW
191 if (SkStrEndsWith(fName.c_str(), ".xml"))
192 fName.writable_str()[fName.size()-3] = 'b';
193#endif
194
195 fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL;
196}
197
198SkFILEStream::~SkFILEStream()
199{
200 if (fFILE)
201 sk_fclose(fFILE);
202}
203
204void SkFILEStream::setPath(const char path[])
205{
206 fName.set(path);
207#ifdef SK_BUILD_FOR_BREW
208 if (SkStrEndsWith(fName.c_str(), ".xml"))
209 fName.writable_str()[fName.size()-3] = 'b';
210#endif
211
212 if (fFILE)
213 {
214 sk_fclose(fFILE);
215 fFILE = NULL;
216 }
217 if (path)
218 fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag);
219}
220
221const char* SkFILEStream::getFileName()
222{
223 return fName.c_str();
224}
225
226bool SkFILEStream::rewind()
227{
228 if (fFILE)
229 {
230 if (sk_frewind(fFILE))
231 return true;
232 // we hit an error
233 sk_fclose(fFILE);
234 fFILE = NULL;
235 }
236 return false;
237}
238
239size_t SkFILEStream::read(void* buffer, size_t size)
240{
241 if (fFILE)
242 {
243 if (buffer == NULL && size == 0) // special signature, they want the total size
244 return sk_fgetsize(fFILE);
245 else
246 return sk_fread(buffer, size, fFILE);
247 }
248 return 0;
249}
250
251////////////////////////////////////////////////////////////////////////////
252
253SkMemoryStream::SkMemoryStream()
254{
255 fWeOwnTheData = false;
256 this->setMemory(NULL, 0);
257}
258
259SkMemoryStream::SkMemoryStream(size_t size) {
260 fWeOwnTheData = true;
261 fOffset = 0;
262 fSize = size;
263 fSrc = sk_malloc_throw(size);
264}
265
266SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData)
267{
268 fWeOwnTheData = false;
269 this->setMemory(src, size, copyData);
270}
271
272SkMemoryStream::~SkMemoryStream()
273{
274 if (fWeOwnTheData)
275 sk_free((void*)fSrc);
276}
277
278void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData)
279{
280 if (fWeOwnTheData)
281 sk_free((void*)fSrc);
282
283 fSize = size;
284 fOffset = 0;
285 fWeOwnTheData = copyData;
286
287 if (copyData)
288 {
289 void* copy = sk_malloc_throw(size);
290 memcpy(copy, src, size);
291 src = copy;
292 }
293 fSrc = src;
294}
295
296void SkMemoryStream::skipToAlign4()
297{
298 // cast to remove unary-minus warning
299 fOffset += -(int)fOffset & 0x03;
300}
301
302bool SkMemoryStream::rewind()
303{
304 fOffset = 0;
305 return true;
306}
307
308size_t SkMemoryStream::read(void* buffer, size_t size)
309{
310 if (buffer == NULL && size == 0) // special signature, they want the total size
311 return fSize;
312
313 // if buffer is NULL, seek ahead by size
314
315 if (size == 0)
316 return 0;
317 if (size > fSize - fOffset)
318 size = fSize - fOffset;
319 if (buffer) {
320 memcpy(buffer, (const char*)fSrc + fOffset, size);
321 }
322 fOffset += size;
323 return size;
324}
325
326const void* SkMemoryStream::getMemoryBase()
327{
328 return fSrc;
329}
330
331const void* SkMemoryStream::getAtPos()
332{
333 return (const char*)fSrc + fOffset;
334}
335
336size_t SkMemoryStream::seek(size_t offset)
337{
338 if (offset > fSize)
339 offset = fSize;
340 fOffset = offset;
341 return offset;
342}
343
344/////////////////////////////////////////////////////////////////////////////////////////////////////////
345
346SkBufferStream::SkBufferStream(SkStream* proxy, size_t bufferSize)
347 : fProxy(proxy)
348{
349 SkASSERT(proxy != NULL);
350 proxy->ref();
351 this->init(NULL, bufferSize);
352}
353
354SkBufferStream::SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize)
355 : fProxy(proxy)
356{
357 SkASSERT(proxy != NULL);
358 SkASSERT(buffer == NULL || bufferSize != 0); // init(addr, 0) makes no sense, we must know how big their buffer is
359 proxy->ref();
360 this->init(buffer, bufferSize);
361}
362
363void SkBufferStream::init(void* buffer, size_t bufferSize)
364{
365 if (bufferSize == 0)
366 bufferSize = kDefaultBufferSize;
367
368 fOrigBufferSize = bufferSize;
369 fBufferSize = bufferSize;
370 fBufferOffset = bufferSize; // to trigger a reload on the first read()
371
372 if (buffer == NULL)
373 {
374 fBuffer = (char*)sk_malloc_throw(fBufferSize);
375 fWeOwnTheBuffer = true;
376 }
377 else
378 {
379 fBuffer = (char*)buffer;
380 fWeOwnTheBuffer = false;
381 }
382}
383
384SkBufferStream::~SkBufferStream()
385{
386 fProxy->unref();
387 if (fWeOwnTheBuffer)
388 sk_free(fBuffer);
389}
390
391bool SkBufferStream::rewind()
392{
393 fBufferOffset = fBufferSize = fOrigBufferSize;
394 return fProxy->rewind();
395}
396
397const char* SkBufferStream::getFileName()
398{
399 return fProxy->getFileName();
400}
401
402#ifdef SK_DEBUG
403// #define SK_TRACE_BUFFERSTREAM
404#endif
405
406size_t SkBufferStream::read(void* buffer, size_t size) {
407#ifdef SK_TRACE_BUFFERSTREAM
408 SkDebugf("Request %d", size);
409#endif
410
411 if (buffer == NULL && size == 0) {
412 return fProxy->read(buffer, size); // requesting total size
413 }
414
415 if (0 == size) {
416 return 0;
417 }
418
419 // skip size bytes
420 if (NULL == buffer) {
421 size_t remaining = fBufferSize - fBufferOffset;
422 if (remaining >= size) {
423 fBufferOffset += size;
424 return size;
425 }
426 // if we get here, we are being asked to skip beyond our current buffer
427 // so reset our offset to force a read next time, and skip the diff
428 // in our proxy
429 fBufferOffset = fOrigBufferSize;
430 return remaining + fProxy->read(NULL, size - remaining);
431 }
432
433 size_t s = size;
434 size_t actuallyRead = 0;
435
436 // flush what we can from our fBuffer
437 if (fBufferOffset < fBufferSize)
438 {
439 if (s > fBufferSize - fBufferOffset)
440 s = fBufferSize - fBufferOffset;
441 memcpy(buffer, fBuffer + fBufferOffset, s);
442#ifdef SK_TRACE_BUFFERSTREAM
443 SkDebugf(" flush %d", s);
444#endif
445 size -= s;
446 fBufferOffset += s;
447 buffer = (char*)buffer + s;
448 actuallyRead = s;
449 }
450
451 // check if there is more to read
452 if (size)
453 {
454 SkASSERT(fBufferOffset >= fBufferSize); // need to refill our fBuffer
455
456 if (size < fBufferSize) // lets try to read more than the request
457 {
458 s = fProxy->read(fBuffer, fBufferSize);
459#ifdef SK_TRACE_BUFFERSTREAM
460 SkDebugf(" read %d into fBuffer", s);
461#endif
462 if (size > s) // they asked for too much
463 size = s;
464 if (size)
465 {
466 memcpy(buffer, fBuffer, size);
467 actuallyRead += size;
468#ifdef SK_TRACE_BUFFERSTREAM
469 SkDebugf(" memcpy %d into dst", size);
470#endif
471 }
472
473 fBufferOffset = size;
474 fBufferSize = s; // record the (possibly smaller) size for the buffer
475 }
476 else // just do a direct read
477 {
478 actuallyRead += fProxy->read(buffer, size);
479#ifdef SK_TRACE_BUFFERSTREAM
480 SkDebugf(" direct read %d", size);
481#endif
482 }
483 }
484#ifdef SK_TRACE_BUFFERSTREAM
485 SkDebugf("\n");
486#endif
487 return actuallyRead;
488}
489
490const void* SkBufferStream::getMemoryBase()
491{
492 return fProxy->getMemoryBase();
493}
494
495/////////////////////////////////////////////////////////////////////////////////////////////////////////
496/////////////////////////////////////////////////////////////////////////////////////////////////////////
497
498SkFILEWStream::SkFILEWStream(const char path[])
499{
500 fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
501}
502
503SkFILEWStream::~SkFILEWStream()
504{
505 if (fFILE)
506 sk_fclose(fFILE);
507}
508
509bool SkFILEWStream::write(const void* buffer, size_t size)
510{
511 if (fFILE == NULL)
512 return false;
513
514 if (sk_fwrite(buffer, size, fFILE) != size)
515 {
516 SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);)
517 sk_fclose(fFILE);
518 fFILE = NULL;
519 return false;
520 }
521 return true;
522}
523
524void SkFILEWStream::flush()
525{
526 if (fFILE)
527 sk_fflush(fFILE);
528}
529
530////////////////////////////////////////////////////////////////////////
531
532SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size)
533 : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0)
534{
535}
536
537bool SkMemoryWStream::write(const void* buffer, size_t size)
538{
539 size = SkMin32(size, fMaxLength - fBytesWritten);
540 if (size > 0)
541 {
542 memcpy(fBuffer + fBytesWritten, buffer, size);
543 fBytesWritten += size;
544 return true;
545 }
546 return false;
547}
548
549////////////////////////////////////////////////////////////////////////
550
551#define SkDynamicMemoryWStream_MinBlockSize 256
552
553struct SkDynamicMemoryWStream::Block {
554 Block* fNext;
555 char* fCurr;
556 char* fStop;
557
558 const char* start() const { return (const char*)(this + 1); }
559 char* start() { return (char*)(this + 1); }
560 size_t avail() const { return fStop - fCurr; }
561 size_t written() const { return fCurr - this->start(); }
562
563 void init(size_t size)
564 {
565 fNext = NULL;
566 fCurr = this->start();
567 fStop = this->start() + size;
568 }
569
570 const void* append(const void* data, size_t size)
571 {
572 SkASSERT((size_t)(fStop - fCurr) >= size);
573 memcpy(fCurr, data, size);
574 fCurr += size;
575 return (const void*)((const char*)data + size);
576 }
577};
578
579SkDynamicMemoryWStream::SkDynamicMemoryWStream() : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopyToCache(NULL)
580{
581}
582
583SkDynamicMemoryWStream::~SkDynamicMemoryWStream()
584{
585 reset();
586}
587
588const char* SkDynamicMemoryWStream::detach()
589{
590 const char* result = getStream();
591 fCopyToCache = NULL;
592 return result;
593}
594
595void SkDynamicMemoryWStream::reset()
596{
597 sk_free(fCopyToCache);
598 Block* block = fHead;
599
600 while (block != NULL) {
601 Block* next = block->fNext;
602 sk_free(block);
603 block = next;
604 }
605 fHead = fTail = NULL;
606 fBytesWritten = 0;
607 fCopyToCache = NULL;
608}
609
610bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
611{
612 if (count > 0) {
613
614 if (fCopyToCache) {
615 sk_free(fCopyToCache);
616 fCopyToCache = NULL;
617 }
618 fBytesWritten += count;
619
620 size_t size;
621
622 if (fTail != NULL && fTail->avail() > 0) {
623 size = SkMin32(fTail->avail(), count);
624 buffer = fTail->append(buffer, size);
625 SkASSERT(count >= size);
626 count -= size;
627 if (count == 0)
628 return true;
629 }
630
631 size = SkMax32(count, SkDynamicMemoryWStream_MinBlockSize);
632 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
633 block->init(size);
634 block->append(buffer, count);
635
636 if (fTail != NULL)
637 fTail->fNext = block;
638 else
639 fHead = fTail = block;
640 fTail = block;
641 }
642 return true;
643}
644
645bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count)
646{
647 if (offset + count > fBytesWritten)
648 return false; // test does not partially modify
649 Block* block = fHead;
650 while (block != NULL) {
651 size_t size = block->written();
652 if (offset < size) {
653 size_t part = offset + count > size ? size - offset : count;
654 memcpy(block->start() + offset, buffer, part);
655 if (count <= part)
656 return true;
657 count -= part;
658 buffer = (const void*) ((char* ) buffer + part);
659 }
660 offset = offset > size ? offset - size : 0;
661 block = block->fNext;
662 }
663 return false;
664}
665
666bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count)
667{
668 if (offset + count > fBytesWritten)
669 return false; // test does not partially modify
670 Block* block = fHead;
671 while (block != NULL) {
672 size_t size = block->written();
673 if (offset < size) {
674 size_t part = offset + count > size ? size - offset : count;
675 memcpy(buffer, block->start() + offset, part);
676 if (count <= part)
677 return true;
678 count -= part;
679 buffer = (void*) ((char* ) buffer + part);
680 }
681 offset = offset > size ? offset - size : 0;
682 block = block->fNext;
683 }
684 return false;
685}
686
687void SkDynamicMemoryWStream::copyTo(void* dst) const
688{
689 Block* block = fHead;
690
691 while (block != NULL) {
692 size_t size = block->written();
693 memcpy(dst, block->start(), size);
694 dst = (void*)((char*)dst + size);
695 block = block->fNext;
696 }
697}
698
699const char* SkDynamicMemoryWStream::getStream() const
700{
701 if (fCopyToCache == NULL) {
702 fCopyToCache = (char*)sk_malloc_throw(fBytesWritten);
703 this->copyTo(fCopyToCache);
704 }
705 return fCopyToCache;
706}
707
708void SkDynamicMemoryWStream::padToAlign4()
709{
710 // cast to remove unary-minus warning
711 int padBytes = -(int)fBytesWritten & 0x03;
712 if (padBytes == 0)
713 return;
714 int zero = 0;
715 write(&zero, padBytes);
716}
717
718/////////////////////////////////////////////////////////////////////////////////////////////////////////
719
720void SkDebugWStream::newline()
721{
722#ifdef SK_DEBUG
723 SkDebugf("\n");
724#endif
725}
726
727bool SkDebugWStream::write(const void* buffer, size_t size)
728{
729#ifdef SK_DEBUG
730 char* s = new char[size+1];
731 memcpy(s, buffer, size);
732 s[size] = 0;
733 SkDebugf("%s", s);
734 delete[] s;
735#endif
736 return true;
737}
738
739/////////////////////////////////////////////////////////////////////////////////////////////////////////
740/////////////////////////////////////////////////////////////////////////////////////////////////////////
741
742#ifdef SK_DEBUG
743
744#include "SkRandom.h"
745
746#ifdef SK_SUPPORT_UNITTEST
747#define MAX_SIZE (256 * 1024)
748
749static void random_fill(SkRandom& rand, void* buffer, size_t size) {
750 char* p = (char*)buffer;
751 char* stop = p + size;
752 while (p < stop) {
753 *p++ = (char)(rand.nextU() >> 8);
754 }
755}
756
757static void test_buffer() {
758 SkRandom rand;
759 SkAutoMalloc am(MAX_SIZE * 2);
760 char* storage = (char*)am.get();
761 char* storage2 = storage + MAX_SIZE;
762
763 random_fill(rand, storage, MAX_SIZE);
764
765 for (int sizeTimes = 0; sizeTimes < 100; sizeTimes++) {
766 int size = rand.nextU() % MAX_SIZE;
767 if (size == 0) {
768 size = MAX_SIZE;
769 }
770 for (int times = 0; times < 100; times++) {
771 int bufferSize = 1 + (rand.nextU() & 0xFFFF);
772 SkMemoryStream mstream(storage, size);
773 SkBufferStream bstream(&mstream, bufferSize);
774
775 int bytesRead = 0;
776 while (bytesRead < size) {
777 int s = 17 + (rand.nextU() & 0xFFFF);
778 int ss = bstream.read(storage2, s);
779 SkASSERT(ss > 0 && ss <= s);
780 SkASSERT(bytesRead + ss <= size);
781 SkASSERT(memcmp(storage + bytesRead, storage2, ss) == 0);
782 bytesRead += ss;
783 }
784 SkASSERT(bytesRead == size);
785 }
786 }
787}
788#endif
789
790void SkStream::UnitTest() {
791#ifdef SK_SUPPORT_UNITTEST
792 {
793 static const char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
794 char copy[sizeof(s)];
795 SkRandom rand;
796
797 for (int i = 0; i < 65; i++)
798 {
799 char* copyPtr = copy;
800 SkMemoryStream mem(s, sizeof(s));
801 SkBufferStream buff(&mem, i);
802
803 do {
804 copyPtr += buff.read(copyPtr, rand.nextU() & 15);
805 } while (copyPtr < copy + sizeof(s));
806 SkASSERT(copyPtr == copy + sizeof(s));
807 SkASSERT(memcmp(s, copy, sizeof(s)) == 0);
808 }
809 }
810 test_buffer();
811#endif
812}
813
814void SkWStream::UnitTest()
815{
816#ifdef SK_SUPPORT_UNITTEST
817 {
818 SkDebugWStream s;
819
820 s.writeText("testing wstream helpers\n");
821 s.writeText("compare: 0 "); s.writeDecAsText(0); s.newline();
822 s.writeText("compare: 591 "); s.writeDecAsText(591); s.newline();
823 s.writeText("compare: -9125 "); s.writeDecAsText(-9125); s.newline();
824 s.writeText("compare: 0 "); s.writeHexAsText(0, 0); s.newline();
825 s.writeText("compare: 03FA "); s.writeHexAsText(0x3FA, 4); s.newline();
826 s.writeText("compare: DEADBEEF "); s.writeHexAsText(0xDEADBEEF, 4); s.newline();
827 s.writeText("compare: 0 "); s.writeScalarAsText(SkIntToScalar(0)); s.newline();
828 s.writeText("compare: 27 "); s.writeScalarAsText(SkIntToScalar(27)); s.newline();
829 s.writeText("compare: -119 "); s.writeScalarAsText(SkIntToScalar(-119)); s.newline();
830 s.writeText("compare: 851.3333 "); s.writeScalarAsText(SkIntToScalar(851) + SK_Scalar1/3); s.newline();
831 s.writeText("compare: -0.08 "); s.writeScalarAsText(-SK_Scalar1*8/100); s.newline();
832 }
833
834 {
835 SkDynamicMemoryWStream ds;
836 const char s[] = "abcdefghijklmnopqrstuvwxyz";
837 int i;
838 for (i = 0; i < 100; i++) {
839 bool result = ds.write(s, 26);
840 SkASSERT(result);
841 }
842 SkASSERT(ds.getOffset() == 100 * 26);
843 char* dst = new char[100 * 26 + 1];
844 dst[100*26] = '*';
845 ds.copyTo(dst);
846 SkASSERT(dst[100*26] == '*');
847 // char* p = dst;
848 for (i = 0; i < 100; i++)
849 SkASSERT(memcmp(&dst[i * 26], s, 26) == 0);
850 SkASSERT(memcmp(dst, ds.getStream(), 100*26) == 0);
851 delete[] dst;
852 }
853#endif
854}
855
856#endif