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 */ 21 SkBaseIStream::SkBaseIStream() : _refcount(1) { } 22 SkBaseIStream::~SkBaseIStream() { } 23 24 HRESULT 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 43 ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) { 44 return (ULONG)InterlockedIncrement(&_refcount); 45 } 46 47 ULONG 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 56 HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv 57 , ULONG cb 58 , ULONG* pcbRead) 59 { return E_NOTIMPL; } 60 61 HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv 62 , ULONG cb 63 , ULONG* pcbWritten) 64 { return E_NOTIMPL; } 65 66 // IStream Interface 67 HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER) 68 { return E_NOTIMPL; } 69 70 HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream* 71 , ULARGE_INTEGER 72 , ULARGE_INTEGER* 73 , ULARGE_INTEGER*) 74 { return E_NOTIMPL; } 75 76 HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD) 77 { return E_NOTIMPL; } 78 79 HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void) 80 { return E_NOTIMPL; } 81 82 HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER 83 , ULARGE_INTEGER 84 , DWORD) 85 { return E_NOTIMPL; } 86 87 HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER 88 , ULARGE_INTEGER 89 , DWORD) 90 { return E_NOTIMPL; } 91 92 HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **) 93 { return E_NOTIMPL; } 94 95 HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove 96 , DWORD dwOrigin 97 , ULARGE_INTEGER* lpNewFilePointer) 98 { return E_NOTIMPL; } 99 100 HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg 101 , DWORD grfStatFlag) 102 { return E_NOTIMPL; } 103 104 105 /** 106 * SkIStream 107 */ 108 SkIStream::SkIStream(SkStream* stream, bool deleteOnRelease) 109 : SkBaseIStream() 110 , fSkStream(stream) 111 , fDeleteOnRelease(deleteOnRelease) 112 , fLocation() 113 { 114 this->fSkStream->rewind(); 115 } 116 117 SkIStream::~SkIStream() { 118 if (fDeleteOnRelease) { 119 delete this->fSkStream; 120 } 121 } 122 123 HRESULT 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 135 HRESULT 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 141 HRESULT STDMETHODCALLTYPE SkIStream::Write(void const* pv 142 , ULONG cb 143 , ULONG* pcbWritten) 144 { 145 return STG_E_CANTSAVE; 146 } 147 148 // IStream Interface 149 HRESULT 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 207 HRESULT 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 */ 227 SkWIStream::SkWIStream(SkWStream* stream) 228 : SkBaseIStream() 229 , fSkWStream(stream) 230 { } 231 232 SkWIStream::~SkWIStream() { 233 if (this->fSkWStream) { 234 this->fSkWStream->flush(); 235 } 236 } 237 238 HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream 239 , IStream ** ppStream) 240 { 241 *ppStream = new SkWIStream(stream); 242 return S_OK; 243 } 244 245 // ISequentialStream Interface 246 HRESULT 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 262 HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) { 263 this->fSkWStream->flush(); 264 return S_OK; 265 } 266 267 HRESULT 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