Home | History | Annotate | Download | only in core
      1 #include "SkWriter32.h"
      2 
      3 struct SkWriter32::Block {
      4     Block*  fNext;
      5     size_t  fSize;
      6     size_t  fAllocated;
      7 
      8     size_t  available() const { return fSize - fAllocated; }
      9     char*   base() { return (char*)(this + 1); }
     10     const char* base() const { return (const char*)(this + 1); }
     11 
     12     uint32_t* alloc(size_t size) {
     13         SkASSERT(SkAlign4(size) == size);
     14         SkASSERT(this->available() >= size);
     15         void* ptr = this->base() + fAllocated;
     16         fAllocated += size;
     17         SkASSERT(fAllocated <= fSize);
     18         return (uint32_t*)ptr;
     19     }
     20 
     21     uint32_t* peek32(size_t offset) {
     22         SkASSERT(offset <= fAllocated + 4);
     23         void* ptr = this->base() + offset;
     24         return (uint32_t*)ptr;
     25     }
     26 
     27     static Block* Create(size_t size) {
     28         SkASSERT(SkAlign4(size) == size);
     29         Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
     30         block->fNext = NULL;
     31         block->fSize = size;
     32         block->fAllocated = 0;
     33         return block;
     34     }
     35 };
     36 
     37 ///////////////////////////////////////////////////////////////////////////////
     38 
     39 SkWriter32::~SkWriter32() {
     40     this->reset();
     41 }
     42 
     43 void SkWriter32::reset() {
     44     Block* block = fHead;
     45     while (block) {
     46         Block* next = block->fNext;
     47         sk_free(block);
     48         block = next;
     49     }
     50 
     51     fSize = 0;
     52     fHead = fTail = NULL;
     53     fSingleBlock = NULL;
     54 }
     55 
     56 void SkWriter32::reset(void* block, size_t size) {
     57     this->reset();
     58     SkASSERT(0 == ((fSingleBlock - (char*)0) & 3));   // need 4-byte alignment
     59     fSingleBlock = (char*)block;
     60     fSingleBlockSize = (size & ~3);
     61 }
     62 
     63 uint32_t* SkWriter32::reserve(size_t size) {
     64     SkASSERT(SkAlign4(size) == size);
     65 
     66     if (fSingleBlock) {
     67         uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
     68         fSize += size;
     69         SkASSERT(fSize <= fSingleBlockSize);
     70         return ptr;
     71     }
     72 
     73     Block* block = fTail;
     74 
     75     if (NULL == block) {
     76         SkASSERT(NULL == fHead);
     77         fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
     78     } else if (block->available() < size) {
     79         fTail = Block::Create(SkMax32(size, fMinSize));
     80         block->fNext = fTail;
     81         block = fTail;
     82     }
     83 
     84     fSize += size;
     85 
     86     return block->alloc(size);
     87 }
     88 
     89 uint32_t* SkWriter32::peek32(size_t offset) {
     90     SkASSERT(SkAlign4(offset) == offset);
     91     SkASSERT(offset <= fSize);
     92 
     93     if (fSingleBlock) {
     94         return (uint32_t*)(fSingleBlock + offset);
     95     }
     96 
     97     Block* block = fHead;
     98     SkASSERT(NULL != block);
     99 
    100     while (offset >= block->fAllocated) {
    101         offset -= block->fAllocated;
    102         block = block->fNext;
    103         SkASSERT(NULL != block);
    104     }
    105     return block->peek32(offset);
    106 }
    107 
    108 void SkWriter32::flatten(void* dst) const {
    109     if (fSingleBlock) {
    110         memcpy(dst, fSingleBlock, fSize);
    111         return;
    112     }
    113 
    114     const Block* block = fHead;
    115     SkDEBUGCODE(size_t total = 0;)
    116 
    117     while (block) {
    118         size_t allocated = block->fAllocated;
    119         memcpy(dst, block->base(), allocated);
    120         dst = (char*)dst + allocated;
    121         block = block->fNext;
    122 
    123         SkDEBUGCODE(total += allocated;)
    124         SkASSERT(total <= fSize);
    125     }
    126     SkASSERT(total == fSize);
    127 }
    128 
    129 void SkWriter32::writePad(const void* src, size_t size) {
    130     size_t alignedSize = SkAlign4(size);
    131     char* dst = (char*)this->reserve(alignedSize);
    132     memcpy(dst, src, size);
    133     dst += size;
    134     int n = alignedSize - size;
    135     while (--n >= 0) {
    136         *dst++ = 0;
    137     }
    138 }
    139 
    140 #include "SkStream.h"
    141 
    142 size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
    143     if (fSingleBlock) {
    144         SkASSERT(fSingleBlockSize >= fSize);
    145         size_t remaining = fSingleBlockSize - fSize;
    146         if (length > remaining) {
    147             length = remaining;
    148         }
    149         stream->read(fSingleBlock + fSize, length);
    150         fSize += length;
    151         return length;
    152     }
    153 
    154     char scratch[1024];
    155     const size_t MAX = sizeof(scratch);
    156     size_t remaining = length;
    157 
    158     while (remaining != 0) {
    159         size_t n = remaining;
    160         if (n > MAX) {
    161             n = MAX;
    162         }
    163         size_t bytes = stream->read(scratch, n);
    164         this->writePad(scratch, bytes);
    165         remaining -= bytes;
    166         if (bytes != n) {
    167             break;
    168         }
    169     }
    170     return length - remaining;
    171 }
    172 
    173 bool SkWriter32::writeToStream(SkWStream* stream) {
    174     if (fSingleBlock) {
    175         return stream->write(fSingleBlock, fSize);
    176     }
    177 
    178     const Block* block = fHead;
    179     while (block) {
    180         if (!stream->write(block->base(), block->fAllocated)) {
    181             return false;
    182         }
    183         block = block->fNext;
    184     }
    185     return true;
    186 }
    187 
    188 ///////////////////////////////////////////////////////////////////////////////
    189 
    190 #include "SkReader32.h"
    191 
    192 const char* SkReader32::readString(size_t* outLen) {
    193     // we need to read at least 1-4 bytes
    194     SkASSERT(this->isAvailable(4));
    195     const uint8_t* base = (const uint8_t*)this->peek();
    196     const uint8_t* ptr = base;
    197 
    198     size_t len = *ptr++;
    199     if (0xFF == len) {
    200         len = (ptr[0] << 8) | ptr[1];
    201         ptr += 2;
    202         SkASSERT(len < 0xFFFF);
    203     }
    204 
    205     // skip what we've read, and 0..3 pad bytes
    206     // add 1 for the terminating 0 that writeString() included
    207     size_t alignedSize = SkAlign4(len + (ptr - base) + 1);
    208     this->skip(alignedSize);
    209 
    210     if (outLen) {
    211         *outLen = len;
    212     }
    213     return (const char*)ptr;
    214 }
    215 
    216 void SkWriter32::writeString(const char str[], size_t len) {
    217     if ((long)len < 0) {
    218         SkASSERT(str);
    219         len = strlen(str);
    220     }
    221     size_t lenBytes = 1;
    222     if (len >= 0xFF) {
    223         lenBytes = 3;
    224         SkASSERT(len < 0xFFFF);
    225     }
    226     // add 1 since we also write a terminating 0
    227     size_t alignedLen = SkAlign4(lenBytes + len + 1);
    228     uint8_t* ptr = (uint8_t*)this->reserve(alignedLen);
    229     if (1 == lenBytes) {
    230         *ptr++ = SkToU8(len);
    231     } else {
    232         *ptr++ = 0xFF;
    233         *ptr++ = SkToU8(len >> 8);
    234         *ptr++ = len & 0xFF;
    235     }
    236     memcpy(ptr, str, len);
    237     ptr[len] = 0;
    238     // we may have left 0,1,2,3 bytes uninitialized, since we reserved align4
    239     // number of bytes. That's ok, since the reader will know to skip those
    240 }
    241 
    242 size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
    243     if ((long)len < 0) {
    244         SkASSERT(str);
    245         len = strlen(str);
    246     }
    247     size_t lenBytes = 1;
    248     if (len >= 0xFF) {
    249         lenBytes = 3;
    250         SkASSERT(len < 0xFFFF);
    251     }
    252     // add 1 since we also write a terminating 0
    253     return SkAlign4(lenBytes + len + 1);
    254 }
    255 
    256 
    257