blob: dfa18a0c657b5f281e21d9edf6d0680909a5407d [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;
12 size_t fSize;
13 size_t fAllocated;
14
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.comacd471f2011-05-03 21:26:46 +000034 static Block* Create(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000035 SkASSERT(SkAlign4(size) == size);
36 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
37 block->fNext = NULL;
38 block->fSize = size;
39 block->fAllocated = 0;
40 return block;
41 }
42};
43
reed@android.com8a1c16f2008-12-17 15:59:43 +000044///////////////////////////////////////////////////////////////////////////////
45
reed@google.comacd471f2011-05-03 21:26:46 +000046SkWriter32::~SkWriter32() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 this->reset();
48}
49
reed@google.comacd471f2011-05-03 21:26:46 +000050void SkWriter32::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 Block* block = fHead;
reed@google.comacd471f2011-05-03 21:26:46 +000052 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 Block* next = block->fNext;
54 sk_free(block);
55 block = next;
56 }
reed@google.comacd471f2011-05-03 21:26:46 +000057
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 fSize = 0;
reed@google.comacd471f2011-05-03 21:26:46 +000059 fHead = fTail = NULL;
60 fSingleBlock = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
reed@google.comacd471f2011-05-03 21:26:46 +000063void SkWriter32::reset(void* block, size_t size) {
64 this->reset();
reed@google.comc9254512011-05-04 14:43:40 +000065 SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment
reed@google.comacd471f2011-05-03 21:26:46 +000066 fSingleBlock = (char*)block;
67 fSingleBlockSize = (size & ~3);
68}
69
70uint32_t* SkWriter32::reserve(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 SkASSERT(SkAlign4(size) == size);
reed@google.comacd471f2011-05-03 21:26:46 +000072
73 if (fSingleBlock) {
74 uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
75 fSize += size;
76 SkASSERT(fSize <= fSingleBlockSize);
77 return ptr;
78 }
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 Block* block = fTail;
81
reed@google.comacd471f2011-05-03 21:26:46 +000082 if (NULL == block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 SkASSERT(NULL == fHead);
84 fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
reed@google.comacd471f2011-05-03 21:26:46 +000085 } else if (block->available() < size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 fTail = Block::Create(SkMax32(size, fMinSize));
87 block->fNext = fTail;
88 block = fTail;
89 }
90
91 fSize += size;
92
93 return block->alloc(size);
94}
95
reed@google.comacd471f2011-05-03 21:26:46 +000096uint32_t* SkWriter32::peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 SkASSERT(SkAlign4(offset) == offset);
98 SkASSERT(offset <= fSize);
99
reed@google.comacd471f2011-05-03 21:26:46 +0000100 if (fSingleBlock) {
101 return (uint32_t*)(fSingleBlock + offset);
102 }
103
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 Block* block = fHead;
105 SkASSERT(NULL != block);
106
reed@google.comacd471f2011-05-03 21:26:46 +0000107 while (offset >= block->fAllocated) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 offset -= block->fAllocated;
109 block = block->fNext;
110 SkASSERT(NULL != block);
111 }
112 return block->peek32(offset);
113}
114
reed@google.comacd471f2011-05-03 21:26:46 +0000115void SkWriter32::flatten(void* dst) const {
116 if (fSingleBlock) {
117 memcpy(dst, fSingleBlock, fSize);
118 return;
119 }
120
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 const Block* block = fHead;
122 SkDEBUGCODE(size_t total = 0;)
123
reed@google.comacd471f2011-05-03 21:26:46 +0000124 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 size_t allocated = block->fAllocated;
126 memcpy(dst, block->base(), allocated);
127 dst = (char*)dst + allocated;
128 block = block->fNext;
129
130 SkDEBUGCODE(total += allocated;)
131 SkASSERT(total <= fSize);
132 }
133 SkASSERT(total == fSize);
134}
135
136void SkWriter32::writePad(const void* src, size_t size) {
137 size_t alignedSize = SkAlign4(size);
138 char* dst = (char*)this->reserve(alignedSize);
139 memcpy(dst, src, size);
140 dst += size;
141 int n = alignedSize - size;
142 while (--n >= 0) {
143 *dst++ = 0;
144 }
145}
146
147#include "SkStream.h"
148
149size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
reed@google.comacd471f2011-05-03 21:26:46 +0000150 if (fSingleBlock) {
151 SkASSERT(fSingleBlockSize >= fSize);
152 size_t remaining = fSingleBlockSize - fSize;
153 if (length > remaining) {
154 length = remaining;
155 }
156 stream->read(fSingleBlock + fSize, length);
157 fSize += length;
158 return length;
159 }
160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 char scratch[1024];
162 const size_t MAX = sizeof(scratch);
163 size_t remaining = length;
164
165 while (remaining != 0) {
166 size_t n = remaining;
167 if (n > MAX) {
168 n = MAX;
169 }
170 size_t bytes = stream->read(scratch, n);
171 this->writePad(scratch, bytes);
172 remaining -= bytes;
173 if (bytes != n) {
174 break;
175 }
176 }
177 return length - remaining;
178}
179
180bool SkWriter32::writeToStream(SkWStream* stream) {
reed@google.comacd471f2011-05-03 21:26:46 +0000181 if (fSingleBlock) {
182 return stream->write(fSingleBlock, fSize);
183 }
184
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 const Block* block = fHead;
186 while (block) {
187 if (!stream->write(block->base(), block->fAllocated)) {
188 return false;
189 }
190 block = block->fNext;
191 }
192 return true;
193}
194
reed@google.comdde09562011-05-23 12:21:05 +0000195///////////////////////////////////////////////////////////////////////////////
196
197#include "SkReader32.h"
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000198#include "SkString.h"
199
200/*
201 * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
202 */
reed@google.comdde09562011-05-23 12:21:05 +0000203
204const char* SkReader32::readString(size_t* outLen) {
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000205 size_t len = this->readInt();
206 const void* ptr = this->peek();
reed@google.comdde09562011-05-23 12:21:05 +0000207
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000208 // skip over teh string + '\0' and then pad to a multiple of 4
209 size_t alignedSize = SkAlign4(len + 1);
reed@google.comdde09562011-05-23 12:21:05 +0000210 this->skip(alignedSize);
211
212 if (outLen) {
213 *outLen = len;
214 }
215 return (const char*)ptr;
216}
217
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000218size_t SkReader32::readIntoString(SkString* copy) {
219 size_t len;
220 const char* ptr = this->readString(&len);
221 if (copy) {
222 copy->set(ptr, len);
223 }
224 return len;
225}
226
reed@google.comdde09562011-05-23 12:21:05 +0000227void SkWriter32::writeString(const char str[], size_t len) {
228 if ((long)len < 0) {
229 SkASSERT(str);
230 len = strlen(str);
231 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000232 this->write32(len);
reed@google.comdde09562011-05-23 12:21:05 +0000233 // add 1 since we also write a terminating 0
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000234 size_t alignedLen = SkAlign4(len + 1);
235 char* ptr = (char*)this->reserve(alignedLen);
reed@google.comdde09562011-05-23 12:21:05 +0000236 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 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000247 const size_t lenBytes = 4; // we use 4 bytes to record the length
reed@google.comdde09562011-05-23 12:21:05 +0000248 // add 1 since we also write a terminating 0
249 return SkAlign4(lenBytes + len + 1);
250}
251
252