• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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  */
8 #include "SkWriter32.h"
9 
10 struct SkWriter32::Block {
11     Block*  fNext;
12     size_t  fSize;
13     size_t  fAllocated;
14 
availableSkWriter32::Block15     size_t  available() const { return fSize - fAllocated; }
baseSkWriter32::Block16     char*   base() { return (char*)(this + 1); }
baseSkWriter32::Block17     const char* base() const { return (const char*)(this + 1); }
18 
allocSkWriter32::Block19     uint32_t* alloc(size_t size) {
20         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 
peek32SkWriter32::Block28     uint32_t* peek32(size_t offset) {
29         SkASSERT(offset <= fAllocated + 4);
30         void* ptr = this->base() + offset;
31         return (uint32_t*)ptr;
32     }
33 
CreateSkWriter32::Block34     static Block* Create(size_t size) {
35         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 
44 ///////////////////////////////////////////////////////////////////////////////
45 
~SkWriter32()46 SkWriter32::~SkWriter32() {
47     this->reset();
48 }
49 
reset()50 void SkWriter32::reset() {
51     Block* block = fHead;
52     while (block) {
53         Block* next = block->fNext;
54         sk_free(block);
55         block = next;
56     }
57 
58     fSize = 0;
59     fHead = fTail = NULL;
60     fSingleBlock = NULL;
61 }
62 
reset(void * block,size_t size)63 void SkWriter32::reset(void* block, size_t size) {
64     this->reset();
65     SkASSERT(0 == ((fSingleBlock - (char*)0) & 3));   // need 4-byte alignment
66     fSingleBlock = (char*)block;
67     fSingleBlockSize = (size & ~3);
68 }
69 
reserve(size_t size)70 uint32_t* SkWriter32::reserve(size_t size) {
71     SkASSERT(SkAlign4(size) == size);
72 
73     if (fSingleBlock) {
74         uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
75         fSize += size;
76         SkASSERT(fSize <= fSingleBlockSize);
77         return ptr;
78     }
79 
80     Block* block = fTail;
81 
82     if (NULL == block) {
83         SkASSERT(NULL == fHead);
84         fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
85     } else if (block->available() < size) {
86         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 
peek32(size_t offset)96 uint32_t* SkWriter32::peek32(size_t offset) {
97     SkASSERT(SkAlign4(offset) == offset);
98     SkASSERT(offset <= fSize);
99 
100     if (fSingleBlock) {
101         return (uint32_t*)(fSingleBlock + offset);
102     }
103 
104     Block* block = fHead;
105     SkASSERT(NULL != block);
106 
107     while (offset >= block->fAllocated) {
108         offset -= block->fAllocated;
109         block = block->fNext;
110         SkASSERT(NULL != block);
111     }
112     return block->peek32(offset);
113 }
114 
flatten(void * dst) const115 void SkWriter32::flatten(void* dst) const {
116     if (fSingleBlock) {
117         memcpy(dst, fSingleBlock, fSize);
118         return;
119     }
120 
121     const Block* block = fHead;
122     SkDEBUGCODE(size_t total = 0;)
123 
124     while (block) {
125         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 
writePad(const void * src,size_t size)136 void 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 
readFromStream(SkStream * stream,size_t length)149 size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
150     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 
161     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 
writeToStream(SkWStream * stream)180 bool SkWriter32::writeToStream(SkWStream* stream) {
181     if (fSingleBlock) {
182         return stream->write(fSingleBlock, fSize);
183     }
184 
185     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 
195 ///////////////////////////////////////////////////////////////////////////////
196 
197 #include "SkReader32.h"
198 #include "SkString.h"
199 
200 /*
201  *  Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
202  */
203 
readString(size_t * outLen)204 const char* SkReader32::readString(size_t* outLen) {
205     size_t len = this->readInt();
206     const void* ptr = this->peek();
207 
208     // skip over teh string + '\0' and then pad to a multiple of 4
209     size_t alignedSize = SkAlign4(len + 1);
210     this->skip(alignedSize);
211 
212     if (outLen) {
213         *outLen = len;
214     }
215     return (const char*)ptr;
216 }
217 
readIntoString(SkString * copy)218 size_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 
writeString(const char str[],size_t len)227 void SkWriter32::writeString(const char str[], size_t len) {
228     if ((long)len < 0) {
229         SkASSERT(str);
230         len = strlen(str);
231     }
232     this->write32(len);
233     // add 1 since we also write a terminating 0
234     size_t alignedLen = SkAlign4(len + 1);
235     char* ptr = (char*)this->reserve(alignedLen);
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     const size_t lenBytes = 4;    // we use 4 bytes to record the length
248     // add 1 since we also write a terminating 0
249     return SkAlign4(lenBytes + len + 1);
250 }
251 
252 
253