diff --git a/netwerk/streamconv/Makefile.in b/netwerk/streamconv/Makefile.in new file mode 100644 index 000000000000..89814b88b6b1 --- /dev/null +++ b/netwerk/streamconv/Makefile.in @@ -0,0 +1,33 @@ +#! gmake +# +# 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. + +DEPTH = ../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +MODULE = streamconv + +include $(DEPTH)/config/autoconf.mk + +DIRS= \ + public \ + src \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/netwerk/streamconv/makefile.win b/netwerk/streamconv/makefile.win new file mode 100644 index 000000000000..4af086ea7266 --- /dev/null +++ b/netwerk/streamconv/makefile.win @@ -0,0 +1,27 @@ +#!gmake +# +# 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. + +DEPTH = ..\.. + +MODULE = streamconv + +DIRS= \ + public \ + src \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> diff --git a/netwerk/streamconv/public/Makefile.in b/netwerk/streamconv/public/Makefile.in new file mode 100644 index 000000000000..c5cfdec3ed15 --- /dev/null +++ b/netwerk/streamconv/public/Makefile.in @@ -0,0 +1,41 @@ +#!gmake +# +# 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. + +DEPTH = ../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +MODULE = streamconv +XPIDL_MODULE = necko_stream_converter + +XPIDLSRCS = \ + nsIStreamConverter.idl \ + nsIStreamConverterService.idl \ + $(NULL) + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# hack until necko lands +ifndef NECKO +PUBLIC = $(DEPTH)/netwerk/dist/include +endif + +include $(topsrcdir)/config/rules.mk diff --git a/netwerk/streamconv/public/makefile.win b/netwerk/streamconv/public/makefile.win new file mode 100644 index 000000000000..88cad0fd5b75 --- /dev/null +++ b/netwerk/streamconv/public/makefile.win @@ -0,0 +1,39 @@ +#!gmake +# +# 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. + +MODULE = streamconv + +DEPTH = ..\..\.. + +// temporary, until we land: +!ifndef NECKO +include <$(DEPTH)/config/config.mak> +PUBLIC = $(DEPTH)\netwerk\dist\include +!endif + + +XPIDLSRCS = \ + .\nsIStreamConverter.idl \ + .\nsIStreamConverterService.idl \ + $(NULL) + +include <$(DEPTH)/config/rules.mak> + +$(DEPTH)\netwerk\dist\include: + -mkdir $(DEPTH)\netwerk\dist + -mkdir $(DEPTH)\netwerk\dist\include + diff --git a/netwerk/streamconv/public/nsIStreamConverter.idl b/netwerk/streamconv/public/nsIStreamConverter.idl new file mode 100644 index 000000000000..d924c9dff8ad --- /dev/null +++ b/netwerk/streamconv/public/nsIStreamConverter.idl @@ -0,0 +1,50 @@ +#include "nsIStreamListener.idl" +#include "nsIInputStream.idl" +#include "nsIURI.idl" + +// There are three ways to use a stream converter: +// 1. SYNCRONOUS. Stream to Stream. +// You can supply the service with a stream of type X +// and it will convert it to your desired output type and return +// a converted stream to you. +// +// 2. ASYNCRONOUS. Stream to nsIStreamListener +// You can supply the service with a stream of type X +// and it will convert it to your desired output type and return +// converted data to you via the nsIStreamListener you passed in +// by calling its nsIStreamListener::OnDataAvailable() method. +// +// 3. ASYNCRONOUS. nsIStreamListener to nsIStreamListener +// You can supply data directly to the service by calling it's +// nsIStreamListener::OnDataAvailable() method. It will then +// convert that data from type X to your desired output type and +// return converted data to you via the nsIStreamListener you passed +// in by calling its OnDataAvailable() method. + +[scriptable, uuid(46484B30-3BD2-11d3-A16C-0050041CAF44)] +interface nsIStreamConverter : nsIStreamListener { + + // SYNCRONOUS VERSION + + // Converts aFromStream of type aFromType, to a resulting stream of type aToType. + // Use this when you have a stream as input. + nsIInputStream Convert(in nsIInputStream aFromStream, + in wstring aFromType, + in wstring aToType); + + // ASYNCRONOUS VERSIONS + + // Converts aFromStream of type aFromType, to type aToType pushing the converted + // data out to the caller via aListener::OnDataAvailable(). + void AsyncConvertStream(in nsIInputStream aFromStream, + in wstring aFromType, + in wstring aToType, + in nsIStreamListener aListener); + + // Converts data arriving via the service's nsIStreamListener::OnDataAvailable() method + // from type aFromType to aToType pushing the converted data out to the caller via + // aListener::OnDataAvailable(). + void AsyncConvertData(in wstring aFromType, + in wstring aToType, + in nsIStreamListener aListener); +}; \ No newline at end of file diff --git a/netwerk/streamconv/public/nsIStreamConverterService.idl b/netwerk/streamconv/public/nsIStreamConverterService.idl new file mode 100644 index 000000000000..2223e9134b0e --- /dev/null +++ b/netwerk/streamconv/public/nsIStreamConverterService.idl @@ -0,0 +1,25 @@ +#include "nsIStreamConverter.idl" + +// The nsIStreamConverterService acts as a higher level stream converter factory +// responsible for locating and creating the appropriate stream converters in order +// to convert data from type X to type Z. It is responsible for any intermediary +// conversion required in order to get from X to Z, if direct conversion is not +// possible. +// + +%{C++ + +#define NS_STREAMCONVERTERSERVICE_CID \ +{ /* 892FFEB0-3F80-11d3-A16C-0050041CAF44 */ \ + 0x892ffeb0, \ + 0x3f80, \ + 0x11d3, \ + {0xa1, 0x6c, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ +} + +%} + +[scriptable, uuid(00362090-3B97-11d3-A16C-0050041CAF44)] +interface nsIStreamConverterService : nsIStreamConverter { + // no methods. only implements nsIStreamConverter +}; diff --git a/netwerk/streamconv/src/Makefile.in b/netwerk/streamconv/src/Makefile.in new file mode 100644 index 000000000000..ba61ff56af8e --- /dev/null +++ b/netwerk/streamconv/src/Makefile.in @@ -0,0 +1,46 @@ +# 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. + +DEPTH = ../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +MODULE = streamconv + +LIBRARY_NAME = streamconv + +IS_COMPONENT = 1 + +include $(DEPTH)/config/autoconf.mk + +CPPSRCS = \ + nsStreamConverterService.cpp \ + nsStreamConvServiceFactory.cpp \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +REQUIRES = xpcom + +# hack until necko lands +ifndef NECKO +PUBLIC = $(DEPTH)/netwerk/dist/include +endif + +TARGET = $(LIBARY) + +include $(topsrcdir)/config/rules.mk diff --git a/netwerk/streamconv/src/makefile.win b/netwerk/streamconv/src/makefile.win new file mode 100644 index 000000000000..4c7b977e7ebf --- /dev/null +++ b/netwerk/streamconv/src/makefile.win @@ -0,0 +1,56 @@ +# 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. + +DEPTH = ..\..\.. + +// temporary, until we land: +!ifndef NECKO +include <$(DEPTH)/config/config.mak> +PUBLIC = $(DEPTH)\netwerk\dist\include +!endif + +MODULE = streamconv + +IS_COMPONENT=1 +MAKE_OBJ_TYPE=DLL +DLLNAME=streamconv +DLL=.\$(OBJDIR)\$(DLLNAME).dll + +LLIBS= $(LLIBS) \ + $(DIST)\lib\xpcom.lib \ + $(NULL) + +LCFLAGS = -DWIN32_LEAN_AND_MEAN -D_IMPL_NS_NET + +CPP_OBJS = \ + .\$(OBJDIR)\nsStreamConverterService.obj \ + .\$(OBJDIR)\nsStreamConvServiceFactory.obj \ + $(NULL) + +LOCAL_INCLUDES=-I. + +INCLUDES = $(LOCAL_INCLUDES) + +INCS = $(INCS) \ + -I$(DEPTH)\dist\include \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +install:: $(DLL) + $(MAKE_INSTALL) $(DLL) $(DIST)\bin\components + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib diff --git a/netwerk/streamconv/src/nsStreamConvServiceFactory.cpp b/netwerk/streamconv/src/nsStreamConvServiceFactory.cpp new file mode 100644 index 000000000000..7fcc46324070 --- /dev/null +++ b/netwerk/streamconv/src/nsStreamConvServiceFactory.cpp @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; 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 "nsCOMPtr.h" +#include "nscore.h" +#include "nsIStreamConverterService.h" +#include "nsStreamConverterService.h" +#include "nsStreamConvServiceFactory.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsXPComFactory.h" + +static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); +static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); +static NS_DEFINE_CID(kStreamConvServiceCID, NS_STREAMCONVERTERSERVICE_CID); + +//////////////////////////////////////////////////////////////////////// + +nsStreamConvServiceFactory::nsStreamConvServiceFactory(const nsCID &aClass, + const char* className, + const char* progID) + : mClassID(aClass), mClassName(className), mProgID(progID) +{ + NS_INIT_REFCNT(); +} + +nsStreamConvServiceFactory::~nsStreamConvServiceFactory() +{ + NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction"); +} + +NS_IMETHODIMP +nsStreamConvServiceFactory::QueryInterface(const nsIID &aIID, void **aResult) +{ + if (! aResult) + return NS_ERROR_NULL_POINTER; + + // Always NULL result, in case of failure + *aResult = nsnull; + + if (aIID.Equals(nsCOMTypeInfo::GetIID())) { + *aResult = NS_STATIC_CAST(nsISupports*, this); + AddRef(); + return NS_OK; + } else if (aIID.Equals(kIFactoryIID)) { + *aResult = NS_STATIC_CAST(nsIFactory*, this); + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsStreamConvServiceFactory); +NS_IMPL_RELEASE(nsStreamConvServiceFactory); + +NS_IMETHODIMP +nsStreamConvServiceFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + *aResult = nsnull; + + nsresult rv = NS_OK; + + nsISupports *inst = nsnull; + if (mClassID.Equals(kStreamConvServiceCID)) { + nsStreamConverterService *service = new nsStreamConverterService(); + if (!service) return NS_ERROR_OUT_OF_MEMORY; + rv = service->Init(); + if (NS_FAILED(rv)) { + delete service; + return rv; + } + service->QueryInterface(nsCOMTypeInfo::GetIID(), (void**)&inst); + } + else { + return NS_ERROR_NO_INTERFACE; + } + + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(inst); + *aResult = inst; + NS_RELEASE(inst); + return rv; +} + +nsresult nsStreamConvServiceFactory::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////// + + + +// return the proper factory to the caller +extern "C" PR_IMPLEMENT(nsresult) +NSGetFactory(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aProgID, + nsIFactory **aFactory) +{ + if (! aFactory) + return NS_ERROR_NULL_POINTER; + + nsStreamConvServiceFactory* factory = new nsStreamConvServiceFactory(aClass, aClassName, aProgID); + if (factory == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(factory); + *aFactory = factory; + return NS_OK; +} + + + +extern "C" PR_IMPLEMENT(nsresult) +NSRegisterSelf(nsISupports* aServMgr , const char* aPath) +{ + nsresult rv; + + nsCOMPtr servMgr(do_QueryInterface(aServMgr, &rv)); + if (NS_FAILED(rv)) return rv; + + NS_WITH_SERVICE(nsIComponentManager, compMgr, kComponentManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = compMgr->RegisterComponent(kStreamConvServiceCID, + "Stream Converter Service", + "component:||netscape|streamConverters", + aPath, PR_TRUE, PR_TRUE); + + if (NS_FAILED(rv)) return rv; + + return NS_OK; +} + + +extern "C" PR_IMPLEMENT(nsresult) +NSUnregisterSelf(nsISupports* aServMgr, const char* aPath) +{ + nsresult rv; + + nsCOMPtr servMgr(do_QueryInterface(aServMgr, &rv)); + if (NS_FAILED(rv)) return rv; + + NS_WITH_SERVICE(nsIComponentManager, compMgr, kComponentManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = compMgr->UnregisterComponent(kStreamConvServiceCID, aPath); + if (NS_FAILED(rv)) return rv; + + return NS_OK; +} diff --git a/netwerk/streamconv/src/nsStreamConvServiceFactory.h b/netwerk/streamconv/src/nsStreamConvServiceFactory.h new file mode 100644 index 000000000000..a8f75def8097 --- /dev/null +++ b/netwerk/streamconv/src/nsStreamConvServiceFactory.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; 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 "nsIFactory.h" + +class nsStreamConvServiceFactory : public nsIFactory +{ +public: + nsStreamConvServiceFactory(const nsCID &aClass, const char* className, const char* progID); + + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + +protected: + virtual ~nsStreamConvServiceFactory(); + +protected: + nsCID mClassID; + const char* mClassName; + const char* mProgID; +}; + diff --git a/netwerk/streamconv/src/nsStreamConverterService.cpp b/netwerk/streamconv/src/nsStreamConverterService.cpp new file mode 100644 index 000000000000..b89574ffaf21 --- /dev/null +++ b/netwerk/streamconv/src/nsStreamConverterService.cpp @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "nsStreamConverterService.h" +#include "nsIServiceManager.h" +#include "nsString2.h" +#include "nsIAtom.h" +#include "nsDeque.h" + +//////////////////////////////////////////////////////////// +// nsISupports methods +NS_IMPL_ISUPPORTS(nsStreamConverterService, nsCOMTypeInfo::GetIID()); + + +//////////////////////////////////////////////////////////// +// nsIStreamConverterService methods + +// Builds the graph represented as an adjacency list (and built up in +// memory using an nsHashtable and nsVoidArray combination). +// +// RegisterConverter takes the given PROGID and parses a single edge from it. +// An edge in this case is comprised of a FROM and TO MIME type combination. The +// edge is then inserted into the service's adjacency list. +// It then turns around and registers the PROGID and the converter with the service +// manager; the true registration mechanism. +// +// PROGID format: +// component://netscape/strmconv?from=text/html?to=text/plain +// XXX curently we only handle a single from and to combo, we should repeat the +// XXX registration process for any series of from-to combos. +// XXX can use nsTokenizer for this. +// + +typedef struct _tableData { + nsHashKey *key; + nsString2 *keyString; + void *data; +} tableData; + +NS_IMETHODIMP +nsStreamConverterService::RegisterConverter(const char *aProgID, nsISupports *aConverter) { + NS_ASSERTION(aProgID, "progid required"); + nsresult rv; + + // first parse out the FROM and TO MIME-types being registered. + + nsString2 ProgIDStr(aProgID, eOneByte); + PRInt32 fromLoc = ProgIDStr.Find("from=") + 5; + PRInt32 toLoc = ProgIDStr.Find("to=") + 3; + if (-1 == fromLoc || -1 == toLoc ) return NS_ERROR_FAILURE; + + nsString2 fromStr(eOneByte), toStr(eOneByte); + PRInt32 fromLen = toLoc - 4 - fromLoc; + PRInt32 toLen = ProgIDStr.Length() - toLoc; + + ProgIDStr.Mid(fromStr, fromLoc, fromLen); + ProgIDStr.Mid(toStr, toLoc, toLen); + + + // Each MIME-type is a vertex in the graph, so first lets make sure + // each MIME-type is represented as a key in our hashtable. + + nsStringKey *fromKey = new nsStringKey(fromStr.GetBuffer()); + nsStringKey *toKey = new nsStringKey(toStr.GetBuffer()); + + tableData *edges = (tableData*)mAdjacencyList->Get(fromKey); + if (!edges) { + // There is no fromStr vertex, create one. + tableData *data = new tableData; + if (!data) return NS_ERROR_OUT_OF_MEMORY; + data->key = fromKey; + data->keyString = new nsString2(fromStr.GetBuffer()); + data->data = new nsVoidArray(); + if (!data->data) return NS_ERROR_OUT_OF_MEMORY; + mAdjacencyList->Put(fromKey, data); + } + + edges = (tableData*)mAdjacencyList->Get(toKey); + if (!edges) { + // There is no toStr vertex, create one. + tableData *data = new tableData; + if (!data) return NS_ERROR_OUT_OF_MEMORY; + data->key = toKey; + data->keyString = new nsString2(toStr.GetBuffer()); + data->data = new nsVoidArray(); + if (!data->data) return NS_ERROR_OUT_OF_MEMORY; + mAdjacencyList->Put(toKey, data); + } + + + // Now we know the FROM and TO types are represented as keys in the hashtable. + // Let's "connect" the verticies, making an edge. + + edges = (tableData*)mAdjacencyList->Get(fromKey); + NS_ASSERTION(edges, "something wrong in adjacency list construction"); + nsIAtom *vertex = NS_NewAtom(toStr); + if (!vertex) return NS_ERROR_OUT_OF_MEMORY; + nsVoidArray *adjacencyList = (nsVoidArray*)edges->data; + adjacencyList->AppendElement(vertex); + + + // We're done building our adjacency list, let's move onto the service + // manager registration. + + rv = nsServiceManager::RegisterService(aProgID, aConverter); + return rv; +} + +//////////////////////////////////////////////////////////// +// nsStreamConverterService methods +nsStreamConverterService::nsStreamConverterService() { + NS_INIT_REFCNT(); +} + +nsStreamConverterService::~nsStreamConverterService() { + //mAdjacencyList->Enumerate(DeleteEntry, nsnull); + //mAdjacencyList->Reset(); + delete mAdjacencyList; +} + +nsresult +nsStreamConverterService::Init() { + mAdjacencyList = new nsHashtable(); + if (!mAdjacencyList) return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + + +enum colors {white, gray, black}; + +typedef struct _BFSState { + colors color; + PRInt32 distance; + nsHashKey *predecessor; +} BFSState; + +// nsHashtable enumerator functions. + +// Initializes the color table. +PRBool InitBFSTable(nsHashKey *aKey, void *aData, void* closure) { + nsHashtable *BFSTable = (nsHashtable*)closure; + if (!BFSTable) return PR_FALSE; + + BFSState *state = new BFSState; + if (!state) return NS_ERROR_OUT_OF_MEMORY; + + state->color = white; + state->distance = -1; + state->predecessor = nsnull; + + tableData *data = new tableData; + if (!data) return NS_ERROR_OUT_OF_MEMORY; + data->key = aKey->Clone(); + + tableData *origData = (tableData*)aData; + NS_ASSERTION(origData, "no data in the table enumeration"); + data->keyString = new nsString2(*origData->keyString); + data->data = state; + + BFSTable->Put(aKey, data); + return PR_TRUE; +}; + +nsresult +nsStreamConverterService::FindConverter(const char *aProgID, PRBool direct, nsCID *aCID, nsVoidArray **aEdgeList) { + + + // FIRST. try a direct lookup. + + // Direct lookup didn't succeed, walk the graph. + // walk the graph in search of the appropriate converter. + + PRInt32 vertexCount = mAdjacencyList->Count(); + if (0 >= vertexCount) + return NS_ERROR_FAILURE; + + // Create a corresponding color table for each vertex in the graph. + nsHashtable lBFSTable; + mAdjacencyList->Enumerate(InitBFSTable, &lBFSTable); + + NS_ASSERTION(lBFSTable.Count() == vertexCount, "strmconv BFS table init problem"); + + // This is our source vertex; our starting point. + nsStringKey *source = new nsStringKey(aProgID); + if (!source) return NS_ERROR_OUT_OF_MEMORY; + + tableData *data = (tableData*)lBFSTable.Get(source); + BFSState *state = (BFSState*)data->data; + // XXX probably don't need this check. + if (!state) + return NS_ERROR_FAILURE; + + state->color = gray; + state->distance = 0; + nsDeque *grayQ = new nsDeque(0); + + // Now generate the shortest path tree. + grayQ->Push(source); + while (0 < grayQ->GetSize()) { + nsHashKey *currentHead = (nsHashKey*)grayQ->Pop(); + tableData *data = (tableData*)mAdjacencyList->Get(currentHead); + nsVoidArray *edges = (nsVoidArray*)data->data; + NS_ASSERTION(edges, "something went wrong with BFS strmconv algorithm"); + + // Get the state of the current head to calculate the distance of each + // reachable vertex in the loop. + data = (tableData*)lBFSTable.Get(currentHead); + BFSState *headVertexState = (BFSState*)data->data; + NS_ASSERTION(headVertexState, "problem with the BFS strmconv algorithm"); + + PRInt32 edgeCount = edges->Count(); + for (int i = 0; i < edgeCount; i++) { + + nsIAtom *curVertexAtom = (nsIAtom*)edges->ElementAt(i); + nsString2 curVertexStr; + curVertexAtom->ToString(curVertexStr); + char * curVertexCString = curVertexStr.ToNewCString(); + nsStringKey *curVertex = new nsStringKey(curVertexCString); + delete [] curVertexCString; + + tableData *data = (tableData*)lBFSTable.Get(curVertex); + BFSState *curVertexState = (BFSState*)data->data; + NS_ASSERTION(curVertexState, "something went wrong with the BFS strmconv algorithm"); + if (white == curVertexState->color) { + curVertexState->color = gray; + curVertexState->distance = headVertexState->distance + 1; + curVertexState->predecessor = currentHead->Clone(); + grayQ->Push(curVertex); + } + } + headVertexState->color = black; + grayQ->Pop(); + } + // The shortest path (if any) has been generated and is represetned by the chain of + // BFSState->predecessor keys. Start at the bottom and work our way up. + + // first parse out the FROM and TO MIME-types being registered. + + nsString2 ProgIDStr(aProgID, eOneByte); + PRInt32 fromLoc = ProgIDStr.Find("from=") + 5; + PRInt32 toLoc = ProgIDStr.Find("to=") + 3; + if (-1 == fromLoc || -1 == toLoc ) return NS_ERROR_FAILURE; + + nsString2 fromStr(eOneByte), toStr(eOneByte); + PRInt32 fromLen = toLoc - 4 - fromLoc; + PRInt32 toLen = ProgIDStr.Length() - toLoc; + + ProgIDStr.Mid(fromStr, fromLoc, fromLen); + ProgIDStr.Mid(toStr, toLoc, toLen); + + + // get the root PROGID + nsString2 ProgIDPrefix(ProgIDStr); + ProgIDPrefix.Truncate(fromLoc - 5); + nsVoidArray *shortestPath = new nsVoidArray(); + nsStringKey *toMIMEType = new nsStringKey(toStr); + data = (tableData*)lBFSTable.Get(toMIMEType); + NS_ASSERTION(data, "problem w/ strmconv BFS algorithm"); + + while (data) { + BFSState *curState = (BFSState*)data->data; + + if (data->keyString->Equals(fromStr)) { + // found it. We're done here. + direct = PR_FALSE; + *aEdgeList = shortestPath; + return NS_OK; + } + + // reconstruct the PROGID. + // Get the predecessor. + tableData *predecessorData = (tableData*)lBFSTable.Get(curState->predecessor); + NS_ASSERTION(predecessorData, "can't get predecessor data"); + + // build out the PROGID. + nsString2 *newProgID = new nsString2(ProgIDPrefix); + newProgID->Append("from="); + + char *from = predecessorData->keyString->ToNewCString(); + newProgID->Append(from); + delete [] from; + + newProgID->Append("?to="); + char *to = data->keyString->ToNewCString(); + newProgID->Append(to); + delete [] to; + + // Add this PROGID to the chain. + shortestPath->AppendElement(newProgID); + + // move up the tree. + data = predecessorData; + } + + return NS_ERROR_FAILURE; // couldn't find a stream converter or chain. + +} + +NS_IMETHODIMP +nsStreamConverterService::OnDataAvailable(nsIChannel *channel, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) { + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsStreamConverterService::OnStartRequest(nsIChannel *channel, nsISupports *ctxt) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsStreamConverterService::OnStopRequest(nsIChannel *channel, nsISupports *ctxt, nsresult status, const PRUnichar *errorMsg) { + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/netwerk/streamconv/src/nsStreamConverterService.h b/netwerk/streamconv/src/nsStreamConverterService.h new file mode 100644 index 000000000000..adf18329325e --- /dev/null +++ b/netwerk/streamconv/src/nsStreamConverterService.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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. + */ + +#ifndef __nsstreamconverterservice__h___ +#define __nsstreamconverterservice__h___ + +#include "nsIStreamConverterService.h" +#include "nsIStreamListener.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" + +class nsStreamConverterService : public nsIStreamConverterService { +public: + ///////////////////////////////////////////////////// + // nsISupports methods + NS_DECL_ISUPPORTS + + + ///////////////////////////////////////////////////// + // nsIStreamConverterService methods + NS_IMETHOD RegisterConverter(const char *aProgID, nsISupports *aConverter); + + + ///////////////////////////////////////////////////// + // nsIStreamConverter methods + NS_IMETHOD Convert(nsIInputStream *aFromStream, const PRUnichar *aFromType, const PRUnichar *aToType, nsIInputStream **_retval) + { return NS_ERROR_NOT_IMPLEMENTED;}; + NS_IMETHOD AsyncConvertStream(nsIInputStream *aFromStream, const PRUnichar *aFromType, const PRUnichar *aToType, nsIStreamListener *aListener) + { return NS_ERROR_NOT_IMPLEMENTED;}; + NS_IMETHOD AsyncConvertData(const PRUnichar *aFromType, const PRUnichar *aToType, nsIStreamListener *aListener) + { return NS_ERROR_NOT_IMPLEMENTED;}; + + + ///////////////////////////////////////////////////// + // nsIStreamListener methods + NS_IMETHOD OnDataAvailable(nsIChannel *channel, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count); + + + ///////////////////////////////////////////////////// + // nsIStreamObserver methods + NS_IMETHOD OnStartRequest(nsIChannel *channel, nsISupports *ctxt); + NS_IMETHOD OnStopRequest(nsIChannel *channel, nsISupports *ctxt, nsresult status, const PRUnichar *errorMsg); + + ///////////////////////////////////////////////////// + // nsStreamConverterService methods + nsStreamConverterService(); + virtual ~nsStreamConverterService(); + + // Initialization routine. Must be called after this object is constructed. + nsresult Init(); + +private: + // Responsible for finding a converter for the given MIME-type. + nsresult FindConverter(const char *aProgID, PRBool direct, nsCID *aCID, nsVoidArray **aEdgeList); + + // member variables + nsHashtable *mAdjacencyList; +}; + +#endif // __nsstreamconverterservice__h___ \ No newline at end of file