1/* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "WebKitDLL.h" 28#include "MemoryStream.h" 29 30using std::min; 31using namespace WebCore; 32 33// MemoryStream --------------------------------------------------------------- 34 35MemoryStream::MemoryStream(PassRefPtr<SharedBuffer> buffer) 36: m_refCount(0) 37, m_buffer(buffer) 38, m_pos(0) 39{ 40 gClassCount++; 41 gClassNameCount.add("MemoryStream"); 42} 43 44MemoryStream::~MemoryStream() 45{ 46 gClassCount--; 47 gClassNameCount.remove("MemoryStream"); 48} 49 50COMPtr<MemoryStream> MemoryStream::createInstance(PassRefPtr<SharedBuffer> buffer) 51{ 52 return new MemoryStream(buffer); 53} 54 55// IUnknown ------------------------------------------------------------------- 56 57HRESULT STDMETHODCALLTYPE MemoryStream::QueryInterface(REFIID riid, void** ppvObject) 58{ 59 *ppvObject = 0; 60 if (IsEqualGUID(riid, IID_IUnknown)) 61 *ppvObject = static_cast<IUnknown*>(this); 62 else if (IsEqualGUID(riid, IID_ISequentialStream)) 63 *ppvObject = static_cast<ISequentialStream*>(this); 64 else if (IsEqualGUID(riid, IID_IStream)) 65 *ppvObject = static_cast<IStream*>(this); 66 else 67 return E_NOINTERFACE; 68 69 AddRef(); 70 return S_OK; 71} 72 73ULONG STDMETHODCALLTYPE MemoryStream::AddRef(void) 74{ 75 return ++m_refCount; 76} 77 78ULONG STDMETHODCALLTYPE MemoryStream::Release(void) 79{ 80 ULONG newRef = --m_refCount; 81 if (!newRef) 82 delete(this); 83 84 return newRef; 85} 86 87// ISequentialStream ---------------------------------------------------------- 88 89HRESULT STDMETHODCALLTYPE MemoryStream::Read( 90 /* [length_is][size_is][out] */ void* pv, 91 /* [in] */ ULONG cb, 92 /* [out] */ ULONG* pcbRead) 93{ 94 *pcbRead = 0; 95 96 if (!m_buffer) 97 return E_FAIL; 98 99 if (m_pos >= m_buffer->size()) 100 return S_FALSE; 101 102 if (m_pos + cb < m_buffer->size()) 103 *pcbRead = cb; 104 else 105 *pcbRead = (ULONG) (m_buffer->size() - m_pos); 106 107 memcpy(pv, m_buffer->data() + m_pos, *pcbRead); 108 m_pos += *pcbRead; 109 110 return S_OK; 111} 112 113HRESULT STDMETHODCALLTYPE MemoryStream::Write( 114 /* [size_is][in] */ const void* /*pv*/, 115 /* [in] */ ULONG /*cb*/, 116 /* [out] */ ULONG* /*pcbWritten*/) 117{ 118 // we use this for read-only streams 119 return STG_E_ACCESSDENIED; 120} 121 122// IStream -------------------------------------------------------------------- 123 124HRESULT STDMETHODCALLTYPE MemoryStream::Seek( 125 /* [in] */ LARGE_INTEGER dlibMove, 126 /* [in] */ DWORD dwOrigin, 127 /* [out] */ ULARGE_INTEGER* plibNewPosition) 128{ 129 if (!m_buffer) 130 return E_FAIL; 131 132 size_t proposedPos = m_pos; 133 size_t lowPartNeg; 134 switch (dwOrigin) { 135 case STREAM_SEEK_SET: 136 proposedPos = dlibMove.LowPart; 137 if (dlibMove.HighPart) 138 return E_FAIL; 139 break; 140 case STREAM_SEEK_CUR: 141 if (!dlibMove.HighPart) { 142 if (dlibMove.LowPart > (m_buffer->size() - m_pos)) 143 return E_FAIL; 144 proposedPos += dlibMove.LowPart; 145 } else if (dlibMove.HighPart == -1) { 146 lowPartNeg = (~dlibMove.LowPart)+1; 147 if (lowPartNeg > m_pos) 148 return E_FAIL; 149 proposedPos = m_pos - lowPartNeg; 150 } else 151 return E_FAIL; 152 break; 153 case STREAM_SEEK_END: 154 if (dlibMove.HighPart != -1) 155 return E_FAIL; 156 lowPartNeg = (~dlibMove.LowPart)+1; 157 if (lowPartNeg > m_buffer->size()) 158 return E_FAIL; 159 proposedPos = m_buffer->size() - lowPartNeg; 160 break; 161 default: 162 return E_FAIL; 163 } 164 165 if (proposedPos >= m_buffer->size()) 166 return E_FAIL; 167 168 if (plibNewPosition) { 169 plibNewPosition->HighPart = 0; 170 plibNewPosition->LowPart = (DWORD) m_pos; 171 } 172 173 return S_OK; 174} 175 176HRESULT STDMETHODCALLTYPE MemoryStream::SetSize( 177 /* [in] */ ULARGE_INTEGER /*libNewSize*/) 178{ 179 return STG_E_INVALIDFUNCTION; 180} 181 182HRESULT STDMETHODCALLTYPE MemoryStream::CopyTo( 183 /* [unique][in] */ IStream* pstm, 184 /* [in] */ ULARGE_INTEGER cb, 185 /* [out] */ ULARGE_INTEGER* pcbRead, 186 /* [out] */ ULARGE_INTEGER* pcbWritten) 187{ 188 if (!m_buffer) 189 return E_FAIL; 190 if (cb.HighPart) { 191 cb.HighPart = 0; 192 cb.LowPart = (DWORD)-1; 193 } 194 195 ULONG written; 196 ULONG read = min(cb.LowPart, (ULONG)(m_buffer->size()-m_pos)); 197 HRESULT hr = pstm->Write(m_buffer->data()+m_pos, read, &written); 198 if (pcbWritten) { 199 pcbWritten->HighPart = 0; 200 pcbWritten->LowPart = written; 201 } 202 if (pcbRead) { 203 pcbRead->HighPart = 0; 204 pcbRead->LowPart = read; 205 } 206 207 return hr; 208} 209 210HRESULT STDMETHODCALLTYPE MemoryStream::Commit( 211 /* [in] */ DWORD /*grfCommitFlags*/) 212{ 213 return S_OK; 214} 215 216HRESULT STDMETHODCALLTYPE MemoryStream::Revert( void) 217{ 218 return S_OK; 219} 220 221HRESULT STDMETHODCALLTYPE MemoryStream::LockRegion( 222 /* [in] */ ULARGE_INTEGER /*libOffset*/, 223 /* [in] */ ULARGE_INTEGER /*cb*/, 224 /* [in] */ DWORD /*dwLockType*/) 225{ 226 return STG_E_INVALIDFUNCTION; 227} 228 229HRESULT STDMETHODCALLTYPE MemoryStream::UnlockRegion( 230 /* [in] */ ULARGE_INTEGER /*libOffset*/, 231 /* [in] */ ULARGE_INTEGER /*cb*/, 232 /* [in] */ DWORD /*dwLockType*/) 233{ 234 return STG_E_INVALIDFUNCTION; 235} 236 237HRESULT STDMETHODCALLTYPE MemoryStream::Stat( 238 /* [out] */ STATSTG* pstatstg, 239 /* [in] */ DWORD /*grfStatFlag*/) 240{ 241 if (!pstatstg) 242 return E_POINTER; 243 244 if (!m_buffer) 245 return E_FAIL; 246 247 memset(pstatstg, 0, sizeof(STATSTG)); 248 pstatstg->type = STGTY_STREAM; 249 pstatstg->cbSize.LowPart = (DWORD) m_buffer->size(); 250 return S_OK; 251} 252 253HRESULT STDMETHODCALLTYPE MemoryStream::Clone( 254 /* [out] */ IStream** ppstm) 255{ 256 MemoryStream::createInstance(m_buffer).copyRefTo(ppstm); 257 // FIXME: MSDN says we should be returning STG_E_INSUFFICIENT_MEMORY instead of E_OUTOFMEMORY here. 258 return (*ppstm) ? S_OK : E_OUTOFMEMORY; 259} 260