private static void TraverseStringRaw(string str, PsoBuilder pb, PsoStructureEntryInfo entry, byte[] data) { switch (entry.Unk_5h) { default: break; case 0: var str0len = (int)((entry.ReferenceKey >> 16) & 0xFFFF); if (!string.IsNullOrEmpty(str)) { byte[] strdata = Encoding.ASCII.GetBytes(str); Buffer.BlockCopy(strdata, 0, data, entry.DataOffset, strdata.Length); if (strdata.Length > str0len) { } } break; case 1: case 2: if (!string.IsNullOrEmpty(str)) { var bptr = pb.AddString(str); var ptr = new PsoPOINTER(bptr.BlockID, bptr.Offset); ptr.SwapEnd(); var val = MetaTypes.ConvertToBytes(ptr); Buffer.BlockCopy(val, 0, data, entry.DataOffset, val.Length); } break; case 3: if (!string.IsNullOrEmpty(str)) { var bptr = pb.AddString(str); var ptr = new CharPointer(bptr.Pointer, str.Length); ptr.SwapEnd(); var val = MetaTypes.ConvertToBytes(ptr); Buffer.BlockCopy(val, 0, data, entry.DataOffset, val.Length); } break; case 7: //hash only? case 8: //hash with STRF entry? var hashVal = string.IsNullOrEmpty(str) ? 0 : GetHash(str); Write(hashVal, data, entry.DataOffset); if (entry.Unk_5h == 8) { pb.AddStringToSTRF(str); } break; } }
private static byte[] Traverse(XmlNode node, PsoBuilder pb, MetaName type = 0, bool isRoot = false) { if (type == 0) { type = (MetaName)(uint)GetHash(node.Name); } var infos = PsoTypes.GetStructureInfo(type); if (infos != null) { byte[] data = new byte[infos.StructureLength]; var arrayResults = new PsoArrayResults(); arrayResults.Structures = new Dictionary <int, Array_Structure>(); arrayResults.StructurePointers = new Dictionary <int, Array_StructurePointer>(); arrayResults.UInts = new Dictionary <int, Array_uint>(); arrayResults.UShorts = new Dictionary <int, Array_ushort>(); arrayResults.UBytes = new Dictionary <int, Array_byte>(); arrayResults.Floats = new Dictionary <int, Array_float>(); arrayResults.Float_XYZs = new Dictionary <int, Array_Vector3>(); arrayResults.Hashes = new Dictionary <int, Array_uint>(); Array.Clear(data, 0, infos.StructureLength); //shouldn't really be necessary... PsoStructureEntryInfo arrEntry = null; //if (isRoot) //{ // pb.EnsureBlock(type); //} for (int i = 0; i < infos.Entries.Length; i++) { var entry = infos.Entries[i]; var cnode = GetEntryNode(node.ChildNodes, entry.EntryNameHash); if (entry.EntryNameHash == (MetaName)MetaTypeName.ARRAYINFO) { arrEntry = entry; continue; } if (cnode == null) { //warning: node not found in XML for this entry! continue; } switch (entry.Type) { case PsoDataType.Array: { TraverseArray(cnode, pb, entry, arrEntry, arrayResults, data, infos); break; } case PsoDataType.Structure: { var stype = (MetaName)entry.ReferenceKey; if (stype == 0) { var stypestr = Xml.GetStringAttribute(cnode, "type"); if (!string.IsNullOrEmpty(stypestr)) { stype = (MetaName)(uint)GetHash(stypestr); } } var struc = Traverse(cnode, pb, stype); if (struc != null) { switch (entry.Unk_5h) { default: //ErrorXml(sb, cind, ename + ": Unexpected Structure subtype: " + entry.Unk_5h.ToString()); break; case 0: //default structure Buffer.BlockCopy(struc, 0, data, entry.DataOffset, struc.Length); break; case 3: //structure pointer... case 4: //also pointer? what's the difference? var bptr = pb.AddItem(stype, struc); var ptr = new PsoPOINTER(bptr.BlockID, bptr.Offset); ptr.SwapEnd(); var ptrb = MetaTypes.ConvertToBytes(ptr); Buffer.BlockCopy(ptrb, 0, data, entry.DataOffset, ptrb.Length); break; } } else { } break; } case PsoDataType.Map: { TraverseMap(cnode, pb, entry, infos, data, arrayResults); break; } case PsoDataType.Bool: { byte val = (cnode.Attributes["value"].Value == "false") ? (byte)0 : (byte)1; data[entry.DataOffset] = val; break; } case PsoDataType.SByte: { var val = Convert.ToSByte(cnode.Attributes["value"].Value); data[entry.DataOffset] = (byte)val; break; } case PsoDataType.UByte: { var val = Convert.ToByte(cnode.Attributes["value"].Value); data[entry.DataOffset] = val; break; } case PsoDataType.SShort: { var val = Convert.ToInt16(cnode.Attributes["value"].Value); Write(val, data, entry.DataOffset); break; } case PsoDataType.UShort: { var val = Convert.ToUInt16(cnode.Attributes["value"].Value); Write(val, data, entry.DataOffset); break; } case PsoDataType.SInt: { var val = Convert.ToInt32(cnode.Attributes["value"].Value); Write(val, data, entry.DataOffset); break; } case PsoDataType.UInt: { switch (entry.Unk_5h) { default: //ErrorXml(sb, cind, ename + ": Unexpected Integer subtype: " + entry.Unk_5h.ToString()); break; case 0: //signed int (? flags?) var sval = Convert.ToInt32(cnode.Attributes["value"].Value); Write(sval, data, entry.DataOffset); break; case 1: //unsigned int var ustr = cnode.Attributes["value"].Value; uint uval = 0; if (ustr.StartsWith("0x")) { ustr = ustr.Substring(2); uval = Convert.ToUInt32(ustr, 16); } else { uval = Convert.ToUInt32(ustr); } Write(uval, data, entry.DataOffset); break; } break; } case PsoDataType.Float: { float val = FloatUtil.Parse(cnode.Attributes["value"].Value); Write(val, data, entry.DataOffset); break; } case PsoDataType.Float2: { float x = FloatUtil.Parse(cnode.Attributes["x"].Value); float y = FloatUtil.Parse(cnode.Attributes["y"].Value); Write(x, data, entry.DataOffset); Write(y, data, entry.DataOffset + sizeof(float)); break; } case PsoDataType.Float3: { float x = FloatUtil.Parse(cnode.Attributes["x"].Value); float y = FloatUtil.Parse(cnode.Attributes["y"].Value); float z = FloatUtil.Parse(cnode.Attributes["z"].Value); Write(x, data, entry.DataOffset); Write(y, data, entry.DataOffset + sizeof(float)); Write(z, data, entry.DataOffset + sizeof(float) * 2); break; } case PsoDataType.Float4: { float x = FloatUtil.Parse(cnode.Attributes["x"].Value); float y = FloatUtil.Parse(cnode.Attributes["y"].Value); float z = FloatUtil.Parse(cnode.Attributes["z"].Value); float w = FloatUtil.Parse(cnode.Attributes["w"].Value); Write(x, data, entry.DataOffset); Write(y, data, entry.DataOffset + sizeof(float)); Write(z, data, entry.DataOffset + sizeof(float) * 2); Write(w, data, entry.DataOffset + sizeof(float) * 3); break; } case PsoDataType.String: { TraverseString(cnode, pb, entry, data); break; } case PsoDataType.Enum: { pb.AddEnumInfo((MetaName)entry.ReferenceKey); switch (entry.Unk_5h) { default: //ErrorXml(sb, cind, ename + ": Unexpected Enum subtype: " + entry.Unk_5h.ToString()); break; case 0: //int enum int ival = GetEnumInt((MetaName)entry.ReferenceKey, cnode.InnerText, entry.Type); Write(ival, data, entry.DataOffset); break; case 1: //short enum? short sval = (short)GetEnumInt((MetaName)entry.ReferenceKey, cnode.InnerText, entry.Type); Write(sval, data, entry.DataOffset); break; case 2: //byte enum byte bval = (byte)GetEnumInt((MetaName)entry.ReferenceKey, cnode.InnerText, entry.Type); data[entry.DataOffset] = bval; break; } break; } case PsoDataType.Flags: { //uint fCount = (entry.ReferenceKey >> 16) & 0x0000FFFF; uint fEntry = (entry.ReferenceKey & 0xFFF); var fEnt = (fEntry != 0xFFF) ? infos.GetEntry((int)fEntry) : null; PsoEnumInfo flagsInfo = null; MetaName fEnum = (MetaName)(fEnt?.ReferenceKey ?? 0); if ((fEnt != null) && (fEnt.EntryNameHash == (MetaName)MetaTypeName.ARRAYINFO)) { flagsInfo = PsoTypes.GetEnumInfo(fEnum); } if (flagsInfo == null) { if (fEntry != 0xFFF) { } //flagsInfo = PsoTypes.GetEnumInfo(entry.EntryNameHash); } if (flagsInfo != null) { pb.AddEnumInfo(flagsInfo.IndexInfo.NameHash); } else { } //error? switch (entry.Unk_5h) { default: //ErrorXml(sb, cind, ename + ": Unexpected Flags subtype: " + entry.Unk_5h.ToString()); break; case 0: //int flags int ival = GetEnumInt(fEnum, cnode.InnerText, entry.Type); Write(ival, data, entry.DataOffset); break; case 1: //short flags short sval = (short)GetEnumInt(fEnum, cnode.InnerText, entry.Type); Write(sval, data, entry.DataOffset); break; case 2: //byte flags byte bval = (byte)GetEnumInt(fEnum, cnode.InnerText, entry.Type); data[entry.DataOffset] = bval; break; } break; } case PsoDataType.Float3a: { float x = FloatUtil.Parse(cnode.Attributes["x"].Value); float y = FloatUtil.Parse(cnode.Attributes["y"].Value); float z = FloatUtil.Parse(cnode.Attributes["z"].Value); Write(x, data, entry.DataOffset); Write(y, data, entry.DataOffset + sizeof(float)); Write(z, data, entry.DataOffset + sizeof(float) * 2); break; } case PsoDataType.Float4a: { float x = FloatUtil.Parse(cnode.Attributes["x"].Value); float y = FloatUtil.Parse(cnode.Attributes["y"].Value); float z = FloatUtil.Parse(cnode.Attributes["z"].Value); //float w = FloatUtil.Parse(cnode.Attributes["w"].Value); Write(x, data, entry.DataOffset); Write(y, data, entry.DataOffset + sizeof(float)); Write(z, data, entry.DataOffset + sizeof(float) * 2); //Write(w, data, entry.DataOffset + sizeof(float) * 3); break; } case PsoDataType.HFloat: { var val = Convert.ToInt16(cnode.Attributes["value"].Value); Write(val, data, entry.DataOffset); break; } case PsoDataType.Long: { var uval = Convert.ToUInt64(cnode.Attributes["value"].Value); Write(uval, data, entry.DataOffset); break; } default: break; } } arrayResults.WriteArrays(data); pb.AddStructureInfo(infos.IndexInfo.NameHash); if (isRoot) { pb.RootPointer = pb.AddItem(type, data); } return(data); } else { } //info not found return(null); }