nsPreloadedStream.cpp (3901B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "nsPreloadedStream.h" 7 #include "nsIRunnable.h" 8 9 #include "nsThreadUtils.h" 10 #include <algorithm> 11 12 namespace mozilla { 13 namespace net { 14 15 NS_IMPL_ISUPPORTS(nsPreloadedStream, nsIInputStream, nsIAsyncInputStream, 16 nsIInputStreamCallback) 17 18 nsPreloadedStream::nsPreloadedStream(nsIAsyncInputStream* aStream, 19 const char* data, uint32_t datalen) 20 : mStream(aStream), 21 mOffset(0), 22 mLen(datalen), 23 mCallback("nsPreloadedStream") { 24 mBuf = (char*)moz_xmalloc(datalen); 25 memcpy(mBuf, data, datalen); 26 } 27 28 nsPreloadedStream::~nsPreloadedStream() { free(mBuf); } 29 30 NS_IMETHODIMP 31 nsPreloadedStream::Close() { 32 mLen = 0; 33 return mStream->Close(); 34 } 35 36 NS_IMETHODIMP 37 nsPreloadedStream::Available(uint64_t* _retval) { 38 uint64_t avail = 0; 39 40 nsresult rv = mStream->Available(&avail); 41 if (NS_FAILED(rv)) return rv; 42 *_retval = avail + mLen; 43 return NS_OK; 44 } 45 46 NS_IMETHODIMP 47 nsPreloadedStream::StreamStatus() { return mStream->StreamStatus(); } 48 49 NS_IMETHODIMP 50 nsPreloadedStream::Read(char* aBuf, uint32_t aCount, uint32_t* _retval) { 51 if (!mLen) return mStream->Read(aBuf, aCount, _retval); 52 53 uint32_t toRead = std::min(mLen, aCount); 54 memcpy(aBuf, mBuf + mOffset, toRead); 55 mOffset += toRead; 56 mLen -= toRead; 57 *_retval = toRead; 58 return NS_OK; 59 } 60 61 NS_IMETHODIMP 62 nsPreloadedStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, 63 uint32_t aCount, uint32_t* result) { 64 if (!mLen) return mStream->ReadSegments(aWriter, aClosure, aCount, result); 65 66 *result = 0; 67 while (mLen > 0 && aCount > 0) { 68 uint32_t toRead = std::min(mLen, aCount); 69 uint32_t didRead = 0; 70 nsresult rv; 71 72 rv = aWriter(this, aClosure, mBuf + mOffset, *result, toRead, &didRead); 73 74 if (NS_FAILED(rv)) return NS_OK; 75 76 *result += didRead; 77 mOffset += didRead; 78 mLen -= didRead; 79 aCount -= didRead; 80 } 81 82 return NS_OK; 83 } 84 85 NS_IMETHODIMP 86 nsPreloadedStream::IsNonBlocking(bool* _retval) { 87 return mStream->IsNonBlocking(_retval); 88 } 89 90 NS_IMETHODIMP 91 nsPreloadedStream::CloseWithStatus(nsresult aStatus) { 92 mLen = 0; 93 return mStream->CloseWithStatus(aStatus); 94 } 95 96 class RunOnThread : public Runnable { 97 public: 98 RunOnThread(nsIAsyncInputStream* aStream, nsIInputStreamCallback* aCallback) 99 : Runnable("net::RunOnThread"), mStream(aStream), mCallback(aCallback) {} 100 101 virtual ~RunOnThread() = default; 102 103 NS_IMETHOD Run() override { 104 mCallback->OnInputStreamReady(mStream); 105 return NS_OK; 106 } 107 108 private: 109 nsCOMPtr<nsIAsyncInputStream> mStream; 110 nsCOMPtr<nsIInputStreamCallback> mCallback; 111 }; 112 113 NS_IMETHODIMP 114 nsPreloadedStream::AsyncWait(nsIInputStreamCallback* aCallback, uint32_t aFlags, 115 uint32_t aRequestedCount, 116 nsIEventTarget* aEventTarget) { 117 if (!mLen) { 118 { 119 auto lock = mCallback.Lock(); 120 *lock = aCallback; 121 } 122 return mStream->AsyncWait(aCallback ? this : nullptr, aFlags, 123 aRequestedCount, aEventTarget); 124 } 125 126 if (!aCallback) return NS_OK; 127 128 if (!aEventTarget) return aCallback->OnInputStreamReady(this); 129 130 nsCOMPtr<nsIRunnable> event = new RunOnThread(this, aCallback); 131 return aEventTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); 132 } 133 134 NS_IMETHODIMP 135 nsPreloadedStream::OnInputStreamReady(nsIAsyncInputStream* aStream) { 136 nsCOMPtr<nsIInputStreamCallback> callback; 137 { 138 auto lock = mCallback.Lock(); 139 callback = lock->forget(); 140 } 141 if (callback) { 142 return callback->OnInputStreamReady(this); 143 } 144 return NS_OK; 145 } 146 147 } // namespace net 148 } // namespace mozilla