| Index: src/codec/SkRawCodec.cpp
|
| diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp
|
| index c7de3172863876cdbf1ec0e2d5a2d0111e6ddc3f..f9a1488e9879156978ec57f444711e52cb494704 100644
|
| --- a/src/codec/SkRawCodec.cpp
|
| +++ b/src/codec/SkRawCodec.cpp
|
| @@ -157,23 +157,66 @@ public:
|
| }
|
| };
|
|
|
| +bool is_asset_stream(const SkStream& stream) {
|
| + return stream.hasLength() && stream.hasPosition();
|
| +}
|
| +
|
| } // namespace
|
|
|
| -// Note: this class could throw exception if it is used as dng_stream.
|
| -class SkRawStream : public ::piex::StreamInterface {
|
| +class SkRawStream {
|
| public:
|
| - // Note that this call will take the ownership of stream.
|
| - explicit SkRawStream(SkStream* stream)
|
| - : fStream(stream), fWholeStreamRead(false) {}
|
| + virtual ~SkRawStream() {}
|
|
|
| - ~SkRawStream() override {}
|
| + /*
|
| + * Gets the length of the stream. Depending on the type of stream, this may require reading to
|
| + * the end of the stream.
|
| + */
|
| + virtual uint64 getLength() = 0;
|
| +
|
| + virtual bool read(void* data, size_t offset, size_t length) = 0;
|
|
|
| /*
|
| * Creates an SkMemoryStream from the offset with size.
|
| * Note: for performance reason, this function is destructive to the SkRawStream. One should
|
| * abandon current object after the function call.
|
| */
|
| - SkMemoryStream* transferBuffer(size_t offset, size_t size) {
|
| + virtual SkMemoryStream* transferBuffer(size_t offset, size_t size) = 0;
|
| +};
|
| +
|
| +class SkRawBufferedStream : public SkRawStream {
|
| +public:
|
| + // Will take the ownership of the stream.
|
| + explicit SkRawBufferedStream(SkStream* stream)
|
| + : fStream(stream)
|
| + , fWholeStreamRead(false)
|
| + {
|
| + // Only use SkRawBufferedStream when the stream is not an asset stream.
|
| + SkASSERT(!is_asset_stream(*stream));
|
| + }
|
| +
|
| + ~SkRawBufferedStream() override {}
|
| +
|
| + uint64 getLength() override {
|
| + if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
|
| + ThrowReadFile();
|
| + }
|
| + return fStreamBuffer.bytesWritten();
|
| + }
|
| +
|
| + bool read(void* data, size_t offset, size_t length) override {
|
| + if (length == 0) {
|
| + return true;
|
| + }
|
| +
|
| + size_t sum;
|
| + if (!safe_add_to_size_t(offset, length, &sum)) {
|
| + return false;
|
| + }
|
| +
|
| + return this->bufferMoreData(sum) && fStreamBuffer.read(data, offset, length);
|
| + }
|
| +
|
| + SkMemoryStream* transferBuffer(size_t offset, size_t size) override {
|
| SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
|
| if (offset > fStreamBuffer.bytesWritten()) {
|
| // If the offset is not buffered, read from fStream directly and skip the buffering.
|
| @@ -208,46 +251,6 @@ public:
|
| return new SkMemoryStream(data);
|
| }
|
|
|
| - // For PIEX
|
| - ::piex::Error GetData(const size_t offset, const size_t length,
|
| - uint8* data) override {
|
| - if (offset == 0 && length == 0) {
|
| - return ::piex::Error::kOk;
|
| - }
|
| - size_t sum;
|
| - if (!safe_add_to_size_t(offset, length, &sum) || !this->bufferMoreData(sum)) {
|
| - return ::piex::Error::kFail;
|
| - }
|
| - if (!fStreamBuffer.read(data, offset, length)) {
|
| - return ::piex::Error::kFail;
|
| - }
|
| - return ::piex::Error::kOk;
|
| - }
|
| -
|
| - // For dng_stream
|
| - uint64 getLength() {
|
| - if (!this->bufferMoreData(kReadToEnd)) { // read whole stream
|
| - ThrowReadFile();
|
| - }
|
| - return fStreamBuffer.bytesWritten();
|
| - }
|
| -
|
| - // For dng_stream
|
| - void read(void* data, uint32 count, uint64 offset) {
|
| - if (count == 0 && offset == 0) {
|
| - return;
|
| - }
|
| - size_t sum;
|
| - if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
|
| - !this->bufferMoreData(sum)) {
|
| - ThrowReadFile();
|
| - }
|
| -
|
| - if (!fStreamBuffer.read(data, static_cast<size_t>(offset), count)) {
|
| - ThrowReadFile();
|
| - }
|
| - }
|
| -
|
| private:
|
| // Note: if the newSize == kReadToEnd (0), this function will read to the end of stream.
|
| bool bufferMoreData(size_t newSize) {
|
| @@ -287,22 +290,115 @@ private:
|
| const size_t kReadToEnd = 0;
|
| };
|
|
|
| +class SkRawAssetStream : public SkRawStream {
|
| +public:
|
| + // Will take the ownership of the stream.
|
| + explicit SkRawAssetStream(SkStream* stream)
|
| + : fStream(stream)
|
| + {
|
| + // Only use SkRawAssetStream when the stream is an asset stream.
|
| + SkASSERT(is_asset_stream(*stream));
|
| + }
|
| +
|
| + ~SkRawAssetStream() override {}
|
| +
|
| + uint64 getLength() override {
|
| + return fStream->getLength();
|
| + }
|
| +
|
| +
|
| + bool read(void* data, size_t offset, size_t length) override {
|
| + if (length == 0) {
|
| + return true;
|
| + }
|
| +
|
| + size_t sum;
|
| + if (!safe_add_to_size_t(offset, length, &sum)) {
|
| + return false;
|
| + }
|
| +
|
| + return fStream->seek(offset) && (fStream->read(data, length) == length);
|
| + }
|
| +
|
| + SkMemoryStream* transferBuffer(size_t offset, size_t size) override {
|
| + if (fStream->getLength() < offset) {
|
| + return nullptr;
|
| + }
|
| +
|
| + size_t sum;
|
| + if (!safe_add_to_size_t(offset, size, &sum)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + // This will allow read less than the requested "size", because the JPEG codec wants to
|
| + // handle also a partial JPEG file.
|
| + const size_t bytesToRead = SkTMin(sum, fStream->getLength()) - offset;
|
| + if (bytesToRead == 0) {
|
| + return nullptr;
|
| + }
|
| +
|
| + if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available.
|
| + SkAutoTUnref<SkData> data(SkData::NewWithCopy(
|
| + static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, bytesToRead));
|
| + fStream.free();
|
| + return new SkMemoryStream(data);
|
| + } else {
|
| + SkAutoTUnref<SkData> data(SkData::NewUninitialized(bytesToRead));
|
| + if (!fStream->seek(offset)) {
|
| + return nullptr;
|
| + }
|
| + const size_t bytesRead = fStream->read(data->writable_data(), bytesToRead);
|
| + if (bytesRead < bytesToRead) {
|
| + data.reset(SkData::NewSubset(data.get(), 0, bytesRead));
|
| + }
|
| + return new SkMemoryStream(data);
|
| + }
|
| + }
|
| +private:
|
| + SkAutoTDelete<SkStream> fStream;
|
| +};
|
| +
|
| +class SkPiexStream : public ::piex::StreamInterface {
|
| +public:
|
| + // Will NOT take the ownership of the stream.
|
| + explicit SkPiexStream(SkRawStream* stream) : fStream(stream) {}
|
| +
|
| + ~SkPiexStream() override {}
|
| +
|
| + ::piex::Error GetData(const size_t offset, const size_t length,
|
| + uint8* data) override {
|
| + return fStream->read(static_cast<void*>(data), offset, length) ?
|
| + ::piex::Error::kOk : ::piex::Error::kFail;
|
| + }
|
| +
|
| +private:
|
| + SkRawStream* fStream;
|
| +};
|
| +
|
| class SkDngStream : public dng_stream {
|
| public:
|
| - SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {}
|
| + // Will NOT take the ownership of the stream.
|
| + SkDngStream(SkRawStream* stream) : fStream(stream) {}
|
| +
|
| + ~SkDngStream() override {}
|
|
|
| - uint64 DoGetLength() override { return fRawStream->getLength(); }
|
| + uint64 DoGetLength() override { return fStream->getLength(); }
|
|
|
| void DoRead(void* data, uint32 count, uint64 offset) override {
|
| - fRawStream->read(data, count, offset);
|
| + size_t sum;
|
| + if (!safe_add_to_size_t(static_cast<uint64>(count), offset, &sum) ||
|
| + !fStream->read(data, static_cast<size_t>(offset), static_cast<size_t>(count))) {
|
| + ThrowReadFile();
|
| + }
|
| }
|
|
|
| private:
|
| - SkRawStream* fRawStream;
|
| + SkRawStream* fStream;
|
| };
|
|
|
| class SkDngImage {
|
| public:
|
| + // Will take the ownership of the stream.
|
| static SkDngImage* NewFromStream(SkRawStream* stream) {
|
| SkAutoTDelete<SkDngImage> dngImage(new SkDngImage(stream));
|
| if (!dngImage->readDng()) {
|
| @@ -439,10 +535,18 @@ private:
|
| * fallback to create SkRawCodec for DNG images.
|
| */
|
| SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
|
| - SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream));
|
| + SkAutoTDelete<SkRawStream> rawStream;
|
| + if (is_asset_stream(*stream)) {
|
| + rawStream.reset(new SkRawAssetStream(stream));
|
| + } else {
|
| + rawStream.reset(new SkRawBufferedStream(stream));
|
| + }
|
| +
|
| + // Does not take the ownership of rawStream.
|
| + SkPiexStream piexStream(rawStream.get());
|
| ::piex::PreviewImageData imageData;
|
| - if (::piex::IsRaw(rawStream.get())) {
|
| - ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imageData);
|
| + if (::piex::IsRaw(&piexStream)) {
|
| + ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData);
|
|
|
| if (error == ::piex::Error::kOk && imageData.preview_length > 0) {
|
| #if !defined(GOOGLE3)
|
| @@ -450,7 +554,7 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
|
| // function call.
|
| // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream.
|
| SkMemoryStream* memoryStream =
|
| - rawStream->transferBuffer(imageData.preview_offset, imageData.preview_length);
|
| + rawStream->transferBuffer(imageData.preview_offset, imageData.preview_length);
|
| return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr;
|
| #else
|
| return nullptr;
|
| @@ -460,6 +564,7 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) {
|
| }
|
| }
|
|
|
| + // Takes the ownership of the rawStream.
|
| SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release()));
|
| if (!dngImage) {
|
| return nullptr;
|
|
|