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