namespace { // This generator intentionally should always fail on all attempts to get its pixels, // simulating a bad or empty codec stream. class EmptyImageGenerator final : public SkImageGenerator {
public:
EmptyImageGenerator(const SkImageInfo& info) : SkImageGenerator(info) { }
void SkReadBuffer::setInvalid() { if (!fError) { // When an error is found, send the read cursor to the end of the stream
fCurr = fStop;
fError = true;
}
}
bool SkReadBuffer::readBool() {
uint32_t value = this->readUInt(); // Boolean value should be either 0 or 1
this->validate(!(value & ~1)); return value != 0;
}
bool SkReadBuffer::readPad32(void* buffer, size_t bytes) { if (constvoid* src = this->skip(bytes)) { // buffer might be null if bytes is zero (see SkAutoMalloc), hence we call // the careful version of memcpy.
sk_careful_memcpy(buffer, src, bytes); return true;
} returnfalse;
}
std::optional<SkPath> SkReadBuffer::readPath() { if (fError) { return {};
}
size_t size = 0; auto path = SkPath::ReadFromMemory(fCurr, this->available(), &size);
// todo: consider moving this 4-byte-alignment check elsewhere // i.e. why is that a burden on SkPath? // why don't we just skipAlign4() or something?
(void)this->validate(SkAlign4(size) == size && path.has_value());
// we move forward, regardless of if the path succeeded
(void)this->skip(size);
SkReadBuffer buffer(data->data(), data->size()); int count = buffer.read32(); if (builder.countLevels() != count) { return img;
} for (int i = 0; i < count; ++i) {
size_t size = buffer.read32(); constvoid* ptr = buffer.skip(size); if (!ptr) { return img;
} // This use of SkData::MakeWithoutCopy is safe because the image goes // out of scope after we read the pixels from it, so we are sure the // data (from buffer) outlives the image.
sk_sp<SkImage> mip = deserialize_image(SkData::MakeWithoutCopy(ptr, size), dProcs,
alphaType); if (!mip) { return img;
}
SkPixmap pm = builder.level(i); if (mip->dimensions() != pm.dimensions()) { return img;
} if (!mip->readPixels(nullptr, pm, 0, 0)) { return img;
}
} if (!buffer.isValid()) { return img;
}
sk_sp<SkImage> raster = img->makeRasterImage(nullptr); if (!raster) { return img;
}
sk_sp<SkImage> rasterWithMips = builder.attachTo(raster);
SkASSERT(rasterWithMips); // attachTo should never return null return rasterWithMips;
}
// If we see a corrupt stream, we return null (fail). If we just fail trying to decode // the image, we don't fail, but return a 1x1 empty image.
sk_sp<SkImage> SkReadBuffer::readImage() {
uint32_t flags = this->read32();
// This flag is not written by new SKPs anymore. if (flags & SkWriteBufferImageFlags::kHasSubsetRect) {
SkIRect subset;
this->readIRect(&subset); if (image) {
image = image->makeSubset(nullptr, subset, {});
}
}
if (flags & SkWriteBufferImageFlags::kHasMipmap) {
sk_sp<SkData> data = this->readByteArrayAsData(); if (!data) {
this->validate(false); return nullptr;
} if (image) {
image = add_mipmaps(image, std::move(data), fProcs, alphaType);
}
} return image ? image : MakeEmptyImage(1, 1);
}
if (fFactoryCount > 0) {
int32_t index = this->read32(); if (0 == index || !this->isValid()) { return nullptr; // writer failed to give us the flattenable
} if (index < 0) {
this->validate(false); return nullptr;
}
index -= 1; // we stored the index-base-1 if ((unsigned)index >= (unsigned)fFactoryCount) {
this->validate(false); return nullptr;
}
factory = fFactoryArray[index];
} else { if (this->peekByte() != 0) { // If the first byte is non-zero, the flattenable is specified by a string.
size_t ignored_length; if (constchar* name = this->readString(&ignored_length)) {
factory = SkFlattenable::NameToFactory(name);
fFlattenableDict.set(fFlattenableDict.count() + 1, factory);
}
} else { // Read the index. We are guaranteed that the first byte // is zeroed, so we must shift down a byte.
uint32_t index = this->readUInt() >> 8; if (index == 0) { return nullptr; // writer failed to give us the flattenable
}
if (SkFlattenable::Factory* found = fFlattenableDict.find(index)) {
factory = *found;
}
}
if (!this->validate(factory != nullptr)) { return nullptr;
}
}
// if we get here, factory may still be null, but if that is the case, the // failure was ours, not the writer.
sk_sp<SkFlattenable> obj;
uint32_t sizeRecorded = this->read32(); if (factory) {
size_t offset = this->offset();
obj = (*factory)(*this); // check that we read the amount we expected
size_t sizeRead = this->offset() - offset; if (sizeRecorded != sizeRead) {
this->validate(false); return nullptr;
}
} else { // we must skip the remaining data
this->skip(sizeRecorded);
} if (!this->isValid()) { return nullptr;
} return obj.release();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.