• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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