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