1#include "SkWriter32.h" 2 3struct SkWriter32::Block { 4 Block* fNext; 5 size_t fSize; 6 size_t fAllocated; 7 8 size_t available() const { return fSize - fAllocated; } 9 char* base() { return (char*)(this + 1); } 10 const char* base() const { return (const char*)(this + 1); } 11 12 uint32_t* alloc(size_t size) { 13 SkASSERT(SkAlign4(size) == size); 14 SkASSERT(this->available() >= size); 15 void* ptr = this->base() + fAllocated; 16 fAllocated += size; 17 SkASSERT(fAllocated <= fSize); 18 return (uint32_t*)ptr; 19 } 20 21 uint32_t* peek32(size_t offset) { 22 SkASSERT(offset <= fAllocated + 4); 23 void* ptr = this->base() + offset; 24 return (uint32_t*)ptr; 25 } 26 27 static Block* Create(size_t size) { 28 SkASSERT(SkAlign4(size) == size); 29 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); 30 block->fNext = NULL; 31 block->fSize = size; 32 block->fAllocated = 0; 33 return block; 34 } 35}; 36 37/////////////////////////////////////////////////////////////////////////////// 38 39SkWriter32::~SkWriter32() { 40 this->reset(); 41} 42 43void SkWriter32::reset() { 44 Block* block = fHead; 45 while (block) { 46 Block* next = block->fNext; 47 sk_free(block); 48 block = next; 49 } 50 51 fSize = 0; 52 fHead = fTail = NULL; 53 fSingleBlock = NULL; 54} 55 56void SkWriter32::reset(void* block, size_t size) { 57 this->reset(); 58 SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment 59 fSingleBlock = (char*)block; 60 fSingleBlockSize = (size & ~3); 61} 62 63uint32_t* SkWriter32::reserve(size_t size) { 64 SkASSERT(SkAlign4(size) == size); 65 66 if (fSingleBlock) { 67 uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize); 68 fSize += size; 69 SkASSERT(fSize <= fSingleBlockSize); 70 return ptr; 71 } 72 73 Block* block = fTail; 74 75 if (NULL == block) { 76 SkASSERT(NULL == fHead); 77 fHead = fTail = block = Block::Create(SkMax32(size, fMinSize)); 78 } else if (block->available() < size) { 79 fTail = Block::Create(SkMax32(size, fMinSize)); 80 block->fNext = fTail; 81 block = fTail; 82 } 83 84 fSize += size; 85 86 return block->alloc(size); 87} 88 89uint32_t* SkWriter32::peek32(size_t offset) { 90 SkASSERT(SkAlign4(offset) == offset); 91 SkASSERT(offset <= fSize); 92 93 if (fSingleBlock) { 94 return (uint32_t*)(fSingleBlock + offset); 95 } 96 97 Block* block = fHead; 98 SkASSERT(NULL != block); 99 100 while (offset >= block->fAllocated) { 101 offset -= block->fAllocated; 102 block = block->fNext; 103 SkASSERT(NULL != block); 104 } 105 return block->peek32(offset); 106} 107 108void SkWriter32::flatten(void* dst) const { 109 if (fSingleBlock) { 110 memcpy(dst, fSingleBlock, fSize); 111 return; 112 } 113 114 const Block* block = fHead; 115 SkDEBUGCODE(size_t total = 0;) 116 117 while (block) { 118 size_t allocated = block->fAllocated; 119 memcpy(dst, block->base(), allocated); 120 dst = (char*)dst + allocated; 121 block = block->fNext; 122 123 SkDEBUGCODE(total += allocated;) 124 SkASSERT(total <= fSize); 125 } 126 SkASSERT(total == fSize); 127} 128 129void SkWriter32::writePad(const void* src, size_t size) { 130 size_t alignedSize = SkAlign4(size); 131 char* dst = (char*)this->reserve(alignedSize); 132 memcpy(dst, src, size); 133 dst += size; 134 int n = alignedSize - size; 135 while (--n >= 0) { 136 *dst++ = 0; 137 } 138} 139 140#include "SkStream.h" 141 142size_t SkWriter32::readFromStream(SkStream* stream, size_t length) { 143 if (fSingleBlock) { 144 SkASSERT(fSingleBlockSize >= fSize); 145 size_t remaining = fSingleBlockSize - fSize; 146 if (length > remaining) { 147 length = remaining; 148 } 149 stream->read(fSingleBlock + fSize, length); 150 fSize += length; 151 return length; 152 } 153 154 char scratch[1024]; 155 const size_t MAX = sizeof(scratch); 156 size_t remaining = length; 157 158 while (remaining != 0) { 159 size_t n = remaining; 160 if (n > MAX) { 161 n = MAX; 162 } 163 size_t bytes = stream->read(scratch, n); 164 this->writePad(scratch, bytes); 165 remaining -= bytes; 166 if (bytes != n) { 167 break; 168 } 169 } 170 return length - remaining; 171} 172 173bool SkWriter32::writeToStream(SkWStream* stream) { 174 if (fSingleBlock) { 175 return stream->write(fSingleBlock, fSize); 176 } 177 178 const Block* block = fHead; 179 while (block) { 180 if (!stream->write(block->base(), block->fAllocated)) { 181 return false; 182 } 183 block = block->fNext; 184 } 185 return true; 186} 187 188/////////////////////////////////////////////////////////////////////////////// 189 190#include "SkReader32.h" 191 192const char* SkReader32::readString(size_t* outLen) { 193 // we need to read at least 1-4 bytes 194 SkASSERT(this->isAvailable(4)); 195 const uint8_t* base = (const uint8_t*)this->peek(); 196 const uint8_t* ptr = base; 197 198 size_t len = *ptr++; 199 if (0xFF == len) { 200 len = (ptr[0] << 8) | ptr[1]; 201 ptr += 2; 202 SkASSERT(len < 0xFFFF); 203 } 204 205 // skip what we've read, and 0..3 pad bytes 206 // add 1 for the terminating 0 that writeString() included 207 size_t alignedSize = SkAlign4(len + (ptr - base) + 1); 208 this->skip(alignedSize); 209 210 if (outLen) { 211 *outLen = len; 212 } 213 return (const char*)ptr; 214} 215 216void SkWriter32::writeString(const char str[], size_t len) { 217 if ((long)len < 0) { 218 SkASSERT(str); 219 len = strlen(str); 220 } 221 size_t lenBytes = 1; 222 if (len >= 0xFF) { 223 lenBytes = 3; 224 SkASSERT(len < 0xFFFF); 225 } 226 // add 1 since we also write a terminating 0 227 size_t alignedLen = SkAlign4(lenBytes + len + 1); 228 uint8_t* ptr = (uint8_t*)this->reserve(alignedLen); 229 if (1 == lenBytes) { 230 *ptr++ = SkToU8(len); 231 } else { 232 *ptr++ = 0xFF; 233 *ptr++ = SkToU8(len >> 8); 234 *ptr++ = len & 0xFF; 235 } 236 memcpy(ptr, str, len); 237 ptr[len] = 0; 238 // we may have left 0,1,2,3 bytes uninitialized, since we reserved align4 239 // number of bytes. That's ok, since the reader will know to skip those 240} 241 242size_t SkWriter32::WriteStringSize(const char* str, size_t len) { 243 if ((long)len < 0) { 244 SkASSERT(str); 245 len = strlen(str); 246 } 247 size_t lenBytes = 1; 248 if (len >= 0xFF) { 249 lenBytes = 3; 250 SkASSERT(len < 0xFFFF); 251 } 252 // add 1 since we also write a terminating 0 253 return SkAlign4(lenBytes + len + 1); 254} 255 256 257