Exemple #1
0
        private static void WriteNode(StringBuilder sb, int indent, PsoCont cont, int blockId, int offset, XmlTagMode tagMode = XmlTagMode.None, MetaName structName = 0)
        {
            var block = cont.Pso.GetBlock(blockId);

            if (block == null)
            {
                ErrorXml(sb, indent, "Couldn't find block " + blockId + "!");
                return;
            }


            var boffset = offset + block.Offset;

            if (structName == 0)
            {
                structName = (MetaName)block.NameHash;
            }

            var name = HashString(structName);
            var data = cont.Pso.DataSection.Data;

            var structInfo = cont.GetStructureInfo(structName);

            if (structInfo == null)
            {
                ErrorXml(sb, indent, "Couldn't find structure info " + name + "!");
                return;
            }
            if (structInfo.Entries == null)
            {
                ErrorXml(sb, indent, "Couldn't find structure info entries for " + name + "!");
                return;
            }

            switch (tagMode)
            {
            case XmlTagMode.Structure:
                OpenTag(sb, indent, name);
                break;

            case XmlTagMode.Item:
                OpenTag(sb, indent, "Item");
                break;

            case XmlTagMode.ItemAndType:
                OpenTag(sb, indent, "Item type=\"" + name + "\"");
                break;
            }


            var cind = indent + 1;

            for (int i = 0; i < structInfo.Entries.Count; i++)
            {
                var entry = structInfo.Entries[i];
                if ((MetaName)entry.EntryNameHash == MetaName.ARRAYINFO)
                {
                    continue;
                }
                var ename   = HashString((MetaName)entry.EntryNameHash);
                var eoffset = boffset + entry.DataOffset;
                switch (entry.Type)
                {
                default:
                    ErrorXml(sb, cind, ename + ": Unexpected entry DataType: " + entry.Type.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.Array:

                    WriteArrayNode(sb, cind, cont, blockId, offset, entry, structInfo, ename);

                    break;

                case RageLib.GTA5.PSO.DataType.Bool:
                    var boolVal = BitConverter.ToBoolean(data, eoffset);
                    ValueTag(sb, cind, ename, boolVal ? "true" : "false");
                    break;

                case RageLib.GTA5.PSO.DataType.SByte:     //was LONG_01h //signed byte?
                    //var long1Val = MetaUtils.SwapBytes(BitConverter.ToUInt64(data, eoffset));
                    //ValueTag(sb, cind, ename, long1Val.ToString());
                    var byte1Val = (sbyte)data[eoffset];
                    ValueTag(sb, cind, ename, byte1Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.UByte:
                    var byte2Val = data[eoffset];
                    ValueTag(sb, cind, ename, byte2Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.Enum:
                    var enumInfo = cont.GetEnumInfo((MetaName)entry.ReferenceKey);
                    switch (entry.Unk_5h)
                    {
                    default:
                        ErrorXml(sb, cind, ename + ": Unexpected Enum subtype: " + entry.Unk_5h.ToString());
                        break;

                    case 0:         //int enum
                        var intEVal = MetaUtils.SwapBytes(BitConverter.ToInt32(data, eoffset));
                        var intE    = enumInfo.FindEntry(intEVal);
                        StringTag(sb, cind, ename, HashString((MetaName)(intE?.EntryNameHash ?? 0)));
                        break;

                    case 2:         //byte enum
                        var byteEVal = data[eoffset];
                        var byteE    = enumInfo.FindEntry(byteEVal);
                        StringTag(sb, cind, ename, HashString((MetaName)(byteE?.EntryNameHash ?? 0)));
                        break;
                    }
                    break;

                case RageLib.GTA5.PSO.DataType.Flags:
                    uint        fCount    = ((uint)entry.ReferenceKey >> 16) & 0x0000FFFF;
                    uint        fEntry    = ((uint)entry.ReferenceKey & 0xFFFF);
                    var         fEnt      = structInfo.GetEntry((int)fEntry);
                    PsoEnumInfo flagsInfo = null;
                    if ((fEnt != null) && ((MetaName)fEnt.EntryNameHash == MetaName.ARRAYINFO))
                    {
                        flagsInfo = cont.GetEnumInfo((MetaName)fEnt.ReferenceKey);
                    }
                    if (flagsInfo == null)
                    {
                        flagsInfo = cont.GetEnumInfo((MetaName)entry.EntryNameHash);
                    }
                    uint?flagsVal = null;
                    switch (entry.Unk_5h)
                    {
                    default:
                        ErrorXml(sb, cind, ename + ": Unexpected Flags subtype: " + entry.Unk_5h.ToString());
                        break;

                    case 0:         //int flags
                        flagsVal = MetaUtils.SwapBytes(BitConverter.ToUInt32(data, eoffset));
                        break;

                    case 1:         //short flags
                        flagsVal = MetaUtils.SwapBytes(BitConverter.ToUInt16(data, eoffset));
                        break;

                    case 2:         //byte flags
                        flagsVal = data[eoffset];
                        break;
                    }
                    if (flagsVal.HasValue)
                    {
                        uint fv = flagsVal.Value;
                        if (flagsInfo != null)
                        {
                            string fstr = "";
                            for (int n = 0; n < flagsInfo.EntriesCount; n++)
                            {
                                var fentry = flagsInfo.Entries[n];
                                var fmask  = (1 << fentry.EntryKey);
                                if ((fv & fmask) > 0)
                                {
                                    if (fstr != "")
                                    {
                                        fstr += " ";
                                    }
                                    fstr += HashString((MetaName)fentry.EntryNameHash);
                                }
                            }
                            StringTag(sb, cind, ename, fstr);
                        }
                        else
                        {
                            if (fv != 0)
                            {
                                ValueTag(sb, cind, ename, fv.ToString());
                            }
                            else
                            {
                                SelfClosingTag(sb, cind, ename);
                            }
                        }
                    }
                    break;

                case RageLib.GTA5.PSO.DataType.Float:
                    var floatVal = MetaUtils.SwapBytes(BitConverter.ToSingle(data, eoffset));
                    ValueTag(sb, cind, ename, FloatUtil.ToString(floatVal));
                    break;

                case RageLib.GTA5.PSO.DataType.Float2:
                    var v2 = MetaUtils.SwapBytes(MetaUtils.ConvertData <Vector2>(data, eoffset));
                    SelfClosingTag(sb, cind, ename + " x=\"" + FloatUtil.ToString(v2.X) + "\" y=\"" + FloatUtil.ToString(v2.Y) + "\"");
                    break;

                case RageLib.GTA5.PSO.DataType.Float3:
                    var v3 = MetaUtils.SwapBytes(MetaUtils.ConvertData <Vector3>(data, eoffset));
                    SelfClosingTag(sb, cind, ename + " x=\"" + FloatUtil.ToString(v3.X) + "\" y=\"" + FloatUtil.ToString(v3.Y) + "\" z=\"" + FloatUtil.ToString(v3.Z) + "\"");
                    break;

                case RageLib.GTA5.PSO.DataType.Float3a:     //TODO: check this!
                    var v3a = MetaUtils.SwapBytes(MetaUtils.ConvertData <Vector3>(data, eoffset));
                    SelfClosingTag(sb, cind, ename + " x=\"" + FloatUtil.ToString(v3a.X) + "\" y=\"" + FloatUtil.ToString(v3a.Y) + "\" z=\"" + FloatUtil.ToString(v3a.Z) + "\"");
                    break;

                case RageLib.GTA5.PSO.DataType.Float4a:     //TODO: check this! //...why are there 3 different types of float3?
                    var v3b = MetaUtils.SwapBytes(MetaUtils.ConvertData <Vector3>(data, eoffset));
                    SelfClosingTag(sb, cind, ename + " x=\"" + FloatUtil.ToString(v3b.X) + "\" y=\"" + FloatUtil.ToString(v3b.Y) + "\" z=\"" + FloatUtil.ToString(v3b.Z) + "\"");
                    break;

                case RageLib.GTA5.PSO.DataType.Float4:
                    var v4 = MetaUtils.SwapBytes(MetaUtils.ConvertData <Vector4>(data, eoffset));
                    SelfClosingTag(sb, cind, ename + " x=\"" + FloatUtil.ToString(v4.X) + "\" y=\"" + FloatUtil.ToString(v4.Y) + "\" z=\"" + FloatUtil.ToString(v4.Z) + "\" w=\"" + FloatUtil.ToString(v4.W) + "\"");
                    break;

                case RageLib.GTA5.PSO.DataType.SInt:     //TODO: convert hashes?
                    var int5Val = MetaUtils.SwapBytes(BitConverter.ToInt32(data, eoffset));
                    ValueTag(sb, cind, ename, int5Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.UInt:
                    switch (entry.Unk_5h)
                    {
                    default:
                        ErrorXml(sb, cind, ename + ": Unexpected Integer subtype: " + entry.Unk_5h.ToString());
                        break;

                    case 0:         //signed int
                        var int6aVal = MetaUtils.SwapBytes(BitConverter.ToInt32(data, eoffset));
                        ValueTag(sb, cind, ename, int6aVal.ToString());
                        break;

                    case 1:         //unsigned int
                        var int6bVal = MetaUtils.SwapBytes(BitConverter.ToUInt32(data, eoffset));
                        ValueTag(sb, cind, ename, "0x" + int6bVal.ToString("X").PadLeft(8, '0'));
                        break;
                    }
                    break;

                case RageLib.GTA5.PSO.DataType.Long:
                    var long2Val = MetaUtils.SwapBytes(BitConverter.ToUInt64(data, eoffset));
                    ValueTag(sb, cind, ename, long2Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.Map:

                    WriteMapNode(sb, indent, cont, eoffset, entry, structInfo, ename);

                    break;

                case RageLib.GTA5.PSO.DataType.SShort:
                    var short3Val = (short)MetaUtils.SwapBytes(BitConverter.ToUInt16(data, eoffset));
                    ValueTag(sb, cind, ename, short3Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.UShort:
                    var short4Val = MetaUtils.SwapBytes(BitConverter.ToUInt16(data, eoffset));
                    ValueTag(sb, cind, ename, short4Val.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.HFloat:    //half float?
                    var short1EVal = MetaUtils.SwapBytes(BitConverter.ToUInt16(data, eoffset));
                    ValueTag(sb, cind, ename, short1EVal.ToString());
                    break;

                case RageLib.GTA5.PSO.DataType.String:
                    var str0 = GetStringValue(cont.Pso, entry, data, eoffset);
                    if (str0 == null)
                    {
                        ErrorXml(sb, cind, ename + ": Unexpected String subtype: " + entry.Unk_5h.ToString());
                    }
                    else
                    {
                        StringTag(sb, cind, ename, str0);
                    }
                    break;

                case RageLib.GTA5.PSO.DataType.Structure:
                    switch (entry.Unk_5h)
                    {
                    default:
                        ErrorXml(sb, cind, ename + ": Unexpected Structure subtype: " + entry.Unk_5h.ToString());
                        break;

                    case 0:         //default structure
                        OpenTag(sb, cind, ename);
                        WriteNode(sb, cind, cont, blockId, offset + entry.DataOffset, XmlTagMode.None, (MetaName)entry.ReferenceKey);
                        CloseTag(sb, cind, ename);
                        break;

                    case 3:         //structure pointer...
                    case 4:         //also pointer? what's the difference?
                        var ptrVal = MetaUtils.ConvertData <PsoPOINTER>(data, eoffset);
                        ptrVal.SwapEnd();
                        var  pbid = ptrVal.BlockID;
                        bool pbok = true;
                        if (pbid <= 0)
                        {
                            pbok = false;         //no block specified?
                        }
                        if (pbid > cont.Pso.DataMappingSection.EntriesCount)
                        {
                            pbok = false;         //bad pointer? different type..? should output an error message here?
                        }
                        if (pbok)
                        {
                            WriteNode(sb, cind, cont, ptrVal.BlockID, (int)ptrVal.ItemOffset, XmlTagMode.None, (MetaName)entry.ReferenceKey);
                        }
                        else
                        {
                            SelfClosingTag(sb, cind, ename);
                        }
                        break;
                    }
                    break;
                }
            }



            switch (tagMode)
            {
            case XmlTagMode.Structure:
                CloseTag(sb, indent, name);
                break;

            case XmlTagMode.Item:
            case XmlTagMode.ItemAndType:
                CloseTag(sb, indent, "Item");
                break;
            }
        }
Exemple #2
0
        private static void WriteArrayNode(StringBuilder sb, int indent, PsoCont cont, int blockId, int offset, PsoStructureEntryInfo entry, PsoStructureInfo estruct, string ename)
        {
            var    block    = cont.Pso.GetBlock(blockId);
            var    boffset  = offset + block.Offset;
            var    eoffset  = boffset + entry.DataOffset;
            var    aOffset  = offset + entry.DataOffset;
            var    aBlockId = blockId;
            uint   aCount   = ((uint)entry.ReferenceKey >> 16) & 0x0000FFFF;
            var    aind     = indent + 1;
            string arrTag   = ename;
            PsoStructureEntryInfo arrEntry = estruct.GetEntry((int)(entry.ReferenceKey & 0xFFFF));

            if (arrEntry == null)
            {
                ErrorXml(sb, indent, "ARRAYINFO not found for " + ename + "!");
                return;
            }

            var data = cont.Pso.DataSection.Data;

            switch (entry.Unk_5h)
            {
            default:
                ErrorXml(sb, indent, ename + ": WIP! Unsupported Array subtype: " + entry.Unk_5h.ToString());
                break;

            case 0:     //Array_Structure
                var arrStruc = MetaUtils.ConvertData <Array_Structure>(data, eoffset);
                arrStruc.SwapEnd();
                aBlockId = (int)arrStruc.PointerDataId;
                aOffset  = (int)arrStruc.PointerDataOffset;
                aCount   = arrStruc.Count1;
                break;

            case 1:     //Raw in-line array
                break;

            case 2:     //also raw in-line array, but how different from above?
                break;

            case 4:                       //pointer array? default array?
                if (arrEntry.Unk_5h == 3) //pointers...
                {
                    var arrStruc4 = MetaUtils.ConvertData <Array_Structure>(data, eoffset);
                    arrStruc4.SwapEnd();
                    aBlockId = (int)arrStruc4.PointerDataId;
                    aOffset  = (int)arrStruc4.PointerDataOffset;
                    aCount   = arrStruc4.Count1;
                }
                break;

            case 129:     //also raw inline array? in junctions.pso
                break;
            }

            switch (arrEntry.Type)
            {
            default:
                ErrorXml(sb, indent, ename + ": WIP! Unsupported array entry DataType: " + arrEntry.Type.ToString());
                break;

            case RageLib.GTA5.PSO.DataType.Array:
                var rk0 = (entry.ReferenceKey >> 16) & 0x0000FFFF;
                if (rk0 > 0)
                {
                    //var arrStruc5 = MetaUtils.ConvertDataArray<Array_StructurePointer>(data, eoffset, (int)rk0);
                    //for (int n = 0; n < rk0; n++) arrStruc5[n].SwapEnd();
                    aOffset = offset + entry.DataOffset;

                    OpenTag(sb, indent, arrTag);
                    for (int n = 0; n < rk0; n++)     //ARRAY ARRAY!
                    {
                        WriteArrayNode(sb, aind, cont, blockId, aOffset, arrEntry, estruct, "Item");

                        aOffset += 16;    //ptr size... todo: what if not pointer array?
                    }
                    CloseTag(sb, indent, ename);
                }
                else
                {
                    SelfClosingTag(sb, indent, arrTag);
                }
                break;

            case RageLib.GTA5.PSO.DataType.Structure:
                switch (arrEntry.Unk_5h)
                {
                case 0:
                    break;

                case 3:        //structure pointer array
                    var arrStrucPtr = MetaUtils.ConvertData <Array_StructurePointer>(data, eoffset);
                    arrStrucPtr.SwapEnd();
                    aBlockId = (int)arrStrucPtr.PointerDataId;
                    aOffset  = (int)arrStrucPtr.PointerDataOffset;
                    aCount   = arrStrucPtr.Count1;
                    if (aCount > 0)
                    {
                        var ptrArr = PsoUtils.GetPointerArray(cont.Pso, arrStrucPtr);
                        OpenTag(sb, indent, arrTag);
                        for (int n = 0; n < aCount; n++)
                        {
                            var ptrVal = ptrArr[n];
                            WriteNode(sb, aind, cont, ptrVal.BlockID, (int)ptrVal.ItemOffset, XmlTagMode.ItemAndType);
                        }
                        CloseTag(sb, indent, ename);
                    }
                    break;

                default:
                    break;
                }
                arrTag += " itemType=\"" + HashString((MetaName)arrEntry.ReferenceKey) + "\"";
                if (aCount > 0)
                {
                    var aBlock = cont.Pso.GetBlock(aBlockId);
                    var atyp   = cont.GetStructureInfo((MetaName)arrEntry.ReferenceKey);
                    if (aBlock == null)
                    {
                        ErrorXml(sb, indent, ename + ": Array block not found: " + aBlockId.ToString());
                    }
                    else if ((MetaName)aBlock.NameHash != MetaName.PsoPOINTER)
                    {
                        OpenTag(sb, indent, arrTag);
                        if (atyp == null)
                        {
                            ErrorXml(sb, indent, ename + ": Array type not found: " + HashString((MetaName)arrEntry.ReferenceKey));
                        }
                        else
                        {
                            for (int n = 0; n < aCount; n++)
                            {
                                WriteNode(sb, aind, cont, aBlockId, aOffset, XmlTagMode.Item, (MetaName)arrEntry.ReferenceKey);
                                aOffset += atyp.StructureLength;
                                if ((n < (aCount - 1)) && (aBlock != null) && (aOffset >= aBlock.Length))
                                {
                                    break;
                                }
                            }
                        }
                        CloseTag(sb, indent, ename);
                    }
                    else
                    {
                    }       //pointer array should get here, but it's already handled above. should improve this.
                }
                else
                {
                    SelfClosingTag(sb, indent, arrTag);
                }
                break;

            case RageLib.GTA5.PSO.DataType.String:
                switch (entry.Unk_5h)
                {
                default:
                    ErrorXml(sb, indent, ename + ": Unexpected String array subtype: " + entry.Unk_5h.ToString());
                    break;

                case 0:         //hash array...
                    var arrHash = MetaUtils.ConvertData <Array_uint>(data, eoffset);
                    arrHash.SwapEnd();
                    var hashArr = PsoUtils.GetHashArray(cont.Pso, arrHash);
                    WriteItemArray(sb, hashArr, indent, ename, "Hash", HashString);
                    break;
                }
                break;

            case RageLib.GTA5.PSO.DataType.Float2:
                aCount  = ((uint)entry.ReferenceKey >> 16) & 0x0000FFFF;
                arrTag += " itemType=\"Vector2\"";
                var v2Arr = MetaUtils.ConvertDataArray <Vector2>(data, eoffset, (int)aCount);
                WriteRawArray(sb, v2Arr, indent, ename, "Vector2", FormatVector2Swap, 1);
                break;

            case RageLib.GTA5.PSO.DataType.Float3:
                aCount  = ((uint)entry.ReferenceKey >> 16) & 0x0000FFFF;
                arrTag += " itemType=\"Vector3\"";     //this is actually aligned as vector4, the W values are crazy in places
                var v4Arr = MetaUtils.ConvertDataArray <Vector4>(data, eoffset, (int)aCount);
                WriteRawArray(sb, v4Arr, indent, ename, "Vector3", FormatVector4SwapXYZOnly, 1);
                break;

            case RageLib.GTA5.PSO.DataType.UByte:
                var barr = new byte[aCount];
                if (aCount > 0)
                {
                    var bblock = cont.Pso.GetBlock(aBlockId);
                    var boffs  = bblock.Offset + aOffset;
                    Buffer.BlockCopy(data, boffs, barr, 0, (int)aCount);
                }
                WriteRawArray(sb, barr, indent, ename, "byte");
                break;

            case RageLib.GTA5.PSO.DataType.Bool:
                var barr2 = new byte[aCount];
                if (aCount > 0)
                {
                    var bblock = cont.Pso.GetBlock(aBlockId);
                    var boffs  = bblock.Offset + aOffset;
                    Buffer.BlockCopy(data, boffs, barr2, 0, (int)aCount);
                }
                WriteRawArray(sb, barr2, indent, ename, "boolean");     //todo: true/false output
                break;

            case RageLib.GTA5.PSO.DataType.Float:
                var arrFloat = MetaUtils.ConvertData <Array_float>(data, eoffset);
                arrFloat.SwapEnd();
                var floatArr = PsoUtils.GetFloatArray(cont.Pso, arrFloat);
                WriteRawArray(sb, floatArr, indent, ename, "float");
                break;

            case RageLib.GTA5.PSO.DataType.UShort:
                var arrShort = MetaUtils.ConvertData <Array_Structure>(data, eoffset);
                arrShort.SwapEnd();
                var shortArr = PsoUtils.GetUShortArray(cont.Pso, arrShort);
                WriteRawArray(sb, shortArr, indent, ename, "ushort");
                break;

            case RageLib.GTA5.PSO.DataType.UInt:
                var intArr = MetaUtils.ConvertDataArray <int>(data, eoffset, (int)aCount);
                WriteRawArray(sb, intArr, indent, ename, "int");
                break;

            case RageLib.GTA5.PSO.DataType.SInt:
                var arrUint2 = MetaUtils.ConvertData <Array_uint>(data, eoffset);
                arrUint2.SwapEnd();
                var intArr2 = PsoUtils.GetUintArray(cont.Pso, arrUint2);
                WriteRawArray(sb, intArr2, indent, ename, "int");
                break;

            case RageLib.GTA5.PSO.DataType.Enum:
                var arrEnum = MetaUtils.ConvertData <Array_uint>(data, eoffset);
                arrEnum.SwapEnd();
                var enumArr = PsoUtils.GetUintArray(cont.Pso, arrEnum);
                var enumDef = cont.GetEnumInfo((MetaName)arrEntry.ReferenceKey);
                WriteItemArray(sb, enumArr, indent, ename, "enum", (ie) => {
                    var eval = enumDef?.FindEntry((int)ie);
                    return(HashString((MetaName)(eval?.EntryNameHash ?? 0)));
                });
                break;
            }
        }