public static T CloneTree <T>(T entry) where T : IEntry { var objectMap = new Dictionary <IEntry, IEntry>(); T newRoot = CloneEntry(entry, objectMap); EntryTree tree = new EntryTree(entry.FileRef); cloneTreeRecursive(entry, newRoot); Relinker.RelinkAll(objectMap); return(newRoot); void cloneTreeRecursive(IEntry originalRootNode, IEntry newRootNode) { foreach (IEntry node in tree.GetDirectChildrenOf(originalRootNode.UIndex)) { IEntry newEntry = CloneEntry(node, objectMap); newEntry.Parent = newRootNode; cloneTreeRecursive(node, newEntry); } } }
public static IEntry cloneTree(IEntry entry) { var objectMap = new Dictionary <IEntry, IEntry>(); IEntry newRoot = cloneEntry(entry, objectMap); EntryTree tree = new EntryTree(entry.FileRef); cloneTreeRecursive(entry, newRoot); IMEPackage pcc = entry.FileRef; Relinker.RelinkAll(objectMap); return(newRoot); void cloneTreeRecursive(IEntry originalRootNode, IEntry newRootNode) { foreach (IEntry node in tree.GetDirectChildrenOf(originalRootNode.UIndex)) { IEntry newEntry = cloneEntry(node, objectMap); newEntry.Parent = newRootNode; cloneTreeRecursive(node, newEntry); } } }
/// <summary> /// Imports <paramref name="sourceEntry"/> (and possibly its children) to <paramref name="destPcc"/> in a manner defined by <paramref name="portingOption"/> /// If no <paramref name="relinkMap"/> is provided, method will create one /// </summary> /// <param name="portingOption"></param> /// <param name="sourceEntry"></param> /// <param name="destPcc"></param> /// <param name="targetLinkEntry">Can be null if cloning as a top-level entry</param> /// <param name="shouldRelink"></param> /// <param name="newEntry"></param> /// <param name="relinkMap"></param> /// <returns></returns> public static List <EntryStringPair> ImportAndRelinkEntries(PortingOption portingOption, IEntry sourceEntry, IMEPackage destPcc, IEntry targetLinkEntry, bool shouldRelink, out IEntry newEntry, Dictionary <IEntry, IEntry> relinkMap = null , Action <string> errorOccuredCallback = null) { relinkMap ??= new Dictionary <IEntry, IEntry>(); IMEPackage sourcePcc = sourceEntry.FileRef; EntryTree sourcePackageTree = new EntryTree(sourcePcc); if (portingOption == PortingOption.ReplaceSingular) { //replace data only if (sourceEntry is ExportEntry entry) { relinkMap.Add(entry, targetLinkEntry); ReplaceExportDataWithAnother(entry, targetLinkEntry as ExportEntry, errorOccuredCallback); } } RelinkerCache cache = null; if (portingOption == PortingOption.MergeTreeChildren || portingOption == PortingOption.ReplaceSingular) { newEntry = targetLinkEntry; //Root item is the one we just dropped. Use that as the root. } else { cache = new RelinkerCache(sourceEntry.FileRef, destPcc); int link = targetLinkEntry?.UIndex ?? 0; if (sourceEntry is ExportEntry sourceExport) { //importing an export newEntry = ImportExport(destPcc, sourceExport, link, portingOption == PortingOption.CloneAllDependencies, relinkMap, errorOccuredCallback, cache); } else { newEntry = GetOrAddCrossImportOrPackage(sourceEntry.FullPath, sourcePcc, destPcc, forcedLink: sourcePackageTree.NumChildrenOf(sourceEntry) == 0 ? link : (int?)null, objectMapping: relinkMap, relinkerCache: cache); } newEntry.idxLink = link; } //if this node has children if ((portingOption == PortingOption.CloneTreeAsChild || portingOption == PortingOption.MergeTreeChildren || portingOption == PortingOption.CloneAllDependencies) && sourcePackageTree.NumChildrenOf(sourceEntry) > 0) { importChildrenOf(sourceEntry, newEntry, cache); } List <EntryStringPair> relinkResults = null; if (shouldRelink) { relinkResults = Relinker.RelinkAll(relinkMap, portingOption == PortingOption.CloneAllDependencies, cache); } // Reindex - disabled for now as it causes issues //Dictionary<string, ExportEntry> itemsToReindex = new Dictionary<string, ExportEntry>(); //foreach (var v in relinkMap.Values) //{ // if (v is ExportEntry export && export.indexValue > 0) // { // itemsToReindex[export.FullPath] = export; // Match on full path. Not instanced full path! // } //} //foreach (var item in itemsToReindex) //{ // ReindexExportEntriesWithSamePath(item.Value); //} cache?.Dispose(); return(relinkResults); void importChildrenOf(IEntry sourceNode, IEntry newParent, RelinkerCache cache) { foreach (IEntry node in sourcePackageTree.GetDirectChildrenOf(sourceNode)) { if (portingOption == PortingOption.MergeTreeChildren) { //we must check to see if there is an item already matching what we are trying to port. //Todo: We may need to enhance target checking here as fullpath may not be reliable enough. Maybe have to do indexing, or something. IEntry sameObjInTarget = newParent.GetChildren().FirstOrDefault(x => node.FullPath == x.FullPath); if (sameObjInTarget != null) { relinkMap[node] = sameObjInTarget; //merge children to this node instead importChildrenOf(node, sameObjInTarget, cache); continue; } } IEntry entry; if (node is ExportEntry exportNode) { entry = ImportExport(destPcc, exportNode, newParent.UIndex, portingOption == PortingOption.CloneAllDependencies, relinkMap, errorOccuredCallback, cache); } else { entry = GetOrAddCrossImportOrPackage(node.FullPath, sourcePcc, destPcc, objectMapping: relinkMap, relinkerCache: cache); } entry.Parent = newParent; importChildrenOf(node, entry, cache); } } }
/// <summary> /// Imports <paramref name="sourceEntry"/> (and possibly its children) to <paramref name="destPcc"/> in a manner defined by <paramref name="portingOption"/> /// If no <paramref name="relinkMap"/> is provided, method will create one /// </summary> /// <param name="portingOption"></param> /// <param name="sourceEntry"></param> /// <param name="destPcc"></param> /// <param name="targetLinkEntry">Can be null if cloning as a top-level entry</param> /// <param name="shouldRelink"></param> /// <param name="newEntry"></param> /// <param name="relinkMap"></param> /// <returns></returns> public static List <string> ImportAndRelinkEntries(PortingOption portingOption, IEntry sourceEntry, IMEPackage destPcc, IEntry targetLinkEntry, bool shouldRelink, out IEntry newEntry, Dictionary <IEntry, IEntry> relinkMap = null) { relinkMap ??= new Dictionary <IEntry, IEntry>(); IMEPackage sourcePcc = sourceEntry.FileRef; EntryTree sourcePackageTree = new EntryTree(sourcePcc); if (portingOption == PortingOption.ReplaceSingular) { //replace data only if (sourceEntry is ExportEntry entry) { relinkMap.Add(entry, targetLinkEntry); ReplaceExportDataWithAnother(entry, targetLinkEntry as ExportEntry); } } if (portingOption == PortingOption.MergeTreeChildren || portingOption == PortingOption.ReplaceSingular) { newEntry = targetLinkEntry; //Root item is the one we just dropped. Use that as the root. } else { int link = targetLinkEntry?.UIndex ?? 0; if (sourceEntry is ExportEntry sourceExport) { //importing an export newEntry = ImportExport(destPcc, sourceExport, link, portingOption == PortingOption.CloneAllDependencies, relinkMap); } else { newEntry = GetOrAddCrossImportOrPackage(sourceEntry.FullPath, sourcePcc, destPcc, forcedLink: sourcePackageTree.NumChildrenOf(sourceEntry) == 0 ? link : (int?)null, objectMapping: relinkMap); } newEntry.idxLink = link; } //if this node has children if ((portingOption == PortingOption.CloneTreeAsChild || portingOption == PortingOption.MergeTreeChildren || portingOption == PortingOption.CloneAllDependencies) && sourcePackageTree.NumChildrenOf(sourceEntry) > 0) { importChildrenOf(sourceEntry, newEntry); } List <string> relinkResults = null; if (shouldRelink) { relinkResults = Relinker.RelinkAll(relinkMap, portingOption == PortingOption.CloneAllDependencies); } return(relinkResults); void importChildrenOf(IEntry sourceNode, IEntry newParent) { foreach (IEntry node in sourcePackageTree.GetDirectChildrenOf(sourceNode)) { if (portingOption == PortingOption.MergeTreeChildren) { //we must check to see if there is an item already matching what we are trying to port. //Todo: We may need to enhance target checking here as fullpath may not be reliable enough. Maybe have to do indexing, or something. IEntry sameObjInTarget = newParent.GetChildren().FirstOrDefault(x => node.FullPath == x.FullPath); if (sameObjInTarget != null) { relinkMap[node] = sameObjInTarget; //merge children to this node instead importChildrenOf(node, sameObjInTarget); continue; } } IEntry entry; if (node is ExportEntry exportNode) { entry = ImportExport(destPcc, exportNode, newParent.UIndex, portingOption == PortingOption.CloneAllDependencies, relinkMap); } else { entry = GetOrAddCrossImportOrPackage(node.FullPath, sourcePcc, destPcc, objectMapping: relinkMap); } entry.Parent = newParent; importChildrenOf(node, entry); } } }