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