public static void ImportProperty(PCCObject pcc, PCCObject importpcc, Property p, string className, System.IO.MemoryStream m, bool inStruct = false) { string name = importpcc.getNameEntry(p.Name); int idxname = pcc.FindNameOrAdd(name); m.Write(BitConverter.GetBytes(idxname), 0, 4); m.Write(new byte[4], 0, 4); if (name == "None") { return; } string type = importpcc.getNameEntry(BitConverter.ToInt32(p.raw, 8)); int idxtype = pcc.FindNameOrAdd(type); m.Write(BitConverter.GetBytes(idxtype), 0, 4); m.Write(new byte[4], 0, 4); string name2; int idxname2; int size, count, pos; List <Property> Props; switch (type) { case "IntProperty": case "FloatProperty": case "ObjectProperty": case "StringRefProperty": m.Write(BitConverter.GetBytes(4), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(p.Value.IntValue), 0, 4); break; case "NameProperty": m.Write(BitConverter.GetBytes(8), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(pcc.FindNameOrAdd(importpcc.getNameEntry(p.Value.IntValue))), 0, 4); //preserve index or whatever the second part of a namereference is m.Write(p.raw, 28, 4); break; case "BoolProperty": m.Write(new byte[8], 0, 8); m.WriteByte((byte)p.Value.IntValue); break; case "BioMask4Property": m.Write(BitConverter.GetBytes(p.Size), 0, 4); m.Write(new byte[4], 0, 4); m.WriteByte((byte)p.Value.IntValue); break; case "ByteProperty": name2 = importpcc.getNameEntry(BitConverter.ToInt32(p.raw, 24)); idxname2 = pcc.FindNameOrAdd(name2); m.Write(BitConverter.GetBytes(p.Size), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(idxname2), 0, 4); m.Write(new byte[4], 0, 4); if (p.Size == 8) { m.Write(BitConverter.GetBytes(pcc.FindNameOrAdd(importpcc.getNameEntry(p.Value.IntValue))), 0, 4); m.Write(new byte[4], 0, 4); } else { m.WriteByte(p.raw[32]); } break; case "DelegateProperty": size = BitConverter.ToInt32(p.raw, 16); if (size == 0xC) { name2 = importpcc.getNameEntry(BitConverter.ToInt32(p.raw, 28)); idxname2 = pcc.FindNameOrAdd(name2); m.Write(BitConverter.GetBytes(0xC), 0, 4); m.Write(new byte[4], 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(idxname2), 0, 4); m.Write(new byte[4], 0, 4); } else { m.Write(BitConverter.GetBytes(size), 0, 4); m.Write(new byte[4], 0, 4); for (int i = 0; i < size; i++) { m.WriteByte(p.raw[24 + i]); } } break; case "StrProperty": name2 = p.Value.StringValue; m.Write(BitConverter.GetBytes(4 + name2.Length * 2), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(-name2.Length), 0, 4); foreach (char c in name2) { m.WriteByte((byte)c); m.WriteByte(0); } break; case "StructProperty": size = BitConverter.ToInt32(p.raw, 16); name2 = importpcc.getNameEntry(BitConverter.ToInt32(p.raw, 24)); idxname2 = pcc.FindNameOrAdd(name2); pos = 32; Props = new List <Property>(); try { Props = ReadProp(importpcc, p.raw, pos); } catch (Exception) { } m.Write(BitConverter.GetBytes(size), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(idxname2), 0, 4); m.Write(new byte[4], 0, 4); if (Props.Count == 0 || Props[0].TypeVal == Type.Unknown) { for (int i = 0; i < size; i++) { m.WriteByte(p.raw[32 + i]); } } else { foreach (Property pp in Props) { ImportProperty(pcc, importpcc, pp, className, m, inStruct); } } break; case "ArrayProperty": size = BitConverter.ToInt32(p.raw, 16); count = BitConverter.ToInt32(p.raw, 24); UnrealObjectInfo.PropertyInfo info = UnrealObjectInfo.getPropertyInfo(className, name, inStruct); UnrealObjectInfo.ArrayType arrayType = UnrealObjectInfo.getArrayType(info); pos = 28; List <Property> AllProps = new List <Property>(); if (arrayType == UnrealObjectInfo.ArrayType.Struct) { for (int i = 0; i < count; i++) { Props = new List <Property>(); try { Props = ReadProp(importpcc, p.raw, pos); } catch (Exception) { } AllProps.AddRange(Props); if (Props.Count != 0) { pos = Props[Props.Count - 1].offend; } } } m.Write(BitConverter.GetBytes(size), 0, 4); m.Write(new byte[4], 0, 4); m.Write(BitConverter.GetBytes(count), 0, 4); if (AllProps.Count != 0 && (info == null || !UnrealObjectInfo.isImmutable(info.reference))) { foreach (Property pp in AllProps) { ImportProperty(pcc, importpcc, pp, className, m, inStruct); } } else if (arrayType == UnrealObjectInfo.ArrayType.Name) { for (int i = 0; i < count; i++) { string s = importpcc.getNameEntry(BitConverter.ToInt32(p.raw, 28 + i * 8)); m.Write(BitConverter.GetBytes(pcc.FindNameOrAdd(s)), 0, 4); //preserve index or whatever the second part of a namereference is m.Write(p.raw, 32 + i * 8, 4); } } else { m.Write(p.raw, 28, size - 4); } break; default: throw new Exception(type); } }
public void GenerateTree(TreeNode localRoot, List <PropHeader> headersList) { foreach (PropHeader header in headersList) { if (readerpos > memory.Length) { throw new IndexOutOfRangeException(": tried to read past bounds of Export Data"); } nodeType type = getType(pcc.getNameEntry(header.type)); if (type != nodeType.ArrayProperty && type != nodeType.StructProperty) { localRoot.Nodes.Add(GenerateNode(header)); } else { if (type == nodeType.ArrayProperty) { TreeNode t = GenerateNode(header); int arrayLength = BitConverter.ToInt32(memory, header.offset + 24); readerpos = header.offset + 28; int tmp = readerpos; UnrealObjectInfo.ArrayType arrayType; try { arrayType = UnrealObjectInfo.getArrayType(className, pcc.getNameEntry(header.name)); } catch (Exception) { arrayType = UnrealObjectInfo.ArrayType.Int; } if (arrayType == UnrealObjectInfo.ArrayType.Struct) { UnrealObjectInfo.PropertyInfo info = UnrealObjectInfo.getPropertyInfo(className, pcc.getNameEntry(header.name)); t.Text = t.Text.Insert(t.Text.IndexOf("Size: ") - 2, $"({info.reference})"); for (int i = 0; i < arrayLength; i++) { readerpos = tmp; int pos = tmp; List <PropHeader> arrayListPropHeaders = ReadHeadersTillNone(); tmp = readerpos; TreeNode n = new TreeNode(i.ToString()); n.Tag = nodeType.ArrayLeafStruct; n.Name = (-pos).ToString(); t.Nodes.Add(n); n = t.LastNode; if (info != null && (UnrealObjectInfo.isImmutable(info.reference) || arrayListPropHeaders.Count == 0)) { readerpos = pos; GenerateSpecialStruct(n, info.reference, header.size / arrayLength); tmp = readerpos; } else if (arrayListPropHeaders.Count > 0) { GenerateTree(n, arrayListPropHeaders); } else { throw new Exception($"at position {readerpos.ToString("X4")}. Could not read element {i} of ArrayProperty {pcc.getNameEntry(header.name)}"); } t.LastNode.Remove(); t.Nodes.Add(n); } localRoot.Nodes.Add(t); } else { t.Text = t.Text.Insert(t.Text.IndexOf("Size: ") - 2, $"({arrayType.ToString()})"); int count = 0; int pos; for (int i = 0; i < (header.size - 4); count++) { pos = header.offset + 28 + i; if (pos > memory.Length) { throw new Exception(": tried to read past bounds of Export Data"); } int val = BitConverter.ToInt32(memory, pos); string s = pos.ToString("X4") + "|" + count + ": "; TreeNode node = new TreeNode(); node.Name = pos.ToString(); if (arrayType == UnrealObjectInfo.ArrayType.Object) { node.Tag = nodeType.ArrayLeafObject; int value = val; if (value == 0) { //invalid s += "Null [" + value + "] "; } else { bool isImport = value < 0; if (isImport) { value = -value; } value--; //0-indexed if (isImport) { if (pcc.Imports.Count > value) { s += pcc.Imports[value].PackageFullName + "." + pcc.Imports[value].ObjectName + " [IMPORT " + value + "]"; } else { s += "Index not in import list [" + value + "]"; } } else { if (pcc.Exports.Count > value) { s += pcc.Exports[value].PackageFullName + "." + pcc.Exports[value].ObjectName + " [EXPORT " + value + "]"; } else { s += "Index not in export list [" + value + "]"; } } } i += 4; } else if (arrayType == UnrealObjectInfo.ArrayType.Name || arrayType == UnrealObjectInfo.ArrayType.Enum) { node.Tag = arrayType == UnrealObjectInfo.ArrayType.Name ? nodeType.ArrayLeafName : nodeType.ArrayLeafEnum; int value = val; if (value < 0) { s += "Invalid Name Index [" + value + "]"; } else { if (pcc.Names.Count > value) { s += $"\"{pcc.Names[value]}\"_{BitConverter.ToInt32(memory, pos + 4)}[NAMEINDEX {value}]"; } else { s += "Index not in name list [" + value + "]"; } } i += 8; } else if (arrayType == UnrealObjectInfo.ArrayType.Float) { node.Tag = nodeType.ArrayLeafFloat; s += BitConverter.ToSingle(memory, pos).ToString("0.0######"); i += 4; } else if (arrayType == UnrealObjectInfo.ArrayType.Byte) { node.Tag = nodeType.ArrayLeafByte; s += "(byte)" + memory[pos]; i += 1; } else if (arrayType == UnrealObjectInfo.ArrayType.Bool) { node.Tag = nodeType.ArrayLeafBool; s += BitConverter.ToBoolean(memory, pos); i += 1; } else if (arrayType == UnrealObjectInfo.ArrayType.String) { node.Tag = nodeType.ArrayLeafString; int sPos = pos + 4; s += "\""; int len = val > 0 ? val : -val; for (int j = 1; j < len; j++) { s += BitConverter.ToChar(memory, sPos); sPos += 2; } s += "\""; i += (len * 2) + 4; } else { node.Tag = nodeType.ArrayLeafInt; s += val.ToString(); i += 4; } node.Text = s; t.Nodes.Add(node); } localRoot.Nodes.Add(t); } } if (type == nodeType.StructProperty) { TreeNode t = GenerateNode(header); readerpos = header.offset + 32; List <PropHeader> ll = ReadHeadersTillNone(); if (ll.Count != 0) { GenerateTree(t, ll); } else { string structType = pcc.getNameEntry(BitConverter.ToInt32(memory, header.offset + 24)); GenerateSpecialStruct(t, structType, header.size); } localRoot.Nodes.Add(t); } } } }