blob: 22655a6e4e30e2d476ee89d29bf777b45f0a75a6 [file] [log] [blame]
djsollen@google.com2b2ede32012-04-12 13:24:04 +00001/*
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00002 * Copyright 2012 Google Inc.
djsollen@google.com2b2ede32012-04-12 13:24:04 +00003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Kevin Lubickc69d9992023-02-15 08:04:24 -05008#include "src/core/SkReadBuffer.h"
9
10#include "include/core/SkAlphaType.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkData.h"
12#include "include/core/SkImage.h"
13#include "include/core/SkImageGenerator.h"
Kevin Lubickc69d9992023-02-15 08:04:24 -050014#include "include/core/SkImageInfo.h"
15#include "include/core/SkM44.h"
16#include "include/core/SkMatrix.h"
17#include "include/core/SkPath.h"
18#include "include/core/SkPoint3.h"
19#include "include/core/SkRRect.h"
20#include "include/core/SkRegion.h"
21#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "include/core/SkTypeface.h"
Kevin Lubickc69d9992023-02-15 08:04:24 -050023#include "include/private/base/SkMalloc.h"
Kevin Lubick1b3aa8b2023-01-19 14:03:31 -050024#include "src/base/SkAutoMalloc.h"
25#include "src/base/SkMathPriv.h"
Kevin Lubick46572b42023-01-18 13:11:06 -050026#include "src/base/SkSafeMath.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/core/SkMatrixPriv.h"
Kevin Lubickc69d9992023-02-15 08:04:24 -050028#include "src/core/SkMipmap.h"
Mike Reed6affa2c2020-11-30 13:09:24 -050029#include "src/core/SkMipmapBuilder.h"
Kevin Lubickc69d9992023-02-15 08:04:24 -050030#include "src/core/SkWriteBuffer.h"
31
32#include <memory>
33#include <optional>
34#include <utility>
djsollen@google.com2b2ede32012-04-12 13:24:04 +000035
reeda9ca05c2016-08-11 03:55:15 -070036namespace {
reeda9ca05c2016-08-11 03:55:15 -070037 // This generator intentionally should always fail on all attempts to get its pixels,
38 // simulating a bad or empty codec stream.
39 class EmptyImageGenerator final : public SkImageGenerator {
40 public:
Kevin Lubickc69d9992023-02-15 08:04:24 -050041 EmptyImageGenerator(const SkImageInfo& info) : SkImageGenerator(info) { }
reeda9ca05c2016-08-11 03:55:15 -070042
reeda9ca05c2016-08-11 03:55:15 -070043 };
44
45 static sk_sp<SkImage> MakeEmptyImage(int width, int height) {
46 return SkImage::MakeFromGenerator(
Mike Kleinf46d5ca2019-12-11 10:45:01 -050047 std::make_unique<EmptyImageGenerator>(SkImageInfo::MakeN32Premul(width, height)));
reeda9ca05c2016-08-11 03:55:15 -070048 }
Mike Kleine54c75f2016-10-13 14:18:09 -040049
reeda9ca05c2016-08-11 03:55:15 -070050} // anonymous namespace
51
Mike Reed34e368a2017-12-07 13:47:24 -050052void SkReadBuffer::setMemory(const void* data, size_t size) {
53 this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size));
54 if (!fError) {
Brian Osmanff7bee92020-06-09 16:04:18 -040055 fBase = fCurr = (const char*)data;
56 fStop = fBase + size;
Mike Reed34e368a2017-12-07 13:47:24 -050057 }
58}
Brian Osmanff7bee92020-06-09 16:04:18 -040059
Mike Reedfadbfcd2017-12-06 16:09:20 -050060void SkReadBuffer::setInvalid() {
61 if (!fError) {
62 // When an error is found, send the read cursor to the end of the stream
Brian Osmanff7bee92020-06-09 16:04:18 -040063 fCurr = fStop;
Mike Reedfadbfcd2017-12-06 16:09:20 -050064 fError = true;
65 }
66}
67
68const void* SkReadBuffer::skip(size_t size) {
69 size_t inc = SkAlign4(size);
70 this->validate(inc >= size);
Brian Osmanff7bee92020-06-09 16:04:18 -040071 const void* addr = fCurr;
72 this->validate(IsPtrAlign4(addr) && this->isAvailable(inc));
Mike Reedfadbfcd2017-12-06 16:09:20 -050073 if (fError) {
74 return nullptr;
75 }
76
Brian Osmanff7bee92020-06-09 16:04:18 -040077 fCurr += inc;
Mike Reedfadbfcd2017-12-06 16:09:20 -050078 return addr;
79}
80
Mike Reed5c68dce2017-12-21 21:54:32 -050081const void* SkReadBuffer::skip(size_t count, size_t size) {
82 return this->skip(SkSafeMath::Mul(count, size));
83}
84
Mike Reed60691a52017-12-05 15:11:24 -050085void SkReadBuffer::setDeserialProcs(const SkDeserialProcs& procs) {
86 fProcs = procs;
reeda9ca05c2016-08-11 03:55:15 -070087}
88
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000089bool SkReadBuffer::readBool() {
Mike Reedefe98422018-01-02 10:10:02 -050090 uint32_t value = this->readUInt();
Mike Reedfadbfcd2017-12-06 16:09:20 -050091 // Boolean value should be either 0 or 1
92 this->validate(!(value & ~1));
93 return value != 0;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000094}
95
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000096SkColor SkReadBuffer::readColor() {
Mike Reedefe98422018-01-02 10:10:02 -050097 return this->readUInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000098}
99
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000100int32_t SkReadBuffer::readInt() {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500101 const size_t inc = sizeof(int32_t);
Brian Osmanff7bee92020-06-09 16:04:18 -0400102 if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) {
103 return 0;
104 }
105 int32_t value = *((const int32_t*)fCurr);
106 fCurr += inc;
107 return value;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000108}
109
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000110SkScalar SkReadBuffer::readScalar() {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500111 const size_t inc = sizeof(SkScalar);
Brian Osmanff7bee92020-06-09 16:04:18 -0400112 if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) {
113 return 0;
114 }
115 SkScalar value = *((const SkScalar*)fCurr);
116 fCurr += inc;
117 return value;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000118}
119
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000120uint32_t SkReadBuffer::readUInt() {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500121 return this->readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000122}
123
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000124int32_t SkReadBuffer::read32() {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500125 return this->readInt();
126}
127
128uint8_t SkReadBuffer::peekByte() {
Brian Osmanff7bee92020-06-09 16:04:18 -0400129 if (this->available() <= 0) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500130 fError = true;
131 return 0;
132 }
Brian Osmanff7bee92020-06-09 16:04:18 -0400133 return *((uint8_t*)fCurr);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000134}
135
Mike Reed60691a52017-12-05 15:11:24 -0500136bool SkReadBuffer::readPad32(void* buffer, size_t bytes) {
Mike Reedefe98422018-01-02 10:10:02 -0500137 if (const void* src = this->skip(bytes)) {
Mike Reed33b1ecc2020-02-18 22:22:49 -0500138 // buffer might be null if bytes is zero (see SkAutoMalloc), hence we call
139 // the careful version of memcpy.
140 sk_careful_memcpy(buffer, src, bytes);
Mike Reedefe98422018-01-02 10:10:02 -0500141 return true;
Mike Reed60691a52017-12-05 15:11:24 -0500142 }
Mike Reedefe98422018-01-02 10:10:02 -0500143 return false;
Mike Reed60691a52017-12-05 15:11:24 -0500144}
145
Mike Kleinbe3929d2018-11-15 09:13:12 -0500146const char* SkReadBuffer::readString(size_t* len) {
147 *len = this->readUInt();
148
149 // The string is len characters and a terminating \0.
150 const char* c_str = this->skipT<char>(*len+1);
151
152 if (this->validate(c_str && c_str[*len] == '\0')) {
153 return c_str;
154 }
155 return nullptr;
156}
157
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000158void SkReadBuffer::readString(SkString* string) {
Mike Kleinbe3929d2018-11-15 09:13:12 -0500159 size_t len;
160 if (const char* c_str = this->readString(&len)) {
161 string->set(c_str, len);
162 return;
Mike Reedfadbfcd2017-12-06 16:09:20 -0500163 }
Mike Reedefe98422018-01-02 10:10:02 -0500164 string->reset();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000165}
166
brianosman97bbf822016-09-25 13:15:58 -0700167void SkReadBuffer::readColor4f(SkColor4f* color) {
Mike Reedefe98422018-01-02 10:10:02 -0500168 if (!this->readPad32(color, sizeof(SkColor4f))) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500169 *color = {0, 0, 0, 0};
170 }
brianosman97bbf822016-09-25 13:15:58 -0700171}
172
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000173void SkReadBuffer::readPoint(SkPoint* point) {
Mike Reed75d55d32017-12-07 13:52:08 -0500174 point->fX = this->readScalar();
175 point->fY = this->readScalar();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000176}
177
Jim Van Verth4123d0f2017-05-22 12:02:21 -0400178void SkReadBuffer::readPoint3(SkPoint3* point) {
Mike Reedefe98422018-01-02 10:10:02 -0500179 this->readPad32(point, sizeof(SkPoint3));
Jim Van Verth4123d0f2017-05-22 12:02:21 -0400180}
181
Mike Reed6d0ab952020-07-20 16:07:01 -0400182void SkReadBuffer::read(SkM44* matrix) {
183 if (this->isValid()) {
184 if (const float* m = (const float*)this->skip(sizeof(float) * 16)) {
185 *matrix = SkM44::ColMajor(m);
186 }
187 }
188 if (!this->isValid()) {
189 *matrix = SkM44();
190 }
191}
192
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000193void SkReadBuffer::readMatrix(SkMatrix* matrix) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500194 size_t size = 0;
Mike Reedefe98422018-01-02 10:10:02 -0500195 if (this->isValid()) {
Brian Osmanff7bee92020-06-09 16:04:18 -0400196 size = SkMatrixPriv::ReadFromMemory(matrix, fCurr, this->available());
Mike Reed2a223352018-02-06 16:58:21 -0500197 (void)this->validate((SkAlign4(size) == size) && (0 != size));
198 }
199 if (!this->isValid()) {
200 matrix->reset();
Mike Reedfadbfcd2017-12-06 16:09:20 -0500201 }
Mike Reedefe98422018-01-02 10:10:02 -0500202 (void)this->skip(size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000203}
204
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000205void SkReadBuffer::readIRect(SkIRect* rect) {
Mike Reedefe98422018-01-02 10:10:02 -0500206 if (!this->readPad32(rect, sizeof(SkIRect))) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500207 rect->setEmpty();
208 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000209}
210
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000211void SkReadBuffer::readRect(SkRect* rect) {
Mike Reedefe98422018-01-02 10:10:02 -0500212 if (!this->readPad32(rect, sizeof(SkRect))) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500213 rect->setEmpty();
214 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000215}
216
Mike Reed4f23dec2020-12-30 14:22:42 +0000217SkRect SkReadBuffer::readRect() {
218 SkRect r;
219 if (!this->readPad32(&r, sizeof(SkRect))) {
220 r.setEmpty();
221 }
222 return r;
223}
224
225SkSamplingOptions SkReadBuffer::readSampling() {
Brian Salomonc8ee7b12022-04-29 13:10:33 -0400226 if (!this->isVersionLT(SkPicturePriv::kAnisotropicFilter)) {
227 int maxAniso = this->readInt();
228 if (maxAniso != 0) {
229 return SkSamplingOptions::Aniso(maxAniso);
230 }
231 }
Mike Reed4f23dec2020-12-30 14:22:42 +0000232 if (this->readBool()) {
233 float B = this->readScalar();
234 float C = this->readScalar();
235 return SkSamplingOptions({B, C});
236 } else {
237 SkFilterMode filter = this->read32LE(SkFilterMode::kLinear);
238 SkMipmapMode mipmap = this->read32LE(SkMipmapMode::kLinear);
239 return SkSamplingOptions(filter, mipmap);
240 }
241}
242
robertphillips9ca06c42016-04-20 11:43:33 -0700243void SkReadBuffer::readRRect(SkRRect* rrect) {
Brian Osmanff7bee92020-06-09 16:04:18 -0400244 size_t size = 0;
245 if (!fError) {
246 size = rrect->readFromMemory(fCurr, this->available());
247 if (!this->validate((SkAlign4(size) == size) && (0 != size))) {
248 rrect->setEmpty();
249 }
Mike Reedfadbfcd2017-12-06 16:09:20 -0500250 }
Brian Osmanff7bee92020-06-09 16:04:18 -0400251 (void)this->skip(size);
robertphillips9ca06c42016-04-20 11:43:33 -0700252}
253
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000254void SkReadBuffer::readRegion(SkRegion* region) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500255 size_t size = 0;
256 if (!fError) {
Brian Osmanff7bee92020-06-09 16:04:18 -0400257 size = region->readFromMemory(fCurr, this->available());
Mike Reed574b06f2018-01-23 12:34:56 -0500258 if (!this->validate((SkAlign4(size) == size) && (0 != size))) {
259 region->setEmpty();
260 }
Mike Reedfadbfcd2017-12-06 16:09:20 -0500261 }
Mike Reedefe98422018-01-02 10:10:02 -0500262 (void)this->skip(size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000263}
264
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000265void SkReadBuffer::readPath(SkPath* path) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500266 size_t size = 0;
267 if (!fError) {
Brian Osmanff7bee92020-06-09 16:04:18 -0400268 size = path->readFromMemory(fCurr, this->available());
Mike Reed574b06f2018-01-23 12:34:56 -0500269 if (!this->validate((SkAlign4(size) == size) && (0 != size))) {
270 path->reset();
271 }
Mike Reedfadbfcd2017-12-06 16:09:20 -0500272 }
Mike Reedefe98422018-01-02 10:10:02 -0500273 (void)this->skip(size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000274}
275
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000276bool SkReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
Mike Reedefe98422018-01-02 10:10:02 -0500277 const uint32_t count = this->readUInt();
278 return this->validate(size == count) &&
279 this->readPad32(value, SkSafeMath::Mul(size, elementSize));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000280}
281
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000282bool SkReadBuffer::readByteArray(void* value, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500283 return this->readArray(value, size, sizeof(uint8_t));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000284}
285
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000286bool SkReadBuffer::readColorArray(SkColor* colors, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500287 return this->readArray(colors, size, sizeof(SkColor));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000288}
289
brianosman97bbf822016-09-25 13:15:58 -0700290bool SkReadBuffer::readColor4fArray(SkColor4f* colors, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500291 return this->readArray(colors, size, sizeof(SkColor4f));
brianosman97bbf822016-09-25 13:15:58 -0700292}
293
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000294bool SkReadBuffer::readIntArray(int32_t* values, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500295 return this->readArray(values, size, sizeof(int32_t));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000296}
297
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000298bool SkReadBuffer::readPointArray(SkPoint* points, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500299 return this->readArray(points, size, sizeof(SkPoint));
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000300}
301
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000302bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) {
Mike Reedefe98422018-01-02 10:10:02 -0500303 return this->readArray(values, size, sizeof(SkScalar));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000304}
305
Brian Osman9e4e4c72020-06-10 07:19:34 -0400306const void* SkReadBuffer::skipByteArray(size_t* size) {
307 const uint32_t count = this->readUInt();
308 const void* buf = this->skip(count);
309 if (size) {
310 *size = this->isValid() ? count : 0;
311 }
312 return buf;
313}
314
Florin Malitac2ea3272018-05-10 09:41:38 -0400315sk_sp<SkData> SkReadBuffer::readByteArrayAsData() {
316 size_t numBytes = this->getArrayCount();
Brian Osmanff7bee92020-06-09 16:04:18 -0400317 if (!this->validate(this->isAvailable(numBytes))) {
Florin Malitac2ea3272018-05-10 09:41:38 -0400318 return nullptr;
319 }
320
321 SkAutoMalloc buffer(numBytes);
322 if (!this->readByteArray(buffer.get(), numBytes)) {
323 return nullptr;
324 }
Florin Malitac2ea3272018-05-10 09:41:38 -0400325 return SkData::MakeFromMalloc(buffer.release(), numBytes);
326}
327
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000328uint32_t SkReadBuffer::getArrayCount() {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500329 const size_t inc = sizeof(uint32_t);
Brian Osmanff7bee92020-06-09 16:04:18 -0400330 if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) {
331 return 0;
332 }
333 return *((uint32_t*)fCurr);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000334}
335
Mike Reedfd6f7092020-07-16 16:29:16 -0400336// If we see a corrupt stream, we return null (fail). If we just fail trying to decode
Kevin Lubickbe03ef12021-06-16 15:28:00 -0400337// the image, we don't fail, but return a 1x1 empty image.
Mike Reedfd6f7092020-07-16 16:29:16 -0400338sk_sp<SkImage> SkReadBuffer::readImage() {
Mike Reedfd6f7092020-07-16 16:29:16 -0400339 uint32_t flags = this->read32();
340
341 sk_sp<SkImage> image;
342 {
343 sk_sp<SkData> data = this->readByteArrayAsData();
344 if (!data) {
345 this->validate(false);
346 return nullptr;
347 }
348 if (fProcs.fImageProc) {
349 image = fProcs.fImageProc(data->data(), data->size(), fProcs.fImageCtx);
350 }
351 if (!image) {
John Stiles7c1dafe2022-02-03 17:08:53 -0500352 std::optional<SkAlphaType> alphaType = std::nullopt;
Brian Osman85bd4df2021-12-02 10:40:56 -0500353 if (flags & SkWriteBufferImageFlags::kUnpremul) {
354 alphaType = kUnpremul_SkAlphaType;
355 }
356 image = SkImage::MakeFromEncoded(std::move(data), alphaType);
Mike Reedfd6f7092020-07-16 16:29:16 -0400357 }
358 }
359
360 if (flags & SkWriteBufferImageFlags::kHasSubsetRect) {
361 SkIRect subset;
362 this->readIRect(&subset);
363 if (image) {
364 image = image->makeSubset(subset);
365 }
366 }
367
368 if (flags & SkWriteBufferImageFlags::kHasMipmap) {
369 sk_sp<SkData> data = this->readByteArrayAsData();
370 if (!data) {
371 this->validate(false);
372 return nullptr;
373 }
374 if (image) {
375 SkMipmapBuilder builder(image->imageInfo());
376 if (SkMipmap::Deserialize(&builder, data->data(), data->size())) {
377 // TODO: need to make lazy images support mips
378 if (auto ri = image->makeRasterImage()) {
379 image = ri;
380 }
Mike Reedb4aa6392020-09-17 13:58:26 -0400381 image = builder.attachTo(image);
Mike Reedfd6f7092020-07-16 16:29:16 -0400382 SkASSERT(image); // withMipmaps should never return null
383 }
384 }
385 }
386 return image ? image : MakeEmptyImage(1, 1);
387}
388
reed2867e762016-08-29 06:57:28 -0700389sk_sp<SkTypeface> SkReadBuffer::readTypeface() {
Mike Reed8e74cbc2017-12-08 13:20:01 -0500390 // Read 32 bits (signed)
391 // 0 -- return null (default font)
392 // >0 -- index
393 // <0 -- custom (serial procs) : negative size in bytes
394
Mike Reed73822252017-12-11 13:58:27 -0500395 int32_t index = this->read32();
Mike Reed8e74cbc2017-12-08 13:20:01 -0500396 if (index == 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700397 return nullptr;
Mike Reed8e74cbc2017-12-08 13:20:01 -0500398 } else if (index > 0) {
399 if (!this->validate(index <= fTFCount)) {
400 return nullptr;
401 }
Ben Wagner5d948222018-07-10 14:20:15 -0400402 return fTFArray[index - 1];
Mike Reed8e74cbc2017-12-08 13:20:01 -0500403 } else { // custom
Mike Reed73822252017-12-11 13:58:27 -0500404 size_t size = sk_negate_to_size_t(index);
Mike Reed8e74cbc2017-12-08 13:20:01 -0500405 const void* data = this->skip(size);
Florin Malitabb091a02017-12-11 15:22:15 -0500406 if (!this->validate(data != nullptr && fProcs.fTypefaceProc)) {
Mike Reed8e74cbc2017-12-08 13:20:01 -0500407 return nullptr;
408 }
409 return fProcs.fTypefaceProc(data, size, fProcs.fTypefaceCtx);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000410 }
411}
412
Brian Osman0817ce72022-02-25 15:06:07 -0500413SkFlattenable* SkReadBuffer::readRawFlattenable() {
halcanary96fcdcc2015-08-27 07:41:13 -0700414 SkFlattenable::Factory factory = nullptr;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000415
Mike Klein4c683fc2018-10-19 17:35:02 -0400416 if (fFactoryCount > 0) {
Mike Reedfadbfcd2017-12-06 16:09:20 -0500417 int32_t index = this->read32();
418 if (0 == index || !this->isValid()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700419 return nullptr; // writer failed to give us the flattenable
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000420 }
Kevin Lubickcf67cbe2022-03-04 15:57:11 -0500421 if (index < 0) {
422 this->validate(false);
423 return nullptr;
424 }
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000425 index -= 1; // we stored the index-base-1
reedb0d25462016-01-21 06:44:18 -0800426 if ((unsigned)index >= (unsigned)fFactoryCount) {
427 this->validate(false);
428 return nullptr;
429 }
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000430 factory = fFactoryArray[index];
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000431 } else {
Mike Kleinbe3929d2018-11-15 09:13:12 -0500432 if (this->peekByte() != 0) {
msaretta3b3b232016-04-22 12:43:07 -0700433 // If the first byte is non-zero, the flattenable is specified by a string.
Mike Kleinbe3929d2018-11-15 09:13:12 -0500434 size_t ignored_length;
435 if (const char* name = this->readString(&ignored_length)) {
436 factory = SkFlattenable::NameToFactory(name);
437 fFlattenableDict.set(fFlattenableDict.count() + 1, factory);
438 }
msaretta3b3b232016-04-22 12:43:07 -0700439 } else {
440 // Read the index. We are guaranteed that the first byte
441 // is zeroed, so we must shift down a byte.
Mike Reed73822252017-12-11 13:58:27 -0500442 uint32_t index = this->readUInt() >> 8;
Mike Reedc183d162018-01-16 13:11:12 -0500443 if (index == 0) {
msaretta3b3b232016-04-22 12:43:07 -0700444 return nullptr; // writer failed to give us the flattenable
445 }
Mike Klein72098a42018-11-14 14:35:48 -0500446
447 if (SkFlattenable::Factory* found = fFlattenableDict.find(index)) {
448 factory = *found;
Mike Reed44aa9b22017-12-07 13:01:39 -0500449 }
msaretta3b3b232016-04-22 12:43:07 -0700450 }
451
Mike Klein72098a42018-11-14 14:35:48 -0500452 if (!this->validate(factory != nullptr)) {
453 return nullptr;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000454 }
455 }
456
457 // if we get here, factory may still be null, but if that is the case, the
458 // failure was ours, not the writer.
reed60c9b582016-04-03 09:11:13 -0700459 sk_sp<SkFlattenable> obj;
Mike Reed75d55d32017-12-07 13:52:08 -0500460 uint32_t sizeRecorded = this->read32();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000461 if (factory) {
Brian Osmanff7bee92020-06-09 16:04:18 -0400462 size_t offset = this->offset();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000463 obj = (*factory)(*this);
464 // check that we read the amount we expected
Brian Osmanff7bee92020-06-09 16:04:18 -0400465 size_t sizeRead = this->offset() - offset;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000466 if (sizeRecorded != sizeRead) {
reedb0d25462016-01-21 06:44:18 -0800467 this->validate(false);
468 return nullptr;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000469 }
470 } else {
471 // we must skip the remaining data
Brian Osmanff7bee92020-06-09 16:04:18 -0400472 this->skip(sizeRecorded);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000473 }
Adrienne Walker27300f02018-06-27 13:04:01 -0700474 if (!this->isValid()) {
475 return nullptr;
476 }
reed60c9b582016-04-03 09:11:13 -0700477 return obj.release();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000478}
Mike Reed48723152017-11-10 14:35:54 -0500479
Brian Osman0817ce72022-02-25 15:06:07 -0500480SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) {
481 SkFlattenable* obj = this->readRawFlattenable();
482 if (obj && obj->getFlattenableType() != ft) {
483 this->validate(false);
Brian Osmanc9710582022-03-08 10:08:27 -0500484 obj->unref();
Brian Osman0817ce72022-02-25 15:06:07 -0500485 return nullptr;
486 }
487 return obj;
488}
489
Mike Reed48723152017-11-10 14:35:54 -0500490///////////////////////////////////////////////////////////////////////////////////////////////////
491
492int32_t SkReadBuffer::checkInt(int32_t min, int32_t max) {
493 SkASSERT(min <= max);
494 int32_t value = this->read32();
495 if (value < min || value > max) {
496 this->validate(false);
497 value = min;
498 }
499 return value;
500}
501
Mike Reed95cc53b2021-07-18 11:49:30 -0400502SkLegacyFQ SkReadBuffer::checkFilterQuality() {
503 return this->checkRange<SkLegacyFQ>(kNone_SkLegacyFQ, kLast_SkLegacyFQ);
Mike Reed48723152017-11-10 14:35:54 -0500504}