SkWriter32.cpp revision dde0956375e87027df2fdd80d430dd819c217aac
1#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
12    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
21    uint32_t* peek32(size_t offset) {
22        SkASSERT(offset <= fAllocated + 4);
23        void* ptr = this->base() + offset;
24        return (uint32_t*)ptr;
25    }
26
27    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
39SkWriter32::~SkWriter32() {
40    this->reset();
41}
42
43void 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
56void 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
63uint32_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
89uint32_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
108void 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
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) {
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
173bool 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
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
257