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 10SkWriter32::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 21SkWriter32::~SkWriter32() { 22 this->reset(); 23} 24 25void 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 44void 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 53SkWriter32::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 74uint32_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 96void 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 147void 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 163uint32_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 175void 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 185size_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 205bool 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 217void 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 247const char* SkReader32::readString(size_t* outLen) { 248 size_t len = this->readInt(); 249 if (0xFFFF == len) { 250 if (outLen) { 251 *outLen = 0; 252 } 253 return NULL; 254 } 255 const void* ptr = this->peek(); 256 257 // skip over teh string + '\0' and then pad to a multiple of 4 258 size_t alignedSize = SkAlign4(len + 1); 259 this->skip(alignedSize); 260 261 if (outLen) { 262 *outLen = len; 263 } 264 return (const char*)ptr; 265} 266 267size_t SkReader32::readIntoString(SkString* copy) { 268 size_t len; 269 const char* ptr = this->readString(&len); 270 if (copy) { 271 copy->set(ptr, len); 272 } 273 return len; 274} 275 276void SkWriter32::writeString(const char str[], size_t len) { 277 if (NULL == str) { 278 // We're already requiring len < 0xFFFF, so we can use that to mark NULL. 279 this->write32(0xFFFF); 280 return; 281 } 282 if ((long)len < 0) { 283 len = strlen(str); 284 } 285 this->write32(len); 286 // add 1 since we also write a terminating 0 287 size_t alignedLen = SkAlign4(len + 1); 288 char* ptr = (char*)this->reserve(alignedLen); 289 { 290 // Write the terminating 0 and fill in the rest with zeroes 291 uint32_t* padding = (uint32_t*)(ptr + (alignedLen - 4)); 292 *padding = 0; 293 } 294 // Copy the string itself. 295 memcpy(ptr, str, len); 296} 297 298size_t SkWriter32::WriteStringSize(const char* str, size_t len) { 299 if ((long)len < 0) { 300 SkASSERT(str); 301 len = strlen(str); 302 } 303 const size_t lenBytes = 4; // we use 4 bytes to record the length 304 // add 1 since we also write a terminating 0 305 return SkAlign4(lenBytes + len + 1); 306} 307