/// <summary> /// See http://www.w3.org/TR/html-imports/#dfn-import-request. /// </summary> public override async Task LoadAsync(IConfiguration configuration, IResourceLoader loader) { var link = Link; var document = link.Owner; var list = ImportLists.GetOrCreateValue(document); var location = Url; var request = link.CreateRequestFor(location); var item = new ImportEntry { Relation = this, IsCycle = CheckCycle(document, location) }; _isasync = link.HasAttribute(AttributeNames.Async); list.Add(item); if (!item.IsCycle) { var nestedStatus = new TaskCompletionSource<Boolean>(); var download = loader.DownloadAsync(request); SetDownload(download); await link.ProcessResponse(download, async response => { var context = new BrowsingContext(document.Context, Sandboxes.None); var options = new CreateDocumentOptions(response, configuration) { ImportAncestor = document }; _import = await context.OpenAsync(options, CancellationToken.None).ConfigureAwait(false); nestedStatus.SetResult(true); }).ConfigureAwait(false); await nestedStatus.Task.ConfigureAwait(false); } }
private void BuildX86CorStub(ImportEntry entry) { int pos = 0; // jmp _blob.Write(ref pos, new byte[] { 0xFF, 0x25 }); // VA of IAT _relocTable.Add(_blob, pos, BaseRelocationType.HIGHLOW); _blob.Write(ref pos, (uint)0); PE.Fixups.Add(new X86CorStubFixup(_blob, entry)); }
private void Scan_WwiseEvent(TreeViewItem topLevelTree, byte[] data, int binarystart) { try { int binarypos = binarystart; List <TreeViewItem> subnodes = new List <TreeViewItem>(); int count = BitConverter.ToInt32(data, binarypos); subnodes.Add(new TreeViewItem() { Header = $"0x{binarypos:X4} Count: {count.ToString()}" }); binarypos += 4; //+ int if (count > 0) { string nodeText = $"0x{binarypos:X4} "; int val = BitConverter.ToInt32(data, binarypos); string name = val.ToString(); if (val > 0 && val <= CurrentLoadedExport.FileRef.Exports.Count) { IExportEntry exp = CurrentLoadedExport.FileRef.Exports[val - 1]; nodeText += $"{name} {exp.PackageFullName}.{exp.ObjectName} ({exp.ClassName})"; } else if (val < 0 && val != int.MinValue && Math.Abs(val) <= CurrentLoadedExport.FileRef.Imports.Count) { int csImportVal = Math.Abs(val) - 1; ImportEntry imp = CurrentLoadedExport.FileRef.Imports[csImportVal]; nodeText += $"{name} {imp.PackageFullName}.{imp.ObjectName} ({imp.ClassName})"; } subnodes.Add(new TreeViewItem() { Header = nodeText, Tag = nodeType.StructLeafObject, Name = "_" + binarypos.ToString() }); /* * * int objectindex = BitConverter.ToInt32(data, binarypos); * IEntry obj = pcc.getEntry(objectindex); * string nodeValue = obj.GetFullPath; * node.Tag = nodeType.StructLeafObject; */ } topLevelTree.ItemsSource = subnodes; } catch (Exception ex) { topLevelTree.Items.Add($"An error occured parsing the wwiseevent: {ex.Message}"); } }
public ImportSection(BinaryReader reader) : base(reader) { uint count = LEB128.ReadUInt32(reader); if (count > int.MaxValue) { throw new NotImplementedException($"Count larger than {int.MaxValue} bytes not supported."); } entries = new ImportEntry[count]; for (uint i = 0; i < count; i++) { entries[i] = new ImportEntry(reader); } }
public static void ReadImports() { int pos = header.ImportOffset; importlist = new List <ImportEntry>(); for (int i = 0; i < header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.Package = GetInt(pos); e.Link = GetInt(pos + 16); e.Name = GetInt(pos + 20); pos += 0x1C; importlist.Add(e); } }
private void BuildAMD64CorStub(ImportEntry entry) { int pos = 0; // rex.w rex.b mov rax,[following address] _blob.Write(ref pos, new byte[] { 0x48, 0xA1 }); // VA of IAT _relocTable.Add(_blob, pos, BaseRelocationType.DIR64); _blob.Write(ref pos, (ulong)0); // jmp [rax] _blob.Write(ref pos, new byte[] { 0xFF, 0xE0 }); PE.Fixups.Add(new AMD64CorStubFixup(_blob, entry)); }
private void ReadImportTable() { try { DebugLog.PrintLn("Reading Import Table..."); Imports = new List <ImportEntry>(); if (GeneralInfo.compressed) { UncompressRange(Header._offsetCompFlagEnd + 0xC, Header.HeaderLength - (Header._offsetCompFlagEnd + 0xC)); Header.DeCompBuffer.Seek(Header.ImportOffset, 0); for (int i = 0; i < Header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.idxPackage = ReadInt(Header.DeCompBuffer); e.Unk1 = ReadInt(Header.DeCompBuffer); e.idxClass = ReadInt(Header.DeCompBuffer); e.Unk2 = ReadInt(Header.DeCompBuffer); e.idxLink = ReadInt(Header.DeCompBuffer); e.idxName = ReadInt(Header.DeCompBuffer); e.Unk3 = ReadInt(Header.DeCompBuffer); Imports.Add(e); } } else { Source.Seek(Header.ImportOffset, 0); for (int i = 0; i < Header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.idxPackage = ReadInt(Source); e.Unk1 = ReadInt(Source); e.idxClass = ReadInt(Source); e.Unk2 = ReadInt(Source); e.idxLink = ReadInt(Source); e.idxName = ReadInt(Source); e.Unk3 = ReadInt(Source); Imports.Add(e); } } DebugLog.PrintLn("Done."); } catch (Exception ex) { DebugLog.PrintLn("PCCPACKAGE::READIMPORTTABLE ERROR:\n" + ex.Message); } }
private void ReadImports(MemoryStream fs) { DebugOutput.PrintLn("Reading Imports..."); Imports = new List <ImportEntry>(); fs.Seek(ImportOffset, SeekOrigin.Begin); for (int i = 0; i < ImportCount; i++) { ImportEntry import = new ImportEntry(); import.Package = Names[fs.ReadValueS32()]; fs.Seek(12, SeekOrigin.Current); import.link = fs.ReadValueS32(); import.Name = Names[fs.ReadValueS32()]; fs.Seek(-24, SeekOrigin.Current); import.raw = fs.ReadBytes(28); Imports.Add(import); } }
public void CloneEntry(int uIndex) { if (uIndex > 0) { ExportEntry e = Exports[uIndex - 1]; ExportEntry n = new ExportEntry(); n.Data = CopyArray(GetObjectData(uIndex - 1)); n.DataLoaded = true; n.Datasize = n.Data.Length; n.idxClass = e.idxClass; n.idxParent = e.idxParent; n.idxLink = e.idxLink; n.idxName = e.idxName; n.Index = GetBiggestIndex() + 1; n.idxArchetype = e.idxArchetype; n.Unk1 = e.Unk1; n.ObjectFlags = e.ObjectFlags; n.Unk2 = e.Unk2; n.Unk3 = new int[e.Unk3.Length]; for (int i = 0; i < e.Unk3.Length; i++) { n.Unk3[i] = e.Unk3[i]; } n.Unk2 = e.Unk4; n.Unk2 = e.Unk5; n.Unk2 = e.Unk6; n.Unk2 = e.Unk7; n.Unk2 = e.Unk8; Exports.Add(n); Header.ExportCount++; } else { ImportEntry e = Imports[-uIndex - 1]; ImportEntry n = new ImportEntry(); n.idxPackage = e.idxPackage; n.Unk1 = e.Unk1; n.idxClass = e.idxClass; n.Unk2 = e.Unk2; n.idxLink = e.idxLink; n.idxName = e.idxName; n.Unk3 = e.Unk3; Imports.Add(n); Header.ImportCount++; } }
private void IndexBox_TextChanged(object sender, EventArgs e) { int destIndex = -1; bool succeeded = Int32.TryParse(indexField.Text, out destIndex); if (succeeded) { if (((SupportedInputTypes & SUPPORTS_EXPORTS_ONLY) != 0)) { if (destIndex >= 0 && destIndex < pcc.Exports.Count) { //Parse IExportEntry destExport = pcc.Exports[destIndex]; selectedItemLabel.Text = destExport.GetFullPath + " (EXPORT)";; acceptButton.Enabled = true; } else { selectedItemLabel.Text = "Invalid export index (out of bounds)"; acceptButton.Enabled = false; } } else if (((SupportedInputTypes & SUPPORTS_IMPORTS_ONLY) != 0)) { if (destIndex < 0 && -destIndex + 1 < pcc.Imports.Count) { //Parse ImportEntry import = pcc.Imports[-destIndex + 1]; selectedItemLabel.Text = import.GetFullPath + " (IMPORT)"; acceptButton.Enabled = true; } else { selectedItemLabel.Text = "Invalid import index (out of bounds)"; acceptButton.Enabled = false; } } } else { selectedItemLabel.Text = "Invalid input"; acceptButton.Enabled = false; } }
public static void TrashEntries(IMEPackage pcc, IEnumerable <IEntry> itemsToTrash) { ExportEntry trashTopLevel = pcc.Exports.FirstOrDefault(x => x.idxLink == 0 && x.ObjectName == UnrealPackageFile.TrashPackageName); ImportEntry packageImport = pcc.Imports.FirstOrDefault(x => x.GetFullPath == "Core.Package"); if (packageImport == null) { ImportEntry coreImport = pcc.Imports.FirstOrDefault(x => x.GetFullPath == "Core"); if (coreImport == null) { //really small file coreImport = new ImportEntry(pcc) { idxObjectName = pcc.FindNameOrAdd("Core"), idxClassName = pcc.FindNameOrAdd("Package"), idxLink = 0, idxPackageFile = pcc.FindNameOrAdd("Core") }; pcc.addImport(coreImport); } //Package isn't an import, could be one of the 2DA files or other small ones packageImport = new ImportEntry(pcc) { idxObjectName = pcc.FindNameOrAdd("Package"), idxClassName = pcc.FindNameOrAdd("Class"), idxLink = coreImport.UIndex, idxPackageFile = pcc.FindNameOrAdd("Core") }; pcc.addImport(packageImport); } foreach (IEntry entry in itemsToTrash) { if (entry == trashTopLevel || entry.ObjectName == "Trash") //don't trash what's already been trashed { continue; } trashTopLevel = TrashEntry(entry, trashTopLevel, packageImport.UIndex); } pcc.RemoveTrailingTrash(); }
public bool Match(ImportEntry importEntry, ImportEntry matchEntry) { if (!importEntry.IsErrorStatusCode()) { _logger.Log("Error status code."); return(false); } if (!importEntry.IsMatching(matchEntry)) { _logger.Log("Error not matching."); return(false); } _logger.Log("Matching hobbies!"); return(true); }
/// <summary> /// Converts an AnimSet export to an import /// </summary> /// <param name="origEntry"></param> /// <param name="targetPackage"></param> /// <returns></returns> private static IEntry ConvertAnimSetExportToImport(IEntry origEntry, IMEPackage targetPackage) { // Check if this item is available already var found = targetPackage.FindEntry(origEntry.InstancedFullPath); if (found != null) { return(found); } // Setup the link for our import var parentPackage = targetPackage.FindEntry(origEntry.Parent.InstancedFullPath); if (parentPackage == null) { // We must add a package import parentPackage = new ImportEntry(targetPackage) { idxLink = 0, ClassName = "Package", ObjectName = origEntry.Parent.ObjectName, PackageFile = "Core" }; targetPackage.AddImport((ImportEntry)parentPackage); } // Install the import ImportEntry imp = new ImportEntry(targetPackage) { ClassName = origEntry.ClassName, idxLink = parentPackage.UIndex, ObjectName = origEntry.ObjectName, PackageFile = "Engine" }; targetPackage.AddImport(imp); return(imp); }
/// <summary> /// See http://www.w3.org/TR/html-imports/#dfn-import-request. /// </summary> public override Task LoadAsync() { var link = Link; var document = link.Owner; var list = ImportLists.GetOrCreateValue(document); var location = Url; var processor = Processor; var item = new ImportEntry { Relation = this, IsCycle = CheckCycle(document, location) }; list.Add(item); if (!item.IsCycle) { var request = link.CreateRequestFor(location); _isasync = link.HasAttribute(AttributeNames.Async); return processor?.ProcessAsync(request); } return null; }
/// <summary> /// See http://www.w3.org/TR/html-imports/#dfn-import-request. /// </summary> public override async Task LoadAsync(IConfiguration configuration, IResourceLoader loader) { var link = Link; var document = link.Owner; var list = ImportLists.GetOrCreateValue(document); var location = Url; var request = link.CreateRequestFor(location); var item = new ImportEntry { Relation = this, IsCycle = CheckCycle(document, location) }; _isasync = link.HasAttribute(AttributeNames.Async); list.Add(item); if (!item.IsCycle) { var nestedStatus = new TaskCompletionSource <Boolean>(); var download = loader.DownloadAsync(request); SetDownload(download); await link.ProcessResponse(download, async response => { var context = new BrowsingContext(document.Context, Sandboxes.None); var options = new CreateDocumentOptions(response, configuration) { ImportAncestor = document }; _import = await context.OpenAsync(options, CancellationToken.None).ConfigureAwait(false); nestedStatus.SetResult(true); }).ConfigureAwait(false); await nestedStatus.Task.ConfigureAwait(false); } }
public static IEntry cloneEntry(IEntry entry, Dictionary <IEntry, IEntry> objectMap = null) { IEntry newEntry; if (entry is ExportEntry export) { ExportEntry ent = export.Clone(); entry.FileRef.AddExport(ent); newEntry = ent; if (objectMap != null) { objectMap[export] = ent; } } else { ImportEntry imp = ((ImportEntry)entry).Clone(); entry.FileRef.AddImport(imp); newEntry = imp; //Imports are not relinked when cloning } return(newEntry); }
/// <summary> /// See http://www.w3.org/TR/html-imports/#dfn-import-request. /// </summary> public override Task LoadAsync() { var link = Link; var document = link.Owner; var list = ImportLists.GetOrCreateValue(document); var location = Url; var processor = Processor; var item = new ImportEntry { Relation = this, IsCycle = location != null && CheckCycle(document, location) }; list.Add(item); if (location != null && !item.IsCycle) { var request = link.CreateRequestFor(location); _async = link.HasAttribute(AttributeNames.Async); return(processor?.ProcessAsync(request)); } return(Task.CompletedTask); }
/// <summary> /// Attempts to relink unreal binary data to object pointers if they are part of the clone tree. /// It's gonna be an ugly mess. /// </summary> /// <param name="importpcc">PCC being imported from</param> private List <string> relinkBinaryObjects(IMEPackage importpcc) { List <string> relinkFailedReport = new List <string>(); foreach (KeyValuePair <int, int> entry in crossPCCObjectMap) { if (entry.Key > 0) { IExportEntry exp = pcc.getExport(entry.Value); byte[] binarydata = exp.getBinaryData(); if (binarydata.Length > 0) { //has binary data //This is temporary until I find a more permanent style for relinking binary try { switch (exp.ClassName) { case "WwiseEvent": { int count = BitConverter.ToInt32(binarydata, 0); for (int i = 0; i < count; i++) { int originalValue = BitConverter.ToInt32(binarydata, 4 + (i * 4)); int currentObjectRef = unrealIndexToME3ExpIndexing(originalValue); //count + i * intsize int mapped; bool isMapped = crossPCCObjectMap.TryGetValue(currentObjectRef, out mapped); if (isMapped) { mapped = me3ExpIndexingToUnreal(mapped, originalValue < 0); //if the value is 0, it would have an error anyways. Debug.WriteLine("Binary relink hit for WwiseEvent Export " + exp.UIndex + " 0x" + (4 + (i * 4)).ToString("X6") + " " + originalValue + " -> " + (mapped + 1)); WriteMem(4 + (i * 4), binarydata, BitConverter.GetBytes(mapped)); int newValue = BitConverter.ToInt32(binarydata, 4 + (i * 4)); Debug.WriteLine(originalValue + " -> " + newValue); } else { Debug.WriteLine("Binary relink missed WwiseEvent Export " + exp.UIndex + " 0x" + (4 + (i * 4)).ToString("X6") + " " + originalValue); relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: WwiseEvent referenced WwiseStream " + originalValue + " is not in the mapping tree and could not be relinked"); } } exp.setBinaryData(binarydata); } break; case "Class": { if (exp.FileRef.Game != importpcc.Game) { //Cannot relink against a different game. continue; } IExportEntry importingExp = importpcc.getExport(entry.Key); if (importingExp.ClassName != "Class") { continue; //the class was not actually set, so this is not really class. } //This is going to be pretty ugly try { byte[] newdata = importpcc.Exports[entry.Key].Data; //may need to rewrite first unreal header byte[] data = importpcc.Exports[entry.Key].Data; int offset = 0; int unrealExportIndex = BitConverter.ToInt32(data, offset); offset += 4; int superclassIndex = BitConverter.ToInt32(data, offset); if (superclassIndex < 0) { //its an import ImportEntry superclassImportEntry = importpcc.Imports[Math.Abs(unrealIndexToME3ExpIndexing(superclassIndex))]; ImportEntry newSuperclassValue = getOrAddCrossImport(superclassImportEntry.GetFullPath, importpcc, exp.FileRef); WriteMem(offset, newdata, BitConverter.GetBytes(newSuperclassValue.UIndex)); } else { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Superclass is an export in the source package and was not relinked."); } int unknown1 = BitConverter.ToInt32(data, offset); offset += 4; int classObjTree = BitConverter.ToInt32(data, offset); //Don't know if I need to do this. offset += 4; //I am not sure what these mean. However if Pt1&2 are 33/25, the following bytes that follow are extended. int headerUnknown1 = BitConverter.ToInt32(data, offset); Int64 ignoreMask = BitConverter.ToInt64(data, offset); offset += 8; Int16 labelOffset = BitConverter.ToInt16(data, offset); offset += 2; int skipAmount = 0x6; //Find end of script block. Seems to be 10 FF's. while (offset + skipAmount + 10 < data.Length) { //Debug.WriteLine("Cheecking at 0x"+(offset + skipAmount + 10).ToString("X4")); bool isEnd = true; for (int i = 0; i < 10; i++) { byte b = data[offset + skipAmount + i]; if (b != 0xFF) { isEnd = false; break; } } if (isEnd) { break; } else { skipAmount++; } } int offsetEnd = offset + skipAmount + 10; offset += skipAmount + 10; //heuristic to find end of script uint stateMask = BitConverter.ToUInt32(data, offset); offset += 4; int localFunctionsTableCount = BitConverter.ToInt32(data, offset); offset += 4; bool isMapped; for (int i = 0; i < localFunctionsTableCount; i++) { int nameTableIndex = BitConverter.ToInt32(data, offset); int nameIndex = BitConverter.ToInt32(data, offset + 4); NameReference importingName = importpcc.getNameEntry(nameTableIndex); int newFuncName = exp.FileRef.FindNameOrAdd(importingName); WriteMem(offset, newdata, BitConverter.GetBytes(newFuncName)); offset += 8; int functionObjectIndex = unrealIndexToME3ExpIndexing(BitConverter.ToInt32(data, offset)); int mapped; isMapped = crossPCCObjectMap.TryGetValue(functionObjectIndex, out mapped); if (isMapped) { mapped = me3ExpIndexingToUnreal(mapped, functionObjectIndex < 0); //if the value is 0, it would have an error anyways. WriteMem(offset, newdata, BitConverter.GetBytes(mapped)); } else { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Local function[" + i + "] could not be remapped during porting: " + functionObjectIndex + " is not in the mapping tree and could not be relinked"); } offset += 4; } int classMask = BitConverter.ToInt32(data, offset); offset += 4; if (importpcc.Game != MEGame.ME3) { offset += 1; //seems to be a blank byte here } int coreReference = BitConverter.ToInt32(data, offset); if (coreReference < 0) { //its an import ImportEntry outerclassReferenceImport = importpcc.Imports[Math.Abs(unrealIndexToME3ExpIndexing(coreReference))]; ImportEntry outerclassNewImport = getOrAddCrossImport(outerclassReferenceImport.GetFullPath, importpcc, exp.FileRef); WriteMem(offset, newdata, BitConverter.GetBytes(outerclassNewImport.UIndex)); } else { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Outerclass is an export in the original package, not relinked."); } offset += 4; if (importpcc.Game == MEGame.ME3) { offset = ClassParser_RelinkComponentsTable(importpcc, exp, relinkFailedReport, ref newdata, offset); offset = ClassParser_ReadImplementsTable(importpcc, exp, relinkFailedReport, ref newdata, offset); int postComponentsNoneNameIndex = BitConverter.ToInt32(data, offset); int postComponentNoneIndex = BitConverter.ToInt32(data, offset + 4); string postCompName = importpcc.getNameEntry(postComponentsNoneNameIndex); //This appears to be unused in ME3, it is always None it seems. int newFuncName = exp.FileRef.FindNameOrAdd(postCompName); WriteMem(offset, newdata, BitConverter.GetBytes(newFuncName)); offset += 8; int unknown4 = BitConverter.ToInt32(data, offset); offset += 4; } else { offset = ClassParser_ReadImplementsTable(importpcc, exp, relinkFailedReport, ref data, offset); offset = ClassParser_RelinkComponentsTable(importpcc, exp, relinkFailedReport, ref data, offset); int me12unknownend1 = BitConverter.ToInt32(data, offset); offset += 4; int me12unknownend2 = BitConverter.ToInt32(data, offset); offset += 4; } int defaultsClassLink = unrealIndexToME3ExpIndexing(BitConverter.ToInt32(data, offset)); int defClassLink; isMapped = crossPCCObjectMap.TryGetValue(defaultsClassLink, out defClassLink); if (isMapped) { defClassLink = me3ExpIndexingToUnreal(defClassLink, defaultsClassLink < 0); //if the value is 0, it would have an error anyways. WriteMem(offset, newdata, BitConverter.GetBytes(defClassLink)); } else { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: DefaultsClassLink cannot be currently automatically relinked by Binary Relinker. Please manually set this in Binary Editor"); } offset += 4; if (importpcc.Game == MEGame.ME3) { int functionsTableCount = BitConverter.ToInt32(data, offset); offset += 4; for (int i = 0; i < functionsTableCount; i++) { int functionsTableIndex = unrealIndexToME3ExpIndexing(BitConverter.ToInt32(data, offset)); int mapped; isMapped = crossPCCObjectMap.TryGetValue(functionsTableIndex, out mapped); if (isMapped) { mapped = me3ExpIndexingToUnreal(mapped, functionsTableIndex < 0); //if the value is 0, it would have an error anyways. WriteMem(offset, newdata, BitConverter.GetBytes(mapped)); } else { if (functionsTableIndex < 0) { ImportEntry functionObjIndex = importpcc.Imports[Math.Abs(functionsTableIndex)]; ImportEntry newFunctionObjIndex = getOrAddCrossImport(functionObjIndex.GetFullPath, importpcc, exp.FileRef); WriteMem(offset, newdata, BitConverter.GetBytes(newFunctionObjIndex.UIndex)); } else { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Full Functions List function[" + i + "] could not be remapped during porting: " + functionsTableIndex + " is not in the mapping tree and could not be relinked"); } } offset += 4; } } exp.Data = newdata; } catch (Exception ex) { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Exception relinking: " + ex.Message); } } break; default: continue; } } catch (Exception e) { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relinking failed: " + e.Message); } //Run an interpreter pass over it - we will find objectleafnodes and attempt to update the same offset in the destination file. //BinaryInterpreter binaryrelinkInterpreter = new ME3Explorer.BinaryInterpreter(importpcc, importpcc.Exports[entry.Key], pcc, pcc.Exports[entry.Value], crossPCCObjectMapping); } } } return(relinkFailedReport); }
public static void ReadImports() { int pos = header.ImportOffset; importlist = new List<ImportEntry>(); for (int i = 0; i < header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.Package = GetInt(pos); e.Link = GetInt(pos + 16); e.Name = GetInt(pos + 20); pos += 0x1C; importlist.Add(e); } }
public static IEntry GetEntryOrAddImport(IMEPackage Pcc, string importFullName) { //foreach (ImportEntry imp in Pcc.Imports) //{ // if (imp.GetFullPath == importFullName) // { // return imp; // } //} var fullPathMappingList = new List <(string fullpath, IEntry entry)>(); foreach (ImportEntry imp in Pcc.Imports) { fullPathMappingList.Add((imp.GetFullPath, imp)); } foreach (ExportEntry exp in Pcc.Exports) { fullPathMappingList.Add((exp.GetFullPath, exp)); } var directMapping = fullPathMappingList.Where(x => x.fullpath == importFullName).ToList(); if (directMapping.Count == 1) { return(directMapping[0].entry); //direct single match } //Find an upstream entry to attach our import to (we can't add exports) string[] importParts = importFullName.Split('.'); int upstreamCount = 1; IEntry upstreamEntryToAttachTo = null; string upstreamfullpath; while (upstreamCount < importParts.Length) { upstreamfullpath = string.Join(".", importParts, 0, importParts.Length - upstreamCount); var upstreammatchinglist = fullPathMappingList.Where(x => x.fullpath == upstreamfullpath).ToList(); if (upstreammatchinglist.Where(x => x.entry is ExportEntry).HasExactly(1) || upstreammatchinglist.Where(x => x.entry is ImportEntry).HasExactly(1)) { upstreamEntryToAttachTo = upstreammatchinglist[0].entry; break; } /*if (upstreamEntryToAttachTo != null) * { * break; * }*/ upstreamCount++; } //upstreamImport = Pcc.Imports.FirstOrDefault(x => x.GetFullPath == upstream); //Check if this is an export instead /* itemAsImport = Pcc.Exports.FirstOrDefault(x => x.GetFullPath == importFullName && x.indexValue == 0); * if (itemAsImport != null) * { * return itemAsImport; * }*/ //Import doesn't exist, so we're gonna need to add it //But first we need to figure out what needs to be added. //string[] importParts = importFullName.Split('.'); //List<int> upstreamLinks = new List<int>(); //0 = top level, 1 = next level... n = what we wanted to import /*ImportEntry upstreamImport = null; * string upstream = null; * while (upstreamCount < importParts.Count()) * { * upstreamfullpath = string.Join(".", importParts, 0, importParts.Count() - upstreamCount); * upstreamImport = Pcc.Imports.FirstOrDefault(x => x.GetFullPath == upstreamfullpath); * * if (upstreamImport != null) * { * break; * } * upstreamCount++; * }*/ if (upstreamEntryToAttachTo == null) { //There is nothing we can attach to. Debug.WriteLine("cannot find a top level item to attach to for " + importFullName); return(null); } //Have an upstream import, now we need to add downstream imports. ImportEntry mostdownstreamimport = null; while (upstreamCount > 0) { upstreamCount--; string fullobjectname = String.Join(".", importParts, 0, importParts.Length - upstreamCount); Dictionary <string, string> importdbinfo = ImportClassDB[fullobjectname]; int downstreamName = Pcc.FindNameOrAdd(importParts[importParts.Length - upstreamCount - 1]); Debug.WriteLine(Pcc.Names[downstreamName]); int downstreamLinkIdx = upstreamEntryToAttachTo.UIndex; Debug.WriteLine(upstreamEntryToAttachTo.GetFullPath); int downstreamPackageName = Pcc.FindNameOrAdd(importdbinfo["packagefile"]); string downstreamClassName = importdbinfo["fullclasspath"]; int lastPeriodIndex = downstreamClassName.LastIndexOf("."); if (lastPeriodIndex > 0) { downstreamClassName = importdbinfo["fullclasspath"].Substring(lastPeriodIndex + 1); } int downstreamClassNameIdx = Pcc.FindNameOrAdd(downstreamClassName); Debug.WriteLine("Finding name " + downstreamClassName); //ImportEntry classImport = getOrAddImport(); //int downstreamClass = 0; //if (classImport != null) { // downstreamClass = classImport.UIndex; //no recursion pls //} else //{ // throw new Exception("No class was found for importing"); //} mostdownstreamimport = new ImportEntry(Pcc) { idxLink = downstreamLinkIdx, idxClassName = downstreamClassNameIdx, idxObjectName = downstreamName, idxPackageFile = downstreamPackageName }; Pcc.addImport(mostdownstreamimport); upstreamEntryToAttachTo = mostdownstreamimport; } return(mostdownstreamimport); }
private void ReadImports(MemoryTributary fs) { DebugOutput.PrintLn("Reading Imports..."); Imports = new List<ImportEntry>(); fs.Seek(ImportOffset, SeekOrigin.Begin); for (int i = 0; i < ImportCount; i++) { ImportEntry import = new ImportEntry(); import.Package = Names[fs.ReadValueS32()]; fs.Seek(12, SeekOrigin.Current); import.link = fs.ReadValueS32(); import.Name = Names[fs.ReadValueS32()]; fs.Seek(-24, SeekOrigin.Current); import.raw = fs.ReadBytes(28); Imports.Add(import); } }
/// <summary> /// UDKFile class constructor. It also load namelist, importlist and exportinfo (not exportdata) from udk file /// </summary> /// <param name="udkFilePath">full path + file name of desired udk file.</param> public UDKFile(string udkFilePath, bool fullFileInMemory = false) { Loaded = true; FileName = Path.GetFullPath(udkFilePath); using (FileStream udkStream = File.OpenRead(FileName)) { Names = new List <NameEntry>(); Imports = new List <ImportEntry>(); Exports = new List <ExportEntry>(); udkStream.Read(header, 0, header.Length); //unsure about magic number. for now just let it try anything if (magic != 2653586369) { //throw new FormatException("not a udk file"); } //again, unsure of what versions ought to be supported if (lowVers != 684 && highVers != 0) { //throw new FormatException("unsupported version"); } Stream listsStream; listsStream = udkStream; headerEnd = NameOffset; // fill names list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { long currOffset = listsStream.Position; int strLength = listsStream.ReadValueS32(); NameEntry n = new NameEntry(); if (strLength < 0) { n.name = listsStream.ReadString(strLength * -2, true, Encoding.Unicode); } else { n.name = listsStream.ReadString(strLength, true, Encoding.ASCII); } n.unk = listsStream.ReadValueS32(); n.flags = listsStream.ReadValueS32(); Names.Add(n); } //Debug.WriteLine("Names done. Current offset: "+listsStream.Position); //Debug.WriteLine("Import Offset: " + ImportOffset); // fill import list //Console.Out.WriteLine("IMPORT OFFSET: " + ImportOffset); listsStream.Seek(ImportOffset, SeekOrigin.Begin); byte[] buffer = new byte[ImportEntry.byteSize]; for (int i = 0; i < ImportCount; i++) { long offset = listsStream.Position; ImportEntry e = new ImportEntry(this, listsStream); Imports.Add(e); //Debug.WriteLine("Read import " + i + " " + e.ObjectName + ", offset: " + offset); } ; // fill export list (only the headers, not the data) listsStream.Seek(ExportOffset, SeekOrigin.Begin); //Console.Out.WriteLine("Export OFFSET: " + ImportOffset); for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); ExportEntry e = new ExportEntry(this, buffer, expInfoOffset); //Debug.WriteLine("Read export " + i + " " + e.ObjectName + ", offset: " + expInfoOffset+ ", size: "+expInfoSize); Exports.Add(e); } } Debug.WriteLine(getMetadataString()); }
public void Remove(ImportEntry item) { _list.Remove(item); }
public void Add(ImportEntry item) { _list.Add(item); }
private string relinkObjectProperty(IMEPackage importingPCC, IMEPackage destinationPCC, ObjectProperty objProperty, List <KeyValuePair <int, int> > crossPCCObjectMappingList) { if (objProperty.Value == 0) { return(null); //do not relink 0 } if (importingPCC == destinationPCC && objProperty.Value < 0) { return(null); //do not relink same-pcc imports. } int sourceObjReference = objProperty.Value; if (sourceObjReference > 0) { sourceObjReference--; //make 0 based for mapping. } if (sourceObjReference < 0) { sourceObjReference++; //make 0 based for mapping. } //if (objProperty.Name != null) //{ // Debug.WriteLine(objProperty.Name); //} KeyValuePair <int, int> mapping = crossPCCObjectMappingList.Where(pair => pair.Key == sourceObjReference).FirstOrDefault(); var defaultKVP = default(KeyValuePair <int, int>); //struct comparison if (!mapping.Equals(defaultKVP)) { //relink int newval = 0; if (mapping.Value > 0) { newval = mapping.Value + 1; //reincrement } else if (mapping.Value < 0) { newval = mapping.Value - 1; //redecrement } objProperty.Value = (newval); IEntry entry = destinationPCC.getEntry(newval); string s = ""; if (entry != null) { s = entry.GetFullPath; } Debug.WriteLine("Relink hit: " + sourceObjReference + objProperty.Name + ": " + s); } else if (objProperty.Value < 0) //It's an unmapped import { //objProperty is currently pointing to importingPCC as that is where we read the properties from int n = objProperty.Value; int origvalue = n; int importZeroIndex = Math.Abs(n) - 1; //Debug.WriteLine("Relink miss, attempting JIT relink on " + n + " " + rootNode.Text); if (n < 0 && importZeroIndex < importingPCC.ImportCount) { //Get the original import ImportEntry origImport = importingPCC.getImport(importZeroIndex); string origImportFullName = origImport.GetFullPath; //Debug.WriteLine("We should import " + origImport.GetFullPath); ImportEntry crossImport = null; string linkFailedDueToError = null; try { crossImport = getOrAddCrossImport(origImportFullName, importingPCC, destinationPCC); } catch (Exception e) { //Error during relink KFreonLib.Debugging.DebugOutput.StartDebugger("PCC Relinker"); DebugOutput.PrintLn("Exception occured during relink: "); DebugOutput.PrintLn(ExceptionHandlerDialogWPF.FlattenException(e)); DebugOutput.PrintLn("You may want to consider discarding this sessions' changes as relinking was not able to properly finish."); linkFailedDueToError = e.Message; } if (crossImport != null) { //cache item. Imports are stored +1, Exports-1. Someday I will go back and make this just 0 indexed crossPCCObjectMappingList.Add(new KeyValuePair <int, int>(sourceObjReference, crossImport.UIndex + 1)); //add to mapping to speed up future relinks objProperty.Value = crossImport.UIndex; Debug.WriteLine("Relink hit: Dynamic CrossImport for " + origvalue + " " + importingPCC.getEntry(origvalue).GetFullPath + " -> " + objProperty.Value); } else { if (linkFailedDueToError != null) { Debug.WriteLine("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + ": " + importingPCC.getEntry(origvalue).GetFullPath); return("Relink failed for " + objProperty.Name + " " + objProperty.Value + ": " + linkFailedDueToError); } else if (destinationPCC.getEntry(objProperty.Value) != null) { Debug.WriteLine("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + ": " + importingPCC.getEntry(origvalue).GetFullPath); return("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + " " + destinationPCC.getEntry(objProperty.Value).GetFullPath); } else { return("Relink failed: New export does not exist - this is probably a bug in cross import code for " + objProperty.Name + " " + objProperty.Value); } } } } else { string path = importingPCC.getEntry(objProperty.Value) != null?importingPCC.getEntry(objProperty.Value).GetFullPath : "Entry not found: " + objProperty.Value; Debug.WriteLine("Relink failed: " + objProperty.Name + " " + objProperty.Value + " " + path); return("Relink failed: " + objProperty.Name + " " + objProperty.Value + " " + path); } return(null); }
private int ClassParser_RelinkComponentsTable(IMEPackage importpcc, IExportEntry exp, List <string> relinkFailedReport, ref byte[] data, int offset) { if (importpcc.Game == MEGame.ME3) { int componentTableNameIndex = BitConverter.ToInt32(data, offset); int componentTableIndex = BitConverter.ToInt32(data, offset + 4); NameReference importingName = importpcc.getNameEntry(componentTableNameIndex); int newComponentTableName = exp.FileRef.FindNameOrAdd(importingName); WriteMem(offset, data, BitConverter.GetBytes(newComponentTableName)); offset += 8; int componentTableCount = BitConverter.ToInt32(data, offset); offset += 4; for (int i = 0; i < componentTableCount; i++) { int nameTableIndex = BitConverter.ToInt32(data, offset); int nameIndex = BitConverter.ToInt32(data, offset + 4); importingName = importpcc.getNameEntry(nameTableIndex); int componentName = exp.FileRef.FindNameOrAdd(importingName); WriteMem(offset, data, BitConverter.GetBytes(componentName)); offset += 8; int componentObjectIndex = BitConverter.ToInt32(data, offset); int mapped; bool isMapped = crossPCCObjectMap.TryGetValue(componentObjectIndex, out mapped); if (isMapped) { mapped = me3ExpIndexingToUnreal(mapped, componentObjectIndex < 0); //if the value is 0, it would have an error anyways. WriteMem(offset, data, BitConverter.GetBytes(mapped)); } else { if (componentObjectIndex < 0) { ImportEntry componentObjectImport = importpcc.Imports[Math.Abs(unrealIndexToME3ExpIndexing(componentObjectIndex))]; ImportEntry newComponentObjectImport = getOrAddCrossImport(componentObjectImport.GetFullPath, importpcc, exp.FileRef); WriteMem(offset, data, BitConverter.GetBytes(newComponentObjectImport.UIndex)); } else if (componentObjectIndex > 0) //we do not remap on 0 here in binary land { relinkFailedReport.Add(exp.Index + " " + exp.GetFullPath + " binary relink error: Component[" + i + "] could not be remapped during porting: " + componentObjectIndex + " is not in the mapping tree"); } } offset += 4; } } else { int componentTableCount = BitConverter.ToInt32(data, offset); offset += 4; for (int i = 0; i < componentTableCount; i++) { int nameTableIndex = BitConverter.ToInt32(data, offset); int nameIndex = BitConverter.ToInt32(data, offset + 4); offset += 8; int componentObjectIndex = BitConverter.ToInt32(data, offset); if (componentObjectIndex != 0) { int mapped; bool isMapped = crossPCCObjectMap.TryGetValue(componentObjectIndex, out mapped); if (isMapped) { mapped = me3ExpIndexingToUnreal(mapped, componentObjectIndex < 0); //if the value is 0, it would have an error anyways. WriteMem(offset, data, BitConverter.GetBytes(mapped)); } else { if (componentObjectIndex < 0) { ImportEntry componentObjectImport = importpcc.Imports[Math.Abs(unrealIndexToME3ExpIndexing(componentObjectIndex))]; ImportEntry newComponentObjectImport = getOrAddCrossImport(componentObjectImport.GetFullPath, importpcc, exp.FileRef); WriteMem(offset, data, BitConverter.GetBytes(newComponentObjectImport.UIndex)); } else { relinkFailedReport.Add("Binary Class Component[" + i + "] could not be remapped during porting: " + componentObjectIndex + " is not in the mapping tree"); } } } offset += 4; } } return(offset); }
private void ReadImportTable() { try { DebugLog.PrintLn("Reading Import Table..."); Imports = new List<ImportEntry>(); if (GeneralInfo.compressed) { UncompressRange(Header._offsetCompFlagEnd + 0xC, Header.HeaderLength - (Header._offsetCompFlagEnd + 0xC)); Header.DeCompBuffer.Seek(Header.ImportOffset, 0); for (int i = 0; i < Header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.idxPackage = ReadInt(Header.DeCompBuffer); e.Unk1 = ReadInt(Header.DeCompBuffer); e.idxClass = ReadInt(Header.DeCompBuffer); e.Unk2 = ReadInt(Header.DeCompBuffer); e.idxLink = ReadInt(Header.DeCompBuffer); e.idxName = ReadInt(Header.DeCompBuffer); e.Unk3 = ReadInt(Header.DeCompBuffer); Imports.Add(e); } } else { Source.Seek(Header.ImportOffset, 0); for (int i = 0; i < Header.ImportCount; i++) { ImportEntry e = new ImportEntry(); e.idxPackage = ReadInt(Source); e.Unk1 = ReadInt(Source); e.idxClass = ReadInt(Source); e.Unk2 = ReadInt(Source); e.idxLink = ReadInt(Source); e.idxName = ReadInt(Source); e.Unk3 = ReadInt(Source); Imports.Add(e); } } DebugLog.PrintLn("Done."); } catch (Exception ex) { DebugLog.PrintLn("PCCPACKAGE::READIMPORTTABLE ERROR:\n" + ex.Message); } }
/// <summary> /// PCCObject class constructor. It also load namelist, importlist and exportinfo (not exportdata) from pcc file /// </summary> /// <param name="pccFilePath">full path + file name of desired pcc file.</param> public PCCObject(string pccFilePath, bool fullFileInMemory = false) { Loaded = true; pccFileName = Path.GetFullPath(pccFilePath); using (FileStream pccStream = File.OpenRead(pccFileName)) { Names = new List<string>(); Imports = new List<ImportEntry>(); Exports = new List<ExportEntry>(); pccStream.Read(header, 0, header.Length); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { throw new FormatException("not a pcc file"); } // BitConverter isn't working?!?! if (magic == 0x9E2A83C1) BitConverter.IsLittleEndian = true; else BitConverter.IsLittleEndian = true; if (lowVers != 684 && highVers != 194) { throw new FormatException("unsupported version"); } Stream listsStream; if (bCompressed) { // seeks the blocks info position pccStream.Seek(idxOffsets + 60, SeekOrigin.Begin); int generator = pccStream.ReadValueS32(); pccStream.Seek((generator * 12) + 20, SeekOrigin.Current); int blockCount = pccStream.ReadValueS32(); blockList = new List<Block>(); // creating the Block list for (int i = 0; i < blockCount; i++) { Block temp = new Block(); temp.uncOffset = pccStream.ReadValueS32(); temp.uncSize = pccStream.ReadValueS32(); temp.cprOffset = pccStream.ReadValueS32(); temp.cprSize = pccStream.ReadValueS32(); blockList.Add(temp); } // correcting the header, in case there's need to be saved Buffer.BlockCopy(BitConverter.GetBytes((int)0), 0, header, header.Length - 12, sizeof(int)); pccStream.Read(header, header.Length - 8, 8); headerEnd = (int)pccStream.Position; // copying the extraNamesList int extraNamesLenght = blockList[0].cprOffset - headerEnd; if (extraNamesLenght > 0) { extraNamesList = new byte[extraNamesLenght]; pccStream.Read(extraNamesList, 0, extraNamesLenght); //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin"); //fileStream.Write(extraNamesList, 0, extraNamesLenght); //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8")); } // decompress first block that holds infos about names, imports and exports pccStream.Seek(blockList[0].cprOffset, SeekOrigin.Begin); byte[] uncBlock = ZBlock.Decompress(pccStream, blockList[0].cprSize); // write decompressed block inside temporary stream listsStream = new MemoryStream(); listsStream.Seek(blockList[0].uncOffset, SeekOrigin.Begin); listsStream.Write(uncBlock, 0, uncBlock.Length); } else { listsStream = pccStream; headerEnd = (int)NameOffset; // copying the extraNamesList int extraNamesLenght = headerEnd - headerSize; if (extraNamesLenght > 0) { extraNamesList = new byte[extraNamesLenght]; listsStream.Seek(headerSize, SeekOrigin.Begin); listsStream.Read(extraNamesList, 0, extraNamesLenght); //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin"); //fileStream.Write(extraNamesList, 0, extraNamesLenght); //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8")); } } /*if(bExtraNamesList) { int extraNamesListSize = namesOffset - headerEnd; extraNamesList = new byte[extraNamesListSize]; pccStream.Seek(headerEnd, SeekOrigin.Begin); pccStream.Read(extraNamesList, 0, extraNamesList.Length); }*/ // fill names list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { long currOffset = listsStream.Position; int strLength = listsStream.ReadValueS32(); string str = listsStream.ReadString(strLength * -2, true, Encoding.Unicode); //Debug.WriteLine("Read name "+i+" "+str+" length: " + strLength+", offset: "+currOffset); Names.Add(str); } //Debug.WriteLine("Names done. Current offset: "+listsStream.Position); //Debug.WriteLine("Import Offset: " + ImportOffset); // fill import list Console.Out.WriteLine("IMPORT OFFSET: " + ImportOffset); listsStream.Seek(ImportOffset, SeekOrigin.Begin); byte[] buffer = new byte[ImportEntry.byteSize]; for (int i = 0; i < ImportCount; i++) { long offset = listsStream.Position; ImportEntry e = new ImportEntry(this, listsStream); Imports.Add(e); //Debug.WriteLine("Read import " + i + " " + e.ObjectName + ", offset: " + offset); } Debug.WriteLine("Imports done. Current offset: " + listsStream.Position); Debug.WriteLine("Export Offset: " + ExportOffset); // fill export list (only the headers, not the data) listsStream.Seek(ExportOffset, SeekOrigin.Begin); Console.Out.WriteLine("Export OFFSET: " + ImportOffset); for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); ExportEntry e = new ExportEntry(this, buffer, expInfoOffset); //Debug.WriteLine("Read export " + i + " " + e.ObjectName + ", offset: " + expInfoOffset+ ", size: "+expInfoSize); Exports.Add(e); } } Debug.WriteLine(getMetadataString()); }
public void CloneEntry(int uIndex) { if (uIndex > 0) { ExportEntry e = Exports[uIndex - 1]; ExportEntry n = new ExportEntry(); n.Data = CopyArray(GetObjectData(uIndex - 1)); n.DataLoaded = true; n.Datasize = n.Data.Length; n.idxClass = e.idxClass; n.idxParent = e.idxParent; n.idxLink = e.idxLink; n.idxName = e.idxName; n.Index = GetBiggestIndex() + 1; n.idxArchetype = e.idxArchetype; n.Unk1 = e.Unk1; n.ObjectFlags = e.ObjectFlags; n.Unk2 = e.Unk2; n.Unk3 = new int[e.Unk3.Length]; for (int i = 0; i < e.Unk3.Length; i++) n.Unk3[i] = e.Unk3[i]; n.Unk2 = e.Unk4; n.Unk2 = e.Unk5; n.Unk2 = e.Unk6; n.Unk2 = e.Unk7; n.Unk2 = e.Unk8; Exports.Add(n); Header.ExportCount++; } else { ImportEntry e = Imports[-uIndex - 1]; ImportEntry n = new ImportEntry(); n.idxPackage = e.idxPackage; n.Unk1 = e.Unk1; n.idxClass = e.idxClass; n.Unk2 = e.Unk2; n.idxLink = e.idxLink; n.idxName = e.idxName; n.Unk3 = e.Unk3; Imports.Add(n); Header.ImportCount++; } }
/// <summary> /// Adds an import from the importingPCC to the destinationPCC with the specified importFullName, or returns the existing one if it can be found. /// This method will look at importingPCC's import upstream chain and check for the most downstream one's existence in destinationPCC, /// including if none can be founc (in which case the entire upstream is copied). It will then create new imports to match the remaining /// downstream ones and return the originally named import, however now located in destinationPCC. /// </summary> /// <param name="importFullName">GetFullPath() of an import from ImportingPCC</param> /// <param name="importingPCC">PCC to import imports from</param> /// <param name="destinationPCC">PCC to add imports to</param> /// <returns></returns> private ImportEntry getOrAddCrossImport(string importFullName, IMEPackage importingPCC, IMEPackage destinationPCC, int?forcedLinkIdx = null) { //This code is kind of ugly, sorry. //see if this import exists locally foreach (ImportEntry imp in destinationPCC.Imports) { if (imp.GetFullPath == importFullName) { return(imp); } } //Import doesn't exist, so we're gonna need to add it //But first we need to figure out what needs to be added upstream as links //Search upstream until we find something, or we can't get any more upstreams ImportEntry mostdownstreamimport = null; string[] importParts = importFullName.Split('.'); if (!forcedLinkIdx.HasValue) { List <int> upstreamLinks = new List <int>(); //0 = top level, 1 = next level... n = what we wanted to import int upstreamCount = 1; ImportEntry upstreamImport = null; //get number of required upstream imports that do not yet exist while (upstreamCount < importParts.Count()) { string upstream = String.Join(".", importParts, 0, importParts.Count() - upstreamCount); foreach (ImportEntry imp in destinationPCC.Imports) { if (imp.GetFullPath == upstream) { upstreamImport = imp; break; } } if (upstreamImport != null) { //We found an upsteam import that already exists break; } upstreamCount++; } IExportEntry donorUpstreamExport = null; if (upstreamImport == null) { //We have to import the entire upstream chain string fullobjectname = importParts[0]; ImportEntry donorTopLevelImport = null; foreach (ImportEntry imp in importingPCC.Imports) //importing side info we will move to our dest pcc { if (imp.GetFullPath == fullobjectname) { donorTopLevelImport = imp; break; } } if (donorTopLevelImport == null) { //This is issue KinkoJiro had. It is aborting relinking at this step. Will need to find a way to //work with exports as parents for imports which will block it. //Update: This has been partially implemented. Debug.WriteLine("No upstream import was found in the source file. It's probably an export: " + importFullName); foreach (IExportEntry exp in destinationPCC.Exports) //importing side info we will move to our dest pcc { //Console.WriteLine(exp.GetFullPath); if (exp.GetFullPath == fullobjectname) { // = imp; //We will need to find a way to cross map this as this will block cross import mapping unless these exports already exist. Debug.WriteLine("FOUND UPSTREAM, AS EXPORT!"); KFreonLib.Debugging.DebugOutput.StartDebugger("Package Editor Relinker"); KFreonLib.Debugging.DebugOutput.PrintLn("Error: Upstream item that is required is an export in the pcc to import from: " + fullobjectname); donorUpstreamExport = exp; upstreamCount--; //level 1 now from the top down //Create new import with this as higher IDK break; } } if (donorUpstreamExport == null) { Debug.WriteLine("An error has occured. Could not find an upstream import or export for relinking: " + fullobjectname + " from " + pcc.FileName); return(null); } } if (donorUpstreamExport == null) { //Create new toplevel import and set that as the most downstream one. (top = bottom at this point) int downstreamPackageFile = destinationPCC.FindNameOrAdd(Path.GetFileNameWithoutExtension(donorTopLevelImport.PackageFile)); int downstreamClassName = destinationPCC.FindNameOrAdd(donorTopLevelImport.ClassName); int downstreamName = destinationPCC.FindNameOrAdd(fullobjectname); mostdownstreamimport = new ImportEntry(destinationPCC); // mostdownstreamimport.idxLink = downstreamLinkIdx; ?? mostdownstreamimport.idxClassName = downstreamClassName; mostdownstreamimport.idxObjectName = downstreamName; mostdownstreamimport.idxPackageFile = downstreamPackageFile; destinationPCC.addImport(mostdownstreamimport); //Add new top level downstream import upstreamImport = mostdownstreamimport; upstreamCount--; //level 1 now from the top down //return null; } } //Have an upstream import, now we need to add downstream imports. while (upstreamCount > 0) { upstreamCount--; string fullobjectname = String.Join(".", importParts, 0, importParts.Count() - upstreamCount); ImportEntry donorImport = null; //Get or create names for creating import and get upstream linkIdx int downstreamName = destinationPCC.FindNameOrAdd(importParts[importParts.Count() - upstreamCount - 1]); foreach (ImportEntry imp in importingPCC.Imports) //importing side info we will move to our dest pcc { if (imp.GetFullPath == fullobjectname) { donorImport = imp; break; } } if (donorImport == null) { throw new Exception("No suitable upstream import was found for porting - this may be an export in the source file that is referenced as a parent or dependency. You should import this object and its parents first. " + fullobjectname + "(as part of " + importFullName + ")"); } int downstreamPackageFile = destinationPCC.FindNameOrAdd(Path.GetFileNameWithoutExtension(donorImport.PackageFile)); int downstreamClassName = destinationPCC.FindNameOrAdd(donorImport.ClassName); mostdownstreamimport = new ImportEntry(destinationPCC); mostdownstreamimport.idxLink = donorUpstreamExport == null ? upstreamImport.UIndex : donorUpstreamExport.UIndex; mostdownstreamimport.idxClassName = downstreamClassName; mostdownstreamimport.idxObjectName = downstreamName; mostdownstreamimport.idxPackageFile = downstreamPackageFile; destinationPCC.addImport(mostdownstreamimport); upstreamImport = mostdownstreamimport; } } else { //get importing import ImportEntry importingImport = importingPCC.Imports.FirstOrDefault(x => x.GetFullPath == importFullName); //this shouldn't be null mostdownstreamimport = new ImportEntry(destinationPCC); mostdownstreamimport.idxLink = forcedLinkIdx.Value; mostdownstreamimport.idxClassName = destinationPCC.FindNameOrAdd(importingImport.ClassName); mostdownstreamimport.idxObjectName = destinationPCC.FindNameOrAdd(importingImport.ObjectName); mostdownstreamimport.idxPackageFile = destinationPCC.FindNameOrAdd(Path.GetFileNameWithoutExtension(importingImport.PackageFile)); destinationPCC.addImport(mostdownstreamimport); } return(mostdownstreamimport); }
/// <summary> /// Creates a preview of the given <see cref="SkeletalMesh"/>. /// </summary> /// <param name="Device">The Direct3D device to use for buffer creation.</param> /// <param name="m">The mesh to generate a preview for.</param> /// <param name="texcache">The texture cache for loading textures.</param> public ModelPreview(Device Device, SkeletalMesh m, PreviewTextureCache texcache, PackageCache assetCache, PreloadedModelData preloadedData = null) { // STEP 1: MATERIALS if (preloadedData == null) { for (int i = 0; i < m.Materials.Length; i++) { UIndex materialUIndex = m.Materials[i]; MaterialInstanceConstant mat = null; if (materialUIndex.value > 0) { mat = new MaterialInstanceConstant(m.Export.FileRef.GetUExport(materialUIndex.value)); } else if (materialUIndex.value < 0) { // The material instance is an import! ImportEntry matImport = m.Export.FileRef.GetImport(materialUIndex.value); var externalAsset = EntryImporter.ResolveImport(matImport, null, assetCache); if (externalAsset != null) { mat = new MaterialInstanceConstant(externalAsset); } } if (mat != null) { ModelPreviewMaterial material; // TODO: pick what material class best fits based on what properties the // MaterialInstanceConstant mat has. // For now, just use the default material. material = new TexturedPreviewMaterial(texcache, mat, assetCache); AddMaterial(material.Properties["Name"], material); } } } else { //Preloaded //sections = preloadedData.sections; var uniqueMaterials = preloadedData.texturePreviewMaterials.Select(x => x.MaterialExport).Distinct(); foreach (var mat in uniqueMaterials) { var material = new TexturedPreviewMaterial(texcache, new MaterialInstanceConstant(mat), assetCache, preloadedData.texturePreviewMaterials); AddMaterial(mat.ObjectName.Name, material); } } // STEP 2: LODS foreach (var lodmodel in m.LODModels) { // Vertices List <WorldVertex> vertices = new List <WorldVertex>(m.Export.Game == MEGame.ME1 ? lodmodel.ME1VertexBufferGPUSkin.Length : lodmodel.VertexBufferGPUSkin.VertexData.Length); if (m.Export.Game == MEGame.ME1) { foreach (var vertex in lodmodel.ME1VertexBufferGPUSkin) { vertices.Add(new WorldVertex(new Vector3(-vertex.Position.X, vertex.Position.Z, vertex.Position.Y), Vector3.Zero, new Vector2(vertex.UV.X, vertex.UV.Y))); } } else { foreach (var vertex in lodmodel.VertexBufferGPUSkin.VertexData) { vertices.Add(new WorldVertex(new Vector3(-vertex.Position.X, vertex.Position.Z, vertex.Position.Y), Vector3.Zero, new Vector2(vertex.UV.X, vertex.UV.Y))); } } // Triangles List <Triangle> triangles = new List <Triangle>(lodmodel.IndexBuffer.Length / 3); for (int i = 0; i < lodmodel.IndexBuffer.Length; i += 3) { triangles.Add(new Triangle(lodmodel.IndexBuffer[i], lodmodel.IndexBuffer[i + 1], lodmodel.IndexBuffer[i + 2])); } WorldMesh mesh = new WorldMesh(Device, triangles, vertices); // Sections List <ModelPreviewSection> sections = new List <ModelPreviewSection>(); foreach (var section in lodmodel.Sections) { if (section.MaterialIndex < Materials.Count) { sections.Add(new ModelPreviewSection(Materials.Keys.ElementAt(section.MaterialIndex), section.BaseIndex, (uint)section.NumTriangles)); } } LODs.Add(new ModelPreviewLOD(mesh, sections)); } }
private void ReadImports(FileStream fs) { int pos = ImportOffset; Imports = new List<ImportEntry>(); for (int i = 0; i < ImportCount; i++) { int start = pos; int package = ReadInt32(fs, pos); pos += 16; int link = ReadInt32(fs, pos); pos += 4; int name = ReadInt32(fs, pos); pos += 8; int len = pos - start; byte[] buff = new byte[len]; fs.Seek(start, SeekOrigin.Begin); for (int j = 0; j < len; j++) buff[j] = (byte)fs.ReadByte(); ImportEntry e = new ImportEntry(); e.Package = package; e.link = link; e.name = name; e.raw = buff; Imports.Add(e); } }
public static bool IsErrorStatusCode(this ImportEntry importEntry) { return(importEntry.StatusCode != 0); }
/// <summary> /// Imports an export from another package file. /// </summary> /// <param name="mePackage"></param> /// <param name="ex">Export object from the other package to import</param> /// <param name="link">Local parent node UIndex</param> /// <param name="outputEntry">Newly generated export entry reference</param> /// <returns></returns> private static bool importExport(IMEPackage mePackage, ExportEntry ex, int link, out ExportEntry outputEntry) { byte[] prePropBinary; if (ex.HasStack) { if (mePackage.Game < MEGame.ME3) { prePropBinary = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }; } else { prePropBinary = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }; } } else { int start = ex.GetPropertyStart(); prePropBinary = new byte[start]; } PropertyCollection props = ex.GetProperties(); //store copy of names list in case something goes wrong List <string> names = mePackage.Names.ToList(); try { if (ex.Game != mePackage.Game) { props = EntryPruner.RemoveIncompatibleProperties(ex.FileRef, props, ex.ClassName, mePackage.Game); } } catch (Exception exception) { //restore namelist in event of failure. mePackage.setNames(names); Console.WriteLine($"Error occured while trying to import {ex.ObjectName} : {exception.Message}"); //MessageBox.Show($"Error occured while trying to import {ex.ObjectName} : {exception.Message}"); outputEntry = null; return(false); } //takes care of slight header differences between ME1/2 and ME3 byte[] newHeader = ex.GenerateHeader(mePackage.Game); //for supported classes, this will add any names in binary to the Name table, as well as take care of binary differences for cross-game importing //for unsupported classes, this will just copy over the binary byte[] binaryData = ExportBinaryConverter.ConvertPostPropBinary(ex, mePackage.Game).ToArray(mePackage); int classValue = 0; int archetype = 0; int superclass = 0; //Set class. This will only work if the class is an import, as we can't reliably pull in exports without lots of other stuff. if (ex.idxClass < 0) { //The class of the export we are importing is an import. We should attempt to relink this. ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxClass); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); classValue = newClassImport.UIndex; } else if (ex.idxClass > 0) { //Todo: Add cross mapping support as multi-mode will allow this to work now ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxClass); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { classValue = matchingExport.UIndex; } } //Set superclass if (ex.idxSuperClass < 0) { //The class of the export we are importing is an import. We should attempt to relink this. ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxSuperClass); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); superclass = newClassImport.UIndex; } else if (ex.idxSuperClass > 0) { //Todo: Add cross mapping support as multi-mode will allow this to work now ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxSuperClass); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { superclass = matchingExport.UIndex; } } //Check archetype. if (ex.idxArchtype < 0) { ImportEntry portingFromClassImport = ex.FileRef.getImport(ex.idxArchtype); IEntry newClassImport = getOrAddCrossImportOrPackage(portingFromClassImport.GetFullPath, ex.FileRef, mePackage); archetype = newClassImport.UIndex; } else if (ex.idxArchtype > 0) { ExportEntry portingInClass = ex.FileRef.getUExport(ex.idxArchtype); ExportEntry matchingExport = mePackage.Exports.FirstOrDefault(x => x.GetIndexedFullPath == portingInClass.GetIndexedFullPath); if (matchingExport != null) { archetype = matchingExport.UIndex; } } outputEntry = new ExportEntry(mePackage, prePropBinary, props, binaryData) { Header = newHeader, idxClass = classValue, idxObjectName = mePackage.FindNameOrAdd(ex.FileRef.getNameEntry(ex.idxObjectName)), idxLink = link, idxSuperClass = superclass, idxArchtype = archetype }; mePackage.addExport(outputEntry); return(true); }
/// <summary> /// PCCObject class constructor. It also load namelist, importlist and exportinfo (not exportdata) from pcc file /// </summary> /// <param name="pccFilePath">full path + file name of desired pcc file.</param> public PCCObject(string pccFilePath, bool fullFileInMemory = false) { Loaded = true; pccFileName = Path.GetFullPath(pccFilePath); Debug.WriteLine("Loading pcc " + pccFileName); using (FileStream pccStream = File.OpenRead(pccFileName)) { Names = new List <string>(); Imports = new List <ImportEntry>(); Exports = new List <ExportEntry>(); pccStream.Read(header, 0, header.Length); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { throw new FormatException("not a pcc file"); } // BitConverter isn't working?!?! if (magic == 0x9E2A83C1) { BitConverter.IsLittleEndian = true; } else { BitConverter.IsLittleEndian = true; } if (lowVers != 684 && highVers != 194) { throw new FormatException("unsupported version"); } Stream listsStream; if (bCompressed) { Debug.WriteLine("COMPRESSED..."); // seeks the blocks info position pccStream.Seek(idxOffsets + 60, SeekOrigin.Begin); int generator = pccStream.ReadValueS32(); pccStream.Seek((generator * 12) + 20, SeekOrigin.Current); int blockCount = pccStream.ReadValueS32(); blockList = new List <Block>(); // creating the Block list for (int i = 0; i < blockCount; i++) { Block temp = new Block(); temp.uncOffset = pccStream.ReadValueS32(); temp.uncSize = pccStream.ReadValueS32(); temp.cprOffset = pccStream.ReadValueS32(); temp.cprSize = pccStream.ReadValueS32(); blockList.Add(temp); } // correcting the header, in case there's need to be saved Buffer.BlockCopy(BitConverter.GetBytes((int)0), 0, header, header.Length - 12, sizeof(int)); pccStream.Read(header, header.Length - 8, 8); headerEnd = (int)pccStream.Position; // copying the extraNamesList int extraNamesLenght = blockList[0].cprOffset - headerEnd; if (extraNamesLenght > 0) { extraNamesList = new byte[extraNamesLenght]; pccStream.Read(extraNamesList, 0, extraNamesLenght); //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin"); //fileStream.Write(extraNamesList, 0, extraNamesLenght); //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8")); } // decompress first block that holds infos about names, imports and exports pccStream.Seek(blockList[0].cprOffset, SeekOrigin.Begin); byte[] uncBlock = ZBlock.Decompress(pccStream, blockList[0].cprSize); // write decompressed block inside temporary stream listsStream = new MemoryStream(); listsStream.Seek(blockList[0].uncOffset, SeekOrigin.Begin); listsStream.Write(uncBlock, 0, uncBlock.Length); } else { listsStream = pccStream; headerEnd = (int)NameOffset; // copying the extraNamesList int extraNamesLenght = headerEnd - headerSize; if (extraNamesLenght > 0) { extraNamesList = new byte[extraNamesLenght]; listsStream.Seek(headerSize, SeekOrigin.Begin); listsStream.Read(extraNamesList, 0, extraNamesLenght); //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin"); //fileStream.Write(extraNamesList, 0, extraNamesLenght); //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8")); } } /*if(bExtraNamesList) * { * int extraNamesListSize = namesOffset - headerEnd; * extraNamesList = new byte[extraNamesListSize]; * pccStream.Seek(headerEnd, SeekOrigin.Begin); * pccStream.Read(extraNamesList, 0, extraNamesList.Length); * }*/ // fill names list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { long currOffset = listsStream.Position; int strLength = listsStream.ReadValueS32(); string str = listsStream.ReadString(strLength * -2, true, Encoding.Unicode); //Debug.WriteLine("Read name "+i+" "+str+" length: " + strLength+", offset: "+currOffset); Names.Add(str); } //Debug.WriteLine("Names done. Current offset: "+listsStream.Position); //Debug.WriteLine("Import Offset: " + ImportOffset); // fill import list //Console.Out.WriteLine("IMPORT OFFSET: " + ImportOffset); listsStream.Seek(ImportOffset, SeekOrigin.Begin); byte[] buffer = new byte[ImportEntry.byteSize]; for (int i = 0; i < ImportCount; i++) { long offset = listsStream.Position; ImportEntry e = new ImportEntry(this, listsStream); Imports.Add(e); //Debug.WriteLine("Read import " + i + " " + e.ObjectName + ", offset: " + offset); } ; // fill export list (only the headers, not the data) listsStream.Seek(ExportOffset, SeekOrigin.Begin); //Console.Out.WriteLine("Export OFFSET: " + ImportOffset); for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); ExportEntry e = new ExportEntry(this, buffer, expInfoOffset); //Debug.WriteLine("Read export " + i + " " + e.ObjectName + ", offset: " + expInfoOffset+ ", size: "+expInfoSize); Exports.Add(e); } } //Debug.WriteLine(getMetadataString()); }
/// <summary> /// Adds an import from the importingPCC to the destinationPCC with the specified importFullName, or returns the existing one if it can be found. /// This will add parent imports and packages as neccesary /// </summary> /// <param name="importFullName">GetFullPath() of an import from ImportingPCC</param> /// <param name="importingPCC">PCC to import imports from</param> /// <param name="destinationPCC">PCC to add imports to</param> /// <param name="forcedLink">force this as parent</param> /// <returns></returns> public static IEntry getOrAddCrossImportOrPackage(string importFullName, IMEPackage importingPCC, IMEPackage destinationPCC, int?forcedLink = null) { if (string.IsNullOrEmpty(importFullName)) { return(null); } //see if this import exists locally foreach (ImportEntry imp in destinationPCC.Imports) { if (imp.GetFullPath == importFullName) { return(imp); } } //see if this is an export Package and exists locally foreach (ExportEntry exp in destinationPCC.Exports) { if (exp.ClassName == "Package" && exp.GetFullPath == importFullName) { return(exp); } } if (forcedLink is int link) { ImportEntry importingImport = importingPCC.Imports.First(x => x.GetFullPath == importFullName); //this shouldn't be null var newImport = new ImportEntry(destinationPCC) { idxLink = link, idxClassName = destinationPCC.FindNameOrAdd(importingImport.ClassName), idxObjectName = destinationPCC.FindNameOrAdd(importingImport.ObjectName), idxPackageFile = destinationPCC.FindNameOrAdd(importingImport.PackageFile) }; destinationPCC.addImport(newImport); return(newImport); } string[] importParts = importFullName.Split('.'); //recursively ensure parent package exists. when importParts.Length == 1, this will return null IEntry parent = getOrAddCrossImportOrPackage(string.Join(".", importParts.Take(importParts.Length - 1)), importingPCC, destinationPCC); foreach (ImportEntry imp in importingPCC.Imports) { if (imp.GetFullPath == importFullName) { var import = new ImportEntry(destinationPCC) { idxLink = parent?.UIndex ?? 0, idxClassName = destinationPCC.FindNameOrAdd(imp.ClassName), idxObjectName = destinationPCC.FindNameOrAdd(imp.ObjectName), idxPackageFile = destinationPCC.FindNameOrAdd(imp.PackageFile) }; destinationPCC.addImport(import); return(import); } } foreach (ExportEntry exp in importingPCC.Exports) { if (exp.ClassName == "Package" && exp.GetFullPath == importFullName) { importExport(destinationPCC, exp, parent?.UIndex ?? 0, out ExportEntry package); return(package); } } throw new Exception($"Unable to add {importFullName} to file! Could not find it!"); }
// Todo: ME3Exp 5.1: Get rid of this and use the import resolver. It must support a cache so we don't constnatly open packages internal static ExportEntry FindExternalAsset(ImportEntry entry, List <ExportEntry> alreadyLoadedPackageEntries, List <IMEPackage> openedPackages) { //Debug.WriteLine("Finding external asset " + entry.GetFullPath); if (entry.Game == MEGame.ME1) { var sourcePackageInternalPath = entry.FullPath.Substring(entry.FullPath.IndexOf('.') + 1); string baseName = entry.FileRef.FollowLink(entry.idxLink).Split('.')[0].ToUpper() + ".upk"; //Get package filename var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(baseName, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null && MELoadedFiles.GetFilesLoadedInGame(MEGame.ME1).TryGetValue(baseName, out string packagePath)) { var package = MEPackageHandler.OpenMEPackage(packagePath); if (openedPackages != null && !openedPackages.Contains(package)) { openedPackages.Add(package); } var foundExp = package.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } if (openedPackages == null) { package.Dispose(); } } else { Debug.WriteLine("ME1 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } else { // Next, split the filename by underscores string filenameWithoutExtension = Path.GetFileNameWithoutExtension(entry.FileRef.FilePath).ToLower(); string containingDirectory = Path.GetDirectoryName(entry.FileRef.FilePath); var packagesToCheck = new List <string>(); var gameFiles = MELoadedFiles.GetFilesLoadedInGame(entry.Game); if (filenameWithoutExtension.StartsWith("bioa_") || filenameWithoutExtension.StartsWith("biod_")) { string[] parts = filenameWithoutExtension.Split('_'); if (parts.Length >= 2) //BioA_Nor_WowThatsAlot310.pcc { string bioad = $"{parts[0]}_{parts[1]}.pcc"; string filename = Path.Combine(containingDirectory, bioad); //BioA_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } string biop = $"BioP_{parts[1]}.pcc"; filename = Path.Combine(containingDirectory, biop); //BioP_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } } } // Add globals packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "SFXGame.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "EntryMenu.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), entry.Game == MEGame.ME3 ? "Startup.pcc" : "Startup_INT.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "Engine.pcc")); packagesToCheck.Add(Path.Combine(MEDirectories.GetCookedPath(entry.Game), "Engine.u")); //ME1 foreach (string packagePath in packagesToCheck) { if (File.Exists(packagePath)) { var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(packagePath, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null) { var sentry = searchPackageForEntry(packagePath, entry.FullPath, entry.ClassName, openedPackages); if (sentry != null) { return(sentry); } } else { Debug.WriteLine("ME2/3 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } } } Debug.WriteLine("Could not find external asset: " + entry.FullPath); return(null); }
private static string relinkUIndex(IMEPackage importingPCC, ExportEntry relinkingExport, ref int uIndex, string propertyName, OrderedMultiValueDictionary <IEntry, IEntry> crossPCCObjectMappingList, string prefix, bool importExportDependencies = false) { if (uIndex == 0) { return(null); //do not relink 0 } IMEPackage destinationPcc = relinkingExport.FileRef; if (importingPCC == destinationPcc && uIndex < 0) { return(null); //do not relink same-pcc imports. } int sourceObjReference = uIndex; //Debug.WriteLine($"{prefix} Relinking:{propertyName}"); if (crossPCCObjectMappingList.TryGetValue(entry => entry.UIndex == sourceObjReference, out IEntry targetEntry)) { //relink uIndex = targetEntry.UIndex; //Debug.WriteLine($"{prefix} Relink hit: {sourceObjReference}{propertyName} : {targetEntry.FullPath}"); } else if (uIndex < 0) //It's an unmapped import { //objProperty is currently pointing to importingPCC as that is where we read the properties from int n = uIndex; int origvalue = n; //Debug.WriteLine("Relink miss, attempting JIT relink on " + n + " " + rootNode.Text); if (importingPCC.IsImport(n)) { //Get the original import ImportEntry origImport = importingPCC.GetImport(n); string origImportFullName = origImport.FullPath; //Debug.WriteLine("We should import " + origImport.GetFullPath); IEntry crossImport = null; string linkFailedDueToError = null; try { crossImport = EntryImporter.GetOrAddCrossImportOrPackage(origImportFullName, importingPCC, destinationPcc); } catch (Exception e) { //Error during relink DebugOutput.StartDebugger("PCC Relinker"); DebugOutput.PrintLn("Exception occured during relink: "); DebugOutput.PrintLn(ExceptionHandlerDialogWPF.FlattenException(e)); DebugOutput.PrintLn("You may want to consider discarding this sessions' changes as relinking was not able to properly finish."); linkFailedDueToError = e.Message; } if (crossImport != null) { crossPCCObjectMappingList.Add(origImport, crossImport); //add to mapping to speed up future relinks uIndex = crossImport.UIndex; // Debug.WriteLine($"Relink hit: Dynamic CrossImport for {origvalue} {importingPCC.GetEntry(origvalue).FullPath} -> {uIndex}"); } else { string path = importingPCC.GetEntry(uIndex) != null?importingPCC.GetEntry(uIndex).FullPath : "Entry not found: " + uIndex; if (linkFailedDueToError != null) { Debug.WriteLine($"Relink failed: CrossImport porting failed for {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} ({uIndex}): {importingPCC.GetEntry(origvalue).FullPath}"); return($"Relink failed for {prefix}{propertyName} {uIndex} in export {path}({relinkingExport.UIndex}): {linkFailedDueToError}"); } if (destinationPcc.GetEntry(uIndex) != null) { Debug.WriteLine($"Relink failed: CrossImport porting failed for {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} ({uIndex}): {importingPCC.GetEntry(origvalue).FullPath}"); return($"Relink failed: CrossImport porting failed for {prefix}{propertyName} {uIndex} {destinationPcc.GetEntry(uIndex).FullPath} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } return($"Relink failed: New export does not exist - this is probably a bug in cross import code for {prefix}{propertyName} {uIndex} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } } } else { //It's an export //Attempt lookup ExportEntry sourceExport = importingPCC.GetUExport(uIndex); string fullPath = sourceExport.FullPath; int indexValue = sourceExport.indexValue; IEntry existingEntry = destinationPcc.Exports.FirstOrDefault(x => x.FullPath == fullPath && indexValue == x.indexValue); existingEntry ??= destinationPcc.Imports.FirstOrDefault(x => x.FullPath == fullPath); if (existingEntry != null) { //Debug.WriteLine($"Relink hit [EXPERIMENTAL]: Existing entry in file was found, linking to it: {uIndex} {sourceExport.InstancedFullPath} -> {existingEntry.InstancedFullPath}"); uIndex = existingEntry.UIndex; } else if (importExportDependencies) { if (!crossPCCObjectMappingList.TryGetValue(sourceExport.Parent, out IEntry parent)) { parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceExport.ParentFullPath, importingPCC, destinationPcc, true, crossPCCObjectMappingList); } ExportEntry importedExport = EntryImporter.ImportExport(destinationPcc, sourceExport, parent?.UIndex ?? 0, true, crossPCCObjectMappingList); uIndex = importedExport.UIndex; } else { string path = importingPCC.GetEntry(uIndex)?.FullPath ?? $"Entry not found: {uIndex}"; Debug.WriteLine($"Relink failed in {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} {uIndex} {path}"); return($"Relink failed: {prefix}{propertyName} {uIndex} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } } return(null); }
/// <summary> /// UDKFile class constructor. It also load namelist, importlist and exportinfo (not exportdata) from udk file /// </summary> /// <param name="udkFilePath">full path + file name of desired udk file.</param> public UDKFile(string udkFilePath, bool fullFileInMemory = false) { Loaded = true; FileName = Path.GetFullPath(udkFilePath); using (FileStream udkStream = File.OpenRead(FileName)) { Names = new List<NameEntry>(); Imports = new List<ImportEntry>(); Exports = new List<ExportEntry>(); udkStream.Read(header, 0, header.Length); //unsure about magic number. for now just let it try anything if (magic != 2653586369) { //throw new FormatException("not a udk file"); } //again, unsure of what versions ought to be supported if (lowVers != 684 && highVers != 0) { //throw new FormatException("unsupported version"); } Stream listsStream; listsStream = udkStream; headerEnd = NameOffset; // fill names list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { long currOffset = listsStream.Position; int strLength = listsStream.ReadValueS32(); NameEntry n = new NameEntry(); if (strLength < 0) { n.name = listsStream.ReadString(strLength * -2, true, Encoding.Unicode); } else { n.name = listsStream.ReadString(strLength, true, Encoding.ASCII); } n.unk = listsStream.ReadValueS32(); n.flags = listsStream.ReadValueS32(); Names.Add(n); } //Debug.WriteLine("Names done. Current offset: "+listsStream.Position); //Debug.WriteLine("Import Offset: " + ImportOffset); // fill import list //Console.Out.WriteLine("IMPORT OFFSET: " + ImportOffset); listsStream.Seek(ImportOffset, SeekOrigin.Begin); byte[] buffer = new byte[ImportEntry.byteSize]; for (int i = 0; i < ImportCount; i++) { long offset = listsStream.Position; ImportEntry e = new ImportEntry(this, listsStream); Imports.Add(e); //Debug.WriteLine("Read import " + i + " " + e.ObjectName + ", offset: " + offset); }; // fill export list (only the headers, not the data) listsStream.Seek(ExportOffset, SeekOrigin.Begin); //Console.Out.WriteLine("Export OFFSET: " + ImportOffset); for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); ExportEntry e = new ExportEntry(this, buffer, expInfoOffset); //Debug.WriteLine("Read export " + i + " " + e.ObjectName + ", offset: " + expInfoOffset+ ", size: "+expInfoSize); Exports.Add(e); } } Debug.WriteLine(getMetadataString()); }