xref: /third_party/skia/src/utils/win/SkIStream.cpp (revision cb93a386)
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 */
17SkBaseIStream::SkBaseIStream() : _refcount(1) { }
18SkBaseIStream::~SkBaseIStream() { }
19
20SK_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
37SK_STDMETHODIMP_(ULONG) SkBaseIStream::AddRef() {
38    return (ULONG)InterlockedIncrement(&_refcount);
39}
40
41SK_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
50SK_STDMETHODIMP SkBaseIStream::Read(void* pv, ULONG cb, ULONG* pcbRead)
51{ return E_NOTIMPL; }
52
53SK_STDMETHODIMP SkBaseIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten)
54{ return E_NOTIMPL; }
55
56// IStream Interface
57SK_STDMETHODIMP SkBaseIStream::SetSize(ULARGE_INTEGER)
58{ return E_NOTIMPL; }
59
60SK_STDMETHODIMP SkBaseIStream::CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*)
61{ return E_NOTIMPL; }
62
63SK_STDMETHODIMP SkBaseIStream::Commit(DWORD)
64{ return E_NOTIMPL; }
65
66SK_STDMETHODIMP SkBaseIStream::Revert()
67{ return E_NOTIMPL; }
68
69SK_STDMETHODIMP SkBaseIStream::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
70{ return E_NOTIMPL; }
71
72SK_STDMETHODIMP SkBaseIStream::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
73{ return E_NOTIMPL; }
74
75SK_STDMETHODIMP SkBaseIStream::Clone(IStream**)
76{ return E_NOTIMPL; }
77
78SK_STDMETHODIMP SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove,
79                                    DWORD dwOrigin,
80                                    ULARGE_INTEGER* lpNewFilePointer)
81{ return E_NOTIMPL; }
82
83SK_STDMETHODIMP SkBaseIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag)
84{ return E_NOTIMPL; }
85
86
87/**
88 * SkIStream
89 */
90SkIStream::SkIStream(std::unique_ptr<SkStreamAsset> stream)
91    : SkBaseIStream()
92    , fSkStream(std::move(stream))
93    , fLocation()
94{
95    this->fSkStream->rewind();
96}
97
98SkIStream::~SkIStream() {}
99
100HRESULT SkIStream::CreateFromSkStream(std::unique_ptr<SkStreamAsset> stream, IStream** ppStream) {
101    if (nullptr == stream) {
102        return E_INVALIDARG;
103    }
104    *ppStream = new SkIStream(std::move(stream));
105    return S_OK;
106}
107
108// ISequentialStream Interface
109SK_STDMETHODIMP SkIStream::Read(void* pv, ULONG cb, ULONG* pcbRead) {
110    *pcbRead = static_cast<ULONG>(this->fSkStream->read(pv, cb));
111    this->fLocation.QuadPart += *pcbRead;
112    return (*pcbRead == cb) ? S_OK : S_FALSE;
113}
114
115SK_STDMETHODIMP SkIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) {
116    return STG_E_CANTSAVE;
117}
118
119// IStream Interface
120SK_STDMETHODIMP SkIStream::Seek(LARGE_INTEGER liDistanceToMove,
121                                DWORD dwOrigin,
122                                ULARGE_INTEGER* lpNewFilePointer)
123{
124    HRESULT hr = S_OK;
125
126    switch(dwOrigin) {
127    case STREAM_SEEK_SET: {
128        if (!this->fSkStream->rewind()) {
129            hr = E_FAIL;
130        } else {
131            size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart);
132            size_t skipped = this->fSkStream->skip(skip);
133            this->fLocation.QuadPart = skipped;
134            if (skipped != skip) {
135                hr = E_FAIL;
136            }
137        }
138        break;
139    }
140    case STREAM_SEEK_CUR: {
141        size_t skip = static_cast<size_t>(liDistanceToMove.QuadPart);
142        size_t skipped = this->fSkStream->skip(skip);
143        this->fLocation.QuadPart += skipped;
144        if (skipped != skip) {
145            hr = E_FAIL;
146        }
147        break;
148    }
149    case STREAM_SEEK_END: {
150        if (!this->fSkStream->rewind()) {
151            hr = E_FAIL;
152        } else {
153            size_t skip = static_cast<size_t>(this->fSkStream->getLength() +
154                                              liDistanceToMove.QuadPart);
155            size_t skipped = this->fSkStream->skip(skip);
156            this->fLocation.QuadPart = skipped;
157            if (skipped != skip) {
158                hr = E_FAIL;
159            }
160        }
161        break;
162    }
163    default:
164        hr = STG_E_INVALIDFUNCTION;
165        break;
166    }
167
168    if (lpNewFilePointer) {
169        lpNewFilePointer->QuadPart = this->fLocation.QuadPart;
170    }
171    return hr;
172}
173
174SK_STDMETHODIMP SkIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) {
175    if (0 == (grfStatFlag & STATFLAG_NONAME)) {
176        return STG_E_INVALIDFLAG;
177    }
178    pStatstg->pwcsName = nullptr;
179    pStatstg->cbSize.QuadPart = this->fSkStream->getLength();
180    pStatstg->clsid = CLSID_NULL;
181    pStatstg->type = STGTY_STREAM;
182    pStatstg->grfMode = STGM_READ;
183    return S_OK;
184}
185
186
187/**
188 * SkIWStream
189 */
190SkWIStream::SkWIStream(SkWStream* stream)
191    : SkBaseIStream()
192    , fSkWStream(stream)
193{ }
194
195SkWIStream::~SkWIStream() {
196    if (this->fSkWStream) {
197        this->fSkWStream->flush();
198    }
199}
200
201HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream, IStream ** ppStream) {
202    *ppStream = new SkWIStream(stream);
203    return S_OK;
204}
205
206// ISequentialStream Interface
207SK_STDMETHODIMP SkWIStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) {
208    HRESULT hr = S_OK;
209    bool wrote = this->fSkWStream->write(pv, cb);
210    if (wrote) {
211        *pcbWritten = cb;
212    } else {
213        *pcbWritten = 0;
214        hr = S_FALSE;
215    }
216    return hr;
217}
218
219// IStream Interface
220SK_STDMETHODIMP SkWIStream::Commit(DWORD) {
221    this->fSkWStream->flush();
222    return S_OK;
223}
224
225SK_STDMETHODIMP SkWIStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) {
226    if (0 == (grfStatFlag & STATFLAG_NONAME)) {
227        return STG_E_INVALIDFLAG;
228    }
229    pStatstg->pwcsName = nullptr;
230    pStatstg->cbSize.QuadPart = 0;
231    pStatstg->clsid = CLSID_NULL;
232    pStatstg->type = STGTY_STREAM;
233    pStatstg->grfMode = STGM_WRITE;
234    return S_OK;
235}
236#endif//defined(SK_BUILD_FOR_WIN)
237