1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkTypes.h" 9#if defined(SK_BUILD_FOR_WIN) 10 11#include "include/core/SkStream.h" 12#include "src/utils/win/SkIStream.h" 13 14/** 15 * SkBaseIStream 16 */ 17SkBaseIStream::SkBaseIStream() : _refcount(1) { } 18SkBaseIStream::~SkBaseIStream() { } 19 20SK_STDMETHODIMP SkBaseIStream::QueryInterface(REFIID iid, void ** ppvObject) { 21 if (nullptr == ppvObject) { 22 return E_INVALIDARG; 23 } 24 if (iid == __uuidof(IUnknown) 25 || iid == __uuidof(IStream) 26 || iid == __uuidof(ISequentialStream)) 27 { 28 *ppvObject = static_cast<IStream*>(this); 29 AddRef(); 30 return S_OK; 31 } else { 32 *ppvObject = nullptr; 33 return E_NOINTERFACE; 34 } 35} 36 37SK_STDMETHODIMP_(ULONG) SkBaseIStream::AddRef() { 38 return (ULONG)InterlockedIncrement(&_refcount); 39} 40 41SK_STDMETHODIMP_(ULONG) SkBaseIStream::Release() { 42 ULONG res = (ULONG) InterlockedDecrement(&_refcount); 43 if (0 == res) { 44 delete this; 45 } 46 return res; 47} 48 49// ISequentialStream Interface 50SK_STDMETHODIMP SkBaseIStream::Read(void* pv, ULONG cb, ULONG* pcbRead) 51{ return E_NOTIMPL; } 52 53SK_STDMETHODIMP SkBaseIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) 54{ return E_NOTIMPL; } 55 56// IStream Interface 57SK_STDMETHODIMP SkBaseIStream::SetSize(ULARGE_INTEGER) 58{ return E_NOTIMPL; } 59 60SK_STDMETHODIMP SkBaseIStream::CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*) 61{ return E_NOTIMPL; } 62 63SK_STDMETHODIMP SkBaseIStream::Commit(DWORD) 64{ return E_NOTIMPL; } 65 66SK_STDMETHODIMP SkBaseIStream::Revert() 67{ return E_NOTIMPL; } 68 69SK_STDMETHODIMP SkBaseIStream::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) 70{ return E_NOTIMPL; } 71 72SK_STDMETHODIMP SkBaseIStream::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) 73{ return E_NOTIMPL; } 74 75SK_STDMETHODIMP SkBaseIStream::Clone(IStream**) 76{ return E_NOTIMPL; } 77 78SK_STDMETHODIMP SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove, 79 DWORD dwOrigin, 80 ULARGE_INTEGER* lpNewFilePointer) 81{ return E_NOTIMPL; } 82 83SK_STDMETHODIMP SkBaseIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) 84{ return E_NOTIMPL; } 85 86 87/** 88 * SkIStream 89 */ 90SkIStream::SkIStream(std::unique_ptr<SkStreamAsset> stream) 91 : SkBaseIStream() 92 , fSkStream(std::move(stream)) 93 , fLocation() 94{ 95 this->fSkStream->rewind(); 96} 97 98SkIStream::~SkIStream() {} 99 100HRESULT SkIStream::CreateFromSkStream(std::unique_ptr<SkStreamAsset> stream, IStream** ppStream) { 101 if (nullptr == stream) { 102 return E_INVALIDARG; 103 } 104 *ppStream = new SkIStream(std::move(stream)); 105 return S_OK; 106} 107 108// ISequentialStream Interface 109SK_STDMETHODIMP SkIStream::Read(void* pv, ULONG cb, ULONG* pcbRead) { 110 *pcbRead = static_cast<ULONG>(this->fSkStream->read(pv, cb)); 111 this->fLocation.QuadPart += *pcbRead; 112 return (*pcbRead == cb) ? S_OK : S_FALSE; 113} 114 115SK_STDMETHODIMP SkIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) { 116 return STG_E_CANTSAVE; 117} 118 119// IStream Interface 120SK_STDMETHODIMP SkIStream::Seek(LARGE_INTEGER liDistanceToMove, 121 DWORD dwOrigin, 122 ULARGE_INTEGER* lpNewFilePointer) 123{ 124 HRESULT hr = S_OK; 125 126 switch(dwOrigin) { 127 case STREAM_SEEK_SET: { 128 if (!this->fSkStream->rewind()) { 129 hr = E_FAIL; 130 } else { 131 size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart); 132 size_t skipped = this->fSkStream->skip(skip); 133 this->fLocation.QuadPart = skipped; 134 if (skipped != skip) { 135 hr = E_FAIL; 136 } 137 } 138 break; 139 } 140 case STREAM_SEEK_CUR: { 141 size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart); 142 size_t skipped = this->fSkStream->skip(skip); 143 this->fLocation.QuadPart += skipped; 144 if (skipped != skip) { 145 hr = E_FAIL; 146 } 147 break; 148 } 149 case STREAM_SEEK_END: { 150 if (!this->fSkStream->rewind()) { 151 hr = E_FAIL; 152 } else { 153 size_t skip = static_cast<size_t>(this->fSkStream->getLength() + 154 liDistanceToMove.QuadPart); 155 size_t skipped = this->fSkStream->skip(skip); 156 this->fLocation.QuadPart = skipped; 157 if (skipped != skip) { 158 hr = E_FAIL; 159 } 160 } 161 break; 162 } 163 default: 164 hr = STG_E_INVALIDFUNCTION; 165 break; 166 } 167 168 if (lpNewFilePointer) { 169 lpNewFilePointer->QuadPart = this->fLocation.QuadPart; 170 } 171 return hr; 172} 173 174SK_STDMETHODIMP SkIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) { 175 if (0 == (grfStatFlag & STATFLAG_NONAME)) { 176 return STG_E_INVALIDFLAG; 177 } 178 pStatstg->pwcsName = nullptr; 179 pStatstg->cbSize.QuadPart = this->fSkStream->getLength(); 180 pStatstg->clsid = CLSID_NULL; 181 pStatstg->type = STGTY_STREAM; 182 pStatstg->grfMode = STGM_READ; 183 return S_OK; 184} 185 186 187/** 188 * SkIWStream 189 */ 190SkWIStream::SkWIStream(SkWStream* stream) 191 : SkBaseIStream() 192 , fSkWStream(stream) 193{ } 194 195SkWIStream::~SkWIStream() { 196 if (this->fSkWStream) { 197 this->fSkWStream->flush(); 198 } 199} 200 201HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream, IStream ** ppStream) { 202 *ppStream = new SkWIStream(stream); 203 return S_OK; 204} 205 206// ISequentialStream Interface 207SK_STDMETHODIMP SkWIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) { 208 HRESULT hr = S_OK; 209 bool wrote = this->fSkWStream->write(pv, cb); 210 if (wrote) { 211 *pcbWritten = cb; 212 } else { 213 *pcbWritten = 0; 214 hr = S_FALSE; 215 } 216 return hr; 217} 218 219// IStream Interface 220SK_STDMETHODIMP SkWIStream::Commit(DWORD) { 221 this->fSkWStream->flush(); 222 return S_OK; 223} 224 225SK_STDMETHODIMP SkWIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) { 226 if (0 == (grfStatFlag & STATFLAG_NONAME)) { 227 return STG_E_INVALIDFLAG; 228 } 229 pStatstg->pwcsName = nullptr; 230 pStatstg->cbSize.QuadPart = 0; 231 pStatstg->clsid = CLSID_NULL; 232 pStatstg->type = STGTY_STREAM; 233 pStatstg->grfMode = STGM_WRITE; 234 return S_OK; 235} 236#endif//defined(SK_BUILD_FOR_WIN) 237