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