blob: 23f51b93fedd7f3cfaa700c7ebfeb61cef41161a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkWriter32.h"
9
10struct SkWriter32::Block {
11 Block* fNext;
reed@google.come49aca92012-04-24 21:12:39 +000012 size_t fSize; // total space allocated (after this)
13 size_t fAllocated; // space used so far
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
15 size_t available() const { return fSize - fAllocated; }
16 char* base() { return (char*)(this + 1); }
17 const char* base() const { return (const char*)(this + 1); }
18
reed@google.comacd471f2011-05-03 21:26:46 +000019 uint32_t* alloc(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 SkASSERT(SkAlign4(size) == size);
21 SkASSERT(this->available() >= size);
22 void* ptr = this->base() + fAllocated;
23 fAllocated += size;
24 SkASSERT(fAllocated <= fSize);
25 return (uint32_t*)ptr;
26 }
27
reed@google.comacd471f2011-05-03 21:26:46 +000028 uint32_t* peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 SkASSERT(offset <= fAllocated + 4);
30 void* ptr = this->base() + offset;
31 return (uint32_t*)ptr;
32 }
33
reed@google.come49aca92012-04-24 21:12:39 +000034 void rewind() {
35 fNext = NULL;
36 fAllocated = 0;
37 // keep fSize as is
38 }
39
reed@google.comacd471f2011-05-03 21:26:46 +000040 static Block* Create(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 SkASSERT(SkAlign4(size) == size);
42 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
43 block->fNext = NULL;
44 block->fSize = size;
45 block->fAllocated = 0;
46 return block;
47 }
reed@google.come49aca92012-04-24 21:12:39 +000048
49 static Block* CreateFromStorage(void* storage, size_t size) {
50 SkASSERT(SkIsAlign4((intptr_t)storage));
51 Block* block = (Block*)storage;
52 block->fNext = NULL;
53 block->fSize = size - sizeof(Block);
54 block->fAllocated = 0;
55 return block;
56 }
57
reed@android.com8a1c16f2008-12-17 15:59:43 +000058};
59
reed@google.come49aca92012-04-24 21:12:39 +000060#define MIN_BLOCKSIZE (sizeof(SkWriter32::Block) + sizeof(intptr_t))
61
reed@android.com8a1c16f2008-12-17 15:59:43 +000062///////////////////////////////////////////////////////////////////////////////
63
reed@google.come49aca92012-04-24 21:12:39 +000064SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
65 fMinSize = minSize;
66 fSize = 0;
67 fSingleBlock = NULL;
68 fSingleBlockSize = 0;
69
70 storageSize &= ~3; // trunc down to multiple of 4
71 if (storageSize >= MIN_BLOCKSIZE) {
72 fHead = fTail = Block::CreateFromStorage(storage, storageSize);
73 fHeadIsExternalStorage = true;
74 } else {
75 fHead = fTail = NULL;
76 fHeadIsExternalStorage = false;
77 }
78}
79
reed@google.comacd471f2011-05-03 21:26:46 +000080SkWriter32::~SkWriter32() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 this->reset();
82}
83
reed@google.comacd471f2011-05-03 21:26:46 +000084void SkWriter32::reset() {
reed@google.come49aca92012-04-24 21:12:39 +000085 Block* block = fHead;
86
87 if (fHeadIsExternalStorage) {
88 SkASSERT(block);
89 // don't 'free' the first block, since it is owned by the caller
90 block = block->fNext;
91 }
reed@google.comacd471f2011-05-03 21:26:46 +000092 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 Block* next = block->fNext;
94 sk_free(block);
95 block = next;
96 }
reed@google.comacd471f2011-05-03 21:26:46 +000097
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 fSize = 0;
reed@google.comacd471f2011-05-03 21:26:46 +000099 fSingleBlock = NULL;
reed@google.come49aca92012-04-24 21:12:39 +0000100 if (fHeadIsExternalStorage) {
reed@google.com08e79112012-05-09 13:58:38 +0000101 SkASSERT(fHead);
reed@google.come49aca92012-04-24 21:12:39 +0000102 fHead->rewind();
103 fTail = fHead;
104 } else {
105 fHead = fTail = NULL;
106 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107}
108
reed@google.comacd471f2011-05-03 21:26:46 +0000109void SkWriter32::reset(void* block, size_t size) {
110 this->reset();
reed@google.comc9254512011-05-04 14:43:40 +0000111 SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment
reed@google.comacd471f2011-05-03 21:26:46 +0000112 fSingleBlock = (char*)block;
113 fSingleBlockSize = (size & ~3);
114}
115
116uint32_t* SkWriter32::reserve(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 SkASSERT(SkAlign4(size) == size);
reed@google.comacd471f2011-05-03 21:26:46 +0000118
119 if (fSingleBlock) {
120 uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
121 fSize += size;
122 SkASSERT(fSize <= fSingleBlockSize);
123 return ptr;
124 }
125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 Block* block = fTail;
127
reed@google.comacd471f2011-05-03 21:26:46 +0000128 if (NULL == block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 SkASSERT(NULL == fHead);
130 fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
reed@google.comacd471f2011-05-03 21:26:46 +0000131 } else if (block->available() < size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 fTail = Block::Create(SkMax32(size, fMinSize));
133 block->fNext = fTail;
134 block = fTail;
135 }
136
137 fSize += size;
138
139 return block->alloc(size);
140}
141
reed@google.comacd471f2011-05-03 21:26:46 +0000142uint32_t* SkWriter32::peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 SkASSERT(SkAlign4(offset) == offset);
144 SkASSERT(offset <= fSize);
145
reed@google.comacd471f2011-05-03 21:26:46 +0000146 if (fSingleBlock) {
147 return (uint32_t*)(fSingleBlock + offset);
148 }
149
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 Block* block = fHead;
151 SkASSERT(NULL != block);
152
reed@google.comacd471f2011-05-03 21:26:46 +0000153 while (offset >= block->fAllocated) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 offset -= block->fAllocated;
155 block = block->fNext;
156 SkASSERT(NULL != block);
157 }
158 return block->peek32(offset);
159}
160
reed@google.comacd471f2011-05-03 21:26:46 +0000161void SkWriter32::flatten(void* dst) const {
162 if (fSingleBlock) {
163 memcpy(dst, fSingleBlock, fSize);
164 return;
165 }
166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 const Block* block = fHead;
168 SkDEBUGCODE(size_t total = 0;)
169
reed@google.comacd471f2011-05-03 21:26:46 +0000170 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 size_t allocated = block->fAllocated;
172 memcpy(dst, block->base(), allocated);
173 dst = (char*)dst + allocated;
174 block = block->fNext;
175
176 SkDEBUGCODE(total += allocated;)
177 SkASSERT(total <= fSize);
178 }
179 SkASSERT(total == fSize);
180}
181
182void SkWriter32::writePad(const void* src, size_t size) {
183 size_t alignedSize = SkAlign4(size);
184 char* dst = (char*)this->reserve(alignedSize);
185 memcpy(dst, src, size);
186 dst += size;
187 int n = alignedSize - size;
188 while (--n >= 0) {
189 *dst++ = 0;
190 }
191}
192
193#include "SkStream.h"
194
195size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
reed@google.comacd471f2011-05-03 21:26:46 +0000196 if (fSingleBlock) {
197 SkASSERT(fSingleBlockSize >= fSize);
198 size_t remaining = fSingleBlockSize - fSize;
199 if (length > remaining) {
200 length = remaining;
201 }
202 stream->read(fSingleBlock + fSize, length);
203 fSize += length;
204 return length;
205 }
206
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 char scratch[1024];
208 const size_t MAX = sizeof(scratch);
209 size_t remaining = length;
210
211 while (remaining != 0) {
212 size_t n = remaining;
213 if (n > MAX) {
214 n = MAX;
215 }
216 size_t bytes = stream->read(scratch, n);
217 this->writePad(scratch, bytes);
218 remaining -= bytes;
219 if (bytes != n) {
220 break;
221 }
222 }
223 return length - remaining;
224}
225
226bool SkWriter32::writeToStream(SkWStream* stream) {
reed@google.comacd471f2011-05-03 21:26:46 +0000227 if (fSingleBlock) {
228 return stream->write(fSingleBlock, fSize);
229 }
230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 const Block* block = fHead;
232 while (block) {
233 if (!stream->write(block->base(), block->fAllocated)) {
234 return false;
235 }
236 block = block->fNext;
237 }
238 return true;
239}
240
reed@google.comdde09562011-05-23 12:21:05 +0000241///////////////////////////////////////////////////////////////////////////////
242
243#include "SkReader32.h"
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000244#include "SkString.h"
245
246/*
247 * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
248 */
reed@google.comdde09562011-05-23 12:21:05 +0000249
250const char* SkReader32::readString(size_t* outLen) {
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000251 size_t len = this->readInt();
252 const void* ptr = this->peek();
reed@google.comdde09562011-05-23 12:21:05 +0000253
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000254 // skip over teh string + '\0' and then pad to a multiple of 4
255 size_t alignedSize = SkAlign4(len + 1);
reed@google.comdde09562011-05-23 12:21:05 +0000256 this->skip(alignedSize);
257
258 if (outLen) {
259 *outLen = len;
260 }
261 return (const char*)ptr;
262}
263
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000264size_t SkReader32::readIntoString(SkString* copy) {
265 size_t len;
266 const char* ptr = this->readString(&len);
267 if (copy) {
268 copy->set(ptr, len);
269 }
270 return len;
271}
272
reed@google.comdde09562011-05-23 12:21:05 +0000273void SkWriter32::writeString(const char str[], size_t len) {
274 if ((long)len < 0) {
275 SkASSERT(str);
276 len = strlen(str);
277 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000278 this->write32(len);
reed@google.comdde09562011-05-23 12:21:05 +0000279 // add 1 since we also write a terminating 0
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000280 size_t alignedLen = SkAlign4(len + 1);
281 char* ptr = (char*)this->reserve(alignedLen);
reed@google.comdde09562011-05-23 12:21:05 +0000282 memcpy(ptr, str, len);
scroggo@google.come9617eb2012-07-23 13:44:10 +0000283 // Add the terminating 0, and pad the rest with 0s
284 ptr += len;
285 int n = alignedLen - len;
286 while (--n >= 0) {
287 *ptr++ = 0;
288 }
reed@google.comdde09562011-05-23 12:21:05 +0000289}
290
291size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
292 if ((long)len < 0) {
293 SkASSERT(str);
294 len = strlen(str);
295 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000296 const size_t lenBytes = 4; // we use 4 bytes to record the length
reed@google.comdde09562011-05-23 12:21:05 +0000297 // add 1 since we also write a terminating 0
298 return SkAlign4(lenBytes + len + 1);
299}
300
301