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