internal AuthChallengeResponse(ResponseFrame frame)
     : base(frame)
 {
     Token = BEBinaryReader.ReadBytes();
 }
Пример #2
0
        public static EXP Load(string path)
        {
            FileInfo fi = new FileInfo(path);

            Logger.LogToFile(Logger.LogLevel.Info, "{0}", path);
            EXP exp = new EXP()
            {
                name     = Path.GetFileNameWithoutExtension(path),
                location = Path.GetDirectoryName(path) + "\\"
            };

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead()))
            {
                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    string section = br.ReadString(4);
                    int    length  = 0;

                    switch (section)
                    {
                    case "FORM":
                        length = (int)br.ReadUInt32();
                        break;

                    case "TERR":
                    case "XOBF":
                        break;

                    case "TITL":
                        length = (int)br.ReadUInt32();
                        if (length > 0)
                        {
                            throw new NotImplementedException(string.Format("TITL section has a length ({0}), don't know what to do!", length));
                        }
                        break;

                    case "TEXT":
                        length = (int)br.ReadUInt32();
                        if (length > 0)
                        {
                            throw new NotImplementedException(string.Format("TEXT section has a length ({0}), don't know what to do!", length));
                        }
                        break;

                    case "HEAD":
                        length = (int)br.ReadUInt32();
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt16());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt32());
                        exp.entryCount = br.ReadUInt16();
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt32());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt16());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt16());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt16());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt32());
                        Logger.LogToFile(Logger.LogLevel.Debug, "U: {0}", br.ReadUInt32());
                        break;

                    case "BIN ":
                        length = (int)br.ReadUInt32();
                        exp.contents.Add(new EXPEntry {
                            Size = length, Offset = (int)br.BaseStream.Position, EntryType = EXPEntryType.Binary
                        });
                        br.ReadBytes(length);
                        break;

                    case "ANM ":
                        length = (int)br.ReadUInt32();
                        exp.contents.Add(new EXPEntry {
                            Size = length, Offset = (int)br.BaseStream.Position, EntryType = EXPEntryType.Animation
                        });
                        br.ReadBytes(length);
                        break;

                    case "PLTX":
                        length = (int)br.ReadUInt32();
                        if (length > 0)
                        {
                            throw new NotImplementedException(string.Format("PLTX section has a length ({0}), don't know what to do!", length));
                        }
                        break;

                    default:
                        throw new NotImplementedException(string.Format("Unexpected section \"{0}\" at {1,0:X0}", section, br.BaseStream.Position - 4));
                    }
                }
            }

            return(exp);
        }
Пример #3
0
        public static ConversionStatus Convert(
            Stream input,
            Stream output)
        {
            using var reader = new BEBinaryReader(input);

            var header = new WoffHeader
            {
                Signature         = reader.ReadUInt32(),
                Flavor            = reader.ReadUInt32(),
                Length            = reader.ReadUInt32(),
                TableCount        = reader.ReadUInt16(),
                Reserved          = reader.ReadUInt16(),
                TotalSfntSize     = reader.ReadUInt32(),
                MajorVersion      = reader.ReadUInt16(),
                MinorVersion      = reader.ReadUInt16(),
                MetaOffset        = reader.ReadUInt32(),
                MetaLength        = reader.ReadUInt32(),
                MetaOrignalLength = reader.ReadUInt32(),
                PrivOffset        = reader.ReadUInt32(),
                PrivLength        = reader.ReadUInt32()
            };

            if (header.Signature is not 0x774F4646)
            {
                if (header.Signature is 0x774F4632)
                {
                    return(ConversionStatus.UnsupportedWOFF2);
                }
                else
                {
                    return(ConversionStatus.UnrecognisedFile);
                }
            }


            UInt32 offset = 12;

            // Read Table Headers
            List <TableDirectory> entries = new List <TableDirectory>();

            for (var i = 0; i < header.TableCount; i++)
            {
                var entry = new TableDirectory
                {
                    Tag              = reader.ReadUInt32(),
                    Offset           = reader.ReadUInt32(),
                    CompressedLength = reader.ReadUInt32(),
                    OriginalLength   = reader.ReadUInt32(),
                    OriginalChecksum = reader.ReadUInt32()
                };

                if (Name(entry.Tag) == "DSIG") // Conversion invalidates
                {
                    continue;
                }

                entries.Add(entry);
                offset += (4 * 4);
            }

            // Amend table count after removing DSIG
            header.TableCount = (ushort)entries.Count;

            // Calculate header values
            UInt16 entrySelector = 0;

            while (Math.Pow(2, entrySelector) <= header.TableCount)
            {
                entrySelector++;
            }
            entrySelector--;

            UInt16 searchRange = (UInt16)(Math.Pow(2, entrySelector) * 16);
            UInt16 rangeShift  = (UInt16)(header.TableCount * 16 - searchRange);

            // Create writer
            using var writer = new BEBinaryWriter(output);

            // Write Font Header
            writer.Write(header.Flavor);
            writer.Write(header.TableCount);
            writer.Write(searchRange);
            writer.Write(entrySelector);
            writer.Write(rangeShift);

            // Write Table Headers
            foreach (var entry in entries)
            {
                writer.Write(entry.Tag);
                writer.Write(entry.OriginalChecksum);
                writer.Write(offset);
                writer.Write(entry.OriginalLength);
                entry.OutputOffset = offset;

                offset += entry.OriginalLength;
                if ((offset % 4) != 0)
                {
                    offset += 4 - (offset % 4);
                }
            }

            // Write Table contents
            foreach (var entry in entries)
            {
                input.Seek(entry.Offset, SeekOrigin.Begin);
                byte[] compressed = reader.ReadBytes((int)entry.CompressedLength);
                byte[] uncompressed;
                if (entry.CompressedLength != entry.OriginalLength)
                {
                    // Decompress table
                    using var comp = new MemoryStream(compressed.AsSpan().Slice(2).ToArray()); // Ignore the ZLib header (2 bytes long)
                    using var outs = new MemoryStream();
                    using var def  = new DeflateStream(comp, CompressionMode.Decompress);
                    def.CopyTo(outs);
                    uncompressed = outs.ToArray();
                }
                else
                {
                    uncompressed = compressed;
                }

                if (uncompressed.Length != entry.OriginalLength)
                {
                    return(ConversionStatus.TableLengthMismatch);
                }

                if (entry.ToString() == "name")
                {
                    if (TryFixNameTable(ref uncompressed) is byte[] ammended)
                    {
                        uncompressed = ammended;
                    }
                }

                output.Seek(entry.OutputOffset, SeekOrigin.Begin);
                writer.Write(uncompressed);
                offset = (uint)output.Position;
                if (offset % 4 != 0)
                {
                    uint padding = 4 - (offset % 4);
                    writer.Write(new byte[padding]);
                }
            }

            writer.Flush();
            output.Flush();

            return(ConversionStatus.OK);
        }
Пример #4
0
        void readEvent(Track track, ref int absoluteTime, BEBinaryReader stream, int chunkSize, Uri fileUri)
        {
            int deltaTime = readVarLengthValue(stream);

            absoluteTime += deltaTime;

            byte firstByte = stream.ReadByte();             //First byte in event

            chunkBytesRead++;
            if (firstByte == 0xff)             //meta or sysex event
            {
                MetaEvent e    = new MetaEvent();
                int       time = absoluteTime;
                e.Type = stream.ReadByte();
                chunkBytesRead++;
                int length = readVarLengthValue(stream);
                if (e.Type == 0x2f && length != 0)
                {
                    throw (new FileFormatException(fileUri, "End-of-track event has data length of " + length + ". Should be 0."));
                }
                e.Data          = stream.ReadBytes(length);
                chunkBytesRead += length;
                if (e.Type == 0x51)                 //Tempo event
                {
                    TempoEvent te = new TempoEvent(absoluteTime, e.Data);
                    if (!double.IsInfinity(te.Tempo))
                    {
                        if (tempoEvents.Count > 0 && te.Time == tempoEvents.Last().Time)
                        {
                            tempoEvents[tempoEvents.Count - 1] = te;
                        }
                        else
                        {
                            tempoEvents.Add(te);
                        }
                    }
                }
                else if (e.Type == 0x03)
                {
                    track.Name = ASCIIEncoding.ASCII.GetString(e.Data);
                }

                if (e.Type == 0x2f && chunkBytesRead != chunkSize)
                {
                    throw (new FileFormatException(fileUri, "End-of-track event at byte " + chunkBytesRead + " of " + chunkSize + "."));
                }
                if (e.Type != 0x2f && chunkBytesRead >= chunkSize)
                {
                    throw (new FileFormatException(fileUri, "End-of-track event missing at end of track."));
                }
            }
            else if (firstByte == 0xf0 || firstByte == 0xf7)             //sysex
            {
                byte b;
                do
                {
                    b = stream.ReadByte();
                    chunkBytesRead++;
                } while (b != 0xf7);
            }
            else             //Channel event
            {
                ChannelEvent chnEvent = new ChannelEvent
                {
                };
                int time = absoluteTime;
                if (firstByte > 127)                 //Status information present
                {
                    chnEvent.Channel = runningStatus.Channel = (byte)(firstByte & 0xf);
                    chnEvent.Type    = runningStatus.EventType = (byte)((firstByte >> 4) & 0xf);
                    chnEvent.Param1  = stream.ReadByte();
                    chunkBytesRead++;
                }
                else                 //Running status
                {
                    chnEvent.Type    = runningStatus.EventType;
                    chnEvent.Channel = runningStatus.Channel;
                    chnEvent.Param1  = firstByte;
                }
                if (chnEvent.Type != 0xc && chnEvent.Type != 0xd)
                {
                    chnEvent.Param2 = stream.ReadByte();
                    chunkBytesRead++;
                }

                if (chnEvent.Type == 0x9)                  //Note on/off
                {
                    //param1 = pitch, param2 = velocity

                    //Note off if velocity is 0
                    if (chnEvent.Param2 == 0)
                    {
                        chnEvent.Type = 0x8;
                    }
                    else                     //Note on
                    {
                        startOfPlayingNotes[chnEvent.Channel, chnEvent.Param1].AddLast(absoluteTime);
                        if (minPitch > chnEvent.Param1)
                        {
                            minPitch = chnEvent.Param1;
                        }
                        if (maxPitch < chnEvent.Param1)
                        {
                            maxPitch = chnEvent.Param1;
                        }
                    }
                }
                if (chnEvent.Type == 0x8)                  //note off
                {
                    //param1 = pitch, param2 = velocity
                    if (startOfPlayingNotes[chnEvent.Channel, chnEvent.Param1].Count == 0)
                    {
                        return;
                    }

                    Note note = new Note();
                    note.start    = startOfPlayingNotes[chnEvent.Channel, chnEvent.Param1].First();
                    note.stop     = absoluteTime;
                    note.channel  = chnEvent.Channel;
                    note.pitch    = chnEvent.Param1;
                    note.velocity = chnEvent.Param2;
                    for (int i = 0; i <= track.Notes.Count; i++)
                    {
                        if (i == track.Notes.Count || track.Notes[i].start > note.start)
                        {
                            track.Notes.Insert(i, note);
                            break;
                        }
                    }
                    startOfPlayingNotes[chnEvent.Channel, chnEvent.Param1].RemoveFirst();
                }

                if (chunkBytesRead >= chunkSize)
                {
                    throw (new FileFormatException(fileUri, "Error at chunk byte " + chunkBytesRead + " of " + chunkSize + ". Last track event is a channel event. Should be meta event."));
                }
            }
        }
Пример #5
0
        public static DAT Load(string path)
        {
            FileInfo fi = new FileInfo(path);

            Logger.LogToFile(Logger.LogLevel.Info, "{0}", path);
            DAT dat = new DAT();

            DatMesh D = new DatMesh();
            int     count;

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead(), Encoding.Default))
            {
                if (br.ReadUInt32() != 0x12 ||
                    br.ReadUInt32() != 0x8 ||
                    br.ReadUInt32() != 0xFACE ||
                    br.ReadUInt32() != 0x2)
                {
                    Logger.LogToFile(Logger.LogLevel.Error, "{0} isn't a valid DAT file", path);
                    return(null);
                }

                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    int tag    = (int)br.ReadUInt32();
                    int length = (int)br.ReadUInt32();

                    switch (tag)
                    {
                    case 54:     // 00 00 00 36
                        D = new DatMesh()
                        {
                            UnknownAttribute = br.ReadUInt16(),       // I think this is actually two byte values
                            Name             = br.ReadString()
                        };
                        break;

                    case 23:     // 00 00 00 17 : vertex data
                        count = (int)br.ReadUInt32();

                        for (int i = 0; i < count; i++)
                        {
                            D.Mesh.AddListVertex(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        }
                        break;

                    case 24:     // 00 00 00 18 : UV co-ordinates
                        count = (int)br.ReadUInt32();

                        for (int i = 0; i < count; i++)
                        {
                            D.Mesh.AddListUV(br.ReadSingle(), br.ReadSingle());
                        }
                        break;

                    case 53:        // 00 00 00 35 : faces
                        count = (int)br.ReadUInt32();

                        for (int i = 0; i < count; i++)
                        {
                            int faceID = D.Mesh.AddFace(br.ReadUInt16(), br.ReadUInt16(), br.ReadUInt16());

                            D.Mesh.Faces[faceID].SmoothingGroup = br.ReadUInt16();

                            br.ReadByte();     // number of edges, 0 and 3 = tri.  4 = quad.
                        }
                        break;

                    case 22:     // 00 00 00 16 : material list
                        D.Mesh.Materials.AddRange(br.ReadStrings((int)br.ReadUInt32()));
                        break;

                    case 26:             // 00 00 00 1A : face textures
                        count = (int)br.ReadUInt32();
                        br.ReadBytes(4); // f**k knows what this is
                        for (int i = 0; i < count; i++)
                        {
                            D.Mesh.SetMaterialForFace(i, br.ReadUInt16() - 1);
                        }
                        break;

                    case 0:
                        // EndOfFile
                        D.Mesh.ProcessMesh();
                        dat.DatMeshes.Add(D);
                        break;

                    default:
                        Logger.LogToFile(Logger.LogLevel.Error, "Unknown DAT tag: {0} ({1:x2})", tag, br.BaseStream.Position);
                        return(null);
                    }
                }
            }

            return(dat);
        }
Пример #6
0
 internal AuthSuccessResponse(ResponseFrame frame)
     : base(frame)
 {
     Token = BEBinaryReader.ReadBytes();
 }
Пример #7
0
        public static MAT Load(string path)
        {
            FileInfo fi = new FileInfo(path);

            Logger.LogToFile(Logger.LogLevel.Info, "{0}", path);
            MAT mat = new MAT();

            MATMaterial M      = new MATMaterial();
            bool        bDebug = false;

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead(), Encoding.Default))
            {
                br.ReadBytes(16); // Header

                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    int tag    = (int)br.ReadUInt32();
                    int length = (int)br.ReadUInt32();

                    switch (tag)
                    {
                    case 0x4:
                        // C1 mat file
                        M = new MATMaterial();

                        M.DiffuseColour[0]    = br.ReadByte();  // R
                        M.DiffuseColour[1]    = br.ReadByte();  // G
                        M.DiffuseColour[2]    = br.ReadByte();  // B
                        M.DiffuseColour[3]    = br.ReadByte();  // A
                        M.AmbientLighting     = br.ReadSingle();
                        M.DirectionalLighting = br.ReadSingle();
                        M.SpecularLighting    = br.ReadSingle();
                        M.SpecularPower       = br.ReadSingle();
                        M.SetFlags((int)br.ReadUInt16());     // Flags
                        if (M.GetFlag(MATMaterial.Settings.UnknownSetting) || M.GetFlag(MATMaterial.Settings.IFromV) || M.GetFlag(MATMaterial.Settings.UFromI) || M.GetFlag(MATMaterial.Settings.VFromI))
                        {
                            bDebug = true;
                        }
                        M.UVMatrix = new Matrix2D(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        byte x1 = br.ReadByte();     // ??
                        byte x2 = br.ReadByte();     // ??
                        M.Name = br.ReadString();

                        if (bDebug)
                        {
                            Console.WriteLine(path + " :: " + M.Name); bDebug = false;
                        }
                        break;

                    case 0x3c:
                        M = new MATMaterial();

                        M.DiffuseColour[0]    = br.ReadByte();  // R
                        M.DiffuseColour[1]    = br.ReadByte();  // G
                        M.DiffuseColour[2]    = br.ReadByte();  // B
                        M.DiffuseColour[3]    = br.ReadByte();  // A
                        M.AmbientLighting     = br.ReadSingle();
                        M.DirectionalLighting = br.ReadSingle();
                        M.SpecularLighting    = br.ReadSingle();
                        M.SpecularPower       = br.ReadSingle();
                        M.SetFlags((int)br.ReadUInt32());     // Flags
                        M.UVMatrix = new Matrix2D(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        if (br.ReadUInt32() != 169803776)
                        {
                            Console.WriteLine("Weird Beard! (" + path + ")");
                        }
                        br.ReadBytes(13);     // 13 bytes of nothing
                        M.Name = br.ReadString();
                        break;

                    case 0x1c:
                        M.Texture = br.ReadString();
                        break;

                    case 0x1f:
                        string _ = br.ReadString();     // shadetable
                        break;

                    case 0x0:
                        mat.Materials.Add(M);
                        break;

                    default:
                        Logger.LogToFile(Logger.LogLevel.Error, "Unknown MAT tag: {0} ({1})", tag, br.BaseStream.Position.ToString("X"));
                        return(null);
                    }
                }
            }

            return(mat);
        }
Пример #8
0
        public static XT2 Load(string path)
        {
            FileInfo fi = new FileInfo(path);

            Console.WriteLine("{0}", path);
            XT2 xt2 = new XT2()
            {
                Name = fi.Name.Replace(fi.Extension, "")
            };

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead()))
            {
                Console.WriteLine("Always 0 : {0}", br.ReadUInt32());

                int magic = (int)br.ReadUInt32();

                br.ReadUInt32();    // datasize
                Console.WriteLine("Always 52 : {0}", br.ReadUInt32());
                Console.WriteLine("Always 0 : {0}", br.ReadUInt16());
                xt2.Width  = br.ReadUInt16();
                xt2.Height = br.ReadUInt16();
                Console.WriteLine("{0} {1}", br.ReadUInt16(), br.ReadUInt16());

                xt2.Header = new D3DBaseTexture(br);

                int W          = 0;
                int H          = 0;
                int TexelPitch = 0;
                int DataSize   = 0;
                int OutSize    = 0;
                int w          = xt2.Width;
                int h          = xt2.Height;

                switch (xt2.Header.DataFormat)
                {
                    //case D3DFormat.X360_A8R8G8B8:
                    //    W = w;
                    //    H = h;
                    //    TexelPitch = 4;
                    //    DataSize = w * h * 4;
                    //    break;

                    //case D3DFormat.X360_DXT1:
                    //    W = w / 4;
                    //    H = h / 4;
                    //    TexelPitch = 8;
                    //    DataSize = w * h / 2;
                    //    break;

                    //case D3DFormat.X360_DXT2:
                    //    W = w / 4;
                    //    H = h / 4;
                    //    TexelPitch = 16;
                    //    DataSize = W * H;
                    //    break;
                }

                if (H % 128 != 0)
                {
                    H += 128 - H % 128;
                }

                switch (xt2.Header.DataFormat)
                {
                    //case D3DFormat.X360_A8R8G8B8:
                    //    OutSize = W * H * TexelPitch;
                    //    break;

                    //case D3DFormat.X360_DXT1:
                    //    OutSize = W * H * TexelPitch;
                    //    break;

                    //case D3DFormat.X360_DXT2:
                    //    DataSize = w * H * 2;
                    //    OutSize = W * H * TexelPitch;
                    //    break;
                }

                byte[] data    = new byte[DataSize];
                byte[] outdata = new byte[OutSize];

                Array.Copy(br.ReadBytes(DataSize), data, DataSize);

                int step = xt2.Header.Endian == 1 ? 2 : 4;
                for (int i = 0; i < data.Length; i += step)
                {
                    for (int j = 0; j < step / 2; j++)
                    {
                        byte tmp = data[i + j];
                        data[i + j]            = data[i + step - j - 1];
                        data[i + step - j - 1] = tmp;
                    }
                }

                for (int y = 0; y < H; y++)
                {
                    for (int x = 0; x < W; x++)
                    {
                        int offset = Xbox360ConvertTextureAddress(x, y, W, TexelPitch);
                        if (offset * TexelPitch < data.Length)
                        {
                            Array.Copy(data, offset * TexelPitch, outdata, (x + y * W) * TexelPitch, TexelPitch);
                        }
                    }
                }

                MipMap mip = new MipMap
                {
                    Width  = xt2.Width,
                    Height = xt2.Height,
                    Data   = data
                };

                xt2.MipMaps.Add(mip);
            }

            return(xt2);
        }
Пример #9
0
        public void WritePackToDirectory(string directory)
        {
            for (int i = 0; i < files; i++)
            {

                using (FileStream s = File.Open(filename, FileMode.Open, FileAccess.Read))
                using (BinaryReader reader = new BEBinaryReader(s))
                using (FileStream outfile = File.Open(directory + Path.DirectorySeparatorChar + filenames[i], FileMode.Create, FileAccess.Write))
                {
                    s.Seek(fileData[i].offset, SeekOrigin.Begin);
                    byte[] file = reader.ReadBytes(fileData[i].size);
                    outfile.Write(file, 0, file.Length);
                }

            }
        }
Пример #10
0
        public static PIX Load(string path)
        {
            Logger.LogToFile(Logger.LogLevel.Info, "{0}", path);
            FileInfo fi  = new FileInfo(path);
            PIX      pix = new PIX();

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead(), Encoding.Default))
            {
                if (br.ReadUInt32() != 0x12 ||
                    br.ReadUInt32() != 0x08 ||
                    br.ReadUInt32() != 0x02 ||
                    br.ReadUInt32() != 0x02)
                {
                    Logger.LogToFile(Logger.LogLevel.Error, "{0} isn't a valid PIX file", path);
                    return(null);
                }

                Stack <PIXIE> pixies = new Stack <PIXIE>();

                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    if (br.BaseStream.Position + 8 > br.BaseStream.Length)
                    {
                        Logger.LogToFile(Logger.LogLevel.Error, $"{path} is malformed.  The last {br.BaseStream.Length - br.BaseStream.Position} bytes are redundant and should be removed");
                        break;
                    }

                    int tag = (int)br.ReadUInt32();
                    br.ReadUInt32();        // length

                    switch (tag)
                    {
                    case 0x03:      // 3
                        pixies.Push(new PIXIE()
                        {
                            Format     = (PIXIE.PixelmapFormat)br.ReadByte(),
                            RowSize    = br.ReadUInt16(),
                            Width      = br.ReadUInt16(),
                            Height     = br.ReadUInt16(),
                            HalfWidth  = br.ReadUInt16(),
                            HalfHeight = br.ReadUInt16(),
                            Name       = br.ReadString()
                        });
                        break;

                    case 0x21:      // 33
                        pixies.Peek().PixelCount = (int)br.ReadUInt32();
                        pixies.Peek().PixelSize  = (int)br.ReadUInt32();
                        pixies.Peek().SetData(br.ReadBytes(pixies.Peek().DataLength));
                        break;

                    case 0x22:      // 34
                    case 0x00:      // 0
                        pix.Pixies.Add(pixies.Pop());
                        break;

                    case 0x3d:
                        pixies.Push(new PIXIE
                        {
                            Format  = (PIXIE.PixelmapFormat)br.ReadByte(),
                            RowSize = br.ReadUInt16(),
                            Width   = br.ReadUInt16(),
                            Height  = br.ReadUInt16()
                        });
                        br.ReadBytes(6);
                        pixies.Peek().Name = br.ReadString();
                        break;

                    default:
                        Logger.LogToFile(Logger.LogLevel.Error, "Unknown PIX tag: {0} ({1:x2})", tag, br.BaseStream.Position);
                        return(null);
                    }
                }
            }

            return(pix);
        }