SkStream.cpp revision 04225dcdec5a01bc9889b7fb03e7aceb87fccc6e
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 "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    SkDEBUGCODE(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    SkDEBUGCODE(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    SkDEBUGCODE(size_t len =) this->read(&value, 4);
63    SkASSERT(4 == len);
64    return value;
65}
66
67SkScalar SkStream::readScalar() {
68    SkScalar value;
69    SkDEBUGCODE(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