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 30 using std::min; 31 using namespace WebCore; 32 33 // MemoryStream --------------------------------------------------------------- 34 35 MemoryStream::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 44 MemoryStream::~MemoryStream() 45 { 46 gClassCount--; 47 gClassNameCount.remove("MemoryStream"); 48 } 49 50 COMPtr<MemoryStream> MemoryStream::createInstance(PassRefPtr<SharedBuffer> buffer) 51 { 52 return new MemoryStream(buffer); 53 } 54 55 // IUnknown ------------------------------------------------------------------- 56 57 HRESULT 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 73 ULONG STDMETHODCALLTYPE MemoryStream::AddRef(void) 74 { 75 return ++m_refCount; 76 } 77 78 ULONG 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 89 HRESULT 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 113 HRESULT 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 124 HRESULT 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 176 HRESULT STDMETHODCALLTYPE MemoryStream::SetSize( 177 /* [in] */ ULARGE_INTEGER /*libNewSize*/) 178 { 179 return STG_E_INVALIDFUNCTION; 180 } 181 182 HRESULT 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 210 HRESULT STDMETHODCALLTYPE MemoryStream::Commit( 211 /* [in] */ DWORD /*grfCommitFlags*/) 212 { 213 return S_OK; 214 } 215 216 HRESULT STDMETHODCALLTYPE MemoryStream::Revert( void) 217 { 218 return S_OK; 219 } 220 221 HRESULT 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 229 HRESULT 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 237 HRESULT 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 253 HRESULT 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