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