| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <windows.h> | |
| #include <ole2.h> | |
| #include "SkIStream.h" | |
| #include "SkStream.h" | |
| /** | |
| * SkBaseIStream | |
| */ | |
| SkBaseIStream::SkBaseIStream() : _refcount(1) { } | |
| SkBaseIStream::~SkBaseIStream() { } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::QueryInterface(REFIID iid | |
| , void ** ppvObject) | |
| { | |
| if (NULL == ppvObject) { | |
| return E_INVALIDARG; | |
| } | |
| if (iid == __uuidof(IUnknown) | |
| || iid == __uuidof(IStream) | |
| || iid == __uuidof(ISequentialStream)) | |
| { | |
| *ppvObject = static_cast<IStream*>(this); | |
| AddRef(); | |
| return S_OK; | |
| } else { | |
| *ppvObject = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| } | |
| ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) { | |
| return (ULONG)InterlockedIncrement(&_refcount); | |
| } | |
| ULONG STDMETHODCALLTYPE SkBaseIStream::Release(void) { | |
| ULONG res = (ULONG) InterlockedDecrement(&_refcount); | |
| if (0 == res) { | |
| delete this; | |
| } | |
| return res; | |
| } | |
| // ISequentialStream Interface | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv | |
| , ULONG cb | |
| , ULONG* pcbRead) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv | |
| , ULONG cb | |
| , ULONG* pcbWritten) | |
| { return E_NOTIMPL; } | |
| // IStream Interface | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream* | |
| , ULARGE_INTEGER | |
| , ULARGE_INTEGER* | |
| , ULARGE_INTEGER*) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER | |
| , ULARGE_INTEGER | |
| , DWORD) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER | |
| , ULARGE_INTEGER | |
| , DWORD) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove | |
| , DWORD dwOrigin | |
| , ULARGE_INTEGER* lpNewFilePointer) | |
| { return E_NOTIMPL; } | |
| HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg | |
| , DWORD grfStatFlag) | |
| { return E_NOTIMPL; } | |
| /** | |
| * SkIStream | |
| */ | |
| SkIStream::SkIStream(SkStream* stream, bool unrefOnRelease) | |
| : SkBaseIStream() | |
| , fSkStream(stream) | |
| , fUnrefOnRelease(unrefOnRelease) | |
| , fLocation() | |
| { | |
| this->fSkStream->rewind(); | |
| } | |
| SkIStream::~SkIStream() { | |
| if (NULL != this->fSkStream && fUnrefOnRelease) { | |
| this->fSkStream->unref(); | |
| } | |
| } | |
| HRESULT SkIStream::CreateFromSkStream(SkStream* stream | |
| , bool unrefOnRelease | |
| , IStream ** ppStream) | |
| { | |
| if (NULL == stream) { | |
| return E_INVALIDARG; | |
| } | |
| *ppStream = new SkIStream(stream, unrefOnRelease); | |
| return S_OK; | |
| } | |
| // ISequentialStream Interface | |
| HRESULT STDMETHODCALLTYPE SkIStream::Read(void* pv, ULONG cb, ULONG* pcbRead) { | |
| *pcbRead = static_cast<ULONG>(this->fSkStream->read(pv, cb)); | |
| this->fLocation.QuadPart += *pcbRead; | |
| return (*pcbRead == cb) ? S_OK : S_FALSE; | |
| } | |
| HRESULT STDMETHODCALLTYPE SkIStream::Write(void const* pv | |
| , ULONG cb | |
| , ULONG* pcbWritten) | |
| { | |
| return STG_E_CANTSAVE; | |
| } | |
| // IStream Interface | |
| HRESULT STDMETHODCALLTYPE SkIStream::Seek(LARGE_INTEGER liDistanceToMove | |
| , DWORD dwOrigin | |
| , ULARGE_INTEGER* lpNewFilePointer) | |
| { | |
| HRESULT hr = S_OK; | |
| switch(dwOrigin) { | |
| case STREAM_SEEK_SET: { | |
| if (!this->fSkStream->rewind()) { | |
| hr = E_FAIL; | |
| } else { | |
| size_t skipped = this->fSkStream->skip( | |
| static_cast<size_t>(liDistanceToMove.QuadPart) | |
| ); | |
| this->fLocation.QuadPart = skipped; | |
| if (skipped != liDistanceToMove.QuadPart) { | |
| hr = E_FAIL; | |
| } | |
| } | |
| break; | |
| } | |
| case STREAM_SEEK_CUR: { | |
| size_t skipped = this->fSkStream->skip( | |
| static_cast<size_t>(liDistanceToMove.QuadPart) | |
| ); | |
| this->fLocation.QuadPart += skipped; | |
| if (skipped != liDistanceToMove.QuadPart) { | |
| hr = E_FAIL; | |
| } | |
| break; | |
| } | |
| case STREAM_SEEK_END: { | |
| if (!this->fSkStream->rewind()) { | |
| hr = E_FAIL; | |
| } else { | |
| // FIXME: Should not depend on getLength. | |
| // See https://code.google.com/p/skia/issues/detail?id=1570 | |
| LONGLONG skip = this->fSkStream->getLength() | |
| + liDistanceToMove.QuadPart; | |
| size_t skipped = this->fSkStream->skip(static_cast<size_t>(skip)); | |
| this->fLocation.QuadPart = skipped; | |
| if (skipped != skip) { | |
| hr = E_FAIL; | |
| } | |
| } | |
| break; | |
| } | |
| default: | |
| hr = STG_E_INVALIDFUNCTION; | |
| break; | |
| } | |
| if (NULL != lpNewFilePointer) { | |
| lpNewFilePointer->QuadPart = this->fLocation.QuadPart; | |
| } | |
| return hr; | |
| } | |
| HRESULT STDMETHODCALLTYPE SkIStream::Stat(STATSTG* pStatstg | |
| , DWORD grfStatFlag) | |
| { | |
| if (0 == (grfStatFlag & STATFLAG_NONAME)) { | |
| return STG_E_INVALIDFLAG; | |
| } | |
| pStatstg->pwcsName = NULL; | |
| // FIXME: Should not depend on getLength | |
| // See https://code.google.com/p/skia/issues/detail?id=1570 | |
| pStatstg->cbSize.QuadPart = this->fSkStream->getLength(); | |
| pStatstg->clsid = CLSID_NULL; | |
| pStatstg->type = STGTY_STREAM; | |
| pStatstg->grfMode = STGM_READ; | |
| return S_OK; | |
| } | |
| /** | |
| * SkIWStream | |
| */ | |
| SkWIStream::SkWIStream(SkWStream* stream) | |
| : SkBaseIStream() | |
| , fSkWStream(stream) | |
| { } | |
| SkWIStream::~SkWIStream() { | |
| if (NULL != this->fSkWStream) { | |
| this->fSkWStream->flush(); | |
| } | |
| } | |
| HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream | |
| , IStream ** ppStream) | |
| { | |
| *ppStream = new SkWIStream(stream); | |
| return S_OK; | |
| } | |
| // ISequentialStream Interface | |
| HRESULT STDMETHODCALLTYPE SkWIStream::Write(void const* pv | |
| , ULONG cb | |
| , ULONG* pcbWritten) | |
| { | |
| HRESULT hr = S_OK; | |
| bool wrote = this->fSkWStream->write(pv, cb); | |
| if (wrote) { | |
| *pcbWritten = cb; | |
| } else { | |
| *pcbWritten = 0; | |
| hr = S_FALSE; | |
| } | |
| return hr; | |
| } | |
| // IStream Interface | |
| HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) { | |
| this->fSkWStream->flush(); | |
| return S_OK; | |
| } | |
| HRESULT STDMETHODCALLTYPE SkWIStream::Stat(STATSTG* pStatstg | |
| , DWORD grfStatFlag) | |
| { | |
| if (0 == (grfStatFlag & STATFLAG_NONAME)) { | |
| return STG_E_INVALIDFLAG; | |
| } | |
| pStatstg->pwcsName = NULL; | |
| pStatstg->cbSize.QuadPart = 0; | |
| pStatstg->clsid = CLSID_NULL; | |
| pStatstg->type = STGTY_STREAM; | |
| pStatstg->grfMode = STGM_WRITE; | |
| return S_OK; | |
| } |