nsStreamUtils.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsStreamUtils.h"
#include "nsCOMPtr.h"
#include "nsIPipe.h"
#include "nsIEventTarget.h"
#include "nsAutoLock.h"
//-----------------------------------------------------------------------------
class nsInputStreamReadyEvent : public PLEvent
, public nsIInputStreamCallback
{
public:
{
}
private:
{
if (mCallback) {
//
// whoa!! looks like we never posted this event. take care to
// release mCallback on the correct thread. if mTarget lives on the
// calling thread, then we are ok. otherwise, we have to try to
// proxy the Release over the right thread. if that thread is dead,
// then there's nothing we can do... better to leak than crash.
//
mCallback = 0;
if (event) {
NS_NOTREACHED("leaking stream event");
}
}
}
}
}
public:
{
// will be released when event is handled
NS_WARNING("PostEvent failed");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
private:
{
// bypass event delivery if this is a cleanup event...
return NULL;
}
{
NS_RELEASE(ev);
}
};
//-----------------------------------------------------------------------------
class nsOutputStreamReadyEvent : public PLEvent
, public nsIOutputStreamCallback
{
public:
{
}
private:
{
if (mCallback) {
//
// whoa!! looks like we never posted this event. take care to
// release mCallback on the correct thread. if mTarget lives on the
// calling thread, then we are ok. otherwise, we have to try to
// proxy the Release over the right thread. if that thread is dead,
// then there's nothing we can do... better to leak than crash.
//
mCallback = 0;
if (event) {
NS_NOTREACHED("leaking stream event");
}
}
}
}
}
public:
{
}
{
// this will be released when the event is handled
NS_WARNING("PostEvent failed");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
private:
{
return NULL;
}
{
}
};
//-----------------------------------------------------------------------------
{
if (!ev)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
{
if (!ev)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
//-----------------------------------------------------------------------------
// NS_AsyncCopy implementation
// abstract stream copier...
class nsAStreamCopier : public nsIInputStreamCallback
, public nsIOutputStreamCallback
{
public:
, mChunkSize(0)
{
}
// virtual since subclasses call superclass Release()
virtual ~nsAStreamCopier()
{
if (mLock)
}
// kick off the async copy...
void *closure,
{
mLock = PR_NewLock();
if (!mLock)
return NS_ERROR_OUT_OF_MEMORY;
return PostContinuationEvent();
}
// implemented by subclasses, returns number of bytes copied and
// sets source and sink condition before returning.
void Process()
{
return;
// ok, copy data from source to sink.
for (;;) {
// need to wait for more data from source. while waiting for
// more source data, be sure to observe failures on output end.
if (mAsyncSink)
mAsyncSink->AsyncWait(this,
0, nsnull);
}
// need to wait for more room in the sink. while waiting for
// more room in the sink, be sure to observer failures on the
// input end.
if (mAsyncSource)
mAsyncSource->AsyncWait(this,
0, nsnull);
}
else {
// close source
if (mAsyncSource)
else
// close sink
if (mAsyncSink)
else
mAsyncSink = nsnull;
// notify state complete...
if (mCallback) {
if (NS_SUCCEEDED(status))
if (status == NS_BASE_STREAM_CLOSED)
}
}
break;
}
}
}
{
return NS_OK;
}
{
return NS_OK;
}
{
// clear "in process" flag and post any pending continuation event
if (self->mEventIsPending) {
}
return nsnull;
}
{
delete event;
}
{
// we cannot post a continuation event if there is currently
// an event in process. doing so could result in Process being
// run simultaneously on multiple threads, so we mark the event
// as pending, and if an event is already in process then we
// just let that existing event take care of posting the real
// continuation event.
return PostContinuationEvent_Locked();
}
{
if (mEventInProcess)
else {
if (!event)
else {
PL_InitEvent(event, this,
if (NS_SUCCEEDED(rv))
else {
NS_ERROR("unable to post continuation event");
}
}
}
return rv;
}
protected:
void *mClosure;
};
class nsStreamCopierIB : public nsAStreamCopier
{
public:
nsStreamCopierIB() : nsAStreamCopier() {}
virtual ~nsStreamCopierIB() {}
struct ReadSegmentsState {
};
void *closure,
const char *buffer,
{
else if (*countWritten == 0)
return state->mSinkCondition;
}
{
PRUint32 n;
return n;
}
};
class nsStreamCopierOB : public nsAStreamCopier
{
public:
nsStreamCopierOB() : nsAStreamCopier() {}
virtual ~nsStreamCopierOB() {}
struct WriteSegmentsState {
};
void *closure,
char *buffer,
{
else if (*countRead == 0)
return state->mSourceCondition;
}
{
PRUint32 n;
return n;
}
};
//-----------------------------------------------------------------------------
void *closure)
{
if (mode == NS_ASYNCCOPY_VIA_READSEGMENTS)
copier = new nsStreamCopierIB();
else
copier = new nsStreamCopierOB();
if (!copier)
return NS_ERROR_OUT_OF_MEMORY;
// Start() takes an owning ref to the copier...
return rv;
}