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