Home | History | Annotate | Download | only in win
      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  */
     19 SkBaseIStream::SkBaseIStream() : _refcount(1) { }
     20 SkBaseIStream::~SkBaseIStream() { }
     21 
     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 
     41 ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) {
     42     return (ULONG)InterlockedIncrement(&_refcount);
     43 }
     44 
     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
     54 HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv
     55                                             , ULONG cb
     56                                             , ULONG* pcbRead)
     57 { return E_NOTIMPL; }
     58 
     59 HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv
     60                                              , ULONG cb
     61                                              , ULONG* pcbWritten)
     62 { return E_NOTIMPL; }
     63 
     64 // IStream Interface
     65 HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER)
     66 { return E_NOTIMPL; }
     67 
     68 HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream*
     69                                               , ULARGE_INTEGER
     70                                               , ULARGE_INTEGER*
     71                                               , ULARGE_INTEGER*)
     72 { return E_NOTIMPL; }
     73 
     74 HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD)
     75 { return E_NOTIMPL; }
     76 
     77 HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void)
     78 { return E_NOTIMPL; }
     79 
     80 HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER
     81                                                   , ULARGE_INTEGER
     82                                                   , DWORD)
     83 { return E_NOTIMPL; }
     84 
     85 HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER
     86                                                     , ULARGE_INTEGER
     87                                                     , DWORD)
     88 { return E_NOTIMPL; }
     89 
     90 HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **)
     91 { return E_NOTIMPL; }
     92 
     93 HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove
     94                                             , DWORD dwOrigin
     95                                             , ULARGE_INTEGER* lpNewFilePointer)
     96 { return E_NOTIMPL; }
     97 
     98 HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg
     99                                             , DWORD grfStatFlag)
    100 { return E_NOTIMPL; }
    101 
    102 
    103 /**
    104  * SkIStream
    105  */
    106 SkIStream::SkIStream(SkStream* stream, bool unrefOnRelease)
    107     : SkBaseIStream()
    108     , fSkStream(stream)
    109     , fUnrefOnRelease(unrefOnRelease)
    110     , fLocation()
    111 {
    112     this->fSkStream->rewind();
    113 }
    114 
    115 SkIStream::~SkIStream() {
    116     if (NULL != this->fSkStream && fUnrefOnRelease) {
    117         this->fSkStream->unref();
    118     }
    119 }
    120 
    121 HRESULT SkIStream::CreateFromSkStream(SkStream* stream
    122                                     , bool unrefOnRelease
    123                                     , IStream ** ppStream)
    124 {
    125     if (NULL == stream) {
    126         return E_INVALIDARG;
    127     }
    128     *ppStream = new SkIStream(stream, unrefOnRelease);
    129     return S_OK;
    130 }
    131 
    132 // ISequentialStream Interface
    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 
    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
    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 (NULL != lpNewFilePointer) {
    200         lpNewFilePointer->QuadPart = this->fLocation.QuadPart;
    201     }
    202     return hr;
    203 }
    204 
    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  */
    225 SkWIStream::SkWIStream(SkWStream* stream)
    226     : SkBaseIStream()
    227     , fSkWStream(stream)
    228 { }
    229 
    230 SkWIStream::~SkWIStream() {
    231     if (NULL != this->fSkWStream) {
    232         this->fSkWStream->flush();
    233     }
    234 }
    235 
    236 HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream
    237                                       , IStream ** ppStream)
    238 {
    239     *ppStream = new SkWIStream(stream);
    240     return S_OK;
    241 }
    242 
    243 // ISequentialStream Interface
    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
    260 HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) {
    261     this->fSkWStream->flush();
    262     return S_OK;
    263 }
    264 
    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