Ejemplo n.º 1
0
        private static void TraverseArray(XmlNode node, PsoBuilder pb, PsoStructureEntryInfo entry, PsoStructureEntryInfo arrEntry, PsoArrayResults results, byte[] data, PsoStructureInfo structInfo)
        {
            int  offset = entry.DataOffset;
            uint aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
            uint aPtr   = (entry.ReferenceKey) & 0x0000FFFF;

            byte[] adata = null;

            //how do we know when it's an "embedded" array?
            bool embedded = true;

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

            case 0:     //Array_Structure
                //var arrStruc = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
                embedded = false;
                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 = MetaTypes.ConvertData<Array_Structure>(data, eoffset);
                    embedded = false;
                }
                else
                {
                }
                break;

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



            switch (arrEntry.Type)
            {
            case PsoDataType.Structure:
            {
                if (embedded)
                {
                    if (arrEntry.ReferenceKey != 0)
                    {
                        var datas   = TraverseArrayStructureRaw(node, pb, (MetaName)arrEntry.ReferenceKey);
                        int aoffset = offset;
                        for (int i = 0; i < datas.Length; i++)
                        {
                            Buffer.BlockCopy(datas[i], 0, data, aoffset, datas[i].Length);
                            aoffset += datas[i].Length;
                        }
                    }
                    else
                    {
                        var ptrs = TraverseArrayStructurePointerRaw(node, pb);
                        adata = MetaTypes.ConvertArrayToBytes(ptrs);
                    }
                }
                else
                {
                    if (arrEntry.ReferenceKey != 0)
                    {
                        results.Structures[offset] = TraverseArrayStructure(node, pb, (MetaName)arrEntry.ReferenceKey);
                    }
                    else
                    {
                        results.StructurePointers[offset] = TraverseArrayStructurePointer(node, pb);
                    }
                }
                break;
            }

            case PsoDataType.Float2:
            {
                var arr = TraverseVector2ArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 8;
                }
                else
                {
                    results.Float_XYZs[offset] = pb.AddVector2ArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.Float3:
            {
                var arr = TraverseVector3ArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 16;
                }
                else
                {
                    results.Float_XYZs[offset] = pb.AddPaddedVector3ArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.UByte:
            {
                var arr = TraverseUByteArrayRaw(node);
                if (embedded)
                {
                    adata = arr;
                }
                else
                {
                    results.UBytes[offset] = pb.AddByteArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.Bool:
            {
                var arr = TraverseUByteArrayRaw(node);
                if (embedded)
                {
                    adata = arr;
                }
                else
                {
                    results.UBytes[offset] = pb.AddByteArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.UInt:
            {
                var arr = TraverseUIntArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 4;
                }
                else
                {
                    results.UInts[offset] = pb.AddUIntArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.SInt:
            {
                var arr = TraverseSIntArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 4;
                }
                else
                {
                    results.UInts[offset] = pb.AddSIntArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.Float:
            {
                var arr = TraverseFloatArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 4;
                }
                else
                {
                    results.Floats[offset] = pb.AddFloatArrayPtr(arr);
                }
                break;
            }

            case PsoDataType.UShort:
            {
                var arr = TraverseUShortArrayRaw(node);
                if (embedded)
                {
                    adata   = MetaTypes.ConvertArrayToBytes(arr);
                    aCount *= 2;
                }
                else
                {
                    results.UShorts[offset] = pb.AddUShortArrayPtr(arr);
                }
                break;
            }

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

                case 0:             //hash array...
                    var hashes = TraverseHashArrayRaw(node);
                    if (embedded)
                    {
                        adata   = MetaTypes.ConvertArrayToBytes(hashes);
                        aCount *= 4;
                    }
                    else
                    {
                        results.Hashes[offset] = pb.AddHashArrayPtr(hashes);
                    }
                    break;
                }


                break;
            }


            case PsoDataType.Enum:
            {
                var hashes = TraverseHashArrayRaw(node);

                if (arrEntry.ReferenceKey != 0)
                {
                    var _infos = PsoTypes.GetEnumInfo((MetaName)arrEntry.ReferenceKey);
                    pb.AddEnumInfo(_infos.IndexInfo.NameHash);

                    var values = new uint[hashes.Length];
                    for (int i = 0; i < hashes.Length; i++)
                    {
                        var enumname = (MetaName)MetaTypes.SwapBytes(hashes[i]);        //yeah swap it back to little endian..!
                        var enuminf  = _infos.FindEntryByName(enumname);
                        if (enuminf != null)
                        {
                            values[i] = MetaTypes.SwapBytes((uint)enuminf.EntryKey);
                        }
                        else
                        {
                        }           //error?
                    }

                    if (embedded)
                    {
                    }           //TODO?
                    else
                    {
                        results.UInts[offset] = pb.AddUIntArrayPtr(values);
                    }
                }
                else
                {
                }


                break;
            }


            case PsoDataType.Array:
            {
                //array array...
                var rk0 = (entry.ReferenceKey >> 16) & 0x0000FFFF;
                var rk1 = arrEntry.ReferenceKey & 0x0000FFFF;
                if (rk0 > 0)         //should be count of items
                {
                    var subarrEntry = structInfo.GetEntry((int)rk1);
                    var subarrType  = (MetaName)subarrEntry.ReferenceKey;

                    var origOffset = arrEntry.DataOffset;
                    arrEntry.DataOffset = entry.DataOffset;        //slight hack for traversing array array
                    foreach (XmlNode cnode in node.ChildNodes)
                    {
                        TraverseArray(cnode, pb, arrEntry, subarrEntry, results, data, structInfo);

                        arrEntry.DataOffset += 16;        //ptr size... todo: what if not pointer array?
                    }
                    arrEntry.DataOffset = origOffset;
                }


                break;
            }



            default:
                break;
            }

            if (embedded)
            {
                if (adata?.Length > 0)
                {
                    if (adata.Length > aCount)
                    {
                    }  //bad! old data won't fit in new slot...

                    Buffer.BlockCopy(adata, 0, data, offset, adata.Length);
                }
                else
                {
                }
            }
        }
Ejemplo n.º 2
0
        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);
        }