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