blob: 9a60b8e66fa580738d486e1b1d93556746b05f26 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#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
reed@google.comacd471f2011-05-03 21:26:46 +000012 uint32_t* alloc(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000013 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
reed@google.comacd471f2011-05-03 21:26:46 +000021 uint32_t* peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 SkASSERT(offset <= fAllocated + 4);
23 void* ptr = this->base() + offset;
24 return (uint32_t*)ptr;
25 }
26
reed@google.comacd471f2011-05-03 21:26:46 +000027 static Block* Create(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000037///////////////////////////////////////////////////////////////////////////////
38
reed@google.comacd471f2011-05-03 21:26:46 +000039SkWriter32::~SkWriter32() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 this->reset();
41}
42
reed@google.comacd471f2011-05-03 21:26:46 +000043void SkWriter32::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 Block* block = fHead;
reed@google.comacd471f2011-05-03 21:26:46 +000045 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 Block* next = block->fNext;
47 sk_free(block);
48 block = next;
49 }
reed@google.comacd471f2011-05-03 21:26:46 +000050
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 fSize = 0;
reed@google.comacd471f2011-05-03 21:26:46 +000052 fHead = fTail = NULL;
53 fSingleBlock = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
reed@google.comacd471f2011-05-03 21:26:46 +000056void SkWriter32::reset(void* block, size_t size) {
57 this->reset();
reed@google.comc9254512011-05-04 14:43:40 +000058 SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment
reed@google.comacd471f2011-05-03 21:26:46 +000059 fSingleBlock = (char*)block;
60 fSingleBlockSize = (size & ~3);
61}
62
63uint32_t* SkWriter32::reserve(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 SkASSERT(SkAlign4(size) == size);
reed@google.comacd471f2011-05-03 21:26:46 +000065
66 if (fSingleBlock) {
67 uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
68 fSize += size;
69 SkASSERT(fSize <= fSingleBlockSize);
70 return ptr;
71 }
72
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 Block* block = fTail;
74
reed@google.comacd471f2011-05-03 21:26:46 +000075 if (NULL == block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 SkASSERT(NULL == fHead);
77 fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
reed@google.comacd471f2011-05-03 21:26:46 +000078 } else if (block->available() < size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 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
reed@google.comacd471f2011-05-03 21:26:46 +000089uint32_t* SkWriter32::peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 SkASSERT(SkAlign4(offset) == offset);
91 SkASSERT(offset <= fSize);
92
reed@google.comacd471f2011-05-03 21:26:46 +000093 if (fSingleBlock) {
94 return (uint32_t*)(fSingleBlock + offset);
95 }
96
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 Block* block = fHead;
98 SkASSERT(NULL != block);
99
reed@google.comacd471f2011-05-03 21:26:46 +0000100 while (offset >= block->fAllocated) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 offset -= block->fAllocated;
102 block = block->fNext;
103 SkASSERT(NULL != block);
104 }
105 return block->peek32(offset);
106}
107
reed@google.comacd471f2011-05-03 21:26:46 +0000108void SkWriter32::flatten(void* dst) const {
109 if (fSingleBlock) {
110 memcpy(dst, fSingleBlock, fSize);
111 return;
112 }
113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 const Block* block = fHead;
115 SkDEBUGCODE(size_t total = 0;)
116
reed@google.comacd471f2011-05-03 21:26:46 +0000117 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 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) {
reed@google.comacd471f2011-05-03 21:26:46 +0000143 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 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) {
reed@google.comacd471f2011-05-03 21:26:46 +0000174 if (fSingleBlock) {
175 return stream->write(fSingleBlock, fSize);
176 }
177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 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
reed@google.comdde09562011-05-23 12:21:05 +0000188///////////////////////////////////////////////////////////////////////////////
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