Home | History | Annotate | Download | only in win
      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_WIN32)
     10 
     11 #include "SkIStream.h"
     12 #include "SkStream.h"
     13 
     14 /**
     15  * SkBaseIStream
     16  */
     17 SkBaseIStream::SkBaseIStream() : _refcount(1) { }
     18 SkBaseIStream::~SkBaseIStream() { }
     19 
     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 
     39 ULONG STDMETHODCALLTYPE SkBaseIStream::AddRef(void) {
     40     return (ULONG)InterlockedIncrement(&_refcount);
     41 }
     42 
     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
     52 HRESULT STDMETHODCALLTYPE SkBaseIStream::Read(void* pv
     53                                             , ULONG cb
     54                                             , ULONG* pcbRead)
     55 { return E_NOTIMPL; }
     56 
     57 HRESULT STDMETHODCALLTYPE SkBaseIStream::Write(void const* pv
     58                                              , ULONG cb
     59                                              , ULONG* pcbWritten)
     60 { return E_NOTIMPL; }
     61 
     62 // IStream Interface
     63 HRESULT STDMETHODCALLTYPE SkBaseIStream::SetSize(ULARGE_INTEGER)
     64 { return E_NOTIMPL; }
     65 
     66 HRESULT STDMETHODCALLTYPE SkBaseIStream::CopyTo(IStream*
     67                                               , ULARGE_INTEGER
     68                                               , ULARGE_INTEGER*
     69                                               , ULARGE_INTEGER*)
     70 { return E_NOTIMPL; }
     71 
     72 HRESULT STDMETHODCALLTYPE SkBaseIStream::Commit(DWORD)
     73 { return E_NOTIMPL; }
     74 
     75 HRESULT STDMETHODCALLTYPE SkBaseIStream::Revert(void)
     76 { return E_NOTIMPL; }
     77 
     78 HRESULT STDMETHODCALLTYPE SkBaseIStream::LockRegion(ULARGE_INTEGER
     79                                                   , ULARGE_INTEGER
     80                                                   , DWORD)
     81 { return E_NOTIMPL; }
     82 
     83 HRESULT STDMETHODCALLTYPE SkBaseIStream::UnlockRegion(ULARGE_INTEGER
     84                                                     , ULARGE_INTEGER
     85                                                     , DWORD)
     86 { return E_NOTIMPL; }
     87 
     88 HRESULT STDMETHODCALLTYPE SkBaseIStream::Clone(IStream **)
     89 { return E_NOTIMPL; }
     90 
     91 HRESULT STDMETHODCALLTYPE SkBaseIStream::Seek(LARGE_INTEGER liDistanceToMove
     92                                             , DWORD dwOrigin
     93                                             , ULARGE_INTEGER* lpNewFilePointer)
     94 { return E_NOTIMPL; }
     95 
     96 HRESULT STDMETHODCALLTYPE SkBaseIStream::Stat(STATSTG* pStatstg
     97                                             , DWORD grfStatFlag)
     98 { return E_NOTIMPL; }
     99 
    100 
    101 /**
    102  * SkIStream
    103  */
    104 SkIStream::SkIStream(SkStream* stream, bool deleteOnRelease)
    105     : SkBaseIStream()
    106     , fSkStream(stream)
    107     , fDeleteOnRelease(deleteOnRelease)
    108     , fLocation()
    109 {
    110     this->fSkStream->rewind();
    111 }
    112 
    113 SkIStream::~SkIStream() {
    114     if (fDeleteOnRelease) {
    115         delete this->fSkStream;
    116     }
    117 }
    118 
    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
    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 
    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
    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 skipped = this->fSkStream->skip(
    157                 static_cast<size_t>(liDistanceToMove.QuadPart)
    158             );
    159             this->fLocation.QuadPart = skipped;
    160             if (skipped != liDistanceToMove.QuadPart) {
    161                 hr = E_FAIL;
    162             }
    163         }
    164         break;
    165     }
    166     case STREAM_SEEK_CUR: {
    167         size_t skipped = this->fSkStream->skip(
    168             static_cast<size_t>(liDistanceToMove.QuadPart)
    169         );
    170         this->fLocation.QuadPart += skipped;
    171         if (skipped != liDistanceToMove.QuadPart) {
    172             hr = E_FAIL;
    173         }
    174         break;
    175     }
    176     case STREAM_SEEK_END: {
    177         if (!this->fSkStream->rewind()) {
    178             hr = E_FAIL;
    179         } else {
    180             // FIXME: Should not depend on getLength.
    181             // See https://code.google.com/p/skia/issues/detail?id=1570
    182             LONGLONG skip = this->fSkStream->getLength()
    183                           + liDistanceToMove.QuadPart;
    184             size_t skipped = this->fSkStream->skip(static_cast<size_t>(skip));
    185             this->fLocation.QuadPart = skipped;
    186             if (skipped != skip) {
    187                 hr = E_FAIL;
    188             }
    189         }
    190         break;
    191     }
    192     default:
    193         hr = STG_E_INVALIDFUNCTION;
    194         break;
    195     }
    196 
    197     if (lpNewFilePointer) {
    198         lpNewFilePointer->QuadPart = this->fLocation.QuadPart;
    199     }
    200     return hr;
    201 }
    202 
    203 HRESULT STDMETHODCALLTYPE SkIStream::Stat(STATSTG* pStatstg
    204                                         , DWORD grfStatFlag)
    205 {
    206     if (0 == (grfStatFlag & STATFLAG_NONAME)) {
    207         return STG_E_INVALIDFLAG;
    208     }
    209     pStatstg->pwcsName = nullptr;
    210     // FIXME: Should not depend on getLength
    211     // See https://code.google.com/p/skia/issues/detail?id=1570
    212     pStatstg->cbSize.QuadPart = this->fSkStream->getLength();
    213     pStatstg->clsid = CLSID_NULL;
    214     pStatstg->type = STGTY_STREAM;
    215     pStatstg->grfMode = STGM_READ;
    216     return S_OK;
    217 }
    218 
    219 
    220 /**
    221  * SkIWStream
    222  */
    223 SkWIStream::SkWIStream(SkWStream* stream)
    224     : SkBaseIStream()
    225     , fSkWStream(stream)
    226 { }
    227 
    228 SkWIStream::~SkWIStream() {
    229     if (this->fSkWStream) {
    230         this->fSkWStream->flush();
    231     }
    232 }
    233 
    234 HRESULT SkWIStream::CreateFromSkWStream(SkWStream* stream
    235                                       , IStream ** ppStream)
    236 {
    237     *ppStream = new SkWIStream(stream);
    238     return S_OK;
    239 }
    240 
    241 // ISequentialStream Interface
    242 HRESULT STDMETHODCALLTYPE SkWIStream::Write(void const* pv
    243                                           , ULONG cb
    244                                           , ULONG* pcbWritten)
    245 {
    246     HRESULT hr = S_OK;
    247     bool wrote = this->fSkWStream->write(pv, cb);
    248     if (wrote) {
    249         *pcbWritten = cb;
    250     } else {
    251         *pcbWritten = 0;
    252         hr = S_FALSE;
    253     }
    254     return hr;
    255 }
    256 
    257 // IStream Interface
    258 HRESULT STDMETHODCALLTYPE SkWIStream::Commit(DWORD) {
    259     this->fSkWStream->flush();
    260     return S_OK;
    261 }
    262 
    263 HRESULT STDMETHODCALLTYPE SkWIStream::Stat(STATSTG* pStatstg
    264                                          , DWORD grfStatFlag)
    265 {
    266     if (0 == (grfStatFlag & STATFLAG_NONAME)) {
    267         return STG_E_INVALIDFLAG;
    268     }
    269     pStatstg->pwcsName = nullptr;
    270     pStatstg->cbSize.QuadPart = 0;
    271     pStatstg->clsid = CLSID_NULL;
    272     pStatstg->type = STGTY_STREAM;
    273     pStatstg->grfMode = STGM_WRITE;
    274     return S_OK;
    275 }
    276 #endif//defined(SK_BUILD_FOR_WIN32)
    277