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_WIN)
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 skip = static_cast<size_t>(liDistanceToMove.QuadPart);
157             size_t skipped = this->fSkStream->skip(skip);
158             this->fLocation.QuadPart = skipped;
159             if (skipped != skip) {
160                 hr = E_FAIL;
161             }
162         }
163         break;
164     }
165     case STREAM_SEEK_CUR: {
166         size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart);
167         size_t skipped = this->fSkStream->skip(skip);
168         this->fLocation.QuadPart += skipped;
169         if (skipped != skip) {
170             hr = E_FAIL;
171         }
172         break;
173     }
174     case STREAM_SEEK_END: {
175         if (!this->fSkStream->rewind()) {
176             hr = E_FAIL;
177         } else {
178             // FIXME: Should not depend on getLength.
179             // See https://code.google.com/p/skia/issues/detail?id=1570
180             size_t skip = static_cast<size_t>(this->fSkStream->getLength() +
181                                               liDistanceToMove.QuadPart);
182             size_t skipped = this->fSkStream->skip(skip);
183             this->fLocation.QuadPart = skipped;
184             if (skipped != skip) {
185                 hr = E_FAIL;
186             }
187         }
188         break;
189     }
190     default:
191         hr = STG_E_INVALIDFUNCTION;
192         break;
193     }
194 
195     if (lpNewFilePointer) {
196         lpNewFilePointer->QuadPart = this->fLocation.QuadPart;
197     }
198     return hr;
199 }
200 
Stat(STATSTG * pStatstg,DWORD grfStatFlag)201 HRESULT STDMETHODCALLTYPE SkIStream::Stat(STATSTG* pStatstg
202                                         , DWORD grfStatFlag)
203 {
204     if (0 == (grfStatFlag & STATFLAG_NONAME)) {
205         return STG_E_INVALIDFLAG;
206     }
207     pStatstg->pwcsName = nullptr;
208     // FIXME: Should not depend on getLength
209     // See https://code.google.com/p/skia/issues/detail?id=1570
210     pStatstg->cbSize.QuadPart = this->fSkStream->getLength();
211     pStatstg->clsid = CLSID_NULL;
212     pStatstg->type = STGTY_STREAM;
213     pStatstg->grfMode = STGM_READ;
214     return S_OK;
215 }
216 
217 
218 /**
219  * SkIWStream
220  */
SkWIStream(SkWStream * stream)221 SkWIStream::SkWIStream(SkWStream* stream)
222     : SkBaseIStream()
223     , fSkWStream(stream)
224 { }
225 
~SkWIStream()226 SkWIStream::~SkWIStream() {
227     if (this->fSkWStream) {
228         this->fSkWStream->flush();
229     }
230 }
231 
CreateFromSkWStream(SkWStream * stream,IStream ** ppStream)232 HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream
233                                       , IStream ** ppStream)
234 {
235     *ppStream = new SkWIStream(stream);
236     return S_OK;
237 }
238 
239 // ISequentialStream Interface
Write(void const * pv,ULONG cb,ULONG * pcbWritten)240 HRESULT STDMETHODCALLTYPE SkWIStream::Write(void const* pv
241                                           , ULONG cb
242                                           , ULONG* pcbWritten)
243 {
244     HRESULT hr = S_OK;
245     bool wrote = this->fSkWStream->write(pv, cb);
246     if (wrote) {
247         *pcbWritten = cb;
248     } else {
249         *pcbWritten = 0;
250         hr = S_FALSE;
251     }
252     return hr;
253 }
254 
255 // IStream Interface
Commit(DWORD)256 HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) {
257     this->fSkWStream->flush();
258     return S_OK;
259 }
260 
Stat(STATSTG * pStatstg,DWORD grfStatFlag)261 HRESULT STDMETHODCALLTYPE SkWIStream::Stat(STATSTG* pStatstg
262                                          , DWORD grfStatFlag)
263 {
264     if (0 == (grfStatFlag & STATFLAG_NONAME)) {
265         return STG_E_INVALIDFLAG;
266     }
267     pStatstg->pwcsName = nullptr;
268     pStatstg->cbSize.QuadPart = 0;
269     pStatstg->clsid = CLSID_NULL;
270     pStatstg->type = STGTY_STREAM;
271     pStatstg->grfMode = STGM_WRITE;
272     return S_OK;
273 }
274 #endif//defined(SK_BUILD_FOR_WIN)
275