mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
ef9c82db1e
DOM: getting rid of JS_GetContextPrivate wherever possible. Use static parent links where we can. When we do need to find this info about the caller we call a function that knows how to get that info rather than inline calls to JS_GetContextPrivate. This is all required for calling DOM objects on non-DOM JSContexts as we do via xpconnect. XPConnect: basic refactoring work to disassociate wrappers from the JSContext that was active when the wrapper was constructed. This allows for calling into wrapped JS objects on the right JSContext and for proper grouping of wrapped native objects so that they can share proto objects. This also allows for better sharing of objects and lays the foundations for threadsafety and interface flattening. Also, xpconnect tests are reorganized and improved. fixes bugs: 13419, 17736, 17746, 17952, 22086 r=vidur r=mccabe r=norris r=cbegle a=chofmann
1421 lines
36 KiB
C++
1421 lines
36 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape 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 http://www.mozilla.org/NPL/
|
|
*
|
|
* 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 Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
/*
|
|
|
|
A directory viewer object. Parses "application/http-index-format"
|
|
per Lou Montulli's original spec:
|
|
|
|
http://www.area.com/~roeber/file_format.html
|
|
|
|
*/
|
|
|
|
#include "jsapi.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsEscape.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsIContentViewer.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDocumentLoader.h"
|
|
#include "nsIDocumentViewer.h"
|
|
#include "nsIEnumerator.h"
|
|
#include "nsIGenericFactory.h"
|
|
#include "nsIHTTPIndex.h"
|
|
#include "nsIRDFContainer.h"
|
|
#include "nsIRDFContainerUtils.h"
|
|
#include "nsIRDFDataSource.h"
|
|
#include "nsIRDFService.h"
|
|
#include "nsIScriptContext.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsIXPConnect.h"
|
|
#include "nsEnumeratorUtils.h"
|
|
#include "nsRDFCID.h"
|
|
#include "nsString.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "rdf.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Common CIDs
|
|
|
|
// {82776710-5690-11d3-BE36-00104BDE6048}
|
|
#define NS_DIRECTORYVIEWERFACTORY_CID \
|
|
{ 0x82776710, 0x5690, 0x11d3, { 0xbe, 0x36, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } }
|
|
|
|
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
|
|
static NS_DEFINE_CID(kDirectoryViewerFactoryCID, NS_DIRECTORYVIEWERFACTORY_CID);
|
|
static NS_DEFINE_CID(kGenericFactoryCID, NS_GENERICFACTORY_CID);
|
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
|
|
|
#define HTTPINDEX_NAMESPACE_URI "urn:http-index-format:"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsHTTPIndex
|
|
|
|
class nsHTTPIndex : public nsIHTTPIndex
|
|
{
|
|
protected:
|
|
// We grab a reference to the content viewer container (which
|
|
// indirectly owns us) so that we can insert ourselves as a global
|
|
// in the script context _after_ the XUL doc has been embedded into
|
|
// content viewer. We'll know that this has happened once we receive
|
|
// an OnStartRequest() notification
|
|
nsISupports* mContainer; // [WEAK]
|
|
|
|
nsCString mBaseURL;
|
|
|
|
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
|
|
|
nsHTTPIndex(nsISupports* aContainer);
|
|
nsresult Init(nsIURI* aBaseURL);
|
|
virtual ~nsHTTPIndex();
|
|
|
|
public:
|
|
|
|
static nsresult Create(nsIURI* aBaseURI, nsISupports* aContainer, nsIHTTPIndex** aResult);
|
|
|
|
// nsISupports interface
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIHTTPIndex interface
|
|
NS_IMETHOD GetBaseURL(char** _result);
|
|
NS_IMETHOD GetDataSource(nsIRDFDataSource** _result);
|
|
NS_IMETHOD CreateListener(nsIStreamListener** _result);
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsHTTPIndexParser
|
|
//
|
|
|
|
class nsHTTPIndexParser : public nsIStreamListener
|
|
{
|
|
protected:
|
|
static nsrefcnt gRefCnt;
|
|
static nsIRDFService* gRDF;
|
|
static nsIRDFResource* kHTTPIndex_Comment;
|
|
static nsIRDFResource* kHTTPIndex_Filename;
|
|
static nsIRDFResource* kHTTPIndex_Loading;
|
|
static nsIRDFLiteral* kTrueLiteral;
|
|
|
|
static nsresult ParseLiteral(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult);
|
|
static nsresult ParseDate(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult);
|
|
static nsresult ParseInt(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult);
|
|
|
|
struct Field {
|
|
const char* mName;
|
|
nsresult (*mParse)(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult);
|
|
nsIRDFResource* mProperty;
|
|
};
|
|
|
|
static Field gFieldTable[];
|
|
|
|
nsHTTPIndex* mHTTPIndex; // [WEAK]
|
|
|
|
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
|
|
|
nsCOMPtr<nsIURI> mDirectoryURI;
|
|
nsCOMPtr<nsIRDFResource> mDirectory;
|
|
nsCOMPtr<nsIRDFContainer> mDirectoryContainer;
|
|
|
|
nsCAutoString mLine;
|
|
nsresult ProcessData();
|
|
nsresult ParseFormat(const char* aFormatStr);
|
|
nsresult ParseData(const char* aDataStr);
|
|
|
|
nsAutoString mComment;
|
|
|
|
nsVoidArray mFormat;
|
|
|
|
nsHTTPIndexParser(nsHTTPIndex* aHTTPIndex, nsISupports* aContainer);
|
|
nsresult Init();
|
|
|
|
virtual ~nsHTTPIndexParser();
|
|
|
|
// If this is set, then we need to bind the nsIHTTPIndex object to
|
|
// the global object when we get an OnStartRequest() notification
|
|
// (at this point, we'll know that the XUL document has been
|
|
// embedded and the global object won't get clobbered.
|
|
nsISupports* mContainer;
|
|
|
|
public:
|
|
static nsresult Create(nsHTTPIndex* aHTTPIndex,
|
|
nsISupports* aContainer,
|
|
nsIStreamListener** aResult);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSISTREAMOBSERVER
|
|
NS_DECL_NSISTREAMLISTENER
|
|
};
|
|
|
|
|
|
nsrefcnt nsHTTPIndexParser::gRefCnt = 0;
|
|
nsIRDFService* nsHTTPIndexParser::gRDF;
|
|
nsIRDFResource* nsHTTPIndexParser::kHTTPIndex_Comment;
|
|
nsIRDFResource* nsHTTPIndexParser::kHTTPIndex_Filename;
|
|
nsIRDFResource* nsHTTPIndexParser::kHTTPIndex_Loading;
|
|
nsIRDFLiteral* nsHTTPIndexParser::kTrueLiteral;
|
|
|
|
nsHTTPIndexParser::Field
|
|
nsHTTPIndexParser::gFieldTable[] = {
|
|
{ "Filename", nsHTTPIndexParser::ParseLiteral, nsnull },
|
|
{ "Content-Length", nsHTTPIndexParser::ParseInt, nsnull },
|
|
{ "Last-Modified", nsHTTPIndexParser::ParseDate, nsnull },
|
|
{ "Content-Type", nsHTTPIndexParser::ParseLiteral, nsnull },
|
|
{ "File-Type", nsHTTPIndexParser::ParseLiteral, nsnull },
|
|
{ "Permissions", nsHTTPIndexParser::ParseLiteral, nsnull },
|
|
{ nsnull, nsHTTPIndexParser::ParseLiteral, nsnull },
|
|
};
|
|
|
|
nsHTTPIndexParser::nsHTTPIndexParser(nsHTTPIndex* aHTTPIndex, nsISupports* aContainer)
|
|
: mHTTPIndex(aHTTPIndex),
|
|
mContainer(aContainer)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::Init()
|
|
{
|
|
NS_PRECONDITION(mHTTPIndex != nsnull, "not initialized");
|
|
if (! mHTTPIndex)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsresult rv;
|
|
rv = mHTTPIndex->GetDataSource(getter_AddRefs(mDataSource));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// No datasource. Uh oh. We won't be much use then.
|
|
if (! mDataSource)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
if (gRefCnt++ == 0) {
|
|
rv = nsServiceManager::GetService("component://netscape/rdf/rdf-service",
|
|
nsCOMTypeInfo<nsIRDFService>::GetIID(),
|
|
NS_REINTERPRET_CAST(nsISupports**, &gRDF));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = gRDF->GetResource(HTTPINDEX_NAMESPACE_URI "Comment", &kHTTPIndex_Comment);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = gRDF->GetResource(HTTPINDEX_NAMESPACE_URI "Filename", &kHTTPIndex_Filename);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = gRDF->GetResource(HTTPINDEX_NAMESPACE_URI "Loading", &kHTTPIndex_Loading);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = gRDF->GetLiteral(nsAutoString("true").GetUnicode(), &kTrueLiteral);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
for (Field* field = gFieldTable; field->mName; ++field) {
|
|
nsCAutoString str(HTTPINDEX_NAMESPACE_URI);
|
|
str += field->mName;
|
|
|
|
rv = gRDF->GetResource(str, &field->mProperty);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
nsHTTPIndexParser::~nsHTTPIndexParser()
|
|
{
|
|
if (--gRefCnt == 0) {
|
|
NS_IF_RELEASE(kHTTPIndex_Comment);
|
|
NS_IF_RELEASE(kHTTPIndex_Filename);
|
|
NS_IF_RELEASE(kHTTPIndex_Loading);
|
|
NS_IF_RELEASE(kTrueLiteral);
|
|
|
|
for (Field* field = gFieldTable; field->mName; ++field) {
|
|
NS_IF_RELEASE(field->mProperty);
|
|
}
|
|
|
|
nsServiceManager::ReleaseService("component://netscape/rdf/rdf-service", gRDF);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::Create(nsHTTPIndex* aHTTPIndex,
|
|
nsISupports* aContainer,
|
|
nsIStreamListener** aResult)
|
|
{
|
|
NS_PRECONDITION(aHTTPIndex != nsnull, "null ptr");
|
|
if (! aHTTPIndex)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsHTTPIndexParser* result = new nsHTTPIndexParser(aHTTPIndex, aContainer);
|
|
if (! result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsresult rv = result->Init();
|
|
if (NS_FAILED(rv)) {
|
|
delete result;
|
|
return rv;
|
|
}
|
|
|
|
NS_ADDREF(result);
|
|
*aResult = result;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsHTTPIndexParser);
|
|
NS_IMPL_RELEASE(nsHTTPIndexParser);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndexParser::QueryInterface(REFNSIID aIID, void** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
if (! aResult)
|
|
return NS_OK;
|
|
|
|
if (aIID.Equals(nsCOMTypeInfo<nsIStreamListener>::GetIID()) ||
|
|
aIID.Equals(nsCOMTypeInfo<nsIStreamObserver>::GetIID()) ||
|
|
aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
|
*aResult = NS_STATIC_CAST(nsIStreamListener*, this);
|
|
NS_ADDREF(this);
|
|
return NS_OK;
|
|
}
|
|
else {
|
|
*aResult = nsnull;
|
|
return NS_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndexParser::OnStartRequest(nsIChannel* aChannel, nsISupports* aContext)
|
|
{
|
|
nsresult rv;
|
|
|
|
// This should only run once...
|
|
if (mContainer) {
|
|
// We need to undo the AddRef() on the nsHTTPIndex object that
|
|
// happened in nsDirectoryViewerFactory::CreateInstance(). We'll
|
|
// stuff it into an nsCOMPtr (because we _know_ it'll get release
|
|
// if any errors occur)...
|
|
nsCOMPtr<nsIHTTPIndex> httpindex = do_QueryInterface(mHTTPIndex);
|
|
|
|
// ...and then _force_ a release here
|
|
mHTTPIndex->Release();
|
|
|
|
// Now get the content viewer container's script object.
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_GetInterface(mContainer));
|
|
NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIScriptContext> context;
|
|
rv = scriptGlobal->GetContext(getter_AddRefs(context));
|
|
NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
|
|
|
|
JSContext* jscontext = NS_REINTERPRET_CAST(JSContext*, context->GetNativeContext());
|
|
JSObject* global = JS_GetGlobalObject(jscontext);
|
|
|
|
// Using XPConnect, wrap the HTTP index object...
|
|
static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
|
|
NS_WITH_SERVICE(nsIXPConnect, xpc, kXPConnectCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
|
rv = xpc->WrapNative(jscontext,
|
|
global,
|
|
httpindex,
|
|
nsCOMTypeInfo<nsIHTTPIndex>::GetIID(),
|
|
getter_AddRefs(wrapper));
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
JSObject* jsobj;
|
|
rv = wrapper->GetJSObject(&jsobj);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get jsobj from xpconnect wrapper");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
jsval jslistener = OBJECT_TO_JSVAL(jsobj);
|
|
|
|
// ...and stuff it into the global context
|
|
PRBool ok;
|
|
ok = JS_SetProperty(jscontext, global, "HTTPIndex", &jslistener);
|
|
|
|
NS_ASSERTION(ok, "unable to set Listener property");
|
|
if (! ok)
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// Save off some information about the stream we're about to parse.
|
|
rv = aChannel->GetURI(getter_AddRefs(mDirectoryURI));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLCString uristr;
|
|
rv = mDirectoryURI->GetSpec(getter_Copies(uristr));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = gRDF->GetResource(uristr, getter_AddRefs(mDirectory));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
NS_WITH_SERVICE(nsIRDFContainerUtils, rdfc, "component://netscape/rdf/container-utils", &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = rdfc->MakeSeq(mDataSource, mDirectory, getter_AddRefs(mDirectoryContainer));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Mark the directory as "loading"
|
|
rv = mDataSource->Assert(mDirectory, kHTTPIndex_Loading, kTrueLiteral, PR_TRUE);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndexParser::OnStopRequest(nsIChannel* aChannel,
|
|
nsISupports* aContext,
|
|
nsresult aStatus,
|
|
const PRUnichar* aErrorMsg)
|
|
{
|
|
// If mDirectory isn't set, then we should just bail. Either an
|
|
// error occurred and OnStartRequest() never got called, or
|
|
// something exploded in OnStartRequest().
|
|
if (! mDirectory)
|
|
return NS_OK;
|
|
|
|
// XXX Should we do anything different if aStatus != NS_OK?
|
|
|
|
if (mLine.Length() > 0)
|
|
ProcessData();
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIRDFLiteral> comment;
|
|
rv = gRDF->GetLiteral(mComment.GetUnicode(), getter_AddRefs(comment));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = mDataSource->Assert(mDirectory, kHTTPIndex_Comment, comment, PR_TRUE);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Remove the 'loading' annotation.
|
|
rv = mDataSource->Unassert(mDirectory, kHTTPIndex_Loading, kTrueLiteral);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndexParser::OnDataAvailable(nsIChannel* aChannel,
|
|
nsISupports* aContext,
|
|
nsIInputStream* aStream,
|
|
PRUint32 aSourceOffset,
|
|
PRUint32 aCount)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (aCount < 1) return(NS_OK);
|
|
|
|
char *buffer = new char[ aCount ];
|
|
if (!buffer) return(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
PRUint32 count;
|
|
if (NS_FAILED(rv = aStream->Read(buffer, aCount, &count)) || (count == 0))
|
|
{
|
|
#ifdef DEBUG
|
|
printf("nsHTTPIndexParser: OnDataAvailable read failure.\n");
|
|
#endif
|
|
delete []buffer;
|
|
return(rv);
|
|
}
|
|
if (count != aCount)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("nsHTTPIndexParser: OnDataAvailable read # of bytes failure.\n");
|
|
#endif
|
|
delete []buffer;
|
|
return(NS_ERROR_UNEXPECTED);
|
|
}
|
|
|
|
mLine.Append(buffer, aCount);
|
|
delete [] buffer;
|
|
|
|
rv = ProcessData();
|
|
return(rv);
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ProcessData()
|
|
{
|
|
while(PR_TRUE)
|
|
{
|
|
PRInt32 eol = mLine.FindCharInSet("\n\r");
|
|
if (eol < 0) break;
|
|
|
|
nsCString aLine;
|
|
mLine.Left(aLine, eol);
|
|
mLine.Cut(0, eol + 1);
|
|
|
|
if (aLine.Length() >= 4)
|
|
{
|
|
nsresult rv;
|
|
const char *buf = aLine;
|
|
|
|
if (buf[0] == '1')
|
|
{
|
|
if (buf[1] == '0')
|
|
{
|
|
if (buf[2] == '0' && buf[3] == ':')
|
|
{
|
|
// 100. Human-readable comment line. Ignore
|
|
}
|
|
else if (buf[2] == '1' && buf[3] == ':')
|
|
{
|
|
// 101. Human-readable information line.
|
|
mComment += (buf + 4);
|
|
}
|
|
else if (buf[2] == '2' && buf[3] == ':')
|
|
{
|
|
// 102. Human-readable information line, HTML.
|
|
mComment += (buf + 4);
|
|
}
|
|
}
|
|
}
|
|
else if (buf[0] == '2')
|
|
{
|
|
if (buf[1] == '0')
|
|
{
|
|
if (buf[2] == '0' && buf[3] == ':')
|
|
{
|
|
// 200. Define field names
|
|
rv = ParseFormat(buf + 4);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
else if (buf[2] == '1' && buf[3] == ':')
|
|
{
|
|
// 201. Field data
|
|
rv = ParseData(buf + 4);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
}
|
|
}
|
|
else if (buf[0] == '3')
|
|
{
|
|
if (buf[1] == '0')
|
|
{
|
|
if (buf[2] == '0' && buf[3] == ':')
|
|
{
|
|
// 300. Self-referring URL
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(NS_OK);
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ParseFormat(const char* aFormatStr)
|
|
{
|
|
// Parse a "200" format line, and remember the fields and their
|
|
// ordering in mFormat. Multiple 200 lines stomp on each other.
|
|
mFormat.Clear();
|
|
|
|
do {
|
|
while (*aFormatStr && nsString::IsSpace(PRUnichar(*aFormatStr)))
|
|
++aFormatStr;
|
|
|
|
if (! *aFormatStr)
|
|
break;
|
|
|
|
nsCAutoString name;
|
|
PRInt32 len = 0;
|
|
while (aFormatStr[len] && !nsString::IsSpace(PRUnichar(aFormatStr[len])))
|
|
++len;
|
|
name.SetCapacity(len + 1);
|
|
name.Append(aFormatStr, len);
|
|
aFormatStr += len;
|
|
|
|
// Okay, we're gonna monkey with the nsStr. Bold!
|
|
name.mLength = nsUnescapeCount(name.mStr);
|
|
|
|
Field* field = nsnull;
|
|
for (Field* i = gFieldTable; i->mName; ++i) {
|
|
if (name.EqualsIgnoreCase(i->mName)) {
|
|
field = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mFormat.AppendElement(field);
|
|
} while (*aFormatStr);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
#define MAX_AUTO_VALUES 8
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ParseData(const char* aDataStr)
|
|
{
|
|
// Parse a "201" data line, using the field ordering specified in
|
|
// mFormat.
|
|
|
|
if (mFormat.Count() == 0) {
|
|
// Ignore if we haven't seen a format yet.
|
|
return NS_OK;
|
|
}
|
|
|
|
// Because the 'file:' protocol won't do this for us, we need to
|
|
// make sure that the mDirectoryURI ends with a '/' before
|
|
// concatenating.
|
|
nsresult rv;
|
|
nsCOMPtr<nsIURI> realbase;
|
|
|
|
{
|
|
nsXPIDLCString orig;
|
|
rv = mDirectoryURI->GetSpec(getter_Copies(orig));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCAutoString basestr(orig);
|
|
if (basestr.Last() != '/')
|
|
basestr.Append('/');
|
|
|
|
rv = NS_NewURI(getter_AddRefs(realbase), (const char*) basestr);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
|
|
// First, we'll iterate through the values and remember each (using
|
|
// an array of autostrings allocated on the stack, if possible). We
|
|
// have to do this, because we don't know up-front the filename for
|
|
// which this 201 refers.
|
|
nsAutoString autovalues[MAX_AUTO_VALUES];
|
|
nsAutoString* values = autovalues;
|
|
|
|
if (mFormat.Count() > MAX_AUTO_VALUES) {
|
|
values = new nsAutoString[mFormat.Count()];
|
|
if (! values)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
rv = NS_OK;
|
|
nsCOMPtr<nsIRDFResource> entry;
|
|
|
|
for (PRInt32 i = 0; i < mFormat.Count(); ++i) {
|
|
// If we've exhausted the data before we run out of fields, just
|
|
// bail.
|
|
if (! *aDataStr)
|
|
break;
|
|
|
|
while (*aDataStr && nsString::IsSpace(PRUnichar(*aDataStr)))
|
|
++aDataStr;
|
|
|
|
nsCAutoString value;
|
|
PRInt32 len;
|
|
|
|
if (*aDataStr == '"' || *aDataStr == '\'') {
|
|
// it's a quoted string. snarf everything up to the next quote character
|
|
const char quotechar = *(aDataStr++);
|
|
len = 0;
|
|
while (aDataStr[len] && (aDataStr[len] != quotechar))
|
|
++len;
|
|
value.SetCapacity(len + 1);
|
|
value.Append(aDataStr, len);
|
|
aDataStr += len;
|
|
|
|
if (! aDataStr) {
|
|
NS_WARNING("quoted value not terminated");
|
|
}
|
|
}
|
|
else {
|
|
// it's unquoted. snarf until we see whitespace.
|
|
len = 0;
|
|
while (aDataStr[len] && !nsString::IsSpace(aDataStr[len]))
|
|
++len;
|
|
value.SetCapacity(len + 1);
|
|
value.Append(aDataStr, len);
|
|
aDataStr += len;
|
|
}
|
|
|
|
// Monkey with the nsStr, because we're bold.
|
|
value.mLength = nsUnescapeCount(value.mStr);
|
|
|
|
values[i] = value;
|
|
|
|
Field* field = NS_STATIC_CAST(Field*, mFormat.ElementAt(i));
|
|
if (field && field->mProperty == kHTTPIndex_Filename) {
|
|
// we found the filename; construct a resource for its entry
|
|
nsAutoString entryuri;
|
|
rv = NS_MakeAbsoluteURI(value, realbase, entryuri);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable make absolute URI");
|
|
if (NS_FAILED(rv)) break;
|
|
rv = gRDF->GetResource(nsCAutoString(entryuri), getter_AddRefs(entry));
|
|
}
|
|
}
|
|
|
|
// At this point, we'll (hopefully) have found the filename and
|
|
// constructed a resource for it, stored in entry. So now take a
|
|
// second pass through the values and add as statements to the RDF
|
|
// datasource.
|
|
if (entry && NS_SUCCEEDED(rv)) {
|
|
for (PRInt32 indx = 0; indx < mFormat.Count(); ++indx) {
|
|
Field* field = NS_REINTERPRET_CAST(Field*, mFormat.ElementAt(indx));
|
|
if (! field)
|
|
continue;
|
|
|
|
nsCOMPtr<nsIRDFNode> value;
|
|
rv = (*field->mParse)(field->mProperty, values[indx], getter_AddRefs(value));
|
|
if (NS_FAILED(rv)) break;
|
|
if (value)
|
|
{
|
|
rv = mDataSource->Assert(entry, field->mProperty, value, PR_TRUE);
|
|
if (NS_FAILED(rv)) break;
|
|
}
|
|
}
|
|
|
|
rv = mDirectoryContainer->AppendElement(entry);
|
|
}
|
|
|
|
// If we needed to spill values onto the heap, make sure we clean up
|
|
// here.
|
|
if (values != autovalues)
|
|
delete[] values;
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ParseLiteral(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (arc == kHTTPIndex_Filename)
|
|
{
|
|
// strip off trailing slash(s) from directory names
|
|
PRInt32 len = aValue.Length();
|
|
if (len > 0)
|
|
{
|
|
if (aValue[len - 1] == '/')
|
|
{
|
|
aValue.SetLength(len - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIRDFLiteral> result;
|
|
rv = gRDF->GetLiteral(aValue.GetUnicode(), getter_AddRefs(result));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return result->QueryInterface(nsCOMTypeInfo<nsIRDFNode>::GetIID(), (void**) aResult);
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ParseDate(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult)
|
|
{
|
|
PRTime tm;
|
|
PRStatus err = PR_ParseTimeString(nsCAutoString(aValue), PR_TRUE, &tm);
|
|
if (err != PR_SUCCESS)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIRDFDate> result;
|
|
rv = gRDF->GetDateLiteral(tm, getter_AddRefs(result));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return result->QueryInterface(nsCOMTypeInfo<nsIRDFNode>::GetIID(), (void**) aResult);
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndexParser::ParseInt(nsIRDFResource *arc, nsString& aValue, nsIRDFNode** aResult)
|
|
{
|
|
PRInt32 err;
|
|
PRInt32 i = aValue.ToInteger(&err);
|
|
if (nsresult(err) != NS_OK)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (i == 0)
|
|
{
|
|
// disregard "zero" values
|
|
*aResult = nsnull;
|
|
return(NS_OK);
|
|
}
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIRDFInt> result;
|
|
rv = gRDF->GetIntLiteral(i, getter_AddRefs(result));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return result->QueryInterface(nsCOMTypeInfo<nsIRDFNode>::GetIID(), (void**) aResult);
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsHTTPIndex implementation
|
|
|
|
nsHTTPIndex::nsHTTPIndex(nsISupports* aContainer)
|
|
: mContainer(aContainer)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndex::Init(nsIURI* aBaseURL)
|
|
{
|
|
NS_PRECONDITION(aBaseURL != nsnull, "null ptr");
|
|
if (! aBaseURL)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv;
|
|
|
|
nsXPIDLCString url;
|
|
rv = aBaseURL->GetSpec(getter_Copies(url));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
mBaseURL = url;
|
|
|
|
static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
|
|
rv = nsComponentManager::CreateInstance(kRDFInMemoryDataSourceCID, nsnull,
|
|
nsCOMTypeInfo<nsIRDFDataSource>::GetIID(),
|
|
getter_AddRefs(mDataSource));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHTTPIndex::Create(nsIURI* aBaseURL, nsISupports* aContainer, nsIHTTPIndex** aResult)
|
|
{
|
|
nsHTTPIndex* result = new nsHTTPIndex(aContainer);
|
|
if (! result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsresult rv = result->Init(aBaseURL);
|
|
if (NS_FAILED(rv)) {
|
|
delete result;
|
|
return rv;
|
|
}
|
|
|
|
NS_ADDREF(result);
|
|
*aResult = result;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
nsHTTPIndex::~nsHTTPIndex()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsHTTPIndex);
|
|
NS_IMPL_RELEASE(nsHTTPIndex);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndex::QueryInterface(REFNSIID aIID, void** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
if (! aResult)
|
|
return NS_OK;
|
|
|
|
if (aIID.Equals(nsCOMTypeInfo<nsIHTTPIndex>::GetIID()) ||
|
|
aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
|
*aResult = NS_STATIC_CAST(nsIHTTPIndex*, this);
|
|
NS_ADDREF(this);
|
|
return NS_OK;
|
|
}
|
|
else {
|
|
*aResult = nsnull;
|
|
return NS_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndex::GetBaseURL(char** _result)
|
|
{
|
|
*_result = nsXPIDLCString::Copy(mBaseURL);
|
|
if (! *_result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result)
|
|
{
|
|
*_result = mDataSource;
|
|
NS_IF_ADDREF(*_result);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTTPIndex::CreateListener(nsIStreamListener** _result)
|
|
{
|
|
nsresult rv;
|
|
rv = nsHTTPIndexParser::Create(this, mContainer, _result);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Clear this: we only need to pass it through once.
|
|
mContainer = nsnull;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsDirectoryViewerFactory
|
|
//
|
|
|
|
class nsDirectoryViewerFactory : public nsIDocumentLoaderFactory
|
|
{
|
|
protected:
|
|
nsDirectoryViewerFactory();
|
|
virtual ~nsDirectoryViewerFactory();
|
|
|
|
public:
|
|
// constructor
|
|
static NS_IMETHODIMP
|
|
Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
|
|
|
// nsISupports interface
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIDocumentLoaderFactory interface
|
|
NS_IMETHOD CreateInstance(const char *aCommand,
|
|
nsIChannel* aChannel,
|
|
nsILoadGroup* aLoadGroup,
|
|
const char* aContentType,
|
|
nsISupports* aContainer,
|
|
nsISupports* aExtraInfo,
|
|
nsIStreamListener** aDocListenerResult,
|
|
nsIContentViewer** aDocViewerResult);
|
|
|
|
NS_IMETHOD CreateInstanceForDocument(nsISupports* aContainer,
|
|
nsIDocument* aDocument,
|
|
const char *aCommand,
|
|
nsIContentViewer** aDocViewerResult);
|
|
};
|
|
|
|
|
|
|
|
nsDirectoryViewerFactory::nsDirectoryViewerFactory()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
|
|
|
|
nsDirectoryViewerFactory::~nsDirectoryViewerFactory()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerFactory::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
|
{
|
|
NS_PRECONDITION(aOuter == nsnull, "no aggregation");
|
|
if (aOuter)
|
|
return NS_ERROR_NO_AGGREGATION;
|
|
|
|
nsDirectoryViewerFactory* result
|
|
= new nsDirectoryViewerFactory();
|
|
|
|
if (! result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(result); // stabilize
|
|
nsresult rv = result->QueryInterface(aIID, aResult);
|
|
NS_RELEASE(result);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsDirectoryViewerFactory);
|
|
NS_IMPL_RELEASE(nsDirectoryViewerFactory);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerFactory::QueryInterface(REFNSIID aIID, void** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
if (! aResult)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (aIID.Equals(nsCOMTypeInfo<nsIDocumentLoaderFactory>::GetIID()) ||
|
|
aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
|
*aResult = NS_STATIC_CAST(nsIDocumentLoaderFactory*, this);
|
|
}
|
|
else {
|
|
*aResult = nsnull;
|
|
return NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
NS_ADDREF(this);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerFactory::CreateInstance(const char *aCommand,
|
|
nsIChannel* aChannel,
|
|
nsILoadGroup* aLoadGroup,
|
|
const char* aContentType,
|
|
nsISupports* aContainer,
|
|
nsISupports* aExtraInfo,
|
|
nsIStreamListener** aDocListenerResult,
|
|
nsIContentViewer** aDocViewerResult)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Create a dummy loader that will load a stub XUL document.
|
|
nsCOMPtr<nsIDocumentLoaderFactory> factory;
|
|
rv = nsComponentManager::CreateInstance(NS_DOCUMENT_LOADER_FACTORY_PROGID_PREFIX "view/text/xul",
|
|
nsnull,
|
|
nsCOMTypeInfo<nsIDocumentLoaderFactory>::GetIID(),
|
|
getter_AddRefs(factory));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
rv = NS_NewURI(getter_AddRefs(uri), "chrome://directory/content/");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
rv = NS_OpenURI(getter_AddRefs(channel), uri, aLoadGroup);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
rv = factory->CreateInstance("view", channel, aLoadGroup, "text/xul",
|
|
aContainer, aExtraInfo, getter_AddRefs(listener),
|
|
aDocViewerResult);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = channel->AsyncRead(0, -1, nsnull, listener);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Create an HTTPIndex object so that we can stuff it into the script context
|
|
nsCOMPtr<nsIURI> baseuri;
|
|
rv = aChannel->GetURI(getter_AddRefs(baseuri));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIHTTPIndex> httpindex;
|
|
rv = nsHTTPIndex::Create(baseuri, aContainer, getter_AddRefs(httpindex));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Now shanghai the stream into our http-index parsing datasource
|
|
// wrapper beastie.
|
|
rv = httpindex->CreateListener(aDocListenerResult);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// addref the nsIHTTPIndex so that it'll live long enough to get
|
|
// added to the embedder's script global object; this happens when
|
|
// the stream's OnStartRequest() is called. (We can feel safe that
|
|
// this'll happen because of the flow-of-control in nsWebShell.cpp)
|
|
nsIHTTPIndex* dummy = httpindex;
|
|
NS_ADDREF(dummy);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer,
|
|
nsIDocument* aDocument,
|
|
const char *aCommand,
|
|
nsIContentViewer** aDocViewerResult)
|
|
{
|
|
NS_NOTYETIMPLEMENTED("didn't expect to get here");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Component Exports
|
|
|
|
#if 1
|
|
|
|
#include "nsIModule.h"
|
|
|
|
|
|
|
|
// Module implementation
|
|
class nsDirectoryViewerModule : public nsIModule
|
|
{
|
|
public:
|
|
nsDirectoryViewerModule();
|
|
virtual ~nsDirectoryViewerModule();
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIMODULE
|
|
|
|
protected:
|
|
nsresult Initialize();
|
|
|
|
void Shutdown();
|
|
|
|
PRBool mInitialized;
|
|
nsCOMPtr<nsIGenericFactory> mDirectoryViewerFactory;
|
|
};
|
|
|
|
|
|
|
|
nsDirectoryViewerModule::nsDirectoryViewerModule()
|
|
: mInitialized(PR_FALSE)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
}
|
|
|
|
nsDirectoryViewerModule::~nsDirectoryViewerModule()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(nsDirectoryViewerModule, NS_GET_IID(nsIModule))
|
|
|
|
|
|
|
|
// Perform our one-time intialization for this module
|
|
nsresult
|
|
nsDirectoryViewerModule::Initialize()
|
|
{
|
|
if (mInitialized) {
|
|
return NS_OK;
|
|
}
|
|
mInitialized = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
// Shutdown this module, releasing all of the module resources
|
|
void
|
|
nsDirectoryViewerModule::Shutdown()
|
|
{
|
|
// Release the factory object
|
|
mDirectoryViewerFactory = nsnull;
|
|
}
|
|
|
|
|
|
|
|
// Create a factory object for creating instances of aClass.
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerModule::GetClassObject(nsIComponentManager *aCompMgr,
|
|
const nsCID& aClass,
|
|
const nsIID& aIID,
|
|
void** r_classObj)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Defensive programming: Initialize *r_classObj in case of error below
|
|
if (!r_classObj) {
|
|
return NS_ERROR_INVALID_POINTER;
|
|
}
|
|
*r_classObj = NULL;
|
|
|
|
// Do one-time-only initialization if necessary
|
|
if (!mInitialized) {
|
|
rv = Initialize();
|
|
if (NS_FAILED(rv)) {
|
|
// Initialization failed! yikes!
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIGenericFactory> fact;
|
|
|
|
// Choose the appropriate factory, based on the desired instance
|
|
// class type (aClass).
|
|
if (aClass.Equals(kDirectoryViewerFactoryCID))
|
|
{
|
|
if (!mDirectoryViewerFactory) {
|
|
rv = NS_NewGenericFactory(getter_AddRefs(mDirectoryViewerFactory),
|
|
nsDirectoryViewerFactory::Create);
|
|
}
|
|
fact = mDirectoryViewerFactory;
|
|
}
|
|
else {
|
|
rv = NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
#ifdef DEBUG
|
|
char* cs = aClass.ToString();
|
|
printf("+++ nsDirectoryViewerModule: unable to create factory for %s\n", cs);
|
|
nsCRT::free(cs);
|
|
#endif
|
|
}
|
|
|
|
if (fact) {
|
|
rv = fact->QueryInterface(aIID, r_classObj);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
struct Components {
|
|
const char* mDescription;
|
|
const nsID* mCID;
|
|
const char* mProgID;
|
|
};
|
|
|
|
// The list of components we register
|
|
static Components gComponents[] = {
|
|
{ "Directory Viewer", &kDirectoryViewerFactoryCID, NS_DOCUMENT_LOADER_FACTORY_PROGID_PREFIX "view/application/http-index-format" },
|
|
};
|
|
#define NUM_COMPONENTS (sizeof(gComponents) / sizeof(gComponents[0]))
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerModule::RegisterSelf(nsIComponentManager *aCompMgr,
|
|
nsIFileSpec* aPath,
|
|
const char* registryLocation,
|
|
const char* componentType)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
#ifdef DEBUG
|
|
printf("*** Registering nsDirectoryViewerModule\n");
|
|
#endif
|
|
|
|
Components* cp = gComponents;
|
|
Components* end = cp + NUM_COMPONENTS;
|
|
while (cp < end) {
|
|
rv = aCompMgr->RegisterComponentSpec(*cp->mCID, cp->mDescription,
|
|
cp->mProgID, aPath, PR_TRUE,
|
|
PR_TRUE);
|
|
if (NS_FAILED(rv)) {
|
|
#ifdef DEBUG
|
|
printf("nsDirectoryViewerModule: unable to register %s component => %x\n",
|
|
cp->mDescription, rv);
|
|
#endif
|
|
break;
|
|
}
|
|
cp++;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerModule::UnregisterSelf(nsIComponentManager* aCompMgr,
|
|
nsIFileSpec* aPath,
|
|
const char* registryLocation)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("*** Unregistering nsDirectoryViewerModule\n");
|
|
#endif
|
|
Components* cp = gComponents;
|
|
Components* end = cp + NUM_COMPONENTS;
|
|
while (cp < end) {
|
|
nsresult rv = aCompMgr->UnregisterComponentSpec(*cp->mCID, aPath);
|
|
if (NS_FAILED(rv)) {
|
|
#ifdef DEBUG
|
|
printf("nsDirectoryViewerModule: unable to unregister %s component => %x\n",
|
|
cp->mDescription, rv);
|
|
#endif
|
|
}
|
|
cp++;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDirectoryViewerModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload)
|
|
{
|
|
if (!okToUnload) {
|
|
return NS_ERROR_INVALID_POINTER;
|
|
}
|
|
*okToUnload = PR_FALSE;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
static nsDirectoryViewerModule *gModule = NULL;
|
|
|
|
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
|
|
nsIFileSpec* location,
|
|
nsIModule** return_cobj)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
NS_ENSURE_ARG_POINTER(return_cobj);
|
|
NS_ENSURE_FALSE(gModule, NS_ERROR_FAILURE);
|
|
|
|
// Create and initialize the module instance
|
|
nsDirectoryViewerModule *m = new nsDirectoryViewerModule();
|
|
if (!m) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// Increase refcnt and store away nsIModule interface to m in return_cobj
|
|
rv = m->QueryInterface(NS_GET_IID(nsIModule), (void**)return_cobj);
|
|
if (NS_FAILED(rv)) {
|
|
delete m;
|
|
m = nsnull;
|
|
}
|
|
gModule = m; // WARNING: Weak Reference
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
extern "C" PR_IMPLEMENT(nsresult)
|
|
NSGetFactory(nsISupports* aServiceMgr,
|
|
const nsCID &aClass,
|
|
const char *aClassName,
|
|
const char *aProgID,
|
|
nsIFactory **aFactory)
|
|
{
|
|
NS_PRECONDITION(aFactory != nsnull, "null ptr");
|
|
if (! aFactory)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsIGenericFactory::ConstructorProcPtr constructor;
|
|
|
|
if (aClass.Equals(kDirectoryViewerFactoryCID)) {
|
|
constructor = nsDirectoryViewerFactory::Create;
|
|
}
|
|
else {
|
|
*aFactory = nsnull;
|
|
return NS_NOINTERFACE; // XXX
|
|
}
|
|
|
|
nsresult rv;
|
|
NS_WITH_SERVICE1(nsIComponentManager, compMgr, aServiceMgr, kComponentManagerCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIGenericFactory> factory;
|
|
rv = compMgr->CreateInstance(kGenericFactoryCID,
|
|
nsnull,
|
|
nsIGenericFactory::GetIID(),
|
|
getter_AddRefs(factory));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = factory->SetConstructor(constructor);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
*aFactory = factory;
|
|
NS_ADDREF(*aFactory);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
extern "C" PR_IMPLEMENT(nsresult)
|
|
NSRegisterSelf(nsISupports* aServMgr , const char* aPath)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIServiceManager> servMgr(do_QueryInterface(aServMgr, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
NS_WITH_SERVICE1(nsIComponentManager, compMgr, servMgr, kComponentManagerCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = compMgr->RegisterComponent(kDirectoryViewerFactoryCID, "Global History",
|
|
NS_DOCUMENT_LOADER_FACTORY_PROGID_PREFIX "view/application/http-index-format",
|
|
aPath, PR_TRUE, PR_TRUE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
extern "C" PR_IMPLEMENT(nsresult)
|
|
NSUnregisterSelf(nsISupports* aServMgr, const char* aPath)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIServiceManager> servMgr(do_QueryInterface(aServMgr, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
NS_WITH_SERVICE1(nsIComponentManager, compMgr, servMgr, kComponentManagerCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = compMgr->UnregisterComponent(kDirectoryViewerFactoryCID, aPath);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
#endif
|