michael@0: /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */ 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: michael@0: #include "BrowserStreamParent.h" michael@0: #include "PluginInstanceParent.h" michael@0: #include "nsNPAPIPlugin.h" michael@0: michael@0: #include "mozilla/unused.h" michael@0: michael@0: // How much data are we willing to send across the wire michael@0: // in one chunk? michael@0: static const int32_t kSendDataChunk = 0x4000; michael@0: michael@0: namespace mozilla { michael@0: namespace plugins { michael@0: michael@0: BrowserStreamParent::BrowserStreamParent(PluginInstanceParent* npp, michael@0: NPStream* stream) michael@0: : mNPP(npp) michael@0: , mStream(stream) michael@0: , mState(ALIVE) michael@0: { michael@0: mStream->pdata = static_cast(this); michael@0: } michael@0: michael@0: BrowserStreamParent::~BrowserStreamParent() michael@0: { michael@0: } michael@0: michael@0: bool michael@0: BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges, michael@0: NPError* result) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: switch (mState) { michael@0: case ALIVE: michael@0: break; michael@0: michael@0: case DYING: michael@0: *result = NPERR_GENERIC_ERROR; michael@0: return true; michael@0: michael@0: default: michael@0: NS_ERROR("Unexpected state"); michael@0: return false; michael@0: } michael@0: michael@0: if (!mStream) michael@0: return false; michael@0: michael@0: if (ranges.size() > INT32_MAX) michael@0: return false; michael@0: michael@0: nsAutoArrayPtr rp(new NPByteRange[ranges.size()]); michael@0: for (uint32_t i = 0; i < ranges.size(); ++i) { michael@0: rp[i].offset = ranges[i].offset; michael@0: rp[i].length = ranges[i].length; michael@0: rp[i].next = &rp[i + 1]; michael@0: } michael@0: rp[ranges.size() - 1].next = nullptr; michael@0: michael@0: *result = mNPP->mNPNIface->requestread(mStream, rp); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: BrowserStreamParent::RecvNPN_DestroyStream(const NPReason& reason) michael@0: { michael@0: switch (mState) { michael@0: case ALIVE: michael@0: break; michael@0: michael@0: case DYING: michael@0: return true; michael@0: michael@0: default: michael@0: NS_ERROR("Unexpected state"); michael@0: return false; michael@0: }; michael@0: michael@0: mNPP->mNPNIface->destroystream(mNPP->mNPP, mStream, reason); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: BrowserStreamParent::NPP_DestroyStream(NPReason reason) michael@0: { michael@0: NS_ASSERTION(ALIVE == mState, "NPP_DestroyStream called twice?"); michael@0: mState = DYING; michael@0: unused << SendNPP_DestroyStream(reason); michael@0: } michael@0: michael@0: bool michael@0: BrowserStreamParent::RecvStreamDestroyed() michael@0: { michael@0: if (DYING != mState) { michael@0: NS_ERROR("Unexpected state"); michael@0: return false; michael@0: } michael@0: michael@0: mStreamPeer = nullptr; michael@0: michael@0: mState = DELETING; michael@0: return Send__delete__(this); michael@0: } michael@0: michael@0: int32_t michael@0: BrowserStreamParent::WriteReady() michael@0: { michael@0: return kSendDataChunk; michael@0: } michael@0: michael@0: int32_t michael@0: BrowserStreamParent::Write(int32_t offset, michael@0: int32_t len, michael@0: void* buffer) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: NS_ASSERTION(ALIVE == mState, "Sending data after NPP_DestroyStream?"); michael@0: NS_ASSERTION(len > 0, "Non-positive length to NPP_Write"); michael@0: michael@0: if (len > kSendDataChunk) michael@0: len = kSendDataChunk; michael@0: michael@0: return SendWrite(offset, michael@0: nsCString(static_cast(buffer), len), michael@0: mStream->end) ? michael@0: len : -1; michael@0: } michael@0: michael@0: void michael@0: BrowserStreamParent::StreamAsFile(const char* fname) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: NS_ASSERTION(ALIVE == mState, michael@0: "Calling streamasfile after NPP_DestroyStream?"); michael@0: michael@0: // Make sure our stream survives until the plugin process tells us we've michael@0: // been destroyed (until RecvStreamDestroyed() is called). Since we retain michael@0: // mStreamPeer at most once, we won't get in trouble if StreamAsFile() is michael@0: // called more than once. michael@0: if (!mStreamPeer) { michael@0: nsNPAPIPlugin::RetainStream(mStream, getter_AddRefs(mStreamPeer)); michael@0: } michael@0: michael@0: unused << SendNPP_StreamAsFile(nsCString(fname)); michael@0: return; michael@0: } michael@0: michael@0: } // namespace plugins michael@0: } // namespace mozilla