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