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