// 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 // CONTRACTID should be made prior to calling this method in an attempt to find a direct // converter rather than walking the graph. nsresult nsStreamConverterService::FindConverter(const char *aContractID, nsTArray<nsCString> **aEdgeList) { nsresult rv; if (!aEdgeList) return NS_ERROR_NULL_POINTER; *aEdgeList = nullptr; // walk the graph in search of the appropriate converter. int32_t vertexCount = mAdjacencyList->Count(); if (0 >= vertexCount) return NS_ERROR_FAILURE; // Create a corresponding color table for each vertex in the graph. nsObjectHashtable lBFSTable(nullptr, nullptr, DeleteBFSEntry, nullptr); mAdjacencyList->Enumerate(InitBFSTable, &lBFSTable); NS_ASSERTION(lBFSTable.Count() == vertexCount, "strmconv BFS table init problem"); // This is our source vertex; our starting point. nsAutoCString 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) { delete source; return NS_ERROR_FAILURE; } BFSState *state = data->data.state; state->color = gray; state->distance = 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()) { nsCStringKey *currentHead = (nsCStringKey*)grayQ.PeekFront(); SCTableData *data2 = (SCTableData*)mAdjacencyList->Get(currentHead); if (!data2) return NS_ERROR_FAILURE; nsCOMArray<nsIAtom> *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; int32_t edgeCount = edges->Count(); for (int32_t i = 0; i < edgeCount; i++) { nsIAtom* curVertexAtom = edges->ObjectAt(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 = (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 // to leak it. (non-discovered vertex's get cleaned up when // they're popped). } } headVertexState->color = black; nsCStringKey *cur = (nsCStringKey*)grayQ.PopFront(); delete cur; cur = nullptr; } // 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. nsAutoCString fromStr, toStr; rv = ParseFromTo(aContractID, fromStr, toStr); if (NS_FAILED(rv)) return rv; // get the root CONTRACTID nsAutoCString ContractIDPrefix(NS_ISTREAMCONVERTER_KEY); nsTArray<nsCString> *shortestPath = new nsTArray<nsCString>(); 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. delete shortestPath; return NS_ERROR_FAILURE; } while (data) { BFSState *curState = data->data.state; nsCStringKey *key = data->key; if (fromStr.Equals(key->GetString())) { // found it. We're done here. *aEdgeList = shortestPath; return NS_OK; } // reconstruct the CONTRACTID. // 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. nsAutoCString newContractID(ContractIDPrefix); newContractID.AppendLiteral("?from="); nsCStringKey *predecessorKey = predecessorData->key; newContractID.Append(predecessorKey->GetString()); newContractID.AppendLiteral("&to="); newContractID.Append(key->GetString()); // Add this CONTRACTID to the chain. rv = shortestPath->AppendElement(newContractID) ? NS_OK : NS_ERROR_FAILURE; // XXX this method incorrectly returns a bool NS_ASSERTION(NS_SUCCEEDED(rv), "AppendElement failed"); // move up the tree. data = predecessorData; } delete shortestPath; return NS_ERROR_FAILURE; // couldn't find a stream converter or chain. }
// 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 // CONTRACTID should be made prior to calling this method in an attempt to find a direct // converter rather than walking the graph. nsresult nsStreamConverterService::FindConverter(const char *aContractID, nsTArray<nsCString> **aEdgeList) { nsresult rv; if (!aEdgeList) return NS_ERROR_NULL_POINTER; *aEdgeList = nullptr; // walk the graph in search of the appropriate converter. uint32_t vertexCount = mAdjacencyList.Count(); if (0 >= vertexCount) return NS_ERROR_FAILURE; // Create a corresponding color table for each vertex in the graph. BFSHashTable lBFSTable; mAdjacencyList.EnumerateRead(InitBFSTable, &lBFSTable); NS_ASSERTION(lBFSTable.Count() == vertexCount, "strmconv BFS table init problem"); // This is our source vertex; our starting point. nsAutoCString fromC, toC; rv = ParseFromTo(aContractID, fromC, toC); if (NS_FAILED(rv)) return rv; BFSTableData *data = lBFSTable.Get(fromC); if (!data) { return NS_ERROR_FAILURE; } data->color = gray; data->distance = 0; CStreamConvDeallocator *dtorFunc = new CStreamConvDeallocator(); nsDeque grayQ(dtorFunc); // Now generate the shortest path tree. grayQ.Push(new nsCString(fromC)); while (0 < grayQ.GetSize()) { nsCString *currentHead = (nsCString*)grayQ.PeekFront(); nsCOMArray<nsIAtom> *data2 = mAdjacencyList.Get(*currentHead); if (!data2) return NS_ERROR_FAILURE; // Get the state of the current head to calculate the distance of each // reachable vertex in the loop. BFSTableData *headVertexState = lBFSTable.Get(*currentHead); if (!headVertexState) return NS_ERROR_FAILURE; int32_t edgeCount = data2->Count(); for (int32_t i = 0; i < edgeCount; i++) { nsIAtom* curVertexAtom = data2->ObjectAt(i); nsCString *curVertex = new nsCString(); curVertexAtom->ToUTF8String(*curVertex); BFSTableData *curVertexState = lBFSTable.Get(*curVertex); if (!curVertexState) { delete curVertex; return NS_ERROR_FAILURE; } if (white == curVertexState->color) { curVertexState->color = gray; curVertexState->distance = headVertexState->distance + 1; curVertexState->predecessor = new nsCString(*currentHead); grayQ.Push(curVertex); } else { delete curVertex; // if this vertex has already been discovered, we don't want // to leak it. (non-discovered vertex's get cleaned up when // they're popped). } } headVertexState->color = black; nsCString *cur = (nsCString*)grayQ.PopFront(); delete cur; cur = nullptr; } // The shortest path (if any) has been generated and is represented by the chain of // BFSTableData->predecessor keys. Start at the bottom and work our way up. // first parse out the FROM and TO MIME-types being registered. nsAutoCString fromStr, toMIMEType; rv = ParseFromTo(aContractID, fromStr, toMIMEType); if (NS_FAILED(rv)) return rv; // get the root CONTRACTID nsAutoCString ContractIDPrefix(NS_ISTREAMCONVERTER_KEY); nsTArray<nsCString> *shortestPath = new nsTArray<nsCString>(); data = 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. delete shortestPath; return NS_ERROR_FAILURE; } while (data) { if (fromStr.Equals(data->key)) { // found it. We're done here. *aEdgeList = shortestPath; return NS_OK; } // reconstruct the CONTRACTID. // Get the predecessor. if (!data->predecessor) break; // no predecessor BFSTableData *predecessorData = lBFSTable.Get(*data->predecessor); if (!predecessorData) break; // no predecessor, chain doesn't exist. // build out the CONTRACTID. nsAutoCString newContractID(ContractIDPrefix); newContractID.AppendLiteral("?from="); newContractID.Append(predecessorData->key); newContractID.AppendLiteral("&to="); newContractID.Append(data->key); // Add this CONTRACTID to the chain. rv = shortestPath->AppendElement(newContractID) ? NS_OK : NS_ERROR_FAILURE; // XXX this method incorrectly returns a bool NS_ASSERTION(NS_SUCCEEDED(rv), "AppendElement failed"); // move up the tree. data = predecessorData; } delete shortestPath; return NS_ERROR_FAILURE; // couldn't find a stream converter or chain. }