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_WIN) 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 skip = static_cast<size_t>(liDistanceToMove.QuadPart); 157 size_t skipped = this->fSkStream->skip(skip); 158 this->fLocation.QuadPart = skipped; 159 if (skipped != skip) { 160 hr = E_FAIL; 161 } 162 } 163 break; 164 } 165 case STREAM_SEEK_CUR: { 166 size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart); 167 size_t skipped = this->fSkStream->skip(skip); 168 this->fLocation.QuadPart += skipped; 169 if (skipped != skip) { 170 hr = E_FAIL; 171 } 172 break; 173 } 174 case STREAM_SEEK_END: { 175 if (!this->fSkStream->rewind()) { 176 hr = E_FAIL; 177 } else { 178 // FIXME: Should not depend on getLength. 179 // See https://code.google.com/p/skia/issues/detail?id=1570 180 size_t skip = static_cast<size_t>(this->fSkStream->getLength() + 181 liDistanceToMove.QuadPart); 182 size_t skipped = this->fSkStream->skip(skip); 183 this->fLocation.QuadPart = skipped; 184 if (skipped != skip) { 185 hr = E_FAIL; 186 } 187 } 188 break; 189 } 190 default: 191 hr = STG_E_INVALIDFUNCTION; 192 break; 193 } 194 195 if (lpNewFilePointer) { 196 lpNewFilePointer->QuadPart = this->fLocation.QuadPart; 197 } 198 return hr; 199 } 200 201 HRESULT STDMETHODCALLTYPE SkIStream::Stat(STATSTG* pStatstg 202 , DWORD grfStatFlag) 203 { 204 if (0 == (grfStatFlag & STATFLAG_NONAME)) { 205 return STG_E_INVALIDFLAG; 206 } 207 pStatstg->pwcsName = nullptr; 208 // FIXME: Should not depend on getLength 209 // See https://code.google.com/p/skia/issues/detail?id=1570 210 pStatstg->cbSize.QuadPart = this->fSkStream->getLength(); 211 pStatstg->clsid = CLSID_NULL; 212 pStatstg->type = STGTY_STREAM; 213 pStatstg->grfMode = STGM_READ; 214 return S_OK; 215 } 216 217 218 /** 219 * SkIWStream 220 */ 221 SkWIStream::SkWIStream(SkWStream* stream) 222 : SkBaseIStream() 223 , fSkWStream(stream) 224 { } 225 226 SkWIStream::~SkWIStream() { 227 if (this->fSkWStream) { 228 this->fSkWStream->flush(); 229 } 230 } 231 232 HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream 233 , IStream ** ppStream) 234 { 235 *ppStream = new SkWIStream(stream); 236 return S_OK; 237 } 238 239 // ISequentialStream Interface 240 HRESULT STDMETHODCALLTYPE SkWIStream::Write(void const* pv 241 , ULONG cb 242 , ULONG* pcbWritten) 243 { 244 HRESULT hr = S_OK; 245 bool wrote = this->fSkWStream->write(pv, cb); 246 if (wrote) { 247 *pcbWritten = cb; 248 } else { 249 *pcbWritten = 0; 250 hr = S_FALSE; 251 } 252 return hr; 253 } 254 255 // IStream Interface 256 HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) { 257 this->fSkWStream->flush(); 258 return S_OK; 259 } 260 261 HRESULT STDMETHODCALLTYPE SkWIStream::Stat(STATSTG* pStatstg 262 , DWORD grfStatFlag) 263 { 264 if (0 == (grfStatFlag & STATFLAG_NONAME)) { 265 return STG_E_INVALIDFLAG; 266 } 267 pStatstg->pwcsName = nullptr; 268 pStatstg->cbSize.QuadPart = 0; 269 pStatstg->clsid = CLSID_NULL; 270 pStatstg->type = STGTY_STREAM; 271 pStatstg->grfMode = STGM_WRITE; 272 return S_OK; 273 } 274 #endif//defined(SK_BUILD_FOR_WIN) 275