michael@0: /* -*- Mode: C++; tab-width: 2; 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 "nsBaseContentStream.h" michael@0: #include "nsStreamUtils.h" michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: void michael@0: nsBaseContentStream::DispatchCallback(bool async) michael@0: { michael@0: if (!mCallback) michael@0: return; michael@0: michael@0: // It's important to clear mCallback and mCallbackTarget up-front because the michael@0: // OnInputStreamReady implementation may call our AsyncWait method. michael@0: michael@0: nsCOMPtr callback; michael@0: if (async) { michael@0: callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget); michael@0: mCallback = nullptr; michael@0: } else { michael@0: callback.swap(mCallback); michael@0: } michael@0: mCallbackTarget = nullptr; michael@0: michael@0: callback->OnInputStreamReady(this); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsBaseContentStream::nsISupports michael@0: michael@0: NS_IMPL_ADDREF(nsBaseContentStream) michael@0: NS_IMPL_RELEASE(nsBaseContentStream) michael@0: michael@0: // We only support nsIAsyncInputStream when we are in non-blocking mode. michael@0: NS_INTERFACE_MAP_BEGIN(nsBaseContentStream) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInputStream) michael@0: NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, mNonBlocking) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) michael@0: NS_INTERFACE_MAP_END_THREADSAFE michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsBaseContentStream::nsIInputStream michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::Close() michael@0: { michael@0: return IsClosed() ? NS_OK : CloseWithStatus(NS_BASE_STREAM_CLOSED); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::Available(uint64_t *result) michael@0: { michael@0: *result = 0; michael@0: return mStatus; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::Read(char *buf, uint32_t count, uint32_t *result) michael@0: { michael@0: return ReadSegments(NS_CopySegmentToBuffer, buf, count, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::ReadSegments(nsWriteSegmentFun fun, void *closure, michael@0: uint32_t count, uint32_t *result) michael@0: { michael@0: *result = 0; michael@0: michael@0: if (mStatus == NS_BASE_STREAM_CLOSED) michael@0: return NS_OK; michael@0: michael@0: // No data yet michael@0: if (!IsClosed() && IsNonBlocking()) michael@0: return NS_BASE_STREAM_WOULD_BLOCK; michael@0: michael@0: return mStatus; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::IsNonBlocking(bool *result) michael@0: { michael@0: *result = mNonBlocking; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsBaseContentStream::nsIAsyncInputStream michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::CloseWithStatus(nsresult status) michael@0: { michael@0: if (IsClosed()) michael@0: return NS_OK; michael@0: michael@0: NS_ENSURE_ARG(NS_FAILED(status)); michael@0: mStatus = status; michael@0: michael@0: DispatchCallback(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBaseContentStream::AsyncWait(nsIInputStreamCallback *callback, michael@0: uint32_t flags, uint32_t requestedCount, michael@0: nsIEventTarget *target) michael@0: { michael@0: // Our _only_ consumer is nsInputStreamPump, so we simplify things here by michael@0: // making assumptions about how we will be called. michael@0: NS_ASSERTION(target, "unexpected parameter"); michael@0: NS_ASSERTION(flags == 0, "unexpected parameter"); michael@0: NS_ASSERTION(requestedCount == 0, "unexpected parameter"); michael@0: michael@0: #ifdef DEBUG michael@0: bool correctThread; michael@0: target->IsOnCurrentThread(&correctThread); michael@0: NS_ASSERTION(correctThread, "event target must be on the current thread"); michael@0: #endif michael@0: michael@0: mCallback = callback; michael@0: mCallbackTarget = target; michael@0: michael@0: if (!mCallback) michael@0: return NS_OK; michael@0: michael@0: // If we're already closed, then dispatch this callback immediately. michael@0: if (IsClosed()) { michael@0: DispatchCallback(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: OnCallbackPending(); michael@0: return NS_OK; michael@0: }