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