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