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