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
10struct SkWriter32::Block {
11    Block*  fNext;
12    size_t  fSize;
13    size_t  fAllocated;
14
15    size_t  available() const { return fSize - fAllocated; }
16    char*   base() { return (char*)(this + 1); }
17    const char* base() const { return (const char*)(this + 1); }
18
19    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
28    uint32_t* peek32(size_t offset) {
29        SkASSERT(offset <= fAllocated + 4);
30        void* ptr = this->base() + offset;
31        return (uint32_t*)ptr;
32    }
33
34    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
46SkWriter32::~SkWriter32() {
47    this->reset();
48}
49
50void 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
63void 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
70uint32_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
96uint32_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
115void 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
136void 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
149size_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
180bool 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
204const 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
218size_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
227void 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
242size_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