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); returntrue;
} returnfalse;
}
static sk_sp<SkImage> deserialize_image(sk_sp<SkData> data, SkDeserialProcs dProcs,
std::optional<SkAlphaType> alphaType) {
sk_sp<SkImage> image; if (dProcs.fImageDataProc) {
image = dProcs.fImageDataProc(data, alphaType, dProcs.fImageCtx);
} elseif (dProcs.fImageProc) { #if !defined(SK_LEGACY_DESERIAL_IMAGE_PROC)
image = dProcs.fImageProc(data->data(), data->size(), dProcs.fImageCtx); #else
image = dProcs.fImageProc(data->data(), data->size(), alphaType, dProcs.fImageCtx); #endif
} if (image) { return image;
} #if !defined(SK_DISABLE_LEGACY_IMAGE_READBUFFER) // The default implementation will encode to PNG unless the input SkImages came from // a codec that was built-in (e.g. JPEG/WEBP). Thus, we should be sure to try all // available codecs when reading images out of an SKP. return SkImages::DeferredFromEncodedData(std::move(data), alphaType); #else
SkDEBUGFAIL("Need to set image proc in SkDeserialProcs"); return nullptr; #endif
}
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(); 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.