public static void Main(string[] args)
        {
            var fullAlpha = false;
            var showHelp  = false;
            var mode      = Mode.Unknown;

            var options = new OptionSet()
            {
                // ReSharper disable AccessToModifiedClosure
                { "full-alpha", "when decoding textures, don't force 1-bit alpha", v => fullAlpha = v != null },
                { "a|assemble", "assemble PEG file", v => mode = v != null ? Mode.Assemble : mode },
                { "d|disassemble", "disassemble PEG file", v => mode = v != null ? Mode.Disassemble : mode },
                { "h|help", "show this message and exit", v => showHelp = v != null },
                // ReSharper restore AccessToModifiedClosure
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (mode == Mode.Unknown && extras.Count > 0)
            {
                // detect mode
                if (Directory.Exists(extras[0]) == true)
                {
                    mode = Mode.Assemble;
                }
                else if (File.Exists(extras[0]) == true)
                {
                    mode = Mode.Disassemble;
                }
            }

            if (extras.Count < 1 || extras.Count > 2 ||
                showHelp == true || mode == Mode.Unknown)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ [-a|-d] input [output]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            if (mode == Mode.Assemble)
            {
                throw new NotImplementedException();
            }
            else if (mode == Mode.Disassemble)
            {
                var inputPath      = Path.GetFullPath(extras[0]);
                var outputBasePath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null);

                using (var input = File.OpenRead(inputPath))
                {
                    var peg = new PegFile();
                    peg.Deserialize(input);

                    if (peg.Textures.Count == 0)
                    {
                        return;
                    }

                    var info = new PegFileInfo()
                    {
                        Endian   = peg.Endian,
                        Version  = peg.Version,
                        Textures = new List <PegTextureInfo>(),
                    };

                    Directory.CreateDirectory(outputBasePath);

                    for (int i = 0; i < peg.Textures.Count; i++)
                    {
                        var nextDataOffset = i + 1 >= peg.Textures.Count
                                                 ? input.Length
                                                 : peg.Textures[i + 1].DataOffset;

                        var texture        = peg.Textures[i];
                        var rawTextureSize = nextDataOffset - texture.DataOffset;
                        var frameSize      = ComputeFrameSize(texture);
                        var textureSize    = frameSize * texture.FrameCount;
                        if (rawTextureSize < textureSize)
                        {
                            throw new FormatException();
                        }

                        input.Position = texture.DataOffset;

                        var textureInfo = new PegTextureInfo()
                        {
                            Width          = texture.Width,
                            Height         = texture.Height,
                            Format         = texture.Format,
                            FormatArgument = texture.FormatArgument,
                            Flags          = texture.Flags,
                            AnimationDelay = texture.AnimationDelay,
                            MipCount       = texture.MipCount,
                            UnknownA       = texture.UnknownA,
                            UnknownB       = texture.UnknownB,
                            Name           = texture.Name,
                        };

                        if (texture.FrameCount == 1)
                        {
                            textureInfo.Path = texture.Name + ".png";
                            var outputPath = Path.Combine(outputBasePath, textureInfo.Path);
                            var bytes      = input.ReadBytes(textureSize);
                            using (var bitmap = ExportTexture(texture, bytes, fullAlpha == false))
                            {
                                bitmap.Save(outputPath, ImageFormat.Png);
                            }
                        }
                        else
                        {
                            textureInfo.FramePaths = new List <string>();
                            for (int j = 0; j < texture.FrameCount; j++)
                            {
                                var texturePath = texture.Name + "_" + j + ".png";
                                textureInfo.FramePaths.Add(texturePath);
                                var outputPath = Path.Combine(outputBasePath, texturePath);
                                var bytes      = input.ReadBytes(frameSize);
                                using (var bitmap = ExportTexture(texture, bytes, fullAlpha == false))
                                {
                                    bitmap.Save(outputPath, ImageFormat.Png);
                                }
                            }
                        }

                        info.Textures.Add(textureInfo);
                    }

                    using (var output = File.Create(Path.Combine(outputBasePath, "@peg.json")))
                        using (var textWriter = new StreamWriter(output, Encoding.UTF8))
                            using (var writer = new JsonTextWriter(textWriter))
                            {
                                writer.Formatting  = Newtonsoft.Json.Formatting.Indented;
                                writer.Indentation = 2;
                                writer.IndentChar  = ' ';

                                var serializer = new JsonSerializer();
                                serializer.Serialize(writer, info);
                            }
                }
            }
        }