|
1 /* |
|
2 * Copyright 2013 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkBitmap.h" |
|
9 #include "SkErrorInternals.h" |
|
10 #include "SkValidatingReadBuffer.h" |
|
11 #include "SkStream.h" |
|
12 #include "SkTypeface.h" |
|
13 |
|
14 SkValidatingReadBuffer::SkValidatingReadBuffer(const void* data, size_t size) : |
|
15 fError(false) { |
|
16 this->setMemory(data, size); |
|
17 this->setFlags(SkReadBuffer::kValidation_Flag); |
|
18 } |
|
19 |
|
20 SkValidatingReadBuffer::~SkValidatingReadBuffer() { |
|
21 } |
|
22 |
|
23 bool SkValidatingReadBuffer::validate(bool isValid) { |
|
24 if (!fError && !isValid) { |
|
25 // When an error is found, send the read cursor to the end of the stream |
|
26 fReader.skip(fReader.available()); |
|
27 fError = true; |
|
28 } |
|
29 return !fError; |
|
30 } |
|
31 |
|
32 bool SkValidatingReadBuffer::isValid() const { |
|
33 return !fError; |
|
34 } |
|
35 |
|
36 void SkValidatingReadBuffer::setMemory(const void* data, size_t size) { |
|
37 this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size)); |
|
38 if (!fError) { |
|
39 fReader.setMemory(data, size); |
|
40 } |
|
41 } |
|
42 |
|
43 const void* SkValidatingReadBuffer::skip(size_t size) { |
|
44 size_t inc = SkAlign4(size); |
|
45 const void* addr = fReader.peek(); |
|
46 this->validate(IsPtrAlign4(addr) && fReader.isAvailable(inc)); |
|
47 if (!fError) { |
|
48 fReader.skip(size); |
|
49 } |
|
50 return addr; |
|
51 } |
|
52 |
|
53 // All the methods in this file funnel down into either readInt(), readScalar() or skip(), |
|
54 // followed by a memcpy. So we've got all our validation in readInt(), readScalar() and skip(); |
|
55 // if they fail they'll return a zero value or skip nothing, respectively, and set fError to |
|
56 // true, which the caller should check to see if an error occurred during the read operation. |
|
57 |
|
58 bool SkValidatingReadBuffer::readBool() { |
|
59 uint32_t value = this->readInt(); |
|
60 // Boolean value should be either 0 or 1 |
|
61 this->validate(!(value & ~1)); |
|
62 return value != 0; |
|
63 } |
|
64 |
|
65 SkColor SkValidatingReadBuffer::readColor() { |
|
66 return this->readInt(); |
|
67 } |
|
68 |
|
69 SkFixed SkValidatingReadBuffer::readFixed() { |
|
70 return this->readInt(); |
|
71 } |
|
72 |
|
73 int32_t SkValidatingReadBuffer::readInt() { |
|
74 const size_t inc = sizeof(int32_t); |
|
75 this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc)); |
|
76 return fError ? 0 : fReader.readInt(); |
|
77 } |
|
78 |
|
79 SkScalar SkValidatingReadBuffer::readScalar() { |
|
80 const size_t inc = sizeof(SkScalar); |
|
81 this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc)); |
|
82 return fError ? 0 : fReader.readScalar(); |
|
83 } |
|
84 |
|
85 uint32_t SkValidatingReadBuffer::readUInt() { |
|
86 return this->readInt(); |
|
87 } |
|
88 |
|
89 int32_t SkValidatingReadBuffer::read32() { |
|
90 return this->readInt(); |
|
91 } |
|
92 |
|
93 void SkValidatingReadBuffer::readString(SkString* string) { |
|
94 const size_t len = this->readInt(); |
|
95 const void* ptr = fReader.peek(); |
|
96 const char* cptr = (const char*)ptr; |
|
97 |
|
98 // skip over the string + '\0' and then pad to a multiple of 4 |
|
99 const size_t alignedSize = SkAlign4(len + 1); |
|
100 this->skip(alignedSize); |
|
101 if (!fError) { |
|
102 this->validate(cptr[len] == '\0'); |
|
103 } |
|
104 if (!fError) { |
|
105 string->set(cptr, len); |
|
106 } |
|
107 } |
|
108 |
|
109 void* SkValidatingReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) { |
|
110 const int32_t encodingType = this->readInt(); |
|
111 this->validate(encodingType == encoding); |
|
112 *length = this->readInt(); |
|
113 const void* ptr = this->skip(SkAlign4(*length)); |
|
114 void* data = NULL; |
|
115 if (!fError) { |
|
116 data = sk_malloc_throw(*length); |
|
117 memcpy(data, ptr, *length); |
|
118 } |
|
119 return data; |
|
120 } |
|
121 |
|
122 void SkValidatingReadBuffer::readPoint(SkPoint* point) { |
|
123 point->fX = this->readScalar(); |
|
124 point->fY = this->readScalar(); |
|
125 } |
|
126 |
|
127 void SkValidatingReadBuffer::readMatrix(SkMatrix* matrix) { |
|
128 size_t size = 0; |
|
129 if (!fError) { |
|
130 size = matrix->readFromMemory(fReader.peek(), fReader.available()); |
|
131 this->validate((SkAlign4(size) == size) && (0 != size)); |
|
132 } |
|
133 if (!fError) { |
|
134 (void)this->skip(size); |
|
135 } |
|
136 } |
|
137 |
|
138 void SkValidatingReadBuffer::readIRect(SkIRect* rect) { |
|
139 const void* ptr = this->skip(sizeof(SkIRect)); |
|
140 if (!fError) { |
|
141 memcpy(rect, ptr, sizeof(SkIRect)); |
|
142 } |
|
143 } |
|
144 |
|
145 void SkValidatingReadBuffer::readRect(SkRect* rect) { |
|
146 const void* ptr = this->skip(sizeof(SkRect)); |
|
147 if (!fError) { |
|
148 memcpy(rect, ptr, sizeof(SkRect)); |
|
149 } |
|
150 } |
|
151 |
|
152 void SkValidatingReadBuffer::readRegion(SkRegion* region) { |
|
153 size_t size = 0; |
|
154 if (!fError) { |
|
155 size = region->readFromMemory(fReader.peek(), fReader.available()); |
|
156 this->validate((SkAlign4(size) == size) && (0 != size)); |
|
157 } |
|
158 if (!fError) { |
|
159 (void)this->skip(size); |
|
160 } |
|
161 } |
|
162 |
|
163 void SkValidatingReadBuffer::readPath(SkPath* path) { |
|
164 size_t size = 0; |
|
165 if (!fError) { |
|
166 size = path->readFromMemory(fReader.peek(), fReader.available()); |
|
167 this->validate((SkAlign4(size) == size) && (0 != size)); |
|
168 } |
|
169 if (!fError) { |
|
170 (void)this->skip(size); |
|
171 } |
|
172 } |
|
173 |
|
174 bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) { |
|
175 const uint32_t count = this->getArrayCount(); |
|
176 this->validate(size == count); |
|
177 (void)this->skip(sizeof(uint32_t)); // Skip array count |
|
178 const size_t byteLength = count * elementSize; |
|
179 const void* ptr = this->skip(SkAlign4(byteLength)); |
|
180 if (!fError) { |
|
181 memcpy(value, ptr, byteLength); |
|
182 return true; |
|
183 } |
|
184 return false; |
|
185 } |
|
186 |
|
187 bool SkValidatingReadBuffer::readByteArray(void* value, size_t size) { |
|
188 return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char)); |
|
189 } |
|
190 |
|
191 bool SkValidatingReadBuffer::readColorArray(SkColor* colors, size_t size) { |
|
192 return readArray(colors, size, sizeof(SkColor)); |
|
193 } |
|
194 |
|
195 bool SkValidatingReadBuffer::readIntArray(int32_t* values, size_t size) { |
|
196 return readArray(values, size, sizeof(int32_t)); |
|
197 } |
|
198 |
|
199 bool SkValidatingReadBuffer::readPointArray(SkPoint* points, size_t size) { |
|
200 return readArray(points, size, sizeof(SkPoint)); |
|
201 } |
|
202 |
|
203 bool SkValidatingReadBuffer::readScalarArray(SkScalar* values, size_t size) { |
|
204 return readArray(values, size, sizeof(SkScalar)); |
|
205 } |
|
206 |
|
207 uint32_t SkValidatingReadBuffer::getArrayCount() { |
|
208 const size_t inc = sizeof(uint32_t); |
|
209 fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc); |
|
210 return fError ? 0 : *(uint32_t*)fReader.peek(); |
|
211 } |
|
212 |
|
213 void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) { |
|
214 const int width = this->readInt(); |
|
215 const int height = this->readInt(); |
|
216 const bool useBitmapHeap = this->readBool(); |
|
217 const size_t length = this->readUInt(); |
|
218 // A size of zero means the SkBitmap was simply flattened. |
|
219 if (!this->validate(!useBitmapHeap && (0 == length))) { |
|
220 return; |
|
221 } |
|
222 bitmap->unflatten(*this); |
|
223 this->validate((bitmap->width() == width) && (bitmap->height() == height)); |
|
224 } |
|
225 |
|
226 SkTypeface* SkValidatingReadBuffer::readTypeface() { |
|
227 // TODO: Implement this (securely) when needed |
|
228 return NULL; |
|
229 } |
|
230 |
|
231 bool SkValidatingReadBuffer::validateAvailable(size_t size) { |
|
232 return this->validate((size <= SK_MaxU32) && fReader.isAvailable(static_cast<uint32_t>(size))); |
|
233 } |
|
234 |
|
235 SkFlattenable* SkValidatingReadBuffer::readFlattenable(SkFlattenable::Type type) { |
|
236 SkString name; |
|
237 this->readString(&name); |
|
238 if (fError) { |
|
239 return NULL; |
|
240 } |
|
241 |
|
242 // Is this the type we wanted ? |
|
243 const char* cname = name.c_str(); |
|
244 SkFlattenable::Type baseType; |
|
245 if (!SkFlattenable::NameToType(cname, &baseType) || (baseType != type)) { |
|
246 return NULL; |
|
247 } |
|
248 |
|
249 SkFlattenable::Factory factory = SkFlattenable::NameToFactory(cname); |
|
250 if (NULL == factory) { |
|
251 return NULL; // writer failed to give us the flattenable |
|
252 } |
|
253 |
|
254 // if we get here, factory may still be null, but if that is the case, the |
|
255 // failure was ours, not the writer. |
|
256 SkFlattenable* obj = NULL; |
|
257 uint32_t sizeRecorded = this->readUInt(); |
|
258 if (factory) { |
|
259 uint32_t offset = fReader.offset(); |
|
260 obj = (*factory)(*this); |
|
261 // check that we read the amount we expected |
|
262 uint32_t sizeRead = fReader.offset() - offset; |
|
263 this->validate(sizeRecorded == sizeRead); |
|
264 if (fError) { |
|
265 // we could try to fix up the offset... |
|
266 delete obj; |
|
267 obj = NULL; |
|
268 } |
|
269 } else { |
|
270 // we must skip the remaining data |
|
271 this->skip(sizeRecorded); |
|
272 SkASSERT(false); |
|
273 } |
|
274 return obj; |
|
275 } |