Index: src/codec/SkRawCodec.cpp |
diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp |
index da3c28c549ff617cc74df0effb9ff18177eca023..6f6fa050ac01cb5b564fc0b3d080940a9e15b29d 100644 |
--- a/src/codec/SkRawCodec.cpp |
+++ b/src/codec/SkRawCodec.cpp |
@@ -159,21 +159,64 @@ public: |
} // 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() {} |
+ |
+ /* |
+ * Gets the length of the stream. Denpending on the type of stream, this may require read to the |
scroggo
2016/02/02 19:23:06
depending*
reading*
yujieqin
2016/02/04 14:50:32
Done.
|
+ * end of stream. |
scroggo
2016/02/02 19:23:06
the* stream
yujieqin
2016/02/04 14:50:31
Done.
|
+ */ |
+ virtual uint64 getLength() = 0; |
- ~SkRawStream() override {} |
+ virtual bool read(size_t offset, size_t length, void* data) = 0; |
scroggo
2016/02/02 19:23:06
nit: We typically put our output parameters first.
yujieqin
2016/02/04 14:50:31
Done.
|
/* |
* 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: |
+ static SkRawStream* NewFromStream(SkStream* stream) { |
+ return new SkRawBufferedStream(stream); |
+ } |
+ |
+ // Will take the ownership of the stream. |
+ explicit SkRawBufferedStream(SkStream* stream) |
+ : fStream(stream) |
+ , fWholeStreamRead(false) |
+ { |
+ // Only use SkRawBufferedStream when the stream is not seekable. |
+ SkASSERT(!fStream->hasPosition()); |
+ } |
+ |
+ ~SkRawBufferedStream() override {} |
+ |
+ uint64 getLength() override { |
+ if (!this->bufferMoreData(kReadToEnd)) { // read whole stream |
+ ThrowReadFile(); |
+ } |
+ return fStreamBuffer.bytesWritten(); |
+ } |
+ |
+ bool read(size_t offset, size_t length, void* data) { |
+ if (offset == 0 && length == 0) { |
scroggo
2016/02/02 19:23:06
Why is there a special case here? I can see why a
yujieqin
2016/02/04 14:50:31
I think you are right. This should be a bug. :)
|
+ 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) { |
@@ -284,18 +287,110 @@ private: |
const size_t kReadToEnd = 0; |
}; |
+class SkRawSeekableStream : public SkRawStream { |
+public: |
+ static SkRawStream* NewFromStream(SkStream* stream) { |
+ return new SkRawSeekableStream(stream); |
+ } |
+ |
+ // Will take the ownership of the stream. |
+ explicit SkRawSeekableStream(SkStream* stream) |
+ : fStream(stream) |
+ { |
+ // Only use SkRawSeekableStream when the stream is seekable. |
+ SkASSERT(fStream->hasPosition()); |
+ } |
+ |
+ ~SkRawSeekableStream() override {} |
+ |
+ uint64 getLength() { |
+ return fStream->getLength(); |
scroggo
2016/02/02 19:23:06
Maybe we should also check hasLength() to determin
yujieqin
2016/02/04 14:50:31
Done.
|
+ } |
+ |
+ |
+ bool read(size_t offset, size_t length, void* data) { |
+ if (offset == 0 && length == 0) { |
+ return true; |
+ } |
+ |
+ size_t sum; |
+ if (!safe_add_to_size_t(offset, length, &sum)) { |
+ return false; |
+ } |
+ |
+ if (sum > fStream->getLength()) { |
scroggo
2016/02/02 19:23:06
I don't think this check is necessary - the below
yujieqin
2016/02/04 14:50:31
Done.
|
+ return false; |
scroggo
2016/02/02 19:23:06
four space indent.
yujieqin
2016/02/04 14:50:31
Done.
|
+ } |
+ return fStream->seek(offset) && (fStream->read(data, length) == length); |
+ } |
+ |
+ SkMemoryStream* transferBuffer(size_t offset, size_t size) { |
+ size_t sum; |
+ if (!safe_add_to_size_t(offset, size, &sum)) { |
+ return nullptr; |
+ } |
+ |
+ if (fStream->getMemoryBase()) { |
+ SkAutoTUnref<SkData> data(SkData::NewWithCopy( |
+ static_cast<const uint8_t*>(fStream->getMemoryBase()) + offset, size)); |
scroggo
2016/02/02 19:23:06
This case should also support a partial jpeg file.
yujieqin
2016/02/04 14:50:31
Done.
|
+ fStream.free(); |
+ return new SkMemoryStream(data); |
+ } else { |
+ SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); |
+ if (!fStream->seek(offset)) { |
+ return nullptr; |
+ } |
+ // Don't check the returned size, because the following JPEG codec may be able to |
scroggo
2016/02/02 19:23:06
We do need to know the returned size, though, beca
yujieqin
2016/02/04 14:50:31
Done.
|
+ // process an incomplete file. |
+ fStream->read(data->writable_data(), size); |
+ return new SkMemoryStream(data); |
+ } |
+ } |
+private: |
+ SkAutoTDelete<SkStream> fStream; |
+}; |
+ |
+class SkPiexStream : public ::piex::StreamInterface { |
+public: |
+ // Note that this call will take the ownership of 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(offset, length, static_cast<void*>(data)) ? |
+ ::piex::Error::kOk : ::piex::Error::kFail; |
+ } |
+ |
+ // Release the fStream. One should abandon current object after this call. |
+ SkRawStream* releaseRawStream() { |
+ return fStream.release(); |
+ } |
+ |
+private: |
+ SkAutoTDelete<SkRawStream> fStream; |
+}; |
+ |
class SkDngStream : public dng_stream { |
public: |
- SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} |
+ // Will NOT take the ownership of the stream, because the stream needs to be able to reuse. |
+ 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) || |
scroggo
2016/02/02 19:23:06
Won't the implementation of fStream->read also mak
yujieqin
2016/02/04 14:50:31
as explained for last patch set, this check is for
|
+ !fStream->read(static_cast<size_t>(offset), static_cast<size_t>(count), data)) { |
+ ThrowReadFile(); |
+ } |
} |
private: |
- SkRawStream* fRawStream; |
+ SkRawStream* fStream; |
}; |
class SkDngImage { |
@@ -436,13 +531,15 @@ private: |
* fallback to create SkRawCodec for DNG images. |
*/ |
SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { |
- SkAutoTDelete<SkRawStream> rawStream(new SkRawStream(stream)); |
+ SkAutoTDelete<SkPiexStream> piexStream(new SkPiexStream( |
+ stream->hasPosition() ? |
+ SkRawSeekableStream::NewFromStream(stream) : SkRawBufferedStream::NewFromStream(stream))); |
scroggo
2016/02/02 19:23:06
I don't think these factory functions are necessar
yujieqin
2016/02/04 14:50:31
Done.
|
::piex::PreviewImageData imageData; |
// FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with small amounts, |
// resulting in many calls to bufferMoreData(). Could we make this more efficient by grouping |
// smaller requests together? |
- if (::piex::IsRaw(rawStream.get())) { |
- ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imageData); |
+ if (::piex::IsRaw(piexStream.get())) { |
+ ::piex::Error error = ::piex::GetPreviewImageData(piexStream.get(), &imageData); |
if (error == ::piex::Error::kOk && imageData.preview_length > 0) { |
#if !defined(GOOGLE3) |
@@ -450,7 +547,8 @@ 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); |
+ piexStream->releaseRawStream()->transferBuffer(imageData.preview_offset, |
scroggo
2016/02/02 19:23:06
This is going to leak the raw stream. I think it m
yujieqin
2016/02/04 14:50:31
Done.
|
+ imageData.preview_length); |
return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr; |
#else |
return nullptr; |
@@ -460,7 +558,7 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { |
} |
} |
- SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(rawStream.release())); |
+ SkAutoTDelete<SkDngImage> dngImage(SkDngImage::NewFromStream(piexStream->releaseRawStream())); |
if (!dngImage) { |
return nullptr; |
} |