Bug 73308 patch=tmutreja@netscape.com r=gagan sr=brendan
This commit is contained in:
badami%netscape.com 2002-02-18 07:46:08 +00:00
Родитель c5488d8591
Коммит a499ff0d85
2 изменённых файлов: 102 добавлений и 70 удалений

Просмотреть файл

@ -69,8 +69,7 @@ nsStreamConverterService::~nsStreamConverterService() {
// Delete all the entries in the adjacency list
static PRBool PR_CALLBACK DeleteAdjacencyEntry(nsHashKey *aKey, void *aData, void* closure) {
SCTableData *entry = (SCTableData*)aData;
NS_ASSERTION(entry->key && entry->data.edges, "malformed adjacency list entry");
delete entry->key;
NS_ASSERTION(entry->data.edges, "malformed adjacency list entry");
NS_RELEASE(entry->data.edges);
delete entry;
return PR_TRUE;
@ -121,7 +120,7 @@ nsStreamConverterService::BuildGraph() {
if (NS_FAILED(rv)) return rv;
// cobble the entry string w/ the converter key to produce a full contractID.
nsCString contractID(NS_ISTREAMCONVERTER_KEY);
nsCAutoString contractID(NS_ISTREAMCONVERTER_KEY);
contractID.Append((const char *)entryString);
// now we've got the CONTRACTID, let's parse it up.
@ -144,65 +143,47 @@ nsStreamConverterService::AddAdjacency(const char *aContractID) {
nsresult rv;
// first parse out the FROM and TO MIME-types.
nsCString fromStr, toStr;
nsCAutoString fromStr, toStr;
rv = ParseFromTo(aContractID, fromStr, toStr);
if (NS_FAILED(rv)) return rv;
// 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.
nsCStringKey *fromKey = new nsCStringKey(ToNewCString(fromStr), fromStr.Length(), nsCStringKey::OWN);
if (!fromKey) return NS_ERROR_OUT_OF_MEMORY;
SCTableData *fromEdges = (SCTableData*)mAdjacencyList->Get(fromKey);
nsCStringKey fromKey(fromStr);
SCTableData *fromEdges = (SCTableData*)mAdjacencyList->Get(&fromKey);
if (!fromEdges) {
// There is no fromStr vertex, create one.
SCTableData *data = new SCTableData;
if (!data) {
delete fromKey;
return NS_ERROR_OUT_OF_MEMORY;
}
SCTableData *data = new SCTableData(fromKey);
if (!data) return NS_ERROR_OUT_OF_MEMORY;
data->key = fromKey;
nsCOMPtr<nsISupportsArray> edgeArray;
rv = NS_NewISupportsArray(getter_AddRefs(edgeArray));
if (NS_FAILED(rv)) {
delete fromKey;
delete data;
return rv;
}
NS_ADDREF(data->data.edges = edgeArray.get());
mAdjacencyList->Put(fromKey, data);
mAdjacencyList->Put(&fromKey, data);
fromEdges = data;
} else {
delete fromKey;
fromKey = nsnull;
}
nsCStringKey *toKey = new nsCStringKey(ToNewCString(toStr), toStr.Length(), nsCStringKey::OWN);
if (!toKey) return NS_ERROR_OUT_OF_MEMORY;
nsCStringKey toKey(toStr);
if (!mAdjacencyList->Get(toKey)) {
if (!mAdjacencyList->Get(&toKey)) {
// There is no toStr vertex, create one.
SCTableData *data = new SCTableData;
if (!data) {
delete toKey;
return NS_ERROR_OUT_OF_MEMORY;
}
SCTableData *data = new SCTableData(toKey);
if (!data) return NS_ERROR_OUT_OF_MEMORY;
data->key = toKey;
nsCOMPtr<nsISupportsArray> edgeArray;
rv = NS_NewISupportsArray(getter_AddRefs(edgeArray));
if (NS_FAILED(rv)) {
delete toKey;
delete data;
return rv;
}
NS_ADDREF(data->data.edges = edgeArray.get());
mAdjacencyList->Put(toKey, data);
} else {
delete toKey;
toKey = nsnull;
mAdjacencyList->Put(&toKey, data);
}
// Now we know the FROM and TO types are represented as keys in the hashtable.
@ -212,6 +193,9 @@ nsStreamConverterService::AddAdjacency(const char *aContractID) {
if (!vertex) return NS_ERROR_OUT_OF_MEMORY;
NS_ASSERTION(fromEdges, "something wrong in adjacency list construction");
if (!fromEdges)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISupportsArray> adjacencyList = fromEdges->data.edges;
return adjacencyList->AppendElement(vertex) ? NS_OK : NS_ERROR_FAILURE; // XXX this method incorrectly returns a bool
}
@ -219,13 +203,16 @@ nsStreamConverterService::AddAdjacency(const char *aContractID) {
nsresult
nsStreamConverterService::ParseFromTo(const char *aContractID, nsCString &aFromRes, nsCString &aToRes) {
nsCString ContractIDStr(aContractID);
nsCAutoString ContractIDStr(aContractID);
PRInt32 fromLoc = ContractIDStr.Find("from=") + 5;
PRInt32 toLoc = ContractIDStr.Find("to=") + 3;
PRInt32 fromLoc = ContractIDStr.Find("from=");
PRInt32 toLoc = ContractIDStr.Find("to=");
if (-1 == fromLoc || -1 == toLoc ) return NS_ERROR_FAILURE;
nsCString fromStr, toStr;
fromLoc = fromLoc + 5;
toLoc = toLoc + 3;
nsCAutoString fromStr, toStr;
ContractIDStr.Mid(fromStr, fromLoc, toLoc - 4 - fromLoc);
ContractIDStr.Mid(toStr, toLoc, ContractIDStr.Length() - toLoc);
@ -246,15 +233,17 @@ static PRBool PR_CALLBACK InitBFSTable(nsHashKey *aKey, void *aData, void* closu
if (!BFSTable) return PR_FALSE;
BFSState *state = new BFSState;
if (!state) return NS_ERROR_OUT_OF_MEMORY;
if (!state) return PR_FALSE;
state->color = white;
state->distance = -1;
state->predecessor = nsnull;
SCTableData *data = new SCTableData;
if (!data) return NS_ERROR_OUT_OF_MEMORY;
data->key = (nsCStringKey*)aKey->Clone();
SCTableData *data = new SCTableData(*NS_STATIC_CAST(nsCStringKey*, aKey));
if (!data) {
delete state;
return PR_FALSE;
}
data->data.state = state;
BFSTable->Put(aKey, data);
@ -264,15 +253,21 @@ static PRBool PR_CALLBACK InitBFSTable(nsHashKey *aKey, void *aData, void* closu
// cleans up the BFS state table
static PRBool PR_CALLBACK DeleteBFSEntry(nsHashKey *aKey, void *aData, void *closure) {
SCTableData *data = (SCTableData*)aData;
delete data->key;
BFSState *state = data->data.state;
if (state->predecessor) // there might not be a predecessor depending on the graph
delete state->predecessor;
delete state;
delete data;
return PR_TRUE;
}
class CStreamConvDeallocator:public nsDequeFunctor {
public:
virtual void* operator()(void* anObject) {
nsCStringKey *key = (nsCStringKey*)anObject;
delete key;
return 0;
}
};
// walks the graph using a breadth-first-search algorithm which generates a discovered
// verticies tree. This tree is then walked up (from destination vertex, to origin vertex)
// and each link in the chain is added to an nsStringArray. A direct lookup for the given
@ -282,6 +277,7 @@ nsresult
nsStreamConverterService::FindConverter(const char *aContractID, nsCStringArray **aEdgeList) {
nsresult rv;
if (!aEdgeList) return NS_ERROR_NULL_POINTER;
*aEdgeList = nsnull;
// walk the graph in search of the appropriate converter.
@ -295,55 +291,80 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsCStringArray
NS_ASSERTION(lBFSTable.Count() == vertexCount, "strmconv BFS table init problem");
// This is our source vertex; our starting point.
nsCString fromC, toC;
nsCAutoString fromC, toC;
rv = ParseFromTo(aContractID, fromC, toC);
if (NS_FAILED(rv)) return rv;
nsCStringKey *source = new nsCStringKey(fromC.get());
if (!source) return NS_ERROR_OUT_OF_MEMORY;
SCTableData *data = (SCTableData*)lBFSTable.Get(source);
if (!data) return NS_ERROR_FAILURE;
if (!data) {
delete source;
return NS_ERROR_FAILURE;
}
BFSState *state = data->data.state;
state->color = gray;
state->distance = 0;
nsDeque grayQ(0);
CStreamConvDeallocator *dtorFunc = new CStreamConvDeallocator();
if (!dtorFunc) {
delete source;
return NS_ERROR_OUT_OF_MEMORY;
}
nsDeque grayQ(dtorFunc);
// Now generate the shortest path tree.
grayQ.Push(source);
while (0 < grayQ.GetSize()) {
nsHashKey *currentHead = (nsHashKey*)grayQ.PeekFront();
nsCStringKey *currentHead = (nsCStringKey*)grayQ.PeekFront();
SCTableData *data2 = (SCTableData*)mAdjacencyList->Get(currentHead);
if (!data2) return NS_ERROR_FAILURE;
nsCOMPtr<nsISupportsArray> edges = data2->data.edges;
NS_ASSERTION(edges, "something went wrong with BFS strmconv algorithm");
if (!edges) return NS_ERROR_FAILURE;
// Get the state of the current head to calculate the distance of each
// reachable vertex in the loop.
data2 = (SCTableData*)lBFSTable.Get(currentHead);
if (!data2) return NS_ERROR_FAILURE;
BFSState *headVertexState = data2->data.state;
NS_ASSERTION(headVertexState, "problem with the BFS strmconv algorithm");
if (!headVertexState) return NS_ERROR_FAILURE;
PRUint32 edgeCount = 0;
rv = edges->Count(&edgeCount);
if (NS_FAILED(rv)) return rv;
for (PRUint32 i = 0; i < edgeCount; i++) {
nsIAtom *curVertexAtom = (nsIAtom*)edges->ElementAt(i);
nsAutoString curVertexStr;
curVertexAtom->ToString(curVertexStr);
nsCStringKey *curVertex = new nsCStringKey(ToNewCString(curVertexStr),
curVertexStr.Length(), nsCStringKey::OWN);
if (!curVertex) return NS_ERROR_OUT_OF_MEMORY;
SCTableData *data3 = (SCTableData*)lBFSTable.Get(curVertex);
if (!data3) {
delete curVertex;
return NS_ERROR_FAILURE;
}
BFSState *curVertexState = data3->data.state;
NS_ASSERTION(curVertexState, "something went wrong with the BFS strmconv algorithm");
if (!curVertexState) return NS_ERROR_FAILURE;
if (white == curVertexState->color) {
curVertexState->color = gray;
curVertexState->distance = headVertexState->distance + 1;
curVertexState->predecessor = currentHead->Clone();
curVertexState->predecessor = (nsCStringKey*)currentHead->Clone();
if (!curVertexState->predecessor) {
delete curVertex;
return NS_ERROR_OUT_OF_MEMORY;
}
grayQ.Push(curVertex);
} else {
delete curVertex; // if this vertex has already been discovered, we don't want
@ -356,32 +377,36 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsCStringArray
delete cur;
cur = nsnull;
}
source = nsnull;
// 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.
nsCString fromStr, toStr;
nsCAutoString fromStr, toStr;
rv = ParseFromTo(aContractID, fromStr, toStr);
if (NS_FAILED(rv)) return rv;
// get the root CONTRACTID
nsCString ContractIDPrefix(NS_ISTREAMCONVERTER_KEY);
nsCAutoString ContractIDPrefix(NS_ISTREAMCONVERTER_KEY);
nsCStringArray *shortestPath = new nsCStringArray();
if (!shortestPath) return NS_ERROR_OUT_OF_MEMORY;
nsCStringKey toMIMEType(toStr);
data = (SCTableData*)lBFSTable.Get(&toMIMEType);
if (!data) {
// If this vertex isn't in the BFSTable, then no-one has registered for it,
// therefore we can't do the conversion.
*aEdgeList = nsnull;
delete shortestPath;
return NS_ERROR_FAILURE;
}
while (data) {
BFSState *curState = data->data.state;
nsCStringKey *key = (nsCStringKey*)data->key;
nsCStringKey *key = &(data->key);
if (fromStr.Equals(key->GetString())) {
// found it. We're done here.
@ -393,13 +418,14 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsCStringArray
// Get the predecessor.
if (!curState->predecessor) break; // no predecessor
SCTableData *predecessorData = (SCTableData*)lBFSTable.Get(curState->predecessor);
if (!predecessorData) break; // no predecessor, chain doesn't exist.
// build out the CONTRACTID.
nsCString newContractID(ContractIDPrefix);
nsCAutoString newContractID(ContractIDPrefix);
newContractID.Append("?from=");
nsCStringKey *predecessorKey = (nsCStringKey*)predecessorData->key;
nsCStringKey *predecessorKey = &(predecessorData->key);
newContractID.Append(predecessorKey->GetString());
newContractID.Append("&to=");
@ -412,10 +438,9 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsCStringArray
// move up the tree.
data = predecessorData;
}
delete shortestPath;
*aEdgeList = nsnull;
return NS_ERROR_FAILURE; // couldn't find a stream converter or chain.
}
@ -432,7 +457,7 @@ nsStreamConverterService::Convert(nsIInputStream *aFromStream,
// first determine whether we can even handle this covnversion
// build a CONTRACTID
nsCString contractID(NS_ISTREAMCONVERTER_KEY);
nsCAutoString contractID(NS_ISTREAMCONVERTER_KEY);
contractID.Append("?from=");
contractID.AppendWithConversion(aFromType);
contractID.Append("&to=");
@ -478,7 +503,7 @@ nsStreamConverterService::Convert(nsIInputStream *aFromStream,
return rv;
}
nsCString fromStr, toStr;
nsCAutoString fromStr, toStr;
rv = ParseFromTo(lContractID, fromStr, toStr);
if (NS_FAILED(rv)) {
delete converterChain;
@ -531,7 +556,7 @@ nsStreamConverterService::AsyncConvertData(const PRUnichar *aFromType,
// first determine whether we can even handle this covnversion
// build a CONTRACTID
nsCString contractID(NS_ISTREAMCONVERTER_KEY);
nsCAutoString contractID(NS_ISTREAMCONVERTER_KEY);
contractID.Append("?from=");
contractID.AppendWithConversion(aFromType);
contractID.Append("&to=");
@ -575,7 +600,7 @@ nsStreamConverterService::AsyncConvertData(const PRUnichar *aFromType,
nsCOMPtr<nsIStreamConverter> converter(do_CreateInstance(lContractID, &rv));
NS_ASSERTION(NS_SUCCEEDED(rv), "graph construction problem, built a contractid that wasn't registered");
nsCString fromStr, toStr;
nsCAutoString fromStr, toStr;
rv = ParseFromTo(lContractID, fromStr, toStr);
if (NS_FAILED(rv)) {
delete converterChain;

Просмотреть файл

@ -80,19 +80,26 @@ private:
// used to establish discovered vertecies.
enum BFScolors {white, gray, black};
typedef struct _BFSState {
struct BFSState {
BFScolors color;
PRInt32 distance;
nsHashKey *predecessor;
} BFSState;
nsCStringKey *predecessor;
~BFSState() {
if(predecessor)
delete predecessor;
}
};
// adjacency list and BFS hashtable data class.
typedef struct _tableData {
nsCStringKey *key;
struct SCTableData {
nsCStringKey key;
union _data {
BFSState *state;
nsISupportsArray *edges;
} data;
} SCTableData;
SCTableData(nsCStringKey& aKey) : key(aKey) {
data.state = nsnull;
}
};
#endif // __nsstreamconverterservice__h___