• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkWriter32.h"
9 
SkWriter32(size_t minSize,void * storage,size_t storageSize)10 SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
11     fMinSize = minSize;
12     fSize = 0;
13     fWrittenBeforeLastBlock = 0;
14     fHead = fTail = NULL;
15 
16     if (storageSize) {
17         this->reset(storage, storageSize);
18     }
19 }
20 
~SkWriter32()21 SkWriter32::~SkWriter32() {
22     this->reset();
23 }
24 
reset()25 void SkWriter32::reset() {
26     Block* block = fHead;
27 
28     if (this->isHeadExternallyAllocated()) {
29         SkASSERT(block);
30         // don't 'free' the first block, since it is owned by the caller
31         block = block->fNext;
32     }
33     while (block) {
34         Block* next = block->fNext;
35         sk_free(block);
36         block = next;
37     }
38 
39     fSize = 0;
40     fWrittenBeforeLastBlock = 0;
41     fHead = fTail = NULL;
42 }
43 
reset(void * storage,size_t storageSize)44 void SkWriter32::reset(void* storage, size_t storageSize) {
45     this->reset();
46 
47     storageSize &= ~3;  // trunc down to multiple of 4
48     if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) {
49         fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize);
50     }
51 }
52 
doReserve(size_t size)53 SkWriter32::Block* SkWriter32::doReserve(size_t size) {
54     SkASSERT(SkAlign4(size) == size);
55 
56     Block* block = fTail;
57     SkASSERT(NULL == block || block->available() < size);
58 
59     if (NULL == block) {
60         SkASSERT(NULL == fHead);
61         fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
62         SkASSERT(0 == fWrittenBeforeLastBlock);
63     } else {
64         fWrittenBeforeLastBlock = fSize;
65 
66         fTail = Block::Create(SkMax32(size, fMinSize));
67         block->fNext = fTail;
68         block = fTail;
69     }
70     return block;
71 }
72 
peek32(size_t offset)73 uint32_t* SkWriter32::peek32(size_t offset) {
74     SkDEBUGCODE(this->validate();)
75 
76     SkASSERT(SkAlign4(offset) == offset);
77     SkASSERT(offset <= fSize);
78 
79     // try the fast case, where offset is within fTail
80     if (offset >= fWrittenBeforeLastBlock) {
81         return fTail->peek32(offset - fWrittenBeforeLastBlock);
82     }
83 
84     Block* block = fHead;
85     SkASSERT(NULL != block);
86 
87     while (offset >= block->fAllocatedSoFar) {
88         offset -= block->fAllocatedSoFar;
89         block = block->fNext;
90         SkASSERT(NULL != block);
91     }
92     return block->peek32(offset);
93 }
94 
rewindToOffset(size_t offset)95 void SkWriter32::rewindToOffset(size_t offset) {
96     if (offset >= fSize) {
97         return;
98     }
99     if (0 == offset) {
100         this->reset();
101         return;
102     }
103 
104     SkDEBUGCODE(this->validate();)
105 
106     SkASSERT(SkAlign4(offset) == offset);
107     SkASSERT(offset <= fSize);
108     fSize = offset;
109 
110     // Try the fast case, where offset is within fTail
111     if (offset >= fWrittenBeforeLastBlock) {
112         fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock;
113     } else {
114         // Similar to peek32, except that we free up any following blocks.
115         // We have to re-compute fWrittenBeforeLastBlock as well.
116 
117         size_t globalOffset = offset;
118         Block* block = fHead;
119         SkASSERT(NULL != block);
120         while (offset >= block->fAllocatedSoFar) {
121             offset -= block->fAllocatedSoFar;
122             block = block->fNext;
123             SkASSERT(NULL != block);
124         }
125 
126         // this has to be recomputed, since we may free up fTail
127         fWrittenBeforeLastBlock = globalOffset - offset;
128 
129         // update the size on the "last" block
130         block->fAllocatedSoFar = offset;
131         // end our list
132         fTail = block;
133         Block* next = block->fNext;
134         block->fNext = NULL;
135         // free up any trailing blocks
136         block = next;
137         while (block) {
138             Block* next = block->fNext;
139             sk_free(block);
140             block = next;
141         }
142     }
143     SkDEBUGCODE(this->validate();)
144 }
145 
flatten(void * dst) const146 void SkWriter32::flatten(void* dst) const {
147     const Block* block = fHead;
148     SkDEBUGCODE(size_t total = 0;)
149 
150     while (block) {
151         size_t allocated = block->fAllocatedSoFar;
152         memcpy(dst, block->base(), allocated);
153         dst = (char*)dst + allocated;
154         block = block->fNext;
155 
156         SkDEBUGCODE(total += allocated;)
157         SkASSERT(total <= fSize);
158     }
159     SkASSERT(total == fSize);
160 }
161 
reservePad(size_t size)162 uint32_t* SkWriter32::reservePad(size_t size) {
163     if (size > 0) {
164         size_t alignedSize = SkAlign4(size);
165         char* dst = (char*)this->reserve(alignedSize);
166         // Pad the last four bytes with zeroes in one step.
167         uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4));
168         *padding = 0;
169         return (uint32_t*) dst;
170     }
171     return this->reserve(0);
172 }
173 
writePad(const void * src,size_t size)174 void SkWriter32::writePad(const void* src, size_t size) {
175     if (size > 0) {
176         char* dst = (char*)this->reservePad(size);
177         // Copy the actual data.
178         memcpy(dst, src, size);
179     }
180 }
181 
182 #include "SkStream.h"
183 
readFromStream(SkStream * stream,size_t length)184 size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
185     char scratch[1024];
186     const size_t MAX = sizeof(scratch);
187     size_t remaining = length;
188 
189     while (remaining != 0) {
190         size_t n = remaining;
191         if (n > MAX) {
192             n = MAX;
193         }
194         size_t bytes = stream->read(scratch, n);
195         this->writePad(scratch, bytes);
196         remaining -= bytes;
197         if (bytes != n) {
198             break;
199         }
200     }
201     return length - remaining;
202 }
203 
writeToStream(SkWStream * stream)204 bool SkWriter32::writeToStream(SkWStream* stream) {
205     const Block* block = fHead;
206     while (block) {
207         if (!stream->write(block->base(), block->fAllocatedSoFar)) {
208             return false;
209         }
210         block = block->fNext;
211     }
212     return true;
213 }
214 
215 #ifdef SK_DEBUG
validate() const216 void SkWriter32::validate() const {
217     SkASSERT(SkIsAlign4(fSize));
218 
219     size_t accum = 0;
220     const Block* block = fHead;
221     while (block) {
222         SkASSERT(SkIsAlign4(block->fSizeOfBlock));
223         SkASSERT(SkIsAlign4(block->fAllocatedSoFar));
224         SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock);
225         if (NULL == block->fNext) {
226             SkASSERT(fTail == block);
227             SkASSERT(fWrittenBeforeLastBlock == accum);
228         }
229         accum += block->fAllocatedSoFar;
230         SkASSERT(accum <= fSize);
231         block = block->fNext;
232     }
233     SkASSERT(accum == fSize);
234 }
235 #endif
236 
237 ///////////////////////////////////////////////////////////////////////////////
238 
239 #include "SkReader32.h"
240 #include "SkString.h"
241 
242 /*
243  *  Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
244  */
245 
readString(size_t * outLen)246 const char* SkReader32::readString(size_t* outLen) {
247     size_t len = this->readInt();
248     const void* ptr = this->peek();
249 
250     // skip over teh string + '\0' and then pad to a multiple of 4
251     size_t alignedSize = SkAlign4(len + 1);
252     this->skip(alignedSize);
253 
254     if (outLen) {
255         *outLen = len;
256     }
257     return (const char*)ptr;
258 }
259 
readIntoString(SkString * copy)260 size_t SkReader32::readIntoString(SkString* copy) {
261     size_t len;
262     const char* ptr = this->readString(&len);
263     if (copy) {
264         copy->set(ptr, len);
265     }
266     return len;
267 }
268 
writeString(const char str[],size_t len)269 void SkWriter32::writeString(const char str[], size_t len) {
270     if (NULL == str) {
271         str = "";
272         len = 0;
273     }
274     if ((long)len < 0) {
275         len = strlen(str);
276     }
277     this->write32(len);
278     // add 1 since we also write a terminating 0
279     size_t alignedLen = SkAlign4(len + 1);
280     char* ptr = (char*)this->reserve(alignedLen);
281     {
282         // Write the terminating 0 and fill in the rest with zeroes
283         uint32_t* padding = (uint32_t*)(ptr + (alignedLen - 4));
284         *padding = 0;
285     }
286     // Copy the string itself.
287     memcpy(ptr, str, len);
288 }
289 
WriteStringSize(const char * str,size_t len)290 size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
291     if ((long)len < 0) {
292         SkASSERT(str);
293         len = strlen(str);
294     }
295     const size_t lenBytes = 4;    // we use 4 bytes to record the length
296     // add 1 since we also write a terminating 0
297     return SkAlign4(lenBytes + len + 1);
298 }
299