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 */ 19SkBaseIStream::SkBaseIStream() : _refcount(1) { } 20SkBaseIStream::~SkBaseIStream() { } 21 22HRESULT 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 41ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) { 42 return (ULONG)InterlockedIncrement(&_refcount); 43} 44 45ULONG 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 54HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv 55 , ULONG cb 56 , ULONG* pcbRead) 57{ return E_NOTIMPL; } 58 59HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv 60 , ULONG cb 61 , ULONG* pcbWritten) 62{ return E_NOTIMPL; } 63 64// IStream Interface 65HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER) 66{ return E_NOTIMPL; } 67 68HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream* 69 , ULARGE_INTEGER 70 , ULARGE_INTEGER* 71 , ULARGE_INTEGER*) 72{ return E_NOTIMPL; } 73 74HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD) 75{ return E_NOTIMPL; } 76 77HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void) 78{ return E_NOTIMPL; } 79 80HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER 81 , ULARGE_INTEGER 82 , DWORD) 83{ return E_NOTIMPL; } 84 85HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER 86 , ULARGE_INTEGER 87 , DWORD) 88{ return E_NOTIMPL; } 89 90HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **) 91{ return E_NOTIMPL; } 92 93HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove 94 , DWORD dwOrigin 95 , ULARGE_INTEGER* lpNewFilePointer) 96{ return E_NOTIMPL; } 97 98HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg 99 , DWORD grfStatFlag) 100{ return E_NOTIMPL; } 101 102 103/** 104 * SkIStream 105 */ 106SkIStream::SkIStream(SkStream* stream, bool deleteOnRelease) 107 : SkBaseIStream() 108 , fSkStream(stream) 109 , fDeleteOnRelease(deleteOnRelease) 110 , fLocation() 111{ 112 this->fSkStream->rewind(); 113} 114 115SkIStream::~SkIStream() { 116 if (fDeleteOnRelease) { 117 delete this->fSkStream; 118 } 119} 120 121HRESULT SkIStream::CreateFromSkStream(SkStream* stream 122 , bool deleteOnRelease 123 , IStream ** ppStream) 124{ 125 if (NULL == stream) { 126 return E_INVALIDARG; 127 } 128 *ppStream = new SkIStream(stream, deleteOnRelease); 129 return S_OK; 130} 131 132// ISequentialStream Interface 133HRESULT 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 139HRESULT STDMETHODCALLTYPE SkIStream::Write(void const* pv 140 , ULONG cb 141 , ULONG* pcbWritten) 142{ 143 return STG_E_CANTSAVE; 144} 145 146// IStream Interface 147HRESULT 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 (lpNewFilePointer) { 200 lpNewFilePointer->QuadPart = this->fLocation.QuadPart; 201 } 202 return hr; 203} 204 205HRESULT 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 */ 225SkWIStream::SkWIStream(SkWStream* stream) 226 : SkBaseIStream() 227 , fSkWStream(stream) 228{ } 229 230SkWIStream::~SkWIStream() { 231 if (this->fSkWStream) { 232 this->fSkWStream->flush(); 233 } 234} 235 236HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream 237 , IStream ** ppStream) 238{ 239 *ppStream = new SkWIStream(stream); 240 return S_OK; 241} 242 243// ISequentialStream Interface 244HRESULT 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 260HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) { 261 this->fSkWStream->flush(); 262 return S_OK; 263} 264 265HRESULT 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