зеркало из https://github.com/mozilla/gecko-dev.git
Merged in file transport stuff (now file transport is obsolete).
This commit is contained in:
Родитель
b1d48ac370
Коммит
d35036b4b4
|
@ -25,8 +25,9 @@ VPATH = @srcdir@
|
|||
|
||||
XPIDL_MODULE = netwerk_file
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIFileChannel.idl \
|
||||
XPIDLSRCS = \
|
||||
.\nsIFileChannel.idl \
|
||||
.\nsIFileProtocolHandler.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
|
|
@ -27,8 +27,9 @@ PUBLIC = $(DEPTH)\netwerk\dist\include
|
|||
|
||||
XPIDL_MODULE = netwerk_file
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsIFileChannel.idl \
|
||||
XPIDLSRCS = \
|
||||
.\nsIFileChannel.idl \
|
||||
.\nsIFileProtocolHandler.idl \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "nsIChannel.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(73025830-0ce2-11d3-9331-00104ba0fd40)]
|
||||
interface nsIFileChannel : nsIChannel
|
||||
{
|
||||
|
@ -42,6 +44,14 @@ interface nsIFileChannel : nsIChannel
|
|||
*/
|
||||
readonly attribute nsIFileChannel Parent;
|
||||
|
||||
/**
|
||||
* Returns an enumeration of the elements in a directory. Each
|
||||
* element in the enumeration is an nsIFileChannel.
|
||||
* @return NS_ERROR_FAILURE if the current nsIFileChannel does
|
||||
* not specify a directory.
|
||||
*/
|
||||
readonly attribute nsISimpleEnumerator Children;
|
||||
|
||||
/**
|
||||
* Returns a native path string suitable to be passes to native platform
|
||||
* routines.
|
||||
|
@ -64,7 +74,7 @@ interface nsIFileChannel : nsIChannel
|
|||
void Delete();
|
||||
|
||||
/**
|
||||
* Move or renames a file.
|
||||
* Move or rename a file.
|
||||
*/
|
||||
void MoveFrom(in nsIURI src);
|
||||
|
||||
|
@ -102,5 +112,11 @@ interface nsIFileChannel : nsIChannel
|
|||
*/
|
||||
string MakeUniqueFileName(in string baseName);
|
||||
|
||||
/**
|
||||
* Executes a program specified by the file channel.
|
||||
* @param args - The program arguments to run with. If not specified,
|
||||
* the Query portion of the URI is used as the argument string.
|
||||
*/
|
||||
void Execute(in string args);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIProtocolHandler.idl"
|
||||
|
||||
interface nsIFileChannel;
|
||||
|
||||
interface nsIFileProtocolHandler : nsIProtocolHandler
|
||||
{
|
||||
nsIFileChannel NewChannelFromNativePath(in string nativePath);
|
||||
};
|
|
@ -29,18 +29,19 @@ MAKE_OBJ_TYPE=DLL
|
|||
DLLNAME=fileprotocol
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
|
||||
LLIBS= $(LLIBS) \
|
||||
$(LIBNSPR) \
|
||||
$(DIST)\lib\plc3.lib \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
LLIBS= $(LLIBS) \
|
||||
$(LIBNSPR) \
|
||||
$(DIST)\lib\plc3.lib \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
$(DIST)\lib\netwerk.lib \
|
||||
$(NULL)
|
||||
|
||||
MISCDEP=$(LLIBS)
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsFileChannel.obj \
|
||||
.\$(OBJDIR)\nsFileProtocolHandler.obj \
|
||||
.\$(OBJDIR)\nsFileProtocolFactory.obj \
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsFileChannel.obj \
|
||||
.\$(OBJDIR)\nsFileProtocolHandler.obj \
|
||||
.\$(OBJDIR)\nsFileProtocolFactory.obj \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES=-I.
|
||||
|
|
|
@ -24,13 +24,27 @@
|
|||
#include "nsIStreamListener.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsFileProtocolHandler.h"
|
||||
#include "nsIBuffer.h"
|
||||
#include "nsIBufferInputStream.h"
|
||||
#include "nsIBufferOutputStream.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "netCore.h"
|
||||
#include "nsIFileStream.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIURL.h"
|
||||
#include "prio.h"
|
||||
|
||||
NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsFileChannel::nsFileChannel()
|
||||
: mURI(nsnull), mGetter(nsnull), mListener(nsnull), mEventQueue(nsnull)
|
||||
: mURI(nsnull), mGetter(nsnull), mListener(nsnull), mEventQueue(nsnull),
|
||||
mContext(nsnull), mState(ENDED),
|
||||
mSuspended(PR_FALSE), mFileStream(nsnull), mBuffer(nsnull),
|
||||
mBufferStream(nsnull), mStatus(NS_OK), mHandler(nsnull), mSourceOffset(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
@ -44,6 +58,10 @@ nsFileChannel::Init(const char* verb, nsIURI* uri, nsIEventSinkGetter* getter,
|
|||
mGetter = getter;
|
||||
NS_ADDREF(mGetter);
|
||||
|
||||
mLock = PR_NewLock();
|
||||
if (mLock == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = getter->GetEventSink(verb, nsIStreamListener::GetIID(), (nsISupports**)&mListener);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
@ -70,6 +88,13 @@ nsFileChannel::~nsFileChannel()
|
|||
NS_IF_RELEASE(mGetter);
|
||||
NS_IF_RELEASE(mListener);
|
||||
NS_IF_RELEASE(mEventQueue);
|
||||
NS_IF_RELEASE(mContext);
|
||||
NS_IF_RELEASE(mHandler);
|
||||
NS_IF_RELEASE(mFileStream);
|
||||
NS_IF_RELEASE(mBuffer);
|
||||
NS_IF_RELEASE(mBufferStream);
|
||||
if (mLock)
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -78,7 +103,7 @@ nsFileChannel::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_ASSERTION(aInstancePtr, "no instance pointer");
|
||||
if (aIID.Equals(nsIFileChannel::GetIID()) ||
|
||||
aIID.Equals(nsIChannel::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID()) ) {
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = NS_STATIC_CAST(nsIFileChannel*, this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
|
@ -108,19 +133,43 @@ nsFileChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
|
|||
NS_IMETHODIMP
|
||||
nsFileChannel::Cancel()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
mStatus = NS_BINDING_ABORTED;
|
||||
if (mSuspended) {
|
||||
Resume();
|
||||
}
|
||||
mState = ENDING;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::Suspend()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!mSuspended) {
|
||||
// XXX close the stream here?
|
||||
mStatus = mHandler->Suspend(this);
|
||||
mSuspended = PR_TRUE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::Resume()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!mSuspended) {
|
||||
// XXX re-open the stream and seek here?
|
||||
mStatus = mHandler->Resume(this);
|
||||
mSuspended = PR_FALSE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -136,17 +185,41 @@ nsFileChannel::GetURI(nsIURI * *aURI)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::OpenInputStream(PRUint32 startPosition, PRInt32 count,
|
||||
nsIInputStream **_retval)
|
||||
nsFileChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount,
|
||||
nsIInputStream **result)
|
||||
{
|
||||
NS_ASSERTION(startPosition == 0 && count == -1, "fix me");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mState != ENDED)
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
|
||||
nsIStreamListener* syncListener;
|
||||
nsIBufferInputStream* inStr;
|
||||
rv = NS_NewSyncStreamListener(&syncListener, &inStr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mListener = syncListener;
|
||||
mState = START_READ;
|
||||
mSourceOffset = startPosition;
|
||||
mAmount = readCount;
|
||||
|
||||
rv = mHandler->DispatchRequest(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(inStr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*result = inStr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream **_retval)
|
||||
{
|
||||
NS_ASSERTION(startPosition == 0, "fix me");
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -156,8 +229,27 @@ nsFileChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
|
|||
nsIEventQueue *eventQueue,
|
||||
nsIStreamListener *listener)
|
||||
{
|
||||
NS_ASSERTION(startPosition == 0 && readCount == -1, "fix me");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsIStreamListener* asyncListener;
|
||||
rv = NS_NewAsyncStreamListener(&asyncListener, eventQueue, listener);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mListener = asyncListener;
|
||||
|
||||
mContext = ctxt;
|
||||
NS_IF_ADDREF(mContext);
|
||||
|
||||
mState = START_READ;
|
||||
mSourceOffset = startPosition;
|
||||
mAmount = readCount;
|
||||
|
||||
rv = mHandler->DispatchRequest(this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -167,7 +259,8 @@ nsFileChannel::AsyncWrite(nsIInputStream *fromStream,
|
|||
nsIEventQueue *eventQueue,
|
||||
nsIStreamObserver *observer)
|
||||
{
|
||||
NS_ASSERTION(startPosition == 0, "fix me");
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -224,6 +317,104 @@ nsFileChannel::GetParent(nsIFileChannel * *aParent)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsDirEnumerator : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDirEnumerator() : mHandler(nsnull), mDir(nsnull), mNext(nsnull) {
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsresult Init(nsFileProtocolHandler* handler, nsFileSpec& spec) {
|
||||
const char* path = spec.GetNativePathCString();
|
||||
mDir = PR_OpenDir(path);
|
||||
if (mDir == nsnull) // not a directory?
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mHandler = handler;
|
||||
NS_ADDREF(mHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD HasMoreElements(PRBool *result) {
|
||||
nsresult rv;
|
||||
if (mNext == nsnull && mDir) {
|
||||
PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH);
|
||||
if (entry == nsnull) {
|
||||
// end of dir entries
|
||||
|
||||
PRStatus status = PR_CloseDir(mDir);
|
||||
if (status != PR_SUCCESS)
|
||||
return NS_ERROR_FAILURE;
|
||||
mDir = nsnull;
|
||||
|
||||
*result = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char* path = entry->name;
|
||||
rv = mHandler->NewChannelFromNativePath(path, &mNext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ASSERTION(mNext, "NewChannel failed");
|
||||
}
|
||||
*result = mNext != nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetNext(nsISupports **result) {
|
||||
nsresult rv;
|
||||
PRBool hasMore;
|
||||
rv = HasMoreElements(&hasMore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*result = mNext; // might return nsnull
|
||||
mNext = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual ~nsDirEnumerator() {
|
||||
if (mDir) {
|
||||
PRStatus status = PR_CloseDir(mDir);
|
||||
NS_ASSERTION(status == PR_SUCCESS, "close failed");
|
||||
}
|
||||
NS_IF_RELEASE(mHandler);
|
||||
NS_IF_RELEASE(mNext);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsFileProtocolHandler* mHandler;
|
||||
PRDir* mDir;
|
||||
nsIFileChannel* mNext;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDirEnumerator, nsISimpleEnumerator::GetIID());
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::GetChildren(nsISimpleEnumerator * *aChildren)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRBool isDir;
|
||||
rv = IsDirectory(&isDir);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!isDir)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsDirEnumerator* dirEnum = new nsDirEnumerator();
|
||||
if (dirEnum == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(dirEnum);
|
||||
rv = dirEnum->Init(mHandler, mSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(dirEnum);
|
||||
return rv;
|
||||
}
|
||||
*aChildren = dirEnum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::GetNativePath(char * *aNativePath)
|
||||
{
|
||||
|
@ -334,4 +525,143 @@ nsFileChannel::MakeUniqueFileName(const char* baseName, char **_retval)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::Execute(const char *args)
|
||||
{
|
||||
nsresult rv;
|
||||
char* queryArgs = nsnull;
|
||||
|
||||
if (args == nsnull) {
|
||||
nsIURL* url;
|
||||
rv = mURI->QueryInterface(nsIURL::GetIID(), (void**)&url);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = url->GetQuery(&queryArgs);
|
||||
NS_RELEASE(url);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
args = queryArgs;
|
||||
}
|
||||
}
|
||||
|
||||
rv = mSpec.Execute(args);
|
||||
if (queryArgs)
|
||||
nsCRT::free(queryArgs);
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIRunnable methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileChannel::Run(void)
|
||||
{
|
||||
while (mState != ENDED && !mSuspended) {
|
||||
Process();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFileChannel::Process(void)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
switch (mState) {
|
||||
case START_READ: {
|
||||
nsISupports* fs;
|
||||
|
||||
mStatus = mListener->OnStartBinding(mContext); // always send the start notification
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewTypicalInputFileStream(&fs, mSpec);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = fs->QueryInterface(nsIInputStream::GetIID(), (void**)&mFileStream);
|
||||
NS_RELEASE(fs);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewBuffer(&mBuffer, NS_FILE_TRANSPORT_BUFFER_SIZE,
|
||||
NS_FILE_TRANSPORT_BUFFER_SIZE);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewBufferInputStream(&mBufferStream, mBuffer, PR_FALSE);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mState = READING;
|
||||
break;
|
||||
}
|
||||
case READING: {
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
PRUint32 amt;
|
||||
nsIInputStream* inStr = NS_STATIC_CAST(nsIInputStream*, mFileStream);
|
||||
PRUint32 inLen;
|
||||
mStatus = inStr->GetLength(&inLen);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = mBuffer->WriteFrom(inStr, inLen, &amt);
|
||||
if (mStatus == NS_BASE_STREAM_EOF) goto error;
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
// and feed the buffer to the application via the byte buffer stream:
|
||||
// XXX maybe amt should be mBufferStream->GetLength():
|
||||
mStatus = mListener->OnDataAvailable(mContext, mBufferStream, mSourceOffset, amt);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mSourceOffset += amt;
|
||||
|
||||
// stay in the READING state
|
||||
break;
|
||||
}
|
||||
case START_WRITE: {
|
||||
nsISupports* fs;
|
||||
|
||||
mStatus = mListener->OnStartBinding(mContext); // always send the start notification
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewTypicalOutputFileStream(&fs, mSpec);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = fs->QueryInterface(nsIOutputStream::GetIID(), (void**)&mFileStream);
|
||||
NS_RELEASE(fs);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewBuffer(&mBuffer, NS_FILE_TRANSPORT_BUFFER_SIZE,
|
||||
NS_FILE_TRANSPORT_BUFFER_SIZE);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mStatus = NS_NewBufferInputStream(&mBufferStream, mBuffer, PR_FALSE);
|
||||
if (NS_FAILED(mStatus)) goto error;
|
||||
|
||||
mState = WRITING;
|
||||
break;
|
||||
}
|
||||
case WRITING: {
|
||||
break;
|
||||
}
|
||||
case ENDING: {
|
||||
NS_IF_RELEASE(mBufferStream);
|
||||
mBufferStream = nsnull;
|
||||
NS_IF_RELEASE(mFileStream);
|
||||
mFileStream = nsnull;
|
||||
NS_IF_RELEASE(mContext);
|
||||
mContext = nsnull;
|
||||
|
||||
// XXX where do we get the error message?
|
||||
(void)mListener->OnStopBinding(mContext, mStatus, nsnull);
|
||||
|
||||
mState = ENDED;
|
||||
break;
|
||||
}
|
||||
case ENDED: {
|
||||
NS_NOTREACHED("trying to continue an ended file transfer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
mState = ENDING;
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -20,12 +20,18 @@
|
|||
#define nsFileChannel_h__
|
||||
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsFileSpec.h"
|
||||
#include "prlock.h"
|
||||
|
||||
class nsIEventSinkGetter;
|
||||
class nsIStreamListener;
|
||||
class nsFileProtocolHandler;
|
||||
class nsIBaseStream;
|
||||
class nsIBuffer;
|
||||
class nsIBufferInputStream;
|
||||
|
||||
class nsFileChannel : public nsIFileChannel {
|
||||
class nsFileChannel : public nsIFileChannel, public nsIRunnable {
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -75,6 +81,9 @@ public:
|
|||
/* readonly attribute nsIFileChannel Parent; */
|
||||
NS_IMETHOD GetParent(nsIFileChannel * *aParent);
|
||||
|
||||
/* readonly attribute nsISimpleEnumerator Children; */
|
||||
NS_IMETHOD GetChildren(nsISimpleEnumerator * *aChildren);
|
||||
|
||||
/* readonly attribute string NativePath; */
|
||||
NS_IMETHOD GetNativePath(char * *aNativePath);
|
||||
|
||||
|
@ -108,6 +117,14 @@ public:
|
|||
/* string MakeUniqueFileName (in string baseName); */
|
||||
NS_IMETHOD MakeUniqueFileName(const char *baseName, char **_retval);
|
||||
|
||||
/* void Execute (in string args); */
|
||||
NS_IMETHOD Execute(const char *args);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsIRunnable methods:
|
||||
|
||||
NS_IMETHOD Run(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// nsFileChannel:
|
||||
|
||||
|
@ -122,13 +139,42 @@ public:
|
|||
nsresult Init(const char* verb, nsIURI* uri, nsIEventSinkGetter* getter,
|
||||
nsIEventQueue* queue);
|
||||
|
||||
protected:
|
||||
nsIURI* mURI;
|
||||
nsIEventSinkGetter* mGetter; // XXX it seems wrong keeping this -- used by GetParent
|
||||
nsIStreamListener* mListener;
|
||||
nsIEventQueue* mEventQueue;
|
||||
void Process(void);
|
||||
|
||||
nsFileSpec mSpec;
|
||||
enum State {
|
||||
START_READ,
|
||||
READING,
|
||||
START_WRITE,
|
||||
WRITING,
|
||||
ENDING,
|
||||
ENDED
|
||||
};
|
||||
|
||||
protected:
|
||||
nsIURI* mURI;
|
||||
nsIEventSinkGetter* mGetter; // XXX it seems wrong keeping this -- used by GetParent
|
||||
nsIStreamListener* mListener;
|
||||
nsIEventQueue* mEventQueue;
|
||||
|
||||
nsFileSpec mSpec;
|
||||
|
||||
nsISupports* mContext;
|
||||
nsFileProtocolHandler* mHandler;
|
||||
State mState;
|
||||
PRBool mSuspended;
|
||||
|
||||
// state variables:
|
||||
nsIBaseStream* mFileStream; // cast to nsIInputStream/nsIOutputStream for reading/writing
|
||||
nsIBuffer* mBuffer;
|
||||
nsIBufferInputStream* mBufferStream;
|
||||
nsresult mStatus;
|
||||
PRUint32 mSourceOffset;
|
||||
PRInt32 mAmount;
|
||||
|
||||
private:
|
||||
PRLock* mLock;
|
||||
};
|
||||
|
||||
#define NS_FILE_TRANSPORT_BUFFER_SIZE (4*1024)
|
||||
|
||||
#endif // nsFileChannel_h__
|
||||
|
|
|
@ -24,16 +24,34 @@
|
|||
#include "nsIServiceManager.h"
|
||||
#include "nsIEventSinkGetter.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsFileSpec.h"
|
||||
|
||||
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsFileProtocolHandler::nsFileProtocolHandler() {
|
||||
nsFileProtocolHandler::nsFileProtocolHandler()
|
||||
: mPool(nsnull)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsFileProtocolHandler::~nsFileProtocolHandler() {
|
||||
nsresult
|
||||
nsFileProtocolHandler::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = NS_NewThreadPool(&mPool, NS_FILE_TRANSPORT_WORKER_COUNT,
|
||||
NS_FILE_TRANSPORT_WORKER_COUNT, 8*1024);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsFileProtocolHandler::~nsFileProtocolHandler()
|
||||
{
|
||||
// this will wait for all outstanding requests to be processed, then
|
||||
// join with the worker threads, and finally free the pool:
|
||||
NS_IF_RELEASE(mPool);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsFileProtocolHandler, nsIProtocolHandler::GetIID());
|
||||
|
@ -48,7 +66,10 @@ nsFileProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult
|
|||
if (ph == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(ph);
|
||||
nsresult rv = ph->QueryInterface(aIID, aResult);
|
||||
nsresult rv = ph->Init();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = ph->QueryInterface(aIID, aResult);
|
||||
}
|
||||
NS_RELEASE(ph);
|
||||
return rv;
|
||||
}
|
||||
|
@ -150,3 +171,70 @@ nsFileProtocolHandler::NewChannel(const char* verb, nsIURI* url,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileProtocolHandler::NewChannelFromNativePath(const char* nativePath,
|
||||
nsIFileChannel* *result)
|
||||
{
|
||||
nsresult rv;
|
||||
nsFileSpec spec(nativePath);
|
||||
nsFileURL fileURL(spec);
|
||||
const char* urlStr = fileURL.GetURLString();
|
||||
nsIURI* uri;
|
||||
|
||||
rv = NewURI(urlStr, nsnull, &uri);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NewChannel("load", // XXX what should this be?
|
||||
uri,
|
||||
nsnull, // XXX bogus getter
|
||||
nsnull, // XXX bogus
|
||||
(nsIChannel**)result);
|
||||
NS_RELEASE(uri);
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
nsFileProtocolHandler::ProcessPendingRequests(void)
|
||||
{
|
||||
return mPool->ProcessPendingRequests();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileProtocolHandler::DispatchRequest(nsIRunnable* runnable)
|
||||
{
|
||||
return mPool->DispatchRequest(runnable);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
nsFileProtocolHandler::Suspend(nsFileChannel* request)
|
||||
{
|
||||
nsresult rv;
|
||||
if (mSuspended == nsnull) {
|
||||
rv = NS_NewISupportsArray(&mSuspended);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return mSuspended->AppendElement(NS_STATIC_CAST(nsIChannel*, request));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileProtocolHandler::Resume(nsFileChannel* request)
|
||||
{
|
||||
nsresult rv;
|
||||
if (mSuspended == nsnull)
|
||||
return NS_ERROR_FAILURE;
|
||||
// XXX RemoveElement returns a bool instead of nsresult!
|
||||
PRBool removed = mSuspended->RemoveElement(NS_STATIC_CAST(nsIChannel*, request));
|
||||
rv = removed ? NS_OK : NS_ERROR_FAILURE;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// restart the request
|
||||
rv = mPool->DispatchRequest(NS_STATIC_CAST(nsIRunnable*, request));
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
|
||||
#include "nsIProtocolHandler.h"
|
||||
|
||||
class nsISupportsArray;
|
||||
|
||||
#define NS_FILE_TRANSPORT_WORKER_COUNT 4
|
||||
|
||||
// {25029490-F132-11d2-9588-00805F369F95}
|
||||
#define NS_FILEPROTOCOLHANDLER_CID \
|
||||
{ /* fbc81170-1f69-11d3-9344-00104ba0fd40 */ \
|
||||
|
@ -47,6 +51,10 @@ public:
|
|||
nsIEventQueue *eventQueue,
|
||||
nsIChannel **_retval);
|
||||
|
||||
// nsIFileProtocolHandler methods:
|
||||
NS_IMETHOD NewChannelFromNativePath(const char* nativePath,
|
||||
nsIFileChannel* *result);
|
||||
|
||||
// nsFileProtocolHandler methods:
|
||||
nsFileProtocolHandler();
|
||||
virtual ~nsFileProtocolHandler();
|
||||
|
@ -54,8 +62,16 @@ public:
|
|||
static NS_METHOD
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
nsresult Init();
|
||||
nsresult DispatchRequest(nsIRunnable* runnable);
|
||||
nsresult Suspend(nsFileChannel* request);
|
||||
nsresult Resume(nsFileChannel* request);
|
||||
nsresult ProcessPendingRequests(void);
|
||||
|
||||
protected:
|
||||
nsISupports* mEventSinkGetter;
|
||||
nsIThreadPool* mPool;
|
||||
nsISupportsArray* mSuspended;
|
||||
};
|
||||
|
||||
#endif /* nsFileProtocolHandler_h___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче