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