示例#1
0
        public static void Main(string[] args)
        {
            bool showHelp       = false;
            bool overwriteFiles = false;
            bool verbose        = true;

            var options = new OptionSet()
            {
                {
                    "o|overwrite",
                    "overwrite existing files",
                    v => overwriteFiles = v != null
                },
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            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 (extras.Count < 1 ||
                extras.Count > 2 ||
                showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_file.rpack [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath  = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack";

            using (var input = File.OpenRead(inputPath))
            {
                var rpack = new ResourcePackageFile();
                rpack.Deserialize(input);

                IResourcePackageLoader loader = null;

                if ((rpack.Flags & ResourcePackage.PackageFlags.UseLZMAForCompression) != 0)
                {
                    return;

                    throw new NotSupportedException();
                }
                else
                {
                    loader = new ResourcePackageLoaderZlib();
                }

                using (loader)
                {
                    foreach (var entry in rpack.Entries)
                    {
                        Console.WriteLine(entry.FirstName);

                        switch (entry.Type)
                        {
                        case ResourcePackage.ResourceType.Texture:
                        {
                            if (entry.Datas.Any(
                                    d =>
                                    d.Type.Type != ResourcePackage.ResourceType.Texture &&
                                    d.Type.Type != ResourcePackage.ResourceType.TextureBitmapData &&
                                    d.Type.Type != ResourcePackage.ResourceType.TextureMipBitmapData) == true)
                            {
                                throw new FormatException();
                            }

                            var headerData = entry.Datas.First();
                            if (headerData.Type.Type != ResourcePackage.ResourceType.Texture)
                            {
                                throw new FormatException();
                            }

                            if (headerData.UncompressedSize != 80)
                            {
                                throw new FormatException();
                            }

                            var header = new ResourcePackage.TextureHeader();
                            header.Deserialize(loader.Read(input, headerData), rpack.LittleEndian);

                            var dataPath = Path.Combine(outputPath, "textures");
                            dataPath = Path.Combine(dataPath, entry.FirstName + ".dds");

                            if (overwriteFiles == true ||
                                File.Exists(dataPath) == false)
                            {
                                Directory.CreateDirectory(Path.GetDirectoryName(dataPath));

                                using (var output = File.Create(dataPath))
                                {
                                    var ddsHeader = new DDS.Header()
                                    {
                                        Size  = 124,
                                        Flags =
                                            DDS.HeaderFlags.Texture |
                                            DDS.HeaderFlags.Mipmap,
                                        Width       = header.Width,
                                        Height      = header.Height,
                                        MipMapCount = header.MipMapCount,
                                        PixelFormat = GetPixelFormat(header.Format),
                                    };

                                    output.WriteValueU32(0x20534444);
                                    ddsHeader.Serialize(output, rpack.LittleEndian);

                                    for (uint i = 0; i < header.MipMapCount; i++)
                                    {
                                        var size = header.MipMapSizes[i];

                                        var mipData = entry.Datas
                                                      .SingleOrDefault(m => m.UncompressedSize == size);
                                        if (mipData == null)
                                        {
                                            output.Seek(size, SeekOrigin.Current);
                                        }
                                        else
                                        {
                                            loader.Read(input, mipData, output);
                                        }
                                    }
                                }
                            }

                            break;
                        }

                        case ResourcePackage.ResourceType.Animation:
                        case ResourcePackage.ResourceType.AnimationScript:
                        case ResourcePackage.ResourceType.Fx:
                        case ResourcePackage.ResourceType.Material:
                        case ResourcePackage.ResourceType.Mesh:
                        case ResourcePackage.ResourceType.TinyObjects:
                        {
                            // dump out raw data for 'unsupported' types

                            int dataIndex = -1;
                            foreach (var data in entry.Datas)
                            {
                                dataIndex++;

                                var dataName = string.Format("{0}.{1}", dataIndex, data.Type.Type);

                                var dataPath = Path.Combine(outputPath, "__UNKNOWN");
                                dataPath = Path.Combine(dataPath, entry.Type.ToString());
                                dataPath = Path.Combine(dataPath, entry.FirstName);
                                dataPath = Path.Combine(dataPath, dataName);

                                if (overwriteFiles == true ||
                                    File.Exists(dataPath) == false)
                                {
                                    Directory.CreateDirectory(Path.GetDirectoryName(dataPath));
                                    using (var output = File.Create(dataPath))
                                    {
                                        loader.Read(input, data, output);
                                    }
                                }
                            }

                            break;
                        }

                        default:
                        {
                            throw new NotSupportedException();
                        }
                        }
                    }
                }
            }
        }
示例#2
0
        public void Deserialize(Stream input)
        {
            var pos = input.Position;

            unsafe
            {
                var buffer = new byte[input.Length - pos];
                input.Read(buffer, 0, buffer.Length);
                TypedReference tr        = __makeref(buffer);
                IntPtr         ptr       = **(IntPtr **)(&tr);
                string         hex       = ptr.ToString("X");
                string         hexOutput = String.Format("Data: 0x{0:X}", hex);
                Debug.WriteLine(hexOutput);
            }
            input.Seek(pos, SeekOrigin.Begin);

            var magic = input.ReadValueU32();

            if (magic != 0x20534444 &&
                magic < 0x44440000 &&
                magic > 0x44445000)
            {
                throw new FormatException("not a DDS texture");
            }

            this.Endian = Endian.Little; // magic == 0x20534444 ? Endian.Little : Endian.Big;

            this.Header = new DDS.Header();
            this.Header.Deserialize(input, this.Endian);

            if ((this.Header.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0)
            {
                var squishFlags = Native.Flags.None;

                switch (this.Header.PixelFormat.FourCC)
                {
                case 0x31545844:     // "DXT1"
                {
                    squishFlags |= Native.Flags.DXT1;
                    break;
                }

                case 0x33545844:     // "DXT3"
                {
                    squishFlags |= Native.Flags.DXT3;
                    break;
                }

                case 0x35545844:     // "DXT5"
                {
                    squishFlags |= Native.Flags.DXT5;
                    break;
                }

                case 0x30315844:     // "DXT5"
                {
                    squishFlags |= Native.Flags.DXT5;
                    break;
                }

                case 0x32495441:     // "ATI"
                {
                    squishFlags |= Native.Flags.DXT5;
                    break;
                }

                default:
                {
                    throw new FormatException("unsupported DDS format");
                }
                }

                // Compute size of compressed block area
                int blockCount = ((this.Width + 3) / 4) * ((this.Height + 3) / 4);
                int blockSize  = ((squishFlags & Native.Flags.DXT1) != 0) ? 8 : 16;

                // Allocate room for compressed blocks, and read data into it.
                var compressedBlocks = new byte[blockCount * blockSize];
                input.Read(compressedBlocks, 0, compressedBlocks.Length);

                // Now decompress..
                this._PixelData = Native.DecompressImage(
                    compressedBlocks, this.Width, this.Height, squishFlags);
            }
            else
            {
                // We can only deal with the non-DXT formats we know about..
                // this is a bit of a mess..
                // Sorry..
                var fileFormat = DDS.FileFormat.INVALID;

                if (this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x00FF0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000FF00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000FF &&
                    this.Header.PixelFormat.AlphaBitMask == 0xFF000000)
                {
                    fileFormat = DDS.FileFormat.A8R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x00FF0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000FF00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000FF &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.X8R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x000000ff &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.AlphaBitMask == 0xff000000)
                {
                    fileFormat = DDS.FileFormat.A8B8G8R8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x000000ff &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.X8B8G8R8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x00007c00 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000003e0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000001f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00008000)
                {
                    fileFormat = DDS.FileFormat.A1R5G5B5;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x00000f00 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000000f0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000000f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x0000f000)
                {
                    fileFormat = DDS.FileFormat.A4R4G4B4;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 24 &&
                    this.Header.PixelFormat.RedBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000ff &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x0000f800 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000007e0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000001f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.R5G6B5;
                }

                if (fileFormat == DDS.FileFormat.INVALID)
                {
                    throw new FormatException("unsupported DDS format");
                }

                int pixelSize = (int)(this.Header.PixelFormat.RGBBitCount / 8);
                int rowPitch  = 0;

                if ((this.Header.Flags & DDS.HeaderFlags.Pitch) != 0)
                {
                    rowPitch = (int)this.Header.PitchOrLinearSize;
                }
                else if ((this.Header.Flags & DDS.HeaderFlags.LinerSize) != 0)
                {
                    /* Linear size specified, compute row pitch. Of course, this
                     * should never happen as linear size is *supposed* to be for
                     * compressed textures. But Microsoft doesn't always play by the
                     * rules when it comes to DDS output. */
                    rowPitch =
                        (int)this.Header.PitchOrLinearSize /
                        this.Header.Height;
                }
                else
                {
                    /* Another case of Microsoft not obeying their standard is the
                     * 'Convert to..' shell extension that ships in the DirectX SDK.
                     * Seems to always leave flags empty, so no indication of pitch
                     * or linear size.
                     *
                     * And - to top it all off - they leave PitchOrLinearSize as
                     * *zero*. Zero??? If we get this bizarre set of inputs, we just
                     * go 'screw it' and compute row pitch ourselves,
                     *
                     * Making sure we DWORD align it (if that code path is enabled). */
                    rowPitch = this.Header.Width * pixelSize;

#if     APPLY_PITCH_ALIGNMENT
                    rowPitch = (((int)rowPitch + 3) & (~3));
#endif
                }

                var pixelData = new byte[rowPitch * this.Header.Height];
                if (input.Read(pixelData, 0, pixelData.Length) != pixelData.Length)
                {
                    throw new EndOfStreamException();
                }

                this._PixelData = new byte[this.Header.Width * this.Header.Height * 4];

                for (int y = 0; y < this.Header.Height; y++)
                {
                    int src = y * rowPitch;
                    int dst = y * 4;

                    for (int x = 0; x < this.Header.Width; x++, src += pixelSize, dst += 4)
                    {
                        // Read our pixel
                        uint color = 0;

                        byte R = 0;
                        byte G = 0;
                        byte B = 0;
                        byte A = 0;

                        // Build our pixel colour as a DWORD
                        for (int loop = 0, shift = 0; loop < pixelSize; loop++, shift += 8)
                        {
                            color |= (uint)pixelData[src + loop] << shift;
                        }

                        switch (fileFormat)
                        {
                        case DDS.FileFormat.A8R8G8B8:
                        {
                            A = (byte)((color >> 24) & 0xFF);
                            R = (byte)((color >> 16) & 0xFF);
                            G = (byte)((color >> 8) & 0xFF);
                            B = (byte)((color >> 0) & 0xFF);
                            break;
                        }

                        case DDS.FileFormat.X8R8G8B8:
                        {
                            A = 0xFF;
                            R = (byte)((color >> 16) & 0xFF);
                            G = (byte)((color >> 8) & 0xFF);
                            B = (byte)((color >> 0) & 0xFF);
                            break;
                        }

                        case DDS.FileFormat.A8B8G8R8:
                        {
                            A = (byte)((color >> 24) & 0xFF);
                            R = (byte)((color >> 0) & 0xFF);
                            G = (byte)((color >> 8) & 0xFF);
                            B = (byte)((color >> 16) & 0xFF);
                            break;
                        }

                        case DDS.FileFormat.X8B8G8R8:
                        {
                            A = 0xFF;
                            R = (byte)((color >> 0) & 0xFF);
                            G = (byte)((color >> 8) & 0xFF);
                            B = (byte)((color >> 16) & 0xFF);
                            break;
                        }

                        case DDS.FileFormat.A1R5G5B5:
                        {
                            A = (byte)((color >> 15) * 0xFF);
                            R = (byte)((color >> 10) & 0x1F);
                            G = (byte)((color >> 5) & 0x1F);
                            B = (byte)((color >> 0) & 0x1F);

                            R = (byte)((R << 3) | (R >> 2));
                            G = (byte)((G << 3) | (G >> 2));
                            B = (byte)((B << 3) | (B >> 2));
                            break;
                        }

                        case DDS.FileFormat.A4R4G4B4:
                        {
                            A = (byte)((color >> 12) & 0xFF);
                            R = (byte)((color >> 8) & 0x0F);
                            G = (byte)((color >> 4) & 0x0F);
                            B = (byte)((color >> 0) & 0x0F);

                            A = (byte)((A << 4) | (A >> 0));
                            R = (byte)((R << 4) | (R >> 0));
                            G = (byte)((G << 4) | (G >> 0));
                            B = (byte)((B << 4) | (B >> 0));
                            break;
                        }

                        case DDS.FileFormat.R8G8B8:
                        {
                            A = 0xFF;
                            R = (byte)((color >> 16) & 0xFF);
                            G = (byte)((color >> 8) & 0xFF);
                            B = (byte)((color >> 0) & 0xFF);
                            break;
                        }

                        case DDS.FileFormat.R5G6B5:
                        {
                            A = 0xFF;
                            R = (byte)((color >> 11) & 0x1F);
                            G = (byte)((color >> 5) & 0x3F);
                            B = (byte)((color >> 0) & 0x1F);

                            R = (byte)((R << 3) | (R >> 2));
                            G = (byte)((G << 2) | (G >> 4));
                            B = (byte)((B << 3) | (B >> 2));
                            break;
                        }

                        default:
                        {
                            throw new NotSupportedException();
                        }
                        }

                        this._PixelData[dst + 0] = R;
                        this._PixelData[dst + 1] = G;
                        this._PixelData[dst + 2] = B;
                        this._PixelData[dst + 3] = A;
                    }
                }
            }
        }
示例#3
0
        public void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32();

            if (magic != 0x20534444 &&
                magic != 0x44445320)
            {
                throw new FormatException("not a DDS texture");
            }

            this.Endian = magic == 0x20534444 ? Endian.Little : Endian.Big;

            this.Header = new DDS.Header();
            this.Header.Deserialize(input, this.Endian);

            if ((this.Header.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0)
            {
                var squishFlags = Native.Flags.None;

                switch (this.Header.PixelFormat.FourCC)
                {
                    case 0x31545844: // "DXT1"
                    {
                        squishFlags |= Native.Flags.DXT1;
                        break;
                    }

                    case 0x33545844: // "DXT3"
                    {
                        squishFlags |= Native.Flags.DXT3;
                        break;
                    }

                    case 0x35545844: // "DXT5"
                    {
                        squishFlags |= Native.Flags.DXT5;
                        break;
                    }

                    default:
                    {
                        throw new FormatException("unsupported DDS format");
                    }
                }

                // Compute size of compressed block area
                int blockCount = ((this.Width + 3) / 4) * ((this.Height + 3) / 4);
                int blockSize = ((squishFlags & Native.Flags.DXT1) != 0) ? 8 : 16;

                // Allocate room for compressed blocks, and read data into it.
                var compressedBlocks = new byte[blockCount * blockSize];
                input.Read(compressedBlocks, 0, compressedBlocks.Length);

                // Now decompress..
                this._PixelData = Native.DecompressImage(
                    compressedBlocks, this.Width, this.Height, squishFlags);
            }
            else
            {
                // We can only deal with the non-DXT formats we know about..
                // this is a bit of a mess..
                // Sorry..
                var fileFormat = DDS.FileFormat.INVALID;

                if (this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x00FF0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000FF00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000FF &&
                    this.Header.PixelFormat.AlphaBitMask == 0xFF000000)
                {
                    fileFormat = DDS.FileFormat.A8R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x00FF0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000FF00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000FF &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.X8R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x000000ff &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.AlphaBitMask == 0xff000000)
                {
                    fileFormat = DDS.FileFormat.A8B8G8R8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 32 &&
                    this.Header.PixelFormat.RedBitMask == 0x000000ff &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.X8B8G8R8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x00007c00 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000003e0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000001f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00008000)
                {
                    fileFormat = DDS.FileFormat.A1R5G5B5;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGBA &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x00000f00 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000000f0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000000f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x0000f000)
                {
                    fileFormat = DDS.FileFormat.A4R4G4B4;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 24 &&
                    this.Header.PixelFormat.RedBitMask == 0x00ff0000 &&
                    this.Header.PixelFormat.GreenBitMask == 0x0000ff00 &&
                    this.Header.PixelFormat.BlueBitMask == 0x000000ff &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.R8G8B8;
                }
                else if (
                    this.Header.PixelFormat.Flags == DDS.PixelFormatFlags.RGB &&
                    this.Header.PixelFormat.RGBBitCount == 16 &&
                    this.Header.PixelFormat.RedBitMask == 0x0000f800 &&
                    this.Header.PixelFormat.GreenBitMask == 0x000007e0 &&
                    this.Header.PixelFormat.BlueBitMask == 0x0000001f &&
                    this.Header.PixelFormat.AlphaBitMask == 0x00000000)
                {
                    fileFormat = DDS.FileFormat.R5G6B5;
                }

                if (fileFormat == DDS.FileFormat.INVALID)
                {
                    throw new FormatException("unsupported DDS format");
                }

                int pixelSize = (int)(this.Header.PixelFormat.RGBBitCount / 8);
                int rowPitch = 0;

                if ((this.Header.Flags & DDS.HeaderFlags.Pitch) != 0)
                {
                    rowPitch = (int)this.Header.PitchOrLinearSize;
                }
                else if ((this.Header.Flags & DDS.HeaderFlags.LinerSize) != 0)
                {
                    /* Linear size specified, compute row pitch. Of course, this
                     * should never happen as linear size is *supposed* to be for
                     * compressed textures. But Microsoft doesn't always play by the
                     * rules when it comes to DDS output. */
                    rowPitch =
                        (int)this.Header.PitchOrLinearSize /
                        this.Header.Height;
                }
                else
                {
                    /* Another case of Microsoft not obeying their standard is the
                     * 'Convert to..' shell extension that ships in the DirectX SDK.
                     * Seems to always leave flags empty, so no indication of pitch
                     * or linear size.
                     *
                     * And - to top it all off - they leave PitchOrLinearSize as
                     * *zero*. Zero??? If we get this bizarre set of inputs, we just
                     * go 'screw it' and compute row pitch ourselves,
                     *
                     * Making sure we DWORD align it (if that code path is enabled). */
                    rowPitch = this.Header.Width * pixelSize;

            #if	APPLY_PITCH_ALIGNMENT
                    rowPitch = (((int)rowPitch + 3) & (~3));
            #endif
                }

                var pixelData = new byte[rowPitch * this.Header.Height];
                if (input.Read(pixelData, 0, pixelData.Length) != pixelData.Length)
                {
                    throw new EndOfStreamException();
                }

                this._PixelData = new byte[this.Header.Width * this.Header.Height * 4];

                for (int y = 0; y < this.Header.Height; y++)
                {
                    int src = y * rowPitch;
                    int dst = y * 4;

                    for (int x = 0; x < this.Header.Width; x++, src += pixelSize, dst += 4)
                    {
                        // Read our pixel
                        uint color = 0;

                        byte R = 0;
                        byte G = 0;
                        byte B = 0;
                        byte A = 0;

                        // Build our pixel colour as a DWORD
                        for (int loop = 0, shift = 0; loop < pixelSize; loop++, shift += 8)
                        {
                            color |= (uint)pixelData[src + loop] << shift;
                        }

                        switch (fileFormat)
                        {
                            case DDS.FileFormat.A8R8G8B8:
                            {
                                A = (byte)((color >> 24) & 0xFF);
                                R = (byte)((color >> 16) & 0xFF);
                                G = (byte)((color >> 8) & 0xFF);
                                B = (byte)((color >> 0) & 0xFF);
                                break;
                            }

                            case DDS.FileFormat.X8R8G8B8:
                            {
                                A = 0xFF;
                                R = (byte)((color >> 16) & 0xFF);
                                G = (byte)((color >> 8) & 0xFF);
                                B = (byte)((color >> 0) & 0xFF);
                                break;
                            }

                            case DDS.FileFormat.A8B8G8R8:
                            {
                                A = (byte)((color >> 24) & 0xFF);
                                R = (byte)((color >> 0) & 0xFF);
                                G = (byte)((color >> 8) & 0xFF);
                                B = (byte)((color >> 16) & 0xFF);
                                break;
                            }

                            case DDS.FileFormat.X8B8G8R8:
                            {
                                A = 0xFF;
                                R = (byte)((color >> 0) & 0xFF);
                                G = (byte)((color >> 8) & 0xFF);
                                B = (byte)((color >> 16) & 0xFF);
                                break;
                            }

                            case DDS.FileFormat.A1R5G5B5:
                            {
                                A = (byte)((color >> 15) * 0xFF);
                                R = (byte)((color >> 10) & 0x1F);
                                G = (byte)((color >> 5) & 0x1F);
                                B = (byte)((color >> 0) & 0x1F);

                                R = (byte)((R << 3) | (R >> 2));
                                G = (byte)((G << 3) | (G >> 2));
                                B = (byte)((B << 3) | (B >> 2));
                                break;
                            }

                            case DDS.FileFormat.A4R4G4B4:
                            {
                                A = (byte)((color >> 12) & 0xFF);
                                R = (byte)((color >> 8) & 0x0F);
                                G = (byte)((color >> 4) & 0x0F);
                                B = (byte)((color >> 0) & 0x0F);

                                A = (byte)((A << 4) | (A >> 0));
                                R = (byte)((R << 4) | (R >> 0));
                                G = (byte)((G << 4) | (G >> 0));
                                B = (byte)((B << 4) | (B >> 0));
                                break;
                            }

                            case DDS.FileFormat.R8G8B8:
                            {
                                A = 0xFF;
                                R = (byte)((color >> 16) & 0xFF);
                                G = (byte)((color >> 8) & 0xFF);
                                B = (byte)((color >> 0) & 0xFF);
                                break;
                            }

                            case DDS.FileFormat.R5G6B5:
                            {
                                A = 0xFF;
                                R = (byte)((color >> 11) & 0x1F);
                                G = (byte)((color >> 5) & 0x3F);
                                B = (byte)((color >> 0) & 0x1F);

                                R = (byte)((R << 3) | (R >> 2));
                                G = (byte)((G << 2) | (G >> 4));
                                B = (byte)((B << 3) | (B >> 2));
                                break;
                            }

                            default:
                            {
                                throw new NotSupportedException();
                            }
                        }

                        this._PixelData[dst + 0] = R;
                        this._PixelData[dst + 1] = G;
                        this._PixelData[dst + 2] = B;
                        this._PixelData[dst + 3] = A;
                    }
                }
            }
        }