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