Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "WMF.h" |
michael@0 | 8 | |
michael@0 | 9 | #include <unknwn.h> |
michael@0 | 10 | #include <ole2.h> |
michael@0 | 11 | |
michael@0 | 12 | #include "WMFByteStream.h" |
michael@0 | 13 | #include "WMFSourceReaderCallback.h" |
michael@0 | 14 | #include "WMFUtils.h" |
michael@0 | 15 | #include "MediaResource.h" |
michael@0 | 16 | #include "nsISeekableStream.h" |
michael@0 | 17 | #include "mozilla/RefPtr.h" |
michael@0 | 18 | #include "nsIThreadPool.h" |
michael@0 | 19 | #include "nsXPCOMCIDInternal.h" |
michael@0 | 20 | #include "nsComponentManagerUtils.h" |
michael@0 | 21 | #include "mozilla/DebugOnly.h" |
michael@0 | 22 | #include "SharedThreadPool.h" |
michael@0 | 23 | #include <algorithm> |
michael@0 | 24 | #include <cassert> |
michael@0 | 25 | |
michael@0 | 26 | namespace mozilla { |
michael@0 | 27 | |
michael@0 | 28 | #ifdef PR_LOGGING |
michael@0 | 29 | PRLogModuleInfo* gWMFByteStreamLog = nullptr; |
michael@0 | 30 | #define WMF_BS_LOG(...) PR_LOG(gWMFByteStreamLog, PR_LOG_DEBUG, (__VA_ARGS__)) |
michael@0 | 31 | #else |
michael@0 | 32 | #define WMF_BS_LOG(...) |
michael@0 | 33 | #endif |
michael@0 | 34 | |
michael@0 | 35 | WMFByteStream::WMFByteStream(MediaResource* aResource, |
michael@0 | 36 | WMFSourceReaderCallback* aSourceReaderCallback) |
michael@0 | 37 | : mSourceReaderCallback(aSourceReaderCallback), |
michael@0 | 38 | mResource(aResource), |
michael@0 | 39 | mReentrantMonitor("WMFByteStream.Data"), |
michael@0 | 40 | mOffset(0), |
michael@0 | 41 | mIsShutdown(false) |
michael@0 | 42 | { |
michael@0 | 43 | NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); |
michael@0 | 44 | NS_ASSERTION(mSourceReaderCallback, "Must have a source reader callback."); |
michael@0 | 45 | |
michael@0 | 46 | #ifdef PR_LOGGING |
michael@0 | 47 | if (!gWMFByteStreamLog) { |
michael@0 | 48 | gWMFByteStreamLog = PR_NewLogModule("WMFByteStream"); |
michael@0 | 49 | } |
michael@0 | 50 | #endif |
michael@0 | 51 | WMF_BS_LOG("[%p] WMFByteStream CTOR", this); |
michael@0 | 52 | MOZ_COUNT_CTOR(WMFByteStream); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | WMFByteStream::~WMFByteStream() |
michael@0 | 56 | { |
michael@0 | 57 | MOZ_COUNT_DTOR(WMFByteStream); |
michael@0 | 58 | WMF_BS_LOG("[%p] WMFByteStream DTOR", this); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | nsresult |
michael@0 | 62 | WMFByteStream::Init() |
michael@0 | 63 | { |
michael@0 | 64 | NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); |
michael@0 | 65 | |
michael@0 | 66 | mThreadPool = SharedThreadPool::Get(NS_LITERAL_CSTRING("WMFByteStream IO"), 4); |
michael@0 | 67 | NS_ENSURE_TRUE(mThreadPool, NS_ERROR_FAILURE); |
michael@0 | 68 | |
michael@0 | 69 | NS_ConvertUTF8toUTF16 contentTypeUTF16(mResource->GetContentType()); |
michael@0 | 70 | if (!contentTypeUTF16.IsEmpty()) { |
michael@0 | 71 | HRESULT hr = wmf::MFCreateAttributes(byRef(mAttributes), 1); |
michael@0 | 72 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 73 | |
michael@0 | 74 | hr = mAttributes->SetString(MF_BYTESTREAM_CONTENT_TYPE, |
michael@0 | 75 | contentTypeUTF16.get()); |
michael@0 | 76 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 77 | |
michael@0 | 78 | WMF_BS_LOG("[%p] WMFByteStream has Content-Type=%s", this, mResource->GetContentType().get()); |
michael@0 | 79 | } |
michael@0 | 80 | return NS_OK; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | nsresult |
michael@0 | 84 | WMFByteStream::Shutdown() |
michael@0 | 85 | { |
michael@0 | 86 | { |
michael@0 | 87 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 88 | mIsShutdown = true; |
michael@0 | 89 | } |
michael@0 | 90 | mSourceReaderCallback->Cancel(); |
michael@0 | 91 | return NS_OK; |
michael@0 | 92 | } |
michael@0 | 93 | |
michael@0 | 94 | // IUnknown Methods |
michael@0 | 95 | STDMETHODIMP |
michael@0 | 96 | WMFByteStream::QueryInterface(REFIID aIId, void **aInterface) |
michael@0 | 97 | { |
michael@0 | 98 | WMF_BS_LOG("[%p] WMFByteStream::QueryInterface %s", this, GetGUIDName(aIId).get()); |
michael@0 | 99 | |
michael@0 | 100 | if (aIId == IID_IMFByteStream) { |
michael@0 | 101 | return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface); |
michael@0 | 102 | } |
michael@0 | 103 | if (aIId == IID_IUnknown) { |
michael@0 | 104 | return DoGetInterface(static_cast<IMFByteStream*>(this), aInterface); |
michael@0 | 105 | } |
michael@0 | 106 | if (aIId == IID_IMFAttributes) { |
michael@0 | 107 | return DoGetInterface(static_cast<IMFAttributes*>(this), aInterface); |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | *aInterface = nullptr; |
michael@0 | 111 | return E_NOINTERFACE; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | NS_IMPL_ADDREF(WMFByteStream) |
michael@0 | 115 | NS_IMPL_RELEASE(WMFByteStream) |
michael@0 | 116 | |
michael@0 | 117 | |
michael@0 | 118 | // Stores data regarding an async read opreation. |
michael@0 | 119 | class ReadRequest MOZ_FINAL : public IUnknown { |
michael@0 | 120 | public: |
michael@0 | 121 | ReadRequest(int64_t aOffset, BYTE* aBuffer, ULONG aLength) |
michael@0 | 122 | : mOffset(aOffset), |
michael@0 | 123 | mBuffer(aBuffer), |
michael@0 | 124 | mBufferLength(aLength), |
michael@0 | 125 | mBytesRead(0) |
michael@0 | 126 | {} |
michael@0 | 127 | |
michael@0 | 128 | // IUnknown Methods |
michael@0 | 129 | STDMETHODIMP QueryInterface(REFIID aRIID, LPVOID *aOutObject); |
michael@0 | 130 | STDMETHODIMP_(ULONG) AddRef(); |
michael@0 | 131 | STDMETHODIMP_(ULONG) Release(); |
michael@0 | 132 | |
michael@0 | 133 | int64_t mOffset; |
michael@0 | 134 | BYTE* mBuffer; |
michael@0 | 135 | ULONG mBufferLength; |
michael@0 | 136 | ULONG mBytesRead; |
michael@0 | 137 | |
michael@0 | 138 | // IUnknown ref counting. |
michael@0 | 139 | ThreadSafeAutoRefCnt mRefCnt; |
michael@0 | 140 | NS_DECL_OWNINGTHREAD |
michael@0 | 141 | }; |
michael@0 | 142 | |
michael@0 | 143 | NS_IMPL_ADDREF(ReadRequest) |
michael@0 | 144 | NS_IMPL_RELEASE(ReadRequest) |
michael@0 | 145 | |
michael@0 | 146 | // IUnknown Methods |
michael@0 | 147 | STDMETHODIMP |
michael@0 | 148 | ReadRequest::QueryInterface(REFIID aIId, void **aInterface) |
michael@0 | 149 | { |
michael@0 | 150 | WMF_BS_LOG("ReadRequest::QueryInterface %s", GetGUIDName(aIId).get()); |
michael@0 | 151 | |
michael@0 | 152 | if (aIId == IID_IUnknown) { |
michael@0 | 153 | return DoGetInterface(static_cast<IUnknown*>(this), aInterface); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | *aInterface = nullptr; |
michael@0 | 157 | return E_NOINTERFACE; |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | class ProcessReadRequestEvent MOZ_FINAL : public nsRunnable { |
michael@0 | 161 | public: |
michael@0 | 162 | ProcessReadRequestEvent(WMFByteStream* aStream, |
michael@0 | 163 | IMFAsyncResult* aResult, |
michael@0 | 164 | ReadRequest* aRequestState) |
michael@0 | 165 | : mStream(aStream), |
michael@0 | 166 | mResult(aResult), |
michael@0 | 167 | mRequestState(aRequestState) {} |
michael@0 | 168 | |
michael@0 | 169 | NS_IMETHOD Run() { |
michael@0 | 170 | mStream->ProcessReadRequest(mResult, mRequestState); |
michael@0 | 171 | return NS_OK; |
michael@0 | 172 | } |
michael@0 | 173 | private: |
michael@0 | 174 | RefPtr<WMFByteStream> mStream; |
michael@0 | 175 | RefPtr<IMFAsyncResult> mResult; |
michael@0 | 176 | RefPtr<ReadRequest> mRequestState; |
michael@0 | 177 | }; |
michael@0 | 178 | |
michael@0 | 179 | // IMFByteStream Methods |
michael@0 | 180 | STDMETHODIMP |
michael@0 | 181 | WMFByteStream::BeginRead(BYTE *aBuffer, |
michael@0 | 182 | ULONG aLength, |
michael@0 | 183 | IMFAsyncCallback *aCallback, |
michael@0 | 184 | IUnknown *aCallerState) |
michael@0 | 185 | { |
michael@0 | 186 | NS_ENSURE_TRUE(aBuffer, E_POINTER); |
michael@0 | 187 | NS_ENSURE_TRUE(aCallback, E_POINTER); |
michael@0 | 188 | |
michael@0 | 189 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 190 | WMF_BS_LOG("[%p] WMFByteStream::BeginRead() mOffset=%lld tell=%lld length=%lu mIsShutdown=%d", |
michael@0 | 191 | this, mOffset, mResource->Tell(), aLength, mIsShutdown); |
michael@0 | 192 | |
michael@0 | 193 | if (mIsShutdown || mOffset < 0) { |
michael@0 | 194 | return E_INVALIDARG; |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | // Create an object to store our state. |
michael@0 | 198 | RefPtr<ReadRequest> requestState = new ReadRequest(mOffset, aBuffer, aLength); |
michael@0 | 199 | |
michael@0 | 200 | // Create an IMFAsyncResult, this is passed back to the caller as a token to |
michael@0 | 201 | // retrieve the number of bytes read. |
michael@0 | 202 | RefPtr<IMFAsyncResult> callersResult; |
michael@0 | 203 | HRESULT hr = wmf::MFCreateAsyncResult(requestState, |
michael@0 | 204 | aCallback, |
michael@0 | 205 | aCallerState, |
michael@0 | 206 | byRef(callersResult)); |
michael@0 | 207 | NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
michael@0 | 208 | |
michael@0 | 209 | // Dispatch an event to perform the read in the thread pool. |
michael@0 | 210 | nsCOMPtr<nsIRunnable> r = new ProcessReadRequestEvent(this, |
michael@0 | 211 | callersResult, |
michael@0 | 212 | requestState); |
michael@0 | 213 | nsresult rv = mThreadPool->Dispatch(r, NS_DISPATCH_NORMAL); |
michael@0 | 214 | |
michael@0 | 215 | if (mResource->GetLength() > -1) { |
michael@0 | 216 | mOffset = std::min<int64_t>(mOffset + aLength, mResource->GetLength()); |
michael@0 | 217 | } else { |
michael@0 | 218 | mOffset += aLength; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | return NS_SUCCEEDED(rv) ? S_OK : E_FAIL; |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | nsresult |
michael@0 | 225 | WMFByteStream::Read(ReadRequest* aRequestState) |
michael@0 | 226 | { |
michael@0 | 227 | // Read in a loop to ensure we fill the buffer, when possible. |
michael@0 | 228 | ULONG totalBytesRead = 0; |
michael@0 | 229 | nsresult rv = NS_OK; |
michael@0 | 230 | while (totalBytesRead < aRequestState->mBufferLength) { |
michael@0 | 231 | BYTE* buffer = aRequestState->mBuffer + totalBytesRead; |
michael@0 | 232 | ULONG bytesRead = 0; |
michael@0 | 233 | ULONG length = aRequestState->mBufferLength - totalBytesRead; |
michael@0 | 234 | rv = mResource->ReadAt(aRequestState->mOffset + totalBytesRead, |
michael@0 | 235 | reinterpret_cast<char*>(buffer), |
michael@0 | 236 | length, |
michael@0 | 237 | reinterpret_cast<uint32_t*>(&bytesRead)); |
michael@0 | 238 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 239 | totalBytesRead += bytesRead; |
michael@0 | 240 | if (bytesRead == 0) { |
michael@0 | 241 | break; |
michael@0 | 242 | } |
michael@0 | 243 | } |
michael@0 | 244 | aRequestState->mBytesRead = totalBytesRead; |
michael@0 | 245 | return NS_OK; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | // Note: This is called on one of the thread pool's threads. |
michael@0 | 249 | void |
michael@0 | 250 | WMFByteStream::ProcessReadRequest(IMFAsyncResult* aResult, |
michael@0 | 251 | ReadRequest* aRequestState) |
michael@0 | 252 | { |
michael@0 | 253 | if (mResource->GetLength() > -1 && |
michael@0 | 254 | aRequestState->mOffset > mResource->GetLength()) { |
michael@0 | 255 | aResult->SetStatus(S_OK); |
michael@0 | 256 | wmf::MFInvokeCallback(aResult); |
michael@0 | 257 | WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read offset greater than length, soft-failing read", this); |
michael@0 | 258 | return; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | nsresult rv = Read(aRequestState); |
michael@0 | 262 | if (NS_FAILED(rv)) { |
michael@0 | 263 | Shutdown(); |
michael@0 | 264 | aResult->SetStatus(E_ABORT); |
michael@0 | 265 | } else { |
michael@0 | 266 | aResult->SetStatus(S_OK); |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | WMF_BS_LOG("[%p] WMFByteStream::ProcessReadRequest() read %d at %lld finished rv=%x", |
michael@0 | 270 | this, aRequestState->mBytesRead, aRequestState->mOffset, rv); |
michael@0 | 271 | |
michael@0 | 272 | // Let caller know read is complete. |
michael@0 | 273 | DebugOnly<HRESULT> hr = wmf::MFInvokeCallback(aResult); |
michael@0 | 274 | NS_ASSERTION(SUCCEEDED(hr), "Failed to invoke callback!"); |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | STDMETHODIMP |
michael@0 | 278 | WMFByteStream::BeginWrite(const BYTE *, ULONG , |
michael@0 | 279 | IMFAsyncCallback *, |
michael@0 | 280 | IUnknown *) |
michael@0 | 281 | { |
michael@0 | 282 | WMF_BS_LOG("[%p] WMFByteStream::BeginWrite()", this); |
michael@0 | 283 | return E_NOTIMPL; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | STDMETHODIMP |
michael@0 | 287 | WMFByteStream::Close() |
michael@0 | 288 | { |
michael@0 | 289 | WMF_BS_LOG("[%p] WMFByteStream::Close()", this); |
michael@0 | 290 | return S_OK; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | STDMETHODIMP |
michael@0 | 294 | WMFByteStream::EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead) |
michael@0 | 295 | { |
michael@0 | 296 | NS_ENSURE_TRUE(aResult, E_POINTER); |
michael@0 | 297 | NS_ENSURE_TRUE(aBytesRead, E_POINTER); |
michael@0 | 298 | |
michael@0 | 299 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 300 | |
michael@0 | 301 | // Extract our state object. |
michael@0 | 302 | RefPtr<IUnknown> unknown; |
michael@0 | 303 | HRESULT hr = aResult->GetObject(byRef(unknown)); |
michael@0 | 304 | if (FAILED(hr) || !unknown) { |
michael@0 | 305 | return E_INVALIDARG; |
michael@0 | 306 | } |
michael@0 | 307 | ReadRequest* requestState = |
michael@0 | 308 | static_cast<ReadRequest*>(unknown.get()); |
michael@0 | 309 | |
michael@0 | 310 | // Report result. |
michael@0 | 311 | *aBytesRead = requestState->mBytesRead; |
michael@0 | 312 | |
michael@0 | 313 | WMF_BS_LOG("[%p] WMFByteStream::EndRead() offset=%lld *aBytesRead=%u mOffset=%lld status=0x%x hr=0x%x eof=%d", |
michael@0 | 314 | this, requestState->mOffset, *aBytesRead, mOffset, aResult->GetStatus(), hr, IsEOS()); |
michael@0 | 315 | |
michael@0 | 316 | return aResult->GetStatus(); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | STDMETHODIMP |
michael@0 | 320 | WMFByteStream::EndWrite(IMFAsyncResult *, ULONG *) |
michael@0 | 321 | { |
michael@0 | 322 | WMF_BS_LOG("[%p] WMFByteStream::EndWrite()", this); |
michael@0 | 323 | return E_NOTIMPL; |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | STDMETHODIMP |
michael@0 | 327 | WMFByteStream::Flush() |
michael@0 | 328 | { |
michael@0 | 329 | WMF_BS_LOG("[%p] WMFByteStream::Flush()", this); |
michael@0 | 330 | return S_OK; |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | STDMETHODIMP |
michael@0 | 334 | WMFByteStream::GetCapabilities(DWORD *aCapabilities) |
michael@0 | 335 | { |
michael@0 | 336 | WMF_BS_LOG("[%p] WMFByteStream::GetCapabilities()", this); |
michael@0 | 337 | NS_ENSURE_TRUE(aCapabilities, E_POINTER); |
michael@0 | 338 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 339 | bool seekable = mResource->IsTransportSeekable(); |
michael@0 | 340 | bool cached = mResource->IsDataCachedToEndOfResource(0); |
michael@0 | 341 | *aCapabilities = MFBYTESTREAM_IS_READABLE | |
michael@0 | 342 | MFBYTESTREAM_IS_SEEKABLE | |
michael@0 | 343 | (!cached ? MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED : 0) | |
michael@0 | 344 | (!seekable ? MFBYTESTREAM_HAS_SLOW_SEEK : 0); |
michael@0 | 345 | return S_OK; |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | STDMETHODIMP |
michael@0 | 349 | WMFByteStream::GetCurrentPosition(QWORD *aPosition) |
michael@0 | 350 | { |
michael@0 | 351 | NS_ENSURE_TRUE(aPosition, E_POINTER); |
michael@0 | 352 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 353 | // Note: Returning the length of stream as position when read |
michael@0 | 354 | // cursor is < 0 seems to be the behaviour expected by WMF, but |
michael@0 | 355 | // also note it doesn't seem to expect that the position is an |
michael@0 | 356 | // unsigned value since if you seek to > length and read WMF |
michael@0 | 357 | // expects the read to succeed after reading 0 bytes, but if you |
michael@0 | 358 | // seek to < 0 and read, the read is expected to fails... So |
michael@0 | 359 | // go figure... |
michael@0 | 360 | *aPosition = mOffset < 0 ? mResource->GetLength() : mOffset; |
michael@0 | 361 | WMF_BS_LOG("[%p] WMFByteStream::GetCurrentPosition() %lld", this, mOffset); |
michael@0 | 362 | return S_OK; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | STDMETHODIMP |
michael@0 | 366 | WMFByteStream::GetLength(QWORD *aLength) |
michael@0 | 367 | { |
michael@0 | 368 | NS_ENSURE_TRUE(aLength, E_POINTER); |
michael@0 | 369 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 370 | *aLength = mResource->GetLength(); |
michael@0 | 371 | WMF_BS_LOG("[%p] WMFByteStream::GetLength() %lld", this, *aLength); |
michael@0 | 372 | return S_OK; |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | bool |
michael@0 | 376 | WMFByteStream::IsEOS() |
michael@0 | 377 | { |
michael@0 | 378 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 379 | return mResource->GetLength() > -1 && |
michael@0 | 380 | (mOffset < 0 || |
michael@0 | 381 | mOffset >= mResource->GetLength()); |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | STDMETHODIMP |
michael@0 | 385 | WMFByteStream::IsEndOfStream(BOOL *aEndOfStream) |
michael@0 | 386 | { |
michael@0 | 387 | NS_ENSURE_TRUE(aEndOfStream, E_POINTER); |
michael@0 | 388 | *aEndOfStream = IsEOS(); |
michael@0 | 389 | WMF_BS_LOG("[%p] WMFByteStream::IsEndOfStream() %d", this, *aEndOfStream); |
michael@0 | 390 | return S_OK; |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | STDMETHODIMP |
michael@0 | 394 | WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead) |
michael@0 | 395 | { |
michael@0 | 396 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 397 | ReadRequest request(mOffset, aBuffer, aBufferLength); |
michael@0 | 398 | if (NS_FAILED(Read(&request))) { |
michael@0 | 399 | WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset); |
michael@0 | 400 | return E_FAIL; |
michael@0 | 401 | } |
michael@0 | 402 | if (aOutBytesRead) { |
michael@0 | 403 | *aOutBytesRead = request.mBytesRead; |
michael@0 | 404 | } |
michael@0 | 405 | WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u", |
michael@0 | 406 | this, mOffset, aBufferLength, request.mBytesRead); |
michael@0 | 407 | mOffset += request.mBytesRead; |
michael@0 | 408 | return S_OK; |
michael@0 | 409 | } |
michael@0 | 410 | |
michael@0 | 411 | STDMETHODIMP |
michael@0 | 412 | WMFByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin, |
michael@0 | 413 | LONGLONG aSeekOffset, |
michael@0 | 414 | DWORD aSeekFlags, |
michael@0 | 415 | QWORD *aCurrentPosition) |
michael@0 | 416 | { |
michael@0 | 417 | WMF_BS_LOG("[%p] WMFByteStream::Seek(%d, %lld)", this, aSeekOrigin, aSeekOffset); |
michael@0 | 418 | |
michael@0 | 419 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 420 | |
michael@0 | 421 | int64_t offset = mOffset; |
michael@0 | 422 | if (aSeekOrigin == msoBegin) { |
michael@0 | 423 | offset = aSeekOffset; |
michael@0 | 424 | } else { |
michael@0 | 425 | offset += aSeekOffset; |
michael@0 | 426 | } |
michael@0 | 427 | int64_t length = mResource->GetLength(); |
michael@0 | 428 | if (length > -1) { |
michael@0 | 429 | mOffset = std::min<int64_t>(offset, length); |
michael@0 | 430 | } else { |
michael@0 | 431 | mOffset = offset; |
michael@0 | 432 | } |
michael@0 | 433 | if (aCurrentPosition) { |
michael@0 | 434 | *aCurrentPosition = mOffset; |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | return S_OK; |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | STDMETHODIMP |
michael@0 | 441 | WMFByteStream::SetCurrentPosition(QWORD aPosition) |
michael@0 | 442 | { |
michael@0 | 443 | ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
michael@0 | 444 | WMF_BS_LOG("[%p] WMFByteStream::SetCurrentPosition(%lld)", |
michael@0 | 445 | this, aPosition); |
michael@0 | 446 | |
michael@0 | 447 | int64_t length = mResource->GetLength(); |
michael@0 | 448 | if (length > -1) { |
michael@0 | 449 | mOffset = std::min<int64_t>(aPosition, length); |
michael@0 | 450 | } else { |
michael@0 | 451 | mOffset = aPosition; |
michael@0 | 452 | } |
michael@0 | 453 | |
michael@0 | 454 | return S_OK; |
michael@0 | 455 | } |
michael@0 | 456 | |
michael@0 | 457 | STDMETHODIMP |
michael@0 | 458 | WMFByteStream::SetLength(QWORD) |
michael@0 | 459 | { |
michael@0 | 460 | WMF_BS_LOG("[%p] WMFByteStream::SetLength()", this); |
michael@0 | 461 | return E_NOTIMPL; |
michael@0 | 462 | } |
michael@0 | 463 | |
michael@0 | 464 | STDMETHODIMP |
michael@0 | 465 | WMFByteStream::Write(const BYTE *, ULONG, ULONG *) |
michael@0 | 466 | { |
michael@0 | 467 | WMF_BS_LOG("[%p] WMFByteStream::Write()", this); |
michael@0 | 468 | return E_NOTIMPL; |
michael@0 | 469 | } |
michael@0 | 470 | |
michael@0 | 471 | // IMFAttributes methods |
michael@0 | 472 | STDMETHODIMP |
michael@0 | 473 | WMFByteStream::GetItem(REFGUID guidKey, PROPVARIANT* pValue) |
michael@0 | 474 | { |
michael@0 | 475 | MOZ_ASSERT(mAttributes); |
michael@0 | 476 | return mAttributes->GetItem(guidKey, pValue); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | STDMETHODIMP |
michael@0 | 480 | WMFByteStream::GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType) |
michael@0 | 481 | { |
michael@0 | 482 | assert(mAttributes); |
michael@0 | 483 | return mAttributes->GetItemType(guidKey, pType); |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | STDMETHODIMP |
michael@0 | 487 | WMFByteStream::CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult) |
michael@0 | 488 | { |
michael@0 | 489 | assert(mAttributes); |
michael@0 | 490 | return mAttributes->CompareItem(guidKey, Value, pbResult); |
michael@0 | 491 | } |
michael@0 | 492 | |
michael@0 | 493 | STDMETHODIMP |
michael@0 | 494 | WMFByteStream::Compare(IMFAttributes* pTheirs, |
michael@0 | 495 | MF_ATTRIBUTES_MATCH_TYPE MatchType, |
michael@0 | 496 | BOOL* pbResult) |
michael@0 | 497 | { |
michael@0 | 498 | assert(mAttributes); |
michael@0 | 499 | return mAttributes->Compare(pTheirs, MatchType, pbResult); |
michael@0 | 500 | } |
michael@0 | 501 | |
michael@0 | 502 | STDMETHODIMP |
michael@0 | 503 | WMFByteStream::GetUINT32(REFGUID guidKey, UINT32* punValue) |
michael@0 | 504 | { |
michael@0 | 505 | assert(mAttributes); |
michael@0 | 506 | return mAttributes->GetUINT32(guidKey, punValue); |
michael@0 | 507 | } |
michael@0 | 508 | |
michael@0 | 509 | STDMETHODIMP |
michael@0 | 510 | WMFByteStream::GetUINT64(REFGUID guidKey, UINT64* punValue) |
michael@0 | 511 | { |
michael@0 | 512 | assert(mAttributes); |
michael@0 | 513 | return mAttributes->GetUINT64(guidKey, punValue); |
michael@0 | 514 | } |
michael@0 | 515 | |
michael@0 | 516 | STDMETHODIMP |
michael@0 | 517 | WMFByteStream::GetDouble(REFGUID guidKey, double* pfValue) |
michael@0 | 518 | { |
michael@0 | 519 | assert(mAttributes); |
michael@0 | 520 | return mAttributes->GetDouble(guidKey, pfValue); |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | STDMETHODIMP |
michael@0 | 524 | WMFByteStream::GetGUID(REFGUID guidKey, GUID* pguidValue) |
michael@0 | 525 | { |
michael@0 | 526 | assert(mAttributes); |
michael@0 | 527 | return mAttributes->GetGUID(guidKey, pguidValue); |
michael@0 | 528 | } |
michael@0 | 529 | |
michael@0 | 530 | STDMETHODIMP |
michael@0 | 531 | WMFByteStream::GetStringLength(REFGUID guidKey, UINT32* pcchLength) |
michael@0 | 532 | { |
michael@0 | 533 | assert(mAttributes); |
michael@0 | 534 | return mAttributes->GetStringLength(guidKey, pcchLength); |
michael@0 | 535 | } |
michael@0 | 536 | |
michael@0 | 537 | STDMETHODIMP |
michael@0 | 538 | WMFByteStream::GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength) |
michael@0 | 539 | { |
michael@0 | 540 | assert(mAttributes); |
michael@0 | 541 | return mAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); |
michael@0 | 542 | } |
michael@0 | 543 | |
michael@0 | 544 | STDMETHODIMP |
michael@0 | 545 | WMFByteStream::GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength) |
michael@0 | 546 | { |
michael@0 | 547 | assert(mAttributes); |
michael@0 | 548 | return mAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | STDMETHODIMP |
michael@0 | 552 | WMFByteStream::GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize) |
michael@0 | 553 | { |
michael@0 | 554 | assert(mAttributes); |
michael@0 | 555 | return mAttributes->GetBlobSize(guidKey, pcbBlobSize); |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | STDMETHODIMP |
michael@0 | 559 | WMFByteStream::GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize) |
michael@0 | 560 | { |
michael@0 | 561 | assert(mAttributes); |
michael@0 | 562 | return mAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | STDMETHODIMP |
michael@0 | 566 | WMFByteStream::GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize) |
michael@0 | 567 | { |
michael@0 | 568 | assert(mAttributes); |
michael@0 | 569 | return mAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize); |
michael@0 | 570 | } |
michael@0 | 571 | |
michael@0 | 572 | STDMETHODIMP |
michael@0 | 573 | WMFByteStream::GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv) |
michael@0 | 574 | { |
michael@0 | 575 | assert(mAttributes); |
michael@0 | 576 | return mAttributes->GetUnknown(guidKey, riid, ppv); |
michael@0 | 577 | } |
michael@0 | 578 | |
michael@0 | 579 | STDMETHODIMP |
michael@0 | 580 | WMFByteStream::SetItem(REFGUID guidKey, REFPROPVARIANT Value) |
michael@0 | 581 | { |
michael@0 | 582 | assert(mAttributes); |
michael@0 | 583 | return mAttributes->SetItem(guidKey, Value); |
michael@0 | 584 | } |
michael@0 | 585 | |
michael@0 | 586 | STDMETHODIMP |
michael@0 | 587 | WMFByteStream::DeleteItem(REFGUID guidKey) |
michael@0 | 588 | { |
michael@0 | 589 | assert(mAttributes); |
michael@0 | 590 | return mAttributes->DeleteItem(guidKey); |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | STDMETHODIMP |
michael@0 | 594 | WMFByteStream::DeleteAllItems() |
michael@0 | 595 | { |
michael@0 | 596 | assert(mAttributes); |
michael@0 | 597 | return mAttributes->DeleteAllItems(); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | STDMETHODIMP |
michael@0 | 601 | WMFByteStream::SetUINT32(REFGUID guidKey, UINT32 unValue) |
michael@0 | 602 | { |
michael@0 | 603 | assert(mAttributes); |
michael@0 | 604 | return mAttributes->SetUINT32(guidKey, unValue); |
michael@0 | 605 | } |
michael@0 | 606 | |
michael@0 | 607 | STDMETHODIMP |
michael@0 | 608 | WMFByteStream::SetUINT64(REFGUID guidKey,UINT64 unValue) |
michael@0 | 609 | { |
michael@0 | 610 | assert(mAttributes); |
michael@0 | 611 | return mAttributes->SetUINT64(guidKey, unValue); |
michael@0 | 612 | } |
michael@0 | 613 | |
michael@0 | 614 | STDMETHODIMP |
michael@0 | 615 | WMFByteStream::SetDouble(REFGUID guidKey, double fValue) |
michael@0 | 616 | { |
michael@0 | 617 | assert(mAttributes); |
michael@0 | 618 | return mAttributes->SetDouble(guidKey, fValue); |
michael@0 | 619 | } |
michael@0 | 620 | |
michael@0 | 621 | STDMETHODIMP |
michael@0 | 622 | WMFByteStream::SetGUID(REFGUID guidKey, REFGUID guidValue) |
michael@0 | 623 | { |
michael@0 | 624 | assert(mAttributes); |
michael@0 | 625 | return mAttributes->SetGUID(guidKey, guidValue); |
michael@0 | 626 | } |
michael@0 | 627 | |
michael@0 | 628 | STDMETHODIMP |
michael@0 | 629 | WMFByteStream::SetString(REFGUID guidKey, LPCWSTR wszValue) |
michael@0 | 630 | { |
michael@0 | 631 | assert(mAttributes); |
michael@0 | 632 | return mAttributes->SetString(guidKey, wszValue); |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | STDMETHODIMP |
michael@0 | 636 | WMFByteStream::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize) |
michael@0 | 637 | { |
michael@0 | 638 | assert(mAttributes); |
michael@0 | 639 | return mAttributes->SetBlob(guidKey, pBuf, cbBufSize); |
michael@0 | 640 | } |
michael@0 | 641 | |
michael@0 | 642 | STDMETHODIMP |
michael@0 | 643 | WMFByteStream::SetUnknown(REFGUID guidKey, IUnknown* pUnknown) |
michael@0 | 644 | { |
michael@0 | 645 | assert(mAttributes); |
michael@0 | 646 | return mAttributes->SetUnknown(guidKey, pUnknown); |
michael@0 | 647 | } |
michael@0 | 648 | |
michael@0 | 649 | STDMETHODIMP |
michael@0 | 650 | WMFByteStream::LockStore() |
michael@0 | 651 | { |
michael@0 | 652 | assert(mAttributes); |
michael@0 | 653 | return mAttributes->LockStore(); |
michael@0 | 654 | } |
michael@0 | 655 | |
michael@0 | 656 | STDMETHODIMP |
michael@0 | 657 | WMFByteStream::UnlockStore() |
michael@0 | 658 | { |
michael@0 | 659 | assert(mAttributes); |
michael@0 | 660 | return mAttributes->UnlockStore(); |
michael@0 | 661 | } |
michael@0 | 662 | |
michael@0 | 663 | STDMETHODIMP |
michael@0 | 664 | WMFByteStream::GetCount(UINT32* pcItems) |
michael@0 | 665 | { |
michael@0 | 666 | assert(mAttributes); |
michael@0 | 667 | return mAttributes->GetCount(pcItems); |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | STDMETHODIMP |
michael@0 | 671 | WMFByteStream::GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue) |
michael@0 | 672 | { |
michael@0 | 673 | assert(mAttributes); |
michael@0 | 674 | return mAttributes->GetItemByIndex(unIndex, pguidKey, pValue); |
michael@0 | 675 | } |
michael@0 | 676 | |
michael@0 | 677 | STDMETHODIMP |
michael@0 | 678 | WMFByteStream::CopyAllItems(IMFAttributes* pDest) |
michael@0 | 679 | { |
michael@0 | 680 | assert(mAttributes); |
michael@0 | 681 | return mAttributes->CopyAllItems(pDest); |
michael@0 | 682 | } |
michael@0 | 683 | |
michael@0 | 684 | } // namespace mozilla |