1 #include "SkWriter32.h"
2
3 struct SkWriter32::Block {
4 Block* fNext;
5 size_t fSize;
6 size_t fAllocated;
7
availableSkWriter32::Block8 size_t available() const { return fSize - fAllocated; }
baseSkWriter32::Block9 char* base() { return (char*)(this + 1); }
baseSkWriter32::Block10 const char* base() const { return (const char*)(this + 1); }
11
allocSkWriter32::Block12 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
peek32SkWriter32::Block21 uint32_t* peek32(size_t offset) {
22 SkASSERT(offset <= fAllocated + 4);
23 void* ptr = this->base() + offset;
24 return (uint32_t*)ptr;
25 }
26
CreateSkWriter32::Block27 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
~SkWriter32()39 SkWriter32::~SkWriter32() {
40 this->reset();
41 }
42
reset()43 void 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
reset(void * block,size_t size)56 void 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
reserve(size_t size)63 uint32_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
peek32(size_t offset)89 uint32_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
flatten(void * dst) const108 void 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
writePad(const void * src,size_t size)129 void 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
readFromStream(SkStream * stream,size_t length)142 size_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
writeToStream(SkWStream * stream)173 bool 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
readString(size_t * outLen)192 const 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
writeString(const char str[],size_t len)216 void 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
WriteStringSize(const char * str,size_t len)242 size_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