blob: 8842086fd8dc45ecf73c40ecfd521f27cd7ea5d7 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#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
reed@google.comacd471f2011-05-03 21:26:46 +000012 uint32_t* alloc(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000013 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
reed@google.comacd471f2011-05-03 21:26:46 +000021 uint32_t* peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 SkASSERT(offset <= fAllocated + 4);
23 void* ptr = this->base() + offset;
24 return (uint32_t*)ptr;
25 }
26
reed@google.comacd471f2011-05-03 21:26:46 +000027 static Block* Create(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000037///////////////////////////////////////////////////////////////////////////////
38
reed@google.comacd471f2011-05-03 21:26:46 +000039SkWriter32::~SkWriter32() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 this->reset();
41}
42
reed@google.comacd471f2011-05-03 21:26:46 +000043void SkWriter32::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 Block* block = fHead;
reed@google.comacd471f2011-05-03 21:26:46 +000045 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 Block* next = block->fNext;
47 sk_free(block);
48 block = next;
49 }
reed@google.comacd471f2011-05-03 21:26:46 +000050
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 fSize = 0;
reed@google.comacd471f2011-05-03 21:26:46 +000052 fHead = fTail = NULL;
53 fSingleBlock = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
reed@google.comacd471f2011-05-03 21:26:46 +000056void SkWriter32::reset(void* block, size_t size) {
57 this->reset();
reed@google.comc9254512011-05-04 14:43:40 +000058 SkASSERT(0 == ((fSingleBlock - (char*)0) & 3)); // need 4-byte alignment
reed@google.comacd471f2011-05-03 21:26:46 +000059 fSingleBlock = (char*)block;
60 fSingleBlockSize = (size & ~3);
61}
62
63uint32_t* SkWriter32::reserve(size_t size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 SkASSERT(SkAlign4(size) == size);
reed@google.comacd471f2011-05-03 21:26:46 +000065
66 if (fSingleBlock) {
67 uint32_t* ptr = (uint32_t*)(fSingleBlock + fSize);
68 fSize += size;
69 SkASSERT(fSize <= fSingleBlockSize);
70 return ptr;
71 }
72
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 Block* block = fTail;
74
reed@google.comacd471f2011-05-03 21:26:46 +000075 if (NULL == block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 SkASSERT(NULL == fHead);
77 fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
reed@google.comacd471f2011-05-03 21:26:46 +000078 } else if (block->available() < size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 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
reed@google.comacd471f2011-05-03 21:26:46 +000089uint32_t* SkWriter32::peek32(size_t offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 SkASSERT(SkAlign4(offset) == offset);
91 SkASSERT(offset <= fSize);
92
reed@google.comacd471f2011-05-03 21:26:46 +000093 if (fSingleBlock) {
94 return (uint32_t*)(fSingleBlock + offset);
95 }
96
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 Block* block = fHead;
98 SkASSERT(NULL != block);
99
reed@google.comacd471f2011-05-03 21:26:46 +0000100 while (offset >= block->fAllocated) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 offset -= block->fAllocated;
102 block = block->fNext;
103 SkASSERT(NULL != block);
104 }
105 return block->peek32(offset);
106}
107
reed@google.comacd471f2011-05-03 21:26:46 +0000108void SkWriter32::flatten(void* dst) const {
109 if (fSingleBlock) {
110 memcpy(dst, fSingleBlock, fSize);
111 return;
112 }
113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 const Block* block = fHead;
115 SkDEBUGCODE(size_t total = 0;)
116
reed@google.comacd471f2011-05-03 21:26:46 +0000117 while (block) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 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) {
reed@google.comacd471f2011-05-03 21:26:46 +0000143 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 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) {
reed@google.comacd471f2011-05-03 21:26:46 +0000174 if (fSingleBlock) {
175 return stream->write(fSingleBlock, fSize);
176 }
177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 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
reed@google.comdde09562011-05-23 12:21:05 +0000188///////////////////////////////////////////////////////////////////////////////
189
190#include "SkReader32.h"
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000191#include "SkString.h"
192
193/*
194 * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
195 */
reed@google.comdde09562011-05-23 12:21:05 +0000196
197const char* SkReader32::readString(size_t* outLen) {
198 // we need to read at least 1-4 bytes
199 SkASSERT(this->isAvailable(4));
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000200 size_t len = this->readInt();
201 const void* ptr = this->peek();
reed@google.comdde09562011-05-23 12:21:05 +0000202
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000203 // skip over teh string + '\0' and then pad to a multiple of 4
204 size_t alignedSize = SkAlign4(len + 1);
reed@google.comdde09562011-05-23 12:21:05 +0000205 this->skip(alignedSize);
206
207 if (outLen) {
208 *outLen = len;
209 }
210 return (const char*)ptr;
211}
212
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000213size_t SkReader32::readIntoString(SkString* copy) {
214 size_t len;
215 const char* ptr = this->readString(&len);
216 if (copy) {
217 copy->set(ptr, len);
218 }
219 return len;
220}
221
reed@google.comdde09562011-05-23 12:21:05 +0000222void SkWriter32::writeString(const char str[], size_t len) {
223 if ((long)len < 0) {
224 SkASSERT(str);
225 len = strlen(str);
226 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000227 this->write32(len);
reed@google.comdde09562011-05-23 12:21:05 +0000228 // add 1 since we also write a terminating 0
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000229 size_t alignedLen = SkAlign4(len + 1);
230 char* ptr = (char*)this->reserve(alignedLen);
reed@google.comdde09562011-05-23 12:21:05 +0000231 memcpy(ptr, str, len);
232 ptr[len] = 0;
233 // we may have left 0,1,2,3 bytes uninitialized, since we reserved align4
234 // number of bytes. That's ok, since the reader will know to skip those
235}
236
237size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
238 if ((long)len < 0) {
239 SkASSERT(str);
240 len = strlen(str);
241 }
reed@google.comfd0ffcf2011-06-21 15:43:11 +0000242 const size_t lenBytes = 4; // we use 4 bytes to record the length
reed@google.comdde09562011-05-23 12:21:05 +0000243 // add 1 since we also write a terminating 0
244 return SkAlign4(lenBytes + len + 1);
245}
246
247