|
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 } |