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