Example #1
0
        public Dune2ShpReader(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            ImageCount = reader.ReadUInt16();

            //Last offset is pointer to end of file.
            uint[] offsets = new uint[ImageCount + 1];

            uint temp = reader.ReadUInt32();

            //If fourth byte in file is non-zero, the offsets are two bytes each.
            bool twoByteOffsets = (temp & 0xFF0000) > 0;

            if (twoByteOffsets)
            {
                offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2;                 //Offset does not account for image count bytes
                offsets[1] = (temp & 0xFFFF) + 2;
            }
            else
            {
                offsets[0] = temp + 2;
            }

            for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++)
            {
                offsets[i] = (twoByteOffsets ? reader.ReadUInt16() : reader.ReadUInt32()) + 2;
            }

            for (int i = 0; i < ImageCount; i++)
            {
                reader.BaseStream.Seek(offsets[i], SeekOrigin.Begin);
                Dune2ImageHeader header  = new Dune2ImageHeader(reader);
                byte[]           imgData = reader.ReadBytes(header.FileSize);
                header.Image = new byte[header.Height * header.Width];

                //Decode image data
                if (header.Flags != Dune2ImageFlags.F2)
                {
                    byte[] tempData = new byte[header.DataSize];
                    Format80.DecodeInto(imgData, tempData);
                    Format2.DecodeInto(tempData, header.Image);
                }
                else
                {
                    Format2.DecodeInto(imgData, header.Image);
                }

                //Lookup values in lookup table
                if (header.LookupTable != null)
                {
                    for (int j = 0; j < header.Image.Length; j++)
                    {
                        header.Image[j] = header.LookupTable[header.Image[j]];
                    }
                }

                headers.Add(header);
            }
        }
Example #2
0
        public Frame(Stream s)
        {
            var flags = (FormatFlags)s.ReadUInt16();

            s.Position += 1;
            var width  = s.ReadUInt16();
            var height = s.ReadUInt8();

            Size = new Size(width, height);

            // Subtract header size
            var dataLeft = s.ReadUInt16() - 10;
            var dataSize = s.ReadUInt16();

            byte[] table;
            if ((flags & FormatFlags.PaletteTable) != 0)
            {
                var n = (flags & FormatFlags.VariableLengthTable) != 0 ? s.ReadUInt8() : (byte)16;
                table = new byte[n];
                for (var i = 0; i < n; i++)
                {
                    table[i] = s.ReadUInt8();
                }

                dataLeft -= n;
            }
            else
            {
                table = new byte[256];
                for (var i = 0; i < 256; i++)
                {
                    table[i] = (byte)i;
                }
                table[1] = 0x7f;
                table[2] = 0x7e;
                table[3] = 0x7d;
                table[4] = 0x7c;
            }

            Data = new byte[width * height];

            // Decode image data
            var compressed = s.ReadBytes(dataLeft);

            if ((flags & FormatFlags.SkipFormat80) == 0)
            {
                var temp = new byte[dataSize];
                Format80.DecodeInto(compressed, temp);
                compressed = temp;
            }

            Format2.DecodeInto(compressed, Data, 0);

            // Lookup values in lookup table
            for (var j = 0; j < Data.Length; j++)
            {
                Data[j] = table[Data[j]];
            }
        }
Example #3
0
        void Decompress(Stream stream, ImageHeader h)
        {
            // No extra work is required for empty frames
            if (h.Size.Width == 0 || h.Size.Height == 0)
            {
                return;
            }

            if (recurseDepth > imageCount)
            {
                throw new InvalidDataException("Format20/40 headers contain infinite loop");
            }

            switch (h.Format)
            {
            case Format.Format20:
            case Format.Format40:
            {
                if (h.RefImage.Data == null)
                {
                    ++recurseDepth;
                    Decompress(stream, h.RefImage);
                    --recurseDepth;
                }

                h.Data = CopyImageData(h.RefImage.Data);
                Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
                break;
            }

            case Format.Format80:
            {
                var imageBytes = new byte[Size.Width * Size.Height];
                Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
                h.Data = imageBytes;
                break;
            }

            default:
                throw new InvalidDataException();
            }
        }
Example #4
0
        public static void Write(Stream s, Size size, IEnumerable <byte[]> frames)
        {
            var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();

            // note: end-of-file and all-zeroes headers
            var dataOffset = 14 + (compressedFrames.Length + 2) * 8;

            using (var bw = new BinaryWriter(s))
            {
                bw.Write((ushort)compressedFrames.Length);
                bw.Write((ushort)0);
                bw.Write((ushort)0);
                bw.Write((ushort)size.Width);
                bw.Write((ushort)size.Height);
                bw.Write((uint)0);

                foreach (var f in compressedFrames)
                {
                    var ih = new ImageHeader {
                        Format = Format.Format80, FileOffset = (uint)dataOffset
                    };
                    dataOffset += f.Length;

                    ih.WriteTo(bw);
                }

                var eof = new ImageHeader {
                    FileOffset = (uint)dataOffset
                };
                eof.WriteTo(bw);

                var allZeroes = new ImageHeader {
                };
                allZeroes.WriteTo(bw);

                foreach (var f in compressedFrames)
                {
                    bw.Write(f);
                }
            }
        }
Example #5
0
        void Decompress(Stream stream, ImageHeader h)
        {
            if (recurseDepth > ImageCount)
            {
                throw new InvalidDataException("Format20/40 headers contain infinite loop");
            }

            switch (h.Format)
            {
            case Format.Format20:
            case Format.Format40:
            {
                if (h.RefImage.Image == null)
                {
                    ++recurseDepth;
                    Decompress(stream, h.RefImage);
                    --recurseDepth;
                }

                h.Image = CopyImageData(h.RefImage.Image);
                Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
                break;
            }

            case Format.Format80:
            {
                var imageBytes = new byte[Width * Height];
                Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
                h.Image = imageBytes;
                break;
            }

            default:
                throw new InvalidDataException();
            }
        }
Example #6
0
        // VQA Frame
        public void DecodeVQFR(Stream s)
        {
            while (true)
            {
                // Chunks are aligned on even bytes; may be padded with a single null
                if (s.Peek() == 0)
                {
                    s.ReadByte();
                }
                var type           = s.ReadASCII(4);
                int subchunkLength = (int)int2.Swap(s.ReadUInt32());

                switch (type)
                {
                // Full frame-modifier
                case "CBFZ":
                    Format80.DecodeInto(s.ReadBytes(subchunkLength), cbf);
                    break;

                case "CBF0":
                    cbf = s.ReadBytes(subchunkLength);
                    break;

                // frame-modifier chunk
                case "CBP0":
                case "CBPZ":
                    // Partial buffer is full; dump and recreate
                    if (cbChunk == cbParts)
                    {
                        if (type == "CBP0")
                        {
                            cbf = (byte[])cbp.Clone();
                        }
                        else
                        {
                            Format80.DecodeInto(cbp, cbf);
                        }

                        cbOffset = cbChunk = 0;
                    }

                    var bytes = s.ReadBytes(subchunkLength);
                    bytes.CopyTo(cbp, cbOffset);
                    cbOffset += subchunkLength;
                    cbChunk++;
                    break;

                // Palette
                case "CPL0":
                    for (int i = 0; i < numColors; i++)
                    {
                        byte r = (byte)(s.ReadUInt8() << 2);
                        byte g = (byte)(s.ReadUInt8() << 2);
                        byte b = (byte)(s.ReadUInt8() << 2);
                        palette[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
                    }
                    break;

                // Frame data
                case "VPTZ":
                    Format80.DecodeInto(s.ReadBytes(subchunkLength), origData);
                    // This is the last subchunk
                    return;

                default:
                    throw new InvalidDataException("Unknown sub-chunk {0}".F(type));
                }
            }
        }
Example #7
0
        // VQA Frame
        public void DecodeVQFR(Stream s, string parentType = "VQFR")
        {
            while (true)
            {
                // Chunks are aligned on even bytes; may be padded with a single null
                if (s.Peek() == 0)
                {
                    s.ReadByte();
                }
                var type           = s.ReadASCII(4);
                var subchunkLength = (int)int2.Swap(s.ReadUInt32());

                switch (type)
                {
                // Full frame-modifier
                case "CBFZ":
                    var decodeMode = s.Peek() == 0;
                    s.ReadBytes(fileBuffer, 0, subchunkLength);
                    Array.Clear(cbf, 0, cbf.Length);
                    Array.Clear(cbfBuffer, 0, cbfBuffer.Length);
                    var decodeCount = 0;
                    decodeCount = Format80.DecodeInto(fileBuffer, cbfBuffer, decodeMode ? 1 : 0, decodeMode);
                    if ((videoFlags & 0x10) == 16)
                    {
                        var p = 0;
                        for (var i = 0; i < decodeCount; i += 2)
                        {
                            var packed = cbfBuffer[i + 1] << 8 | cbfBuffer[i];

                            /* 15      bit      0
                             * 0rrrrrgg gggbbbbb
                             * HI byte  LO byte*/
                            cbf[p++] = (byte)((packed & 0x7C00) >> 7);
                            cbf[p++] = (byte)((packed & 0x3E0) >> 2);
                            cbf[p++] = (byte)((packed & 0x1f) << 3);
                        }
                    }
                    else
                    {
                        cbf = cbfBuffer;
                    }

                    if (parentType == "VQFL")
                    {
                        return;
                    }
                    break;

                case "CBF0":
                    cbf = s.ReadBytes(subchunkLength);
                    break;

                // frame-modifier chunk
                case "CBP0":
                case "CBPZ":
                    // Partial buffer is full; dump and recreate
                    if (currentChunkBuffer == chunkBufferParts)
                    {
                        if (type == "CBP0")
                        {
                            cbf = (byte[])cbp.Clone();
                        }
                        else
                        {
                            Format80.DecodeInto(cbp, cbf);
                        }

                        chunkBufferOffset = currentChunkBuffer = 0;
                    }

                    var bytes = s.ReadBytes(subchunkLength);
                    bytes.CopyTo(cbp, chunkBufferOffset);
                    chunkBufferOffset += subchunkLength;
                    currentChunkBuffer++;
                    break;

                // Palette
                case "CPL0":
                    for (var i = 0; i < numColors; i++)
                    {
                        var r = (byte)(s.ReadUInt8() << 2);
                        var g = (byte)(s.ReadUInt8() << 2);
                        var b = (byte)(s.ReadUInt8() << 2);
                        palette[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
                    }

                    break;

                // Frame data
                case "VPTZ":
                    Format80.DecodeInto(s.ReadBytes(subchunkLength), origData);

                    // This is the last subchunk
                    return;

                case "VPRZ":
                    Array.Clear(origData, 0, origData.Length);
                    s.ReadBytes(fileBuffer, 0, subchunkLength);
                    if (fileBuffer[0] != 0)
                    {
                        vtprSize = Format80.DecodeInto(fileBuffer, origData);
                    }
                    else
                    {
                        Format80.DecodeInto(fileBuffer, origData, 1, true);
                    }
                    return;

                case "VPTR":
                    Array.Clear(origData, 0, origData.Length);
                    s.ReadBytes(origData, 0, subchunkLength);
                    vtprSize = subchunkLength;
                    return;

                default:
                    throw new InvalidDataException("Unknown sub-chunk {0}".F(type));
                }
            }
        }