Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkWriter32.h"
      9 
     10 SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
     11     fMinSize = minSize;
     12     fSize = 0;
     13     fWrittenBeforeLastBlock = 0;
     14     fHead = fTail = NULL;
     15 
     16     if (storageSize) {
     17         this->reset(storage, storageSize);
     18     }
     19 }
     20 
     21 SkWriter32::~SkWriter32() {
     22     this->reset();
     23 }
     24 
     25 void SkWriter32::reset() {
     26     Block* block = fHead;
     27 
     28     if (this->isHeadExternallyAllocated()) {
     29         SkASSERT(block);
     30         // don't 'free' the first block, since it is owned by the caller
     31         block = block->fNext;
     32     }
     33     while (block) {
     34         Block* next = block->fNext;
     35         sk_free(block);
     36         block = next;
     37     }
     38 
     39     fSize = 0;
     40     fWrittenBeforeLastBlock = 0;
     41     fHead = fTail = NULL;
     42 }
     43 
     44 void SkWriter32::reset(void* storage, size_t storageSize) {
     45     this->reset();
     46 
     47     storageSize &= ~3;  // trunc down to multiple of 4
     48     if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) {
     49         fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize);
     50     }
     51 }
     52 
     53 SkWriter32::Block* SkWriter32::doReserve(size_t size) {
     54     SkASSERT(SkAlign4(size) == size);
     55 
     56     Block* block = fTail;
     57     SkASSERT(NULL == block || block->available() < size);
     58 
     59     if (NULL == block) {
     60         SkASSERT(NULL == fHead);
     61         fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
     62         SkASSERT(0 == fWrittenBeforeLastBlock);
     63     } else {
     64         SkASSERT(fSize > 0);
     65         fWrittenBeforeLastBlock = fSize;
     66 
     67         fTail = Block::Create(SkMax32(size, fMinSize));
     68         block->fNext = fTail;
     69         block = fTail;
     70     }
     71     return block;
     72 }
     73 
     74 uint32_t* SkWriter32::peek32(size_t offset) {
     75     SkDEBUGCODE(this->validate();)
     76 
     77     SkASSERT(SkAlign4(offset) == offset);
     78     SkASSERT(offset <= fSize);
     79 
     80     // try the fast case, where offset is within fTail
     81     if (offset >= fWrittenBeforeLastBlock) {
     82         return fTail->peek32(offset - fWrittenBeforeLastBlock);
     83     }
     84 
     85     Block* block = fHead;
     86     SkASSERT(NULL != block);
     87 
     88     while (offset >= block->fAllocatedSoFar) {
     89         offset -= block->fAllocatedSoFar;
     90         block = block->fNext;
     91         SkASSERT(NULL != block);
     92     }
     93     return block->peek32(offset);
     94 }
     95 
     96 void SkWriter32::rewindToOffset(size_t offset) {
     97     if (offset >= fSize) {
     98         return;
     99     }
    100     if (0 == offset) {
    101         this->reset();
    102         return;
    103     }
    104 
    105     SkDEBUGCODE(this->validate();)
    106 
    107     SkASSERT(SkAlign4(offset) == offset);
    108     SkASSERT(offset <= fSize);
    109     fSize = offset;
    110 
    111     // Try the fast case, where offset is within fTail
    112     if (offset >= fWrittenBeforeLastBlock) {
    113         fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock;
    114     } else {
    115         // Similar to peek32, except that we free up any following blocks.
    116         // We have to re-compute fWrittenBeforeLastBlock as well.
    117 
    118         size_t globalOffset = offset;
    119         Block* block = fHead;
    120         SkASSERT(NULL != block);
    121         while (offset >= block->fAllocatedSoFar) {
    122             offset -= block->fAllocatedSoFar;
    123             block = block->fNext;
    124             SkASSERT(NULL != block);
    125         }
    126 
    127         // this has to be recomputed, since we may free up fTail
    128         fWrittenBeforeLastBlock = globalOffset - offset;
    129 
    130         // update the size on the "last" block
    131         block->fAllocatedSoFar = offset;
    132         // end our list
    133         fTail = block;
    134         Block* next = block->fNext;
    135         block->fNext = NULL;
    136         // free up any trailing blocks
    137         block = next;
    138         while (block) {
    139             Block* next = block->fNext;
    140             sk_free(block);
    141             block = next;
    142         }
    143     }
    144     SkDEBUGCODE(this->validate();)
    145 }
    146 
    147 void SkWriter32::flatten(void* dst) const {
    148     const Block* block = fHead;
    149     SkDEBUGCODE(size_t total = 0;)
    150 
    151     while (block) {
    152         size_t allocated = block->fAllocatedSoFar;
    153         memcpy(dst, block->base(), allocated);
    154         dst = (char*)dst + allocated;
    155         block = block->fNext;
    156 
    157         SkDEBUGCODE(total += allocated;)
    158         SkASSERT(total <= fSize);
    159     }
    160     SkASSERT(total == fSize);
    161 }
    162 
    163 uint32_t* SkWriter32::reservePad(size_t size) {
    164     if (size > 0) {
    165         size_t alignedSize = SkAlign4(size);
    166         char* dst = (char*)this->reserve(alignedSize);
    167         // Pad the last four bytes with zeroes in one step.
    168         uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4));
    169         *padding = 0;
    170         return (uint32_t*) dst;
    171     }
    172     return this->reserve(0);
    173 }
    174 
    175 void SkWriter32::writePad(const void* src, size_t size) {
    176     if (size > 0) {
    177         char* dst = (char*)this->reservePad(size);
    178         // Copy the actual data.
    179         memcpy(dst, src, size);
    180     }
    181 }
    182 
    183 #include "SkStream.h"
    184 
    185 size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
    186     char scratch[1024];
    187     const size_t MAX = sizeof(scratch);
    188     size_t remaining = length;
    189 
    190     while (remaining != 0) {
    191         size_t n = remaining;
    192         if (n > MAX) {
    193             n = MAX;
    194         }
    195         size_t bytes = stream->read(scratch, n);
    196         this->writePad(scratch, bytes);
    197         remaining -= bytes;
    198         if (bytes != n) {
    199             break;
    200         }
    201     }
    202     return length - remaining;
    203 }
    204 
    205 bool SkWriter32::writeToStream(SkWStream* stream) {
    206     const Block* block = fHead;
    207     while (block) {
    208         if (!stream->write(block->base(), block->fAllocatedSoFar)) {
    209             return false;
    210         }
    211         block = block->fNext;
    212     }
    213     return true;
    214 }
    215 
    216 #ifdef SK_DEBUG
    217 void SkWriter32::validate() const {
    218     SkASSERT(SkIsAlign4(fSize));
    219 
    220     size_t accum = 0;
    221     const Block* block = fHead;
    222     while (block) {
    223         SkASSERT(SkIsAlign4(block->fSizeOfBlock));
    224         SkASSERT(SkIsAlign4(block->fAllocatedSoFar));
    225         SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock);
    226         if (NULL == block->fNext) {
    227             SkASSERT(fTail == block);
    228             SkASSERT(fWrittenBeforeLastBlock == accum);
    229         }
    230         accum += block->fAllocatedSoFar;
    231         SkASSERT(accum <= fSize);
    232         block = block->fNext;
    233     }
    234     SkASSERT(accum == fSize);
    235 }
    236 #endif
    237 
    238 ///////////////////////////////////////////////////////////////////////////////
    239 
    240 #include "SkReader32.h"
    241 #include "SkString.h"
    242 
    243 /*
    244  *  Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
    245  */
    246 
    247 const char* SkReader32::readString(size_t* outLen) {
    248     size_t len = this->readInt();
    249     const void* ptr = this->peek();
    250 
    251     // skip over teh string + '\0' and then pad to a multiple of 4
    252     size_t alignedSize = SkAlign4(len + 1);
    253     this->skip(alignedSize);
    254 
    255     if (outLen) {
    256         *outLen = len;
    257     }
    258     return (const char*)ptr;
    259 }
    260 
    261 size_t SkReader32::readIntoString(SkString* copy) {
    262     size_t len;
    263     const char* ptr = this->readString(&len);
    264     if (copy) {
    265         copy->set(ptr, len);
    266     }
    267     return len;
    268 }
    269 
    270 void SkWriter32::writeString(const char str[], size_t len) {
    271     if ((long)len < 0) {
    272         SkASSERT(str);
    273         len = strlen(str);
    274     }
    275     this->write32(len);
    276     // add 1 since we also write a terminating 0
    277     size_t alignedLen = SkAlign4(len + 1);
    278     char* ptr = (char*)this->reserve(alignedLen);
    279     {
    280         // Write the terminating 0 and fill in the rest with zeroes
    281         uint32_t* padding = (uint32_t*)(ptr + (alignedLen - 4));
    282         *padding = 0;
    283     }
    284     // Copy the string itself.
    285     memcpy(ptr, str, len);
    286 }
    287 
    288 size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
    289     if ((long)len < 0) {
    290         SkASSERT(str);
    291         len = strlen(str);
    292     }
    293     const size_t lenBytes = 4;    // we use 4 bytes to record the length
    294     // add 1 since we also write a terminating 0
    295     return SkAlign4(lenBytes + len + 1);
    296 }
    297