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