Updating (not in the build, yet)

This commit is contained in:
law%netscape.com 1999-07-28 05:37:44 +00:00
parent 418ea5fa47
commit dc6684f17b
2 changed files with 390 additions and 21 deletions

View File

@ -17,19 +17,354 @@
*/
#include "nsStreamXferOp.h"
#include "nsIStreamTransfer.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsFileStream.h"
#include "nsFileSpec.h"
#include "nsIObserver.h"
#include "nsIDOMWindow.h"
#include "nsIScriptGlobalObject.h"
#ifndef NECKO
#include "nsIServiceManager.h"
#include "nsINetService.h"
static NS_DEFINE_IID( kNetServiceCID, NS_NETSERVICE_CID );
#else
#include "nsNeckoUtil.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsIEventQueueService.h"
#include "nsIBufferInputStream.h"
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
#endif // NECKO
#include "jsapi.h"
#include "prprf.h"
#ifdef NS_DEBUG
#define DEBUG_PRINTF PR_fprintf
#else
#define DEBUG_PRINTF (void)
#endif
// ctor - save arguments in data members.
nsStreamXfer::nsStreamXferOp( const nsString &source, const nsString &target )
nsStreamXferOp::nsStreamXferOp( const nsString &source, const nsString &target )
: mSource( source ),
mTarget( target ),
mObserver( 0 ) {
mObserver( 0 ),
mBufLen( 8192 ),
mBuffer( new char[ mBufLen ] ),
mStopped( PR_FALSE ),
mOutput( 0 ) {
// Properly initialize refcnt.
NS_INIT_REFCNT();
}
// dtor - standard
nsStreamXfer::~nsStreamXferOp() {
// dtor
nsStreamXferOp::~nsStreamXferOp() {
// Delete dynamically allocated members (file and buffer).
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp destructor called\n" );
delete mOutput;
delete [] mBuffer;
}
// Invoke nsIDOMWindow::OpenDialog, passing this object as argument.
NS_IMETHODIMP
nsStreamXferOp::OpenDialog( nsIDOMWindow *parent ) {
nsresult rv = NS_OK;
// Get JS context from parent window.
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface( parent, &rv );
if ( NS_SUCCEEDED( rv ) && sgo ) {
nsCOMPtr<nsIScriptContext> context;
sgo->GetContext( getter_AddRefs( context ) );
if ( context ) {
JSContext *jsContext = (JSContext*)context->GetNativeContext();
if ( jsContext ) {
void *stackPtr;
jsval *argv = JS_PushArguments( jsContext,
&stackPtr,
"svs%ip",
"chrome://global/content/downloadProgress.xul",
JSVAL_NULL,
"chrome",
(const nsIID*)(&nsCOMTypeInfo<nsIStreamTransferOperation>::GetIID()),
(nsISupports*)(nsIStreamTransferOperation*)this );
if ( argv ) {
nsIDOMWindow *newWindow;
rv = parent->OpenDialog( jsContext, argv, 4, &newWindow );
if ( NS_SUCCEEDED( rv ) ) {
newWindow->Release();
} else {
}
JS_PopArguments( jsContext, stackPtr );
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: JS_PushArguments failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetNativeContext failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetContext failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: QueryInterface (for nsIScriptGlobalObject) failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
return rv;
}
// Start the download by opening the output file and then loading the source location.
NS_IMETHODIMP
nsStreamXferOp::Start( void ) {
nsresult rv = NS_OK;
if ( !mOutput ) {
// Open the output file stream.
mOutput = new nsOutputFileStream( nsFileSpec( mTarget.GetBuffer() ) );
if ( mOutput ) {
if ( !mOutput->failed() ) {
nsIURI *url = 0;
#ifndef NECKO
rv = NS_NewURL( &url, mSource.GetBuffer() );
if ( NS_SUCCEEDED( rv ) && url ) {
nsINetService *inet = 0;
nsresult rv = nsServiceManager::GetService( kNetServiceCID,
nsCOMTypeInfo<nsINetService>::GetIID(),
(nsISupports**)&inet );
if ( NS_SUCCEEDED( rv ) && inet ) {
rv = inet->OpenStream( url, this );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: OpenStream failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
nsServiceManager::ReleaseService( kNetServiceCID, inet );
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error getting Net Service, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: NS_NewURL failed, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
}
#else
rv = NS_NewURI( &url, mSource.GetBuffer() );
if ( NS_SUCCEEDED( rv ) && url ) {
nsresult rv = NS_OpenURI( this, nsnull, mUrl );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: NS_OpenURI failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: NS_NewURI failed, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
}
#endif // NECKO
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: error opening output file, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)mOutput->error() );
delete mOutput;
mOutput = 0;
}
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: nsStreamXferOp already started\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_ALREADY_INITIALIZED;
}
return rv;
}
// Terminate the download by setting flag (checked in OnDataAvailable).
NS_IMETHODIMP
nsStreamXferOp::Stop( void ) {
nsresult rv = NS_OK;
// Set flag indicating netlib xfer should cease.
mStopped = PR_TRUE;
return rv;
}
// Process the data by reading it and then writing it to the output file.
NS_IMETHODIMP
#ifdef NECKO
nsStreamXferOp::OnDataAvailable( nsIChannel *channel,
nsISupports *aContext,
nsIInputStream *aIStream,
PRUint32 offset,
PRUint32 aLength ) {
#else
nsStreamXferOp::OnDataAvailable( nsIURI *aURL,
nsIInputStream *aIStream,
PRUint32 aLength ) {
#endif
nsresult rv = NS_OK;
// Check for download cancelled by user.
if ( mStopped ) {
// Close the output file.
if ( mOutput ) {
mOutput->close();
}
// Close the input stream.
aIStream->Close();
} else {
// Allocate buffer space.
if ( aLength > mBufLen ) {
char *oldBuffer = mBuffer;
mBuffer = new char[ aLength ];
if ( mBuffer ) {
// Use new (bigger) buffer.
mBufLen = aLength;
// Delete old (smaller) buffer.
delete [] oldBuffer;
} else {
// Keep the one we've got.
mBuffer = oldBuffer;
}
}
// Read the data.
PRUint32 bytesRead;
rv = aIStream->Read( mBuffer, ( mBufLen > aLength ) ? aLength : mBufLen, &bytesRead );
if ( NS_SUCCEEDED(rv) ) {
// Write the data just read to the output stream.
if ( mOutput ) {
mOutput->write( mBuffer, bytesRead );
if ( mOutput->failed() ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error writing file, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)mOutput->error() );
}
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error reading stream, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
return rv;
}
// We aren't interested in this notification; simply return NS_OK.
NS_IMETHODIMP
#ifdef NECKO
nsStreamXferOp::OnStartRequest(nsIChannel* channel, nsISupports* aContext) {
#else
nsStreamXferOp::OnStartRequest(nsIURI* aURL, const char *aContentType) {
#endif
nsresult rv = NS_OK;
return rv;
}
// Pass notification to our observer (if we have one). This object is the
// "subject", the topic is the component progid (plus ";onProgress"), and
// the data is the progress numbers (in the form "%lu %lu" where the first
// value is the number of bytes processed, the second the total number
// expected.
NS_IMETHODIMP
#ifdef NECKO
nsStreamXferOp::OnProgress(nsIChannel* channel, nsISupports* aContext,
PRUint32 aProgress, PRUint32 aProgressMax) {
#else
nsStreamXferOp::OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax) {
#endif
nsresult rv = NS_OK;
if ( mObserver ) {
char buf[32];
PR_snprintf( buf, sizeof buf, "%lu %lu", (unsigned long)aProgress, (unsigned long)aProgressMax );
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsString( NS_ISTREAMTRANSFER_PROGID ";onProgress" ).GetUnicode(),
nsString( buf ).GetUnicode() );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Observe failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
return rv;
}
// Pass notification to our observer (if we have one). This object is the
// "subject", the topic is the component progid (plus ";onStatus"), and
// the data is the status text.
NS_IMETHODIMP
#ifdef NECKO
nsStreamXferOp::OnStatus( nsIChannel *channel,
nsISupports *aContext,
const PRUnichar *aMsg ) {
#else
nsStreamXferOp::OnStatus( nsIURI *aURL,
const PRUnichar *aMsg ) {
#endif
nsresult rv = NS_OK;
if ( mObserver ) {
nsString msg = aMsg;
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsString( NS_ISTREAMTRANSFER_PROGID ";onStatus" ).GetUnicode(),
nsString( msg ).GetUnicode() );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Observe failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
return rv;
}
// Close the output stream. In addition, notify our observer
// (if we have one).
NS_IMETHODIMP
#ifdef NECKO
nsStreamXferOp::OnStopRequest( nsIChannel *channel,
nsISupports *aContext,
nsresult aStatus,
const PRUnichar *aMsg ) {
#else
nsStreamXferOp::OnStopRequest( nsIURI *aURL,
nsresult aStatus,
const PRUnichar *aMsg ) {
#endif
nsresult rv = NS_OK;
// Close the output file.
if ( mOutput ) {
mOutput->close();
}
// Notify observer.
if ( mObserver ) {
nsString msg = aMsg;
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsString( NS_ISTREAMTRANSFER_PROGID ";onCompletion" ).GetUnicode(),
nsString( msg ).GetUnicode() );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Observe failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
return rv;
}
// Attribute getters/setters...
NS_IMETHODIMP
nsStreamXferOp::GetSource( char**result ) {
nsresult rv = NS_OK;
@ -68,7 +403,7 @@ nsStreamXferOp::GetObserver( nsIObserver**result ) {
if ( result ) {
*result = mObserver;
NS_ADDREF( *result );
NS_IF_ADDREF( *result );
} else {
rv = NS_ERROR_NULL_POINTER;
}
@ -80,21 +415,9 @@ NS_IMETHODIMP
nsStreamXferOp::SetObserver( nsIObserver*aObserver ) {
nsresult rv = NS_OK;
NS_IF_RELEASE( mObserver );
mObserver = aObserver;
return rv;
}
NS_IMETHODIMP
nsStreamXferOp::Start( void ) {
nsresult rv = NS_OK;
return rv;
}
NS_IMETHODIMP
nsStreamXferOp::Stop( void ) {
nsresult rv = NS_OK;
NS_IF_ADDREF( mObserver );
return rv;
}
@ -103,3 +426,43 @@ nsStreamXferOp::Stop( void ) {
NS_IMPL_ADDREF( nsStreamXferOp )
NS_IMPL_RELEASE( nsStreamXferOp )
// QueryInterface, supports all the interfaces we implement.
NS_IMETHODIMP
nsStreamXferOp::QueryInterface( REFNSIID aIID, void** aInstancePtr ) {
if (aInstancePtr == NULL) {
return NS_ERROR_NULL_POINTER;
}
// Always NULL result, in case of failure
*aInstancePtr = NULL;
#ifdef NECKO
if (aIID.Equals(nsCOMTypeInfo<nsIProgressEventSink>::GetIID())) {
*aInstancePtr = (void*) ((nsIProgressEventSink*)this);
NS_ADDREF_THIS();
return NS_OK;
}
#endif
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
*aInstancePtr = (void*) ((nsIStreamObserver*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIStreamObserver>::GetIID())) {
*aInstancePtr = (void*) ((nsIStreamObserver*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIStreamListener>::GetIID())) {
*aInstancePtr = (void*) ((nsIStreamListener*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIStreamTransferOperation>::GetIID())) {
*aInstancePtr = (void*) ((nsIStreamTransferOperation*)this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}

View File

@ -18,6 +18,7 @@
#ifndef __nsStreamXferOp_h
#define __nsStreamXferOp_h
#include "nsString.h"
#include "nsIStreamTransferOperation.h"
#include "nsIStreamListener.h"
#ifdef NECKO
@ -25,6 +26,7 @@
#endif
class nsIDOMWindow;
class nsOutputFileStream;
// Implementation of the stream transfer operation interface.
//
@ -69,10 +71,14 @@ public:
#endif
private:
nsString mSource;
nsString mTarget;
nsCString mSource;
nsCString mTarget;
nsIObserver *mObserver; // Not owned; owner should call SetObserver(0) prior
// to this object getting destroyed.
PRUint32 mBufLen;
char *mBuffer; // Owned; deleted in dtor.
PRBool mStopped;
nsOutputFileStream *mOutput; // Owned; deleted in dtor.
}; // nsStreamXferOp