Esempio n. 1
0
        public override Entry Load(byte[][] items, int eid)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }
            if (items.Length != 2)
            {
                ErrorManager.SignalError("WavebankEntry: Wrong number of items");
            }
            if (items[0].Length != 8)
            {
                ErrorManager.SignalError("WavebankEntry: First item length is wrong");
            }
            int id     = BitConv.FromInt32(items[0], 0);
            int length = BitConv.FromInt32(items[0], 4);

            if (id < 0 || id > 6)
            {
                ErrorManager.SignalIgnorableError("WavebankEntry: ID is invalid");
            }
            if (length != items[1].Length)
            {
                ErrorManager.SignalIgnorableError("WavebankEntry: Length field mismatch");
            }
            return(new WavebankEntry(id, SampleSet.Load(items[1]), eid));
        }
Esempio n. 2
0
        public override Entry Load(byte[][] items, int eid)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }
            if (items.Length != 2)
            {
                ErrorManager.SignalError("OldModelEntry: Wrong number of items");
            }
            int polygoncount = BitConv.FromInt32(items[0], 0);

            if (items[1].Length != polygoncount * 8)
            {
                ErrorManager.SignalError("OldModelEntry: Polygon count mismatch");
            }
            OldModelPolygon[] polygons = new OldModelPolygon [polygoncount];
            for (int i = 0; i < polygoncount; i++)
            {
                byte[] polygondata = new byte [8];
                Array.Copy(items[1], i * 8, polygondata, 0, polygondata.Length);
                polygons[i] = OldModelPolygon.Load(polygondata);
            }
            return(new OldModelEntry(items[0], polygons, eid));
        }
Esempio n. 3
0
        public static SceneryTriangle Load(byte[] adata, byte[] bdata)
        {
            if (adata == null)
            {
                throw new ArgumentNullException("adata");
            }
            if (bdata == null)
            {
                throw new ArgumentNullException("bdata");
            }
            if (adata.Length != 4)
            {
                throw new ArgumentException("Value must be 4 bytes long.", "adata");
            }
            if (bdata.Length != 2)
            {
                throw new ArgumentException("Value must be 2 bytes long.", "adata");
            }
            int   avalue   = BitConv.FromInt32(adata, 0);
            short bvalue   = BitConv.FromInt16(bdata, 0);
            int   vertexa  = (avalue >> 8) & 0xFFF;
            int   vertexb  = (avalue >> 20) & 0xFFF;
            int   vertexc  = (bvalue >> 4) & 0xFFF;
            byte  unknown1 = (byte)avalue;
            byte  unknown2 = (byte)(bvalue & 0xF);

            return(new SceneryTriangle(vertexa, vertexb, vertexc, unknown1, unknown2));
        }
Esempio n. 4
0
        public static SceneryVertex Load(byte[] xydata, byte[] zdata)
        {
            if (xydata == null)
            {
                throw new ArgumentNullException("xydata");
            }
            if (zdata == null)
            {
                throw new ArgumentNullException("zdata");
            }
            if (xydata.Length != 4)
            {
                throw new ArgumentException("Value must be 4 bytes long.", "xydata");
            }
            if (zdata.Length != 2)
            {
                throw new ArgumentException("Value must be 2 bytes long.", "zdata");
            }
            int   xy       = BitConv.FromInt32(xydata, 0);
            short z        = BitConv.FromInt16(zdata, 0);
            short y        = (short)(xy >> 16);
            short x        = (short)xy;
            int   unknownx = x & 0xF;
            int   unknowny = y & 0xF;
            int   unknownz = z & 0xF;

            x >>= 4;
            y >>= 4;
            z >>= 4;
            return(new SceneryVertex(x, y, z, unknownx, unknowny, unknownz));
        }
Esempio n. 5
0
        public sealed override Chunk Load(int chunkid, byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length != Chunk.Length)
            {
                throw new ArgumentException("Data must be 65536 bytes long.");
            }
            int id         = BitConv.FromInt32(data, 4);
            int entrycount = BitConv.FromInt32(data, 8);
            int checksum   = BitConv.FromInt32(data, 12);
            int headersize = 20 + entrycount * 4;

            if (id != chunkid)
            {
                ErrorManager.SignalIgnorableError("EntryChunk: Chunk id is incorrect");
            }
            if (entrycount < 0)
            {
                ErrorManager.SignalError("EntryChunk: Entry count is negative");
            }
            if (checksum != Chunk.CalculateChecksum(data))
            {
                ErrorManager.SignalIgnorableError("Chunk: Checksum is wrong");
            }
            if (headersize > data.Length)
            {
                ErrorManager.SignalError("EntryChunk: Data is too short");
            }
            Entry[] entries = new Entry [entrycount];
            byte[]  entrydata;
            for (int i = 0; i < entrycount; i++)
            {
                int entrystart = BitConv.FromInt32(data, 16 + i * 4);
                int entryend   = BitConv.FromInt32(data, 20 + i * 4);
                if (entrystart < 0)
                {
                    ErrorManager.SignalError("EntryChunk: Entry begins out of bounds");
                }
                if (entryend < entrystart)
                {
                    ErrorManager.SignalError("EntryChunk: Entry ends before it begins");
                }
                if (entryend > data.Length)
                {
                    ErrorManager.SignalError("EntryChunk: Entry ends out of bounds");
                }
                int entrysize = entryend - entrystart;
                entrydata = new byte [entrysize];
                Array.Copy(data, entrystart, entrydata, 0, entrysize);
                entries[i] = Entry.Load(entrydata);
            }
            return(Load(entries));
        }
Esempio n. 6
0
        public static UnprocessedEntry Load(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length < 16)
            {
                ErrorManager.SignalError("Entry: Data is too short");
            }
            int magic     = BitConv.FromInt32(data, 0);
            int eid       = BitConv.FromInt32(data, 4);
            int type      = BitConv.FromInt32(data, 8);
            int itemcount = BitConv.FromInt32(data, 12);

            if (magic != Magic)
            {
                ErrorManager.SignalIgnorableError("Entry: Magic number is wrong");
            }
            if (itemcount < 0)
            {
                ErrorManager.SignalError("Entry: Item count is negative");
            }
            if (data.Length < 20 + itemcount * 4)
            {
                ErrorManager.SignalError("Entry: Data is too short");
            }
            byte[][] items = new byte [itemcount][];
            byte[]   itemdata;
            for (int i = 0; i < itemcount; i++)
            {
                int itemstart = BitConv.FromInt32(data, 16 + i * 4);
                int itemend   = BitConv.FromInt32(data, 20 + i * 4);
                if (itemstart < 0)
                {
                    ErrorManager.SignalError("Entry: Item begins out of bounds");
                }
                if (itemend < itemstart)
                {
                    ErrorManager.SignalError("Entry: Item ends before it begins");
                }
                if (itemend > data.Length)
                {
                    ErrorManager.SignalError("Entry: Item ends out of bounds");
                }
                int itemsize = itemend - itemstart;
                itemdata = new byte [itemsize];
                Array.Copy(data, itemstart, itemdata, 0, itemsize);
                items[i] = itemdata;
            }
            return(new UnprocessedEntry(items, eid, type));
        }
Esempio n. 7
0
        public static int FromInt32(Endianness endianness, byte[] str, int offset)
        {
            switch (endianness)
            {
            case Endianness.LittleEndian:
                return(BitConv.FromInt32(str, offset));

            case Endianness.BigEndian:
                return(BEBitConv.FromInt32(str, offset));

            default:
                throw new ArgumentException("Endianness is invalid.");
            }
        }
Esempio n. 8
0
        public static NSD Load(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length < 1312)
            {
                ErrorManager.SignalError("NSD: Data is too short");
            }
            int[] unknown1 = new int [256];
            for (int i = 0; i < 256; i++)
            {
                unknown1[i] = BitConv.FromInt32(data, i * 4);
            }
            int chunkcount = BitConv.FromInt32(data, 1024);
            int entrycount = BitConv.FromInt32(data, 1028);

            int[] unknown2 = new int [70];
            for (int i = 0; i < 70; i++)
            {
                unknown2[i] = BitConv.FromInt32(data, 1032 + i * 4);
            }
            if (chunkcount < 0)
            {
                ErrorManager.SignalError("NSD: Chunk count is negative");
            }
            if (entrycount < 0)
            {
                ErrorManager.SignalError("NSD: Entry count is negative");
            }
            if (data.Length < 1312 + 8 * entrycount)
            {
                ErrorManager.SignalError("NSD: Data is too short");
            }
            NSDLink[] index = new NSDLink [entrycount];
            for (int i = 0; i < entrycount; i++)
            {
                int chunkid = BitConv.FromInt32(data, 1312 + 8 * i);
                int entryid = BitConv.FromInt32(data, 1316 + 8 * i);
                index[i] = new NSDLink(chunkid, entryid);
            }
            int extralength = data.Length - (1312 + 8 * entrycount);

            byte[] extradata = new byte [extralength];
            Array.Copy(data, 1312 + 8 * entrycount, extradata, 0, extralength);
            return(new NSD(unknown1, chunkcount, unknown2, index, extradata));
        }
Esempio n. 9
0
        public static OldFrame Load(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length < 56)
            {
                ErrorManager.SignalError("OldFrame: Data is too short");
            }
            int vertexcount = BitConv.FromInt32(data, 0);

            if (vertexcount < 0 || vertexcount > Chunk.Length / 6)
            {
                ErrorManager.SignalError("OldFrame: Vertex count is invalid");
            }
            if (data.Length < 56 + vertexcount * 6 + 2)
            {
                ErrorManager.SignalError("OldFrame: Data is too short");
            }
            int modeleid = BitConv.FromInt32(data, 4);
            int xoffset  = BitConv.FromInt32(data, 8);
            int yoffset  = BitConv.FromInt32(data, 12);
            int zoffset  = BitConv.FromInt32(data, 16);
            int x1       = BitConv.FromInt32(data, 20);
            int y1       = BitConv.FromInt32(data, 24);
            int z1       = BitConv.FromInt32(data, 28);
            int x2       = BitConv.FromInt32(data, 32);
            int y2       = BitConv.FromInt32(data, 36);
            int z2       = BitConv.FromInt32(data, 40);
            int xglobal  = BitConv.FromInt32(data, 44);
            int yglobal  = BitConv.FromInt32(data, 48);
            int zglobal  = BitConv.FromInt32(data, 52);

            OldFrameVertex[] vertices = new OldFrameVertex [vertexcount];
            for (int i = 0; i < vertexcount; i++)
            {
                byte[] vertexdata = new byte [6];
                Array.Copy(data, 56 + i * 6, vertexdata, 0, vertexdata.Length);
                vertices[i] = OldFrameVertex.Load(vertexdata);
            }
            short unknown = BitConv.FromInt16(data, 56 + vertexcount * 6);

            return(new OldFrame(modeleid, xoffset, yoffset, zoffset, x1, y1, z1, x2, y2, z2, xglobal, yglobal, zglobal, vertices, unknown));
        }
Esempio n. 10
0
        public static VHProgram Load(byte[] data, byte[] tonedata, bool isoldversion)
        {
            if (data.Length != 16)
            {
                throw new ArgumentException("Value must be 16 bytes long.", "data");
            }
            if (tonedata.Length != 32 * 16)
            {
                throw new ArgumentException("Value must be 512 bytes long.", "tonedata");
            }
            byte  tonecount = data[0];
            byte  volume    = data[1];
            byte  priority  = data[2];
            byte  mode      = data[3];
            byte  panning   = data[4];
            byte  reserved1 = data[5];
            short attribute = BitConv.FromInt16(data, 6);
            int   reserved2 = BitConv.FromInt32(data, 8);
            int   reserved3 = BitConv.FromInt32(data, 12);

            if (tonecount < 0 || tonecount > 16)
            {
                ErrorManager.SignalError("VHProgram: Tone count is wrong");
            }
            if (reserved1 != (isoldversion ? 0x00 : 0xFF))
            {
                ErrorManager.SignalIgnorableError("VHProgram: Reserved value 1 is wrong");
            }
            if (reserved2 != -1)
            {
                ErrorManager.SignalIgnorableError("VHProgram: Reserved value 2 is wrong");
            }
            if (reserved3 != -1)
            {
                ErrorManager.SignalIgnorableError("VHProgram: Reserved value 3 is wrong");
            }
            VHTone[] tones = new VHTone [tonecount];
            for (int i = 0; i < tonecount; i++)
            {
                byte[] thistonedata = new byte [32];
                Array.Copy(tonedata, i * 32, thistonedata, 0, 32);
                tones[i] = VHTone.Load(thistonedata);
            }
            return(new VHProgram(isoldversion, volume, priority, mode, panning, attribute, tones));
        }
Esempio n. 11
0
        public static SceneryQuad Load(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length != 8)
            {
                throw new ArgumentException("Value must be 8 bytes long.", "data");
            }
            int  worda    = BitConv.FromInt32(data, 0);
            int  wordb    = BitConv.FromInt32(data, 4);
            int  vertexa  = (worda >> 8) & 0xFFF;
            int  vertexb  = (worda >> 20) & 0xFFF;
            int  vertexd  = (wordb >> 8) & 0xFFF;
            int  vertexc  = (wordb >> 20) & 0xFFF;
            byte unknown2 = (byte)worda;
            byte unknown3 = (byte)wordb;

            return(new SceneryQuad(vertexa, vertexb, vertexc, vertexd, unknown2, unknown3));
        }
Esempio n. 12
0
        public static OldSceneryPolygon Load(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (data.Length != 8)
            {
                throw new ArgumentException("Value must be 8 bytes long.", "data");
            }
            int  worda    = BitConv.FromInt32(data, 0);
            int  wordb    = BitConv.FromInt32(data, 4);
            int  vertexa  = (worda >> 20) & 0xFFF;
            int  vertexb  = (wordb >> 8) & 0xFFF;
            int  vertexc  = (wordb >> 20) & 0xFFF;
            int  unknown1 = (worda >> 8) & 0xFFF;
            byte unknown2 = (byte)(worda & 0xFF);
            byte unknown3 = (byte)(wordb & 0xFF);

            return(new OldSceneryPolygon(vertexa, vertexb, vertexc, unknown1, unknown2, unknown3));
        }
Esempio n. 13
0
        public override Entry Load(byte[][] items, int eid)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }
            if (items.Length != 3)
            {
                ErrorManager.SignalError("MusicEntry: Wrong number of items");
            }
            if (items[0].Length != 36)
            {
                ErrorManager.SignalError("MusicEntry: First item length is wrong");
            }
            int seqcount = BitConv.FromInt32(items[0], 0);
            int vheid    = BitConv.FromInt32(items[0], 4);
            int vb0eid   = BitConv.FromInt32(items[0], 8);
            int vb1eid   = BitConv.FromInt32(items[0], 12);
            int vb2eid   = BitConv.FromInt32(items[0], 16);
            int vb3eid   = BitConv.FromInt32(items[0], 20);
            int vb4eid   = BitConv.FromInt32(items[0], 24);
            int vb5eid   = BitConv.FromInt32(items[0], 28);
            int vb6eid   = BitConv.FromInt32(items[0], 32);
            VH  vh;

            if (items[1].Length != 0)
            {
                vh = VH.Load(items[1]);
            }
            else
            {
                vh = null;
            }
            SEP sep = SEP.Load(items[2], seqcount);

            return(new MusicEntry(vheid, vb0eid, vb1eid, vb2eid, vb3eid, vb4eid, vb5eid, vb6eid, vh, sep, eid));
        }
Esempio n. 14
0
        public static VH Load(byte[] data)
        {
            if (data.Length < 2592)
            {
                ErrorManager.SignalError("VH: Data is too short");
            }
            int magic   = BitConv.FromInt32(data, 0);
            int version = BitConv.FromInt32(data, 4);

            if (magic != Magic)
            {
                ErrorManager.SignalIgnorableError("VH: Magic number is wrong");
            }
            bool isoldversion;

            if (version == Version)
            {
                isoldversion = false;
            }
            else if (version == OldVersion)
            {
                ErrorManager.SignalIgnorableError("VH: VABv6 (crash 1) is not fully supported");
                isoldversion = true;
            }
            else
            {
                ErrorManager.SignalIgnorableError("VH: Version number is wrong");
                isoldversion = true;
            }
            int   id           = BitConv.FromInt32(data, 8);
            int   size         = BitConv.FromInt32(data, 12);
            short reserved1    = BitConv.FromInt16(data, 16);
            short programcount = BitConv.FromInt16(data, 18);
            short tonecount    = BitConv.FromInt16(data, 20);
            short wavecount    = BitConv.FromInt16(data, 22);
            byte  volume       = data[24];
            byte  panning      = data[25];
            byte  attribute1   = data[26];
            byte  attribute2   = data[27];
            int   reserved2    = BitConv.FromInt32(data, 28);

            if (id != 0)
            {
                ErrorManager.SignalIgnorableError("VH: ID is wrong");
            }
            if (size < data.Length)
            {
                ErrorManager.SignalError("VH: Size field mismatch");
            }
            if ((size - data.Length) % 16 != 0)
            {
                ErrorManager.SignalError("VH: Size field is invalid");
            }
            int vbsize = (size - data.Length) / 16;

            if (reserved1 != -0x1112)
            {
                ErrorManager.SignalIgnorableError("VH: Reserved value 1 is wrong");
            }
            if (programcount < 0 || programcount > 128)
            {
                ErrorManager.SignalError("VH: Program count is invalid");
            }
            if (tonecount < 0 || tonecount > 2048)
            {
                ErrorManager.SignalError("VH: Tone count is invalid");
            }
            if (wavecount < 0 || wavecount > 254)
            {
                ErrorManager.SignalError("VH: Wave count is invalid");
            }
            if (reserved2 != -1)
            {
                ErrorManager.SignalIgnorableError("VH: Reserved value 2 is wrong");
            }
            if (data.Length < 2592 + 32 * 16 * programcount)
            {
                ErrorManager.SignalError("VH: Data is too short");
            }
            Dictionary <int, VHProgram> programs = new Dictionary <int, VHProgram>();

            for (int i = 0; i < 128; i++)
            {
                byte[] programdata = new byte [16];
                Array.Copy(data, 32 + 16 * i, programdata, 0, 16);
                if (programdata[0] == 0)
                {
                    continue;
                }
                if (programs.Count == programcount)
                {
                    ErrorManager.SignalError("VH: Program count field mismatch");
                }
                byte[] tonedata = new byte [32 * 16];
                Array.Copy(data, 32 + 16 * 128 + 32 * 16 * programs.Count, tonedata, 0, 32 * 16);
                programs.Add(i, VHProgram.Load(programdata, tonedata, isoldversion));
            }
            if (programs.Count != programcount)
            {
                ErrorManager.SignalError("VH: Program count field mismatch");
            }
            int[] waves = new int [wavecount];
            for (int i = 0; i < wavecount; i++)
            {
                int wave = BitConv.FromInt16(data, 32 + 16 * 128 + 32 * 16 * programcount + 2 + i * 2);
                if (wave % 2 != 0)
                {
                    ErrorManager.SignalError("VH: Wave size is invalid");
                }
                waves[i] = wave / 2;
            }
            return(new VH(isoldversion, vbsize, volume, panning, attribute1, attribute2, programs, waves));
        }
Esempio n. 15
0
        private static byte[] ReadChunk(byte[] data, ref int offset, out bool compressed)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (offset < 0 || offset > data.Length)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (data.Length < offset + 2)
            {
                ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
            }
            byte[] result = new byte [Chunk.Length];
            short  magic  = BitConv.FromInt16(data, offset);

            if (magic == Chunk.Magic)
            {
                compressed = false;
                if (data.Length < offset + Chunk.Length)
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                }
                Array.Copy(data, offset, result, 0, Chunk.Length);
                offset += Chunk.Length;
            }
            else if (magic == Chunk.CompressedMagic)
            {
                compressed = true;
                int pos = 0;
                if (data.Length < offset + 12)
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                }
                short zero   = BitConv.FromInt16(data, offset + 2);
                int   length = BitConv.FromInt32(data, offset + 4);
                int   skip   = BitConv.FromInt32(data, offset + 8);
                if (zero != 0)
                {
                    ErrorManager.SignalIgnorableError("NSF.ReadChunk: Zero value is wrong");
                }
                if (length < 0 || length > Chunk.Length)
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Length field is invalid");
                }
                if (skip < 0)
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Skip value is negative");
                }
                offset += 12;
                while (pos < length)
                {
                    if (data.Length < offset + 1)
                    {
                        ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                    }
                    byte prefix = data[offset];
                    offset++;
                    if ((prefix & 0x80) != 0)
                    {
                        prefix &= 0x7F;
                        if (data.Length < offset + 1)
                        {
                            ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                        }
                        int seek = data[offset];
                        offset++;
                        int span = seek & 7;
                        seek >>= 3;
                        seek  |= prefix << 5;
                        if (span == 7)
                        {
                            span = 64;
                        }
                        else
                        {
                            span += 3;
                        }
                        if (pos - seek < 0)
                        {
                            ErrorManager.SignalError("NSF.ReadChunk: Repeat begins out of bounds");
                        }
                        if (pos + span > Chunk.Length)
                        {
                            ErrorManager.SignalError("NSF.ReadChunk: Repeat ends out of bounds");
                        }
                        // Do NOT use Array.Copy as
                        // overlap is possible i.e. span
                        // may be greater than seek
                        for (int i = 0; i < span; i++)
                        {
                            result[pos + i] = result[pos - seek + i];
                        }
                        pos += span;
                    }
                    else
                    {
                        if (data.Length < offset + prefix)
                        {
                            ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                        }
                        Array.Copy(data, offset, result, pos, prefix);
                        offset += prefix;
                        pos    += prefix;
                    }
                }
                if (data.Length < offset + skip)
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                }
                offset += skip;
                if (data.Length < offset + (Chunk.Length - length))
                {
                    ErrorManager.SignalError("NSF.ReadChunk: Data is too short");
                }
                Array.Copy(data, offset, result, pos, Chunk.Length - length);
                offset += (Chunk.Length - length);
            }
            else
            {
                compressed = false; // Fixes a stupid compile error
                ErrorManager.SignalError("NSF.ReadChunk: Unknown magic number");
            }
            return(result);
        }
Esempio n. 16
0
 protected override int LoadElement(byte[] data)
 {
     return(BitConv.FromInt32(data, 0));
 }
Esempio n. 17
0
        public static Entity Load(byte[] data)
        {
            if (data.Length < 16)
            {
                ErrorManager.SignalError("Entity: Data is too short");
            }
            int length        = BitConv.FromInt32(data, 0);
            int blank1        = BitConv.FromInt32(data, 4);
            int blank2        = BitConv.FromInt32(data, 8);
            int propertycount = BitConv.FromInt32(data, 12);

            if (length != data.Length)
            {
                ErrorManager.SignalIgnorableError("Entity: Length field mismatch");
            }
            if (blank1 != 0 || blank2 != 0)
            {
                ErrorManager.SignalIgnorableError("Entity: Blank value is wrong");
            }
            if (propertycount < 0 || propertycount > ushort.MaxValue)
            {
                ErrorManager.SignalError("Entity: Property count is invalid");
            }
            if (data.Length < 16 + propertycount * 8)
            {
                ErrorManager.SignalError("Entity: Data is too short");
            }
            Dictionary <short, EntityProperty> properties = new Dictionary <short, EntityProperty>();

            for (int i = 0; i < propertycount; i++)
            {
                short id          = BitConv.FromInt16(data, 16 + i * 8);
                int   offset      = (ushort)BitConv.FromInt16(data, 18 + i * 8) + 12;
                int   nextoffset  = (i == propertycount - 1) ? data.Length : ((ushort)BitConv.FromInt16(data, 26 + i * 8) + 12);
                byte  type        = data[20 + i * 8];
                byte  elementsize = data[21 + i * 8];
                short unknown     = BitConv.FromInt16(data, 22 + i * 8);
                if (offset > data.Length)
                {
                    ErrorManager.SignalError("Entity: Property begins out of bounds");
                }
                if (nextoffset < offset)
                {
                    ErrorManager.SignalError("Entity: Property ends before it begins");
                }
                if (nextoffset > data.Length)
                {
                    ErrorManager.SignalError("Entity: Property ends out of bounds");
                }
                if (properties.ContainsKey(id))
                {
                    ErrorManager.SignalIgnorableError("Entity: Duplicate property");
                }
                else
                {
                    byte[] propertydata = new byte [nextoffset - offset];
                    Array.Copy(data, offset, propertydata, 0, propertydata.Length);
                    EntityProperty property = EntityProperty.Load(type, elementsize, unknown, i == propertycount - 1, propertydata);
                    properties.Add(id, property);
                }
            }
            return(new Entity(properties));
        }