michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPreloadedStream.h" michael@0: #include "nsIRunnable.h" michael@0: michael@0: #include "nsThreadUtils.h" michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPreloadedStream, michael@0: nsIInputStream, michael@0: nsIAsyncInputStream) michael@0: michael@0: nsPreloadedStream::nsPreloadedStream(nsIAsyncInputStream *aStream, michael@0: const char *data, uint32_t datalen) michael@0: : mStream(aStream), michael@0: mOffset(0), michael@0: mLen(datalen) michael@0: { michael@0: mBuf = (char *) moz_xmalloc(datalen); michael@0: memcpy(mBuf, data, datalen); michael@0: } michael@0: michael@0: nsPreloadedStream::~nsPreloadedStream() michael@0: { michael@0: moz_free(mBuf); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::Close() michael@0: { michael@0: mLen = 0; michael@0: return mStream->Close(); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::Available(uint64_t *_retval) michael@0: { michael@0: uint64_t avail = 0; michael@0: michael@0: nsresult rv = mStream->Available(&avail); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: *_retval = avail + mLen; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::Read(char *aBuf, uint32_t aCount, michael@0: uint32_t *_retval) michael@0: { michael@0: if (!mLen) michael@0: return mStream->Read(aBuf, aCount, _retval); michael@0: michael@0: uint32_t toRead = std::min(mLen, aCount); michael@0: memcpy(aBuf, mBuf + mOffset, toRead); michael@0: mOffset += toRead; michael@0: mLen -= toRead; michael@0: *_retval = toRead; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::ReadSegments(nsWriteSegmentFun aWriter, michael@0: void *aClosure, uint32_t aCount, michael@0: uint32_t *result) michael@0: { michael@0: if (!mLen) michael@0: return mStream->ReadSegments(aWriter, aClosure, aCount, result); michael@0: michael@0: *result = 0; michael@0: while (mLen > 0 && aCount > 0) { michael@0: uint32_t toRead = std::min(mLen, aCount); michael@0: uint32_t didRead = 0; michael@0: nsresult rv; michael@0: michael@0: rv = aWriter(this, aClosure, mBuf + mOffset, *result, toRead, &didRead); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return NS_OK; michael@0: michael@0: *result += didRead; michael@0: mOffset += didRead; michael@0: mLen -= didRead; michael@0: aCount -= didRead; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::IsNonBlocking(bool *_retval) michael@0: { michael@0: return mStream->IsNonBlocking(_retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::CloseWithStatus(nsresult aStatus) michael@0: { michael@0: mLen = 0; michael@0: return mStream->CloseWithStatus(aStatus); michael@0: } michael@0: michael@0: class RunOnThread : public nsRunnable michael@0: { michael@0: public: michael@0: RunOnThread(nsIAsyncInputStream *aStream, michael@0: nsIInputStreamCallback *aCallback) michael@0: : mStream(aStream), michael@0: mCallback(aCallback) {} michael@0: michael@0: virtual ~RunOnThread() {} michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: mCallback->OnInputStreamReady(mStream); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mStream; michael@0: nsCOMPtr mCallback; michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: nsPreloadedStream::AsyncWait(nsIInputStreamCallback *aCallback, michael@0: uint32_t aFlags, michael@0: uint32_t aRequestedCount, michael@0: nsIEventTarget *aEventTarget) michael@0: { michael@0: if (!mLen) michael@0: return mStream->AsyncWait(aCallback, aFlags, aRequestedCount, michael@0: aEventTarget); michael@0: michael@0: if (!aCallback) michael@0: return NS_OK; michael@0: michael@0: if (!aEventTarget) michael@0: return aCallback->OnInputStreamReady(this); michael@0: michael@0: nsCOMPtr event = michael@0: new RunOnThread(this, aCallback); michael@0: return aEventTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); michael@0: } michael@0: michael@0: } // namespace net michael@0: } // namespace mozilla