Exemple #1
0
		public WavLoader(Stream s)
		{
			while (s.Position < s.Length)
			{
				if ((s.Position & 1) == 1)
					s.ReadByte(); // Alignment

				var type = s.ReadASCII(4);
				switch (type)
				{
					case "RIFF":
						FileSize = s.ReadInt32();
						Format = s.ReadASCII(4);
						if (Format != "WAVE")
							throw new NotSupportedException("Not a canonical WAVE file.");
						break;
					case "fmt ":
						FmtChunkSize = s.ReadInt32();
						AudioFormat = s.ReadInt16();
						Type = (WaveType)AudioFormat;
						if (Type != WaveType.Pcm && Type != WaveType.ImaAdpcm)
							throw new NotSupportedException("Compression type is not supported.");
						Channels = s.ReadInt16();
						SampleRate = s.ReadInt32();
						ByteRate = s.ReadInt32();
						BlockAlign = s.ReadInt16();
						BitsPerSample = s.ReadInt16();

						s.ReadBytes(FmtChunkSize - 16);
						break;
					case "fact":
						{
							var chunkSize = s.ReadInt32();
							UncompressedSize = s.ReadInt32();
							s.ReadBytes(chunkSize - 4);
						}

						break;
					case "data":
						DataSize = s.ReadInt32();
						RawOutput = s.ReadBytes(DataSize);
						break;
					default:
						// Ignore unknown chunks
						{
							var chunkSize = s.ReadInt32();
							s.ReadBytes(chunkSize);
						}

						break;
				}
			}

			if (Type == WaveType.ImaAdpcm)
			{
				RawOutput = DecodeImaAdpcmData();
				BitsPerSample = 16;
			}
		}
Exemple #2
0
        public BigFile(FileSystem context, string filename)
        {
            Name = filename;

            s = context.Open(filename);
            try
            {
                if (s.ReadASCII(4) != "BIGF")
                    throw new InvalidDataException("Header is not BIGF");

                // Total archive size.
                s.ReadUInt32();

                var entryCount = s.ReadUInt32();
                if (BitConverter.IsLittleEndian)
                    entryCount = int2.Swap(entryCount);

                // First entry offset? This is apparently bogus for EA's .big files
                // and we don't have to try seeking there since the entries typically start next in EA's .big files.
                s.ReadUInt32();

                for (var i = 0; i < entryCount; i++)
                {
                    var entry = new Entry(s);
                    index.Add(entry.Path, entry);
                }
            }
            catch
            {
                Dispose();
                throw;
            }
        }
Exemple #3
0
        public MSCabCompression(Stream stream)
        {
            this.stream = stream;

            var signature = stream.ReadASCII(4);
            if (signature != "MSCF")
                throw new InvalidDataException("Not a Microsoft CAB package!");

            stream.Position += 12;
            var filesOffset = stream.ReadUInt32();
            stream.Position += 6;
            var folderCount = stream.ReadUInt16();
            var fileCount = stream.ReadUInt16();
            if (stream.ReadUInt16() != 0)
                throw new InvalidDataException("Only plain packages (without reserved header space or prev/next archives) are supported!");

            stream.Position += 4;

            folders = new CabFolder[folderCount];
            for (var i = 0; i < folderCount; i++)
            {
                folders[i] = new CabFolder(stream);
                if (folders[i].CompressionType != 1)
                    throw new InvalidDataException("Compression type is not supported");
            }

            files = new CabFile[fileCount];
            stream.Seek(filesOffset, SeekOrigin.Begin);
            for (var i = 0; i < fileCount; i++)
                files[i] = new CabFile(stream);
        }
Exemple #4
0
        public VxlReader(Stream s)
        {
            if (!s.ReadASCII(16).StartsWith("Voxel Animation"))
                throw new InvalidDataException("Invalid vxl header");

            s.ReadUInt32();
            LimbCount = s.ReadUInt32();
            s.ReadUInt32();
            BodySize = s.ReadUInt32();
            s.Seek(770, SeekOrigin.Current);

            // Read Limb headers
            Limbs = new VxlLimb[LimbCount];
            for (var i = 0; i < LimbCount; i++)
            {
                Limbs[i] = new VxlLimb();
                Limbs[i].Name = s.ReadASCII(16);
                s.Seek(12, SeekOrigin.Current);
            }

            // Skip to the Limb footers
            s.Seek(802 + 28*LimbCount + BodySize, SeekOrigin.Begin);

            var LimbDataOffset = new uint[LimbCount];
            for (var i = 0; i < LimbCount; i++)
            {
                LimbDataOffset[i] = s.ReadUInt32();
                s.Seek(8, SeekOrigin.Current);
                Limbs[i].Scale = s.ReadFloat();
                s.Seek(48, SeekOrigin.Current);

                Limbs[i].Bounds = new float[6];
                for (var j = 0; j < 6; j++)
                    Limbs[i].Bounds[j] = s.ReadFloat();
                Limbs[i].Size = s.ReadBytes(3);
                Limbs[i].Type = (NormalType)s.ReadByte();
            }

            for (var i = 0; i < LimbCount; i++)
            {
                s.Seek(802 + 28*LimbCount + LimbDataOffset[i], SeekOrigin.Begin);
                ReadVoxelData(s, Limbs[i]);
            }
        }
Exemple #5
0
        public WavLoader(Stream s)
        {
            while (s.Position < s.Length)
            {
                if ((s.Position & 1) == 1)
                    s.ReadByte(); // Alignment

                var type = s.ReadASCII(4);
                switch (type)
                {
                    case "RIFF":
                        FileSize = s.ReadInt32();
                        Format = s.ReadASCII(4);
                        if (Format != "WAVE")
                            throw new NotSupportedException("Not a canonical WAVE file.");
                        break;
                    case "fmt ":
                        FmtChunkSize = s.ReadInt32();
                        if (FmtChunkSize != 16)
                            throw new NotSupportedException("{0} fmt chunk size is not a supported encoding scheme.".F(FmtChunkSize));
                        AudioFormat = s.ReadInt16();
                        if (AudioFormat != 1)
                            throw new NotSupportedException("Non-PCM compression is not supported.");
                        Channels = s.ReadInt16();
                        SampleRate = s.ReadInt32();
                        ByteRate = s.ReadInt32();
                        BlockAlign = s.ReadInt16();
                        BitsPerSample = s.ReadInt16();
                        break;
                    case "data":
                        DataSize = s.ReadInt32();
                        RawOutput = s.ReadBytes(DataSize);
                        break;
                    default:
                        // Ignore unknown chunks
                        var chunkSize = s.ReadInt32();
                        s.ReadBytes(chunkSize);
                        break;
                }
            }
        }
        public InstallShieldPackage(FileSystem context, string filename)
        {
            Name = filename;

            s = context.Open(filename);
            try
            {
                // Parse package header
                var signature = s.ReadUInt32();
                if (signature != 0x8C655D13)
                    throw new InvalidDataException("Not an Installshield package");

                s.Position += 8;
                /*var FileCount = */s.ReadUInt16();
                s.Position += 4;
                /*var ArchiveSize = */s.ReadUInt32();
                s.Position += 19;
                var tocAddress = s.ReadInt32();
                s.Position += 4;
                var dirCount = s.ReadUInt16();

                // Parse the directory list
                s.Position = tocAddress;

                // Parse directories
                var directories = new Dictionary<string, uint>();
                for (var i = 0; i < dirCount; i++)
                {
                    // Parse directory header
                    var fileCount = s.ReadUInt16();
                    var chunkSize = s.ReadUInt16();
                    var nameLength = s.ReadUInt16();
                    var dirName = s.ReadASCII(nameLength);

                    // Skip to the end of the chunk
                    s.ReadBytes(chunkSize - nameLength - 6);
                    directories.Add(dirName, fileCount);
                }

                // Parse files
                foreach (var dir in directories)
                    for (var i = 0; i < dir.Value; i++)
                        ParseFile(s, dir.Key);
            }
            catch
            {
                Dispose();
                throw;
            }
        }
Exemple #7
0
        public static float WaveLength(Stream s)
        {
            s.Position = 12;
            var fmt = s.ReadASCII(4);

            if (fmt != "fmt ")
                return 0;

            s.Position = 22;
            var channels = s.ReadInt16();
            var sampleRate = s.ReadInt32();

            s.Position = 34;
            var bitsPerSample = s.ReadInt16();
            var length = s.Length * 8;

            return length / (channels * sampleRate * bitsPerSample);
        }
            void ParseFile(string dirName)
            {
                s.Position += 7;
                var compressedSize = s.ReadUInt32();

                s.Position += 12;
                var chunkSize = s.ReadUInt16();

                s.Position += 4;
                var nameLength = s.ReadByte();
                var fileName   = dirName + "\\" + s.ReadASCII(nameLength);

                // Use index syntax to overwrite any duplicate entries with the last value
                index[fileName]  = new Entry(accumulatedData, compressedSize);
                accumulatedData += compressedSize;

                // Skip to the end of the chunk
                s.Position += chunkSize - nameLength - 30;
            }
        public MSCabCompression(Stream stream)
        {
            this.stream = stream;

            var signature = stream.ReadASCII(4);

            if (signature != "MSCF")
            {
                throw new InvalidDataException("Not a Microsoft CAB package!");
            }

            stream.Position += 12;
            var filesOffset = stream.ReadUInt32();

            stream.Position += 6;
            var folderCount = stream.ReadUInt16();
            var fileCount   = stream.ReadUInt16();

            if (stream.ReadUInt16() != 0)
            {
                throw new InvalidDataException("Only plain packages (without reserved header space or prev/next archives) are supported!");
            }

            stream.Position += 4;

            folders = new CabFolder[folderCount];
            for (var i = 0; i < folderCount; i++)
            {
                folders[i] = new CabFolder(stream);
                if (folders[i].CompressionType != 1)
                {
                    throw new InvalidDataException("Compression type is not supported");
                }
            }

            files = new CabFile[fileCount];
            stream.Seek(filesOffset, SeekOrigin.Begin);
            for (var i = 0; i < fileCount; i++)
            {
                files[i] = new CabFile(stream);
            }
        }
Exemple #10
0
        bool ISoundLoader.TryParseSound(Stream stream, out ISoundFormat?soundFormat)
        {
            if (stream.Position + 72 <= stream.Length)
            {
                stream.Position += 52;
                var filename = stream.ReadASCII(20);
                stream.Position -= 72;

                if (filename.Contains(".smp"))
                {
                    soundFormat = new Soun(stream);

                    return(true);
                }
            }

            soundFormat = null;

            return(false);
        }
Exemple #11
0
        public static float WaveLength(Stream s)
        {
            s.Position = 12;
            var fmt = s.ReadASCII(4);

            if (fmt != "fmt ")
            {
                return(0);
            }

            s.Position = 22;
            var channels   = s.ReadInt16();
            var sampleRate = s.ReadInt32();

            s.Position = 34;
            var bitsPerSample = s.ReadInt16();
            var length        = s.Length * 8;

            return(length / (channels * sampleRate * bitsPerSample));
        }
Exemple #12
0
            public SdfPackage(Stream sBase, string filename)
            {
                s    = sBase;
                Name = filename;

                var numFiles = sBase.ReadUInt32();

                for (var i = 0; i < numFiles; i++)
                {
                    var fileName = sBase.ReadASCII(64).Replace("\0", string.Empty);
                    sBase.Position += 28;

                    while (index.ContainsKey(fileName + ".SDF"))
                    {
                        fileName += "_Z";
                    }

                    index.Add(fileName + ".SDF", sBase.Position - 28);
                }
            }
Exemple #13
0
        public IdxEntry(Stream s)
        {
            var asciiname = s.ReadASCII(16);

            var pos = asciiname.IndexOf('\0');

            if (pos != 0)
            {
                asciiname = asciiname.Substring(0, pos);
            }

            Name       = asciiname;
            Extension  = DefaultExtension;
            Offset     = s.ReadUInt32();
            Length     = s.ReadUInt32();
            SampleRate = s.ReadUInt32();
            Flags      = s.ReadUInt32();
            ChunkSize  = s.ReadUInt32();
            Hash       = HashFilename(string.Concat(Name, ".", Extension), PackageHashType.CRC32);
        }
Exemple #14
0
        public bool TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package)
        {
            if (filename.EndsWith(".lpk") ||          // Spritesheet container
                filename.EndsWith(".bpk") ||             // Image container
                filename.EndsWith(".spk") ||             // Sound set
                filename.EndsWith(".lps") ||             // Singleplayer map
                filename.EndsWith(".lpm") ||             // Multiplayer map
                filename.EndsWith(".mpk"))                // Matrix set (destroyable map part, tile replacements)
            {
                s = Crypter.Decrypt(s);
            }

            var signature = s.ReadASCII(4);

            var version = Version.UNKNOWN;

            if (signature.Equals("DATA"))
            {
                version = Version.KKND1;
            }

            if (signature.Equals("DAT2"))
            {
                version = Version.KKND2;
            }

            if (version == Version.UNKNOWN)
            {
                s.Position -= 4;
                package     = null;
                return(false);
            }

            var tmp        = s.ReadBytes(4);      // Big-Endian
            var dataLength = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];

            package = new LvlPackage(new SegmentStream(s, 8, dataLength), filename, context);

            return(true);
        }
        private bool IsDrSpr(Stream s)
        {
            var start = s.Position;
            var h     = new SprHeader()
            {
                Magic1  = s.ReadASCII(4),
                Version = s.ReadInt32(),
                Nanims  = s.ReadInt32(),
                Nrots   = s.ReadInt32(),
                Szx     = s.ReadInt32(),
                Szy     = s.ReadInt32(),
                Npics   = s.ReadInt32(),
                Nsects  = s.ReadInt32()
            };

            if (h.Magic1 != "RSPR" && h.Magic1 != "SSPR")
            {
                s.Position = start;
                return(false);
            }

            if (h.Magic1 == "SSPR")
            {
                h.IsShadow = true;
            }

            if (h.Version != 0x0210)
            {
                s.Position = start;
                return(false);
            }

            h.OffSections = HeaderSize + 4 * h.Nanims * h.Nrots;
            h.OffAnims    = h.OffSections + 16 * h.Nsects;
            h.OffPicoffs  = h.OffAnims + 4 * h.Nanims;
            h.OffBits     = h.OffPicoffs + 8 * h.Npics + 4;
            header        = h;

            return(true);
        }
        private static bool IsDrTil(Stream s)
        {
            var start = s.Position;
            var h     = new TilHeader()
            {
                Magic1  = s.ReadASCII(4),
                Version = s.ReadInt32()
            };

            if (h.Magic1 != "TILE")
            {
                s.Position = start;
                return(false);
            }

            if (h.Version == 0x0240)
            {
                return(true);
            }
            s.Position = start;
            return(false);
        }
Exemple #17
0
        public VbcFrame(Stream stream)
        {
            // TODO this crashes on gen1 briefings! This is because in addition to audio and video, they context a text chunk!
            stream.ReadUInt32();             // Length
            var flags = stream.ReadUInt16();

            if ((flags & 0x0001) != 0)
            {
                this.globalMotion = new(stream.ReadInt16(), stream.ReadInt16());
            }

            if ((flags & 0x0004) != 0)
            {
                this.Audio = stream.ReadBytes(stream.ReadInt32() - 4);
            }

            if ((flags & 0x0008) != 0)
            {
                var length = stream.ReadUInt32() - 4;
                this.video       = new(stream, stream.Position, length);
                stream.Position += length;
            }

            if ((flags & 0x0010) != 0)
            {
                var length = stream.ReadUInt32() - 4;
                this.colors      = new(stream, stream.Position, length);
                stream.Position += length;
            }

            if ((flags & 0x0020) != 0)
            {
                stream.ReadUInt16();                 // Duration
            }
            if ((flags & 0x0040) != 0)
            {
                this.Text = stream.ReadASCII(stream.ReadInt32() - 4);
            }
        }
Exemple #18
0
            public FtgFile(Stream stream, string filename)
            {
                Name        = filename;
                this.stream = stream;

                try
                {
                    stream.ReadBytes(4);
                    var directoryOffset = BitConverter.ToInt32(stream.ReadBytes(4), 0);
                    var fileCount       = BitConverter.ToInt32(stream.ReadBytes(4), 0);

                    stream.Seek(directoryOffset, SeekOrigin.Begin);
                    for (int i = 0; i < fileCount; i++)
                    {
                        var entryFilename = stream.ReadASCII(28);
                        entryFilename = entryFilename.Replace("\0", string.Empty);

                        var offset = BitConverter.ToInt32(stream.ReadBytes(4), 0);
                        var size   = BitConverter.ToInt32(stream.ReadBytes(4), 0);

                        // Ignore duplicate files
                        if (index.ContainsKey(entryFilename))
                        {
                            continue;
                        }

                        var info = new FtgEntry()
                        {
                            Filename = entryFilename, Offset = offset, Size = size
                        };
                        index.Add(entryFilename, info);
                    }
                }
                catch
                {
                    Dispose();
                    throw;
                }
            }
Exemple #19
0
        public BigFile(FileSystem context, string filename, int priority)
        {
            Name     = filename;
            Priority = priority;

            s = context.Open(filename);
            try
            {
                if (s.ReadASCII(4) != "BIGF")
                {
                    throw new InvalidDataException("Header is not BIGF");
                }

                // Total archive size.
                s.ReadUInt32();

                var entryCount = s.ReadUInt32();
                if (BitConverter.IsLittleEndian)
                {
                    entryCount = int2.Swap(entryCount);
                }

                // First entry offset? This is apparently bogus for EA's .big files
                // and we don't have to try seeking there since the entries typically start next in EA's .big files.
                s.ReadUInt32();

                for (var i = 0; i < entryCount; i++)
                {
                    var entry = new Entry(s);
                    entries.Add(entry.Path, entry);
                }
            }
            catch
            {
                Dispose();
                throw;
            }
        }
Exemple #20
0
        private static BitmapSpriteFrame[] ParseFrames(Stream s)
        {
            var       start     = s.Position;
            var       frames    = new List <BitmapSpriteFrame>();
            const int tileWidth = 32;
            var       dataSize  = new Size(tileWidth * 8, tileWidth * 8);
            var       size      = new Size(tileWidth, tileWidth);
            var       frameSize = new Size(0, 0);

            s.Seek(12, SeekOrigin.Begin);
            var something = s.ReadDouble();
            var width     = s.ReadUInt32();
            var height    = s.ReadUInt32();
            var numTiles  = height / width;

            s.Seek(1088, SeekOrigin.Begin);
            var header = s.ReadASCII(4);

            var blockSize = s.ReadUInt32();

            for (var i = 0; i < numTiles; i++)
            {
                var bytes = s.ReadBytes(tileWidth * tileWidth);
                var tile  = new BitmapSpriteFrame
                {
                    Size      = size,
                    FrameSize = size,
                    Data      = bytes,
                    Type      = SpriteFrameType.Indexed,
                };

                frames.Add(tile);
            }

            s.Position = start;

            return(frames.ToArray());
        }
Exemple #21
0
        public Blit(Stream stream)
        {
            this.Frames = new BlitFrame[stream.ReadInt32()];
            var frameOffsets = new int[this.Frames.Length];

            stream.ReadInt32();             // TODO Unk
            var paletteOffset = stream.ReadInt32();
            var identifier    = new string(stream.ReadASCII(4).Reverse().ToArray());

            if (identifier != "BLT8")
            {
                throw new("Unknown blit type.");
            }

            for (var i = 0; i < this.Frames.Length; i++)
            {
                frameOffsets[i] = stream.ReadInt32();
            }

            stream.Position = paletteOffset;

            var palette = new byte[256 * 4];

            for (var i = 0; i < palette.Length;)
            {
                var color16 = stream.ReadUInt16();
                palette[i++] = (byte)(((color16 & 0x001f) << 3) & 0xff);
                palette[i++] = (byte)(((color16 & 0x03e0) >> 2) & 0xff);
                palette[i++] = (byte)(((color16 & 0x7c00) >> 7) & 0xff);
                palette[i++] = 0xff;
            }

            for (var i = 0; i < this.Frames.Length; i++)
            {
                stream.Position = frameOffsets[i];
                this.Frames[i]  = new(stream, palette);
            }
        }
Exemple #22
0
        bool IsIcnD2(Stream s)
        {
            if (s.Length < 0x20)
            {
                return(false);
            }

            var start = s.Position;

            s.Position = 0x18;
            if (s.ReadASCII(4) != "SSET")
            {
                s.Position = start;
                return(false);
            }

            ssetLength  = int2.Swap(s.ReadUInt32()) - 8;
            s.Position += 3;
            ssetOffset  = 0x18 + 16;
            if (s.Length < ssetOffset + ssetLength)
            {
                s.Position = start;
                return(false);
            }

            s.Position = ssetOffset + ssetLength;
            if (s.ReadASCII(4) != "RPAL")
            {
                s.Position = start;
                return(false);
            }

            rpalLength = int2.Swap(s.ReadUInt32());
            rpalOffset = ssetOffset + ssetLength + 8;
            if (s.Length < rpalOffset + rpalLength)
            {
                s.Position = start;
                return(false);
            }

            s.Position = rpalOffset + rpalLength;
            if (s.ReadASCII(4) != "RTBL")
            {
                s.Position = start;
                return(false);
            }

            rtblLength = int2.Swap(s.ReadUInt32());
            rtblOffset = rpalOffset + rpalLength + 8;

            if (s.Length < rtblOffset + rtblLength)
            {
                s.Position = start;
                return(false);
            }

            numTiles = ssetLength / TileSize;

            if (rtblLength < numTiles)
            {
                s.Position = start;
                return(false);
            }

            s.Position = start;
            return(true);
        }
Exemple #23
0
        public bool LoadSound(Stream s)
        {
            var type = s.ReadASCII(4);
            if (type != "RIFF")
                return false;

            FileSize = s.ReadInt32();
            Format = s.ReadASCII(4);
            if (Format != "WAVE")
                return false;
            while (s.Position < s.Length)
            {
                if ((s.Position & 1) == 1)
                    s.ReadByte(); // Alignment

                type = s.ReadASCII(4);
                switch (type)
                {
                    case "fmt ":
                        FmtChunkSize = s.ReadInt32();
                        AudioFormat = s.ReadInt16();
                        Type = (WaveType)AudioFormat;

                        if (!Enum.IsDefined(typeof(WaveType), Type))
                            throw new NotSupportedException("Compression type {0} is not supported.".F(AudioFormat));

                        Channels = s.ReadInt16();
                        SampleRate = s.ReadInt32();
                        ByteRate = s.ReadInt32();
                        BlockAlign = s.ReadInt16();
                        BitsPerSample = s.ReadInt16();

                        s.ReadBytes(FmtChunkSize - 16);
                        break;
                    case "fact":
                        var chunkSize = s.ReadInt32();
                        UncompressedSize = s.ReadInt32();
                        s.ReadBytes(chunkSize - 4);
                        break;
                    case "data":
                        DataSize = s.ReadInt32();
                        RawOutput = s.ReadBytes(DataSize);
                        break;
                    default:
                        var unknownChunkSize = s.ReadInt32();
                        s.ReadBytes(unknownChunkSize);
                        break;
                }
            }

            if (Type == WaveType.ImaAdpcm)
            {
                RawOutput = DecodeImaAdpcmData();
                BitsPerSample = 16;
            }

            return true;
        }
Exemple #24
0
        private static bool IsBmp(Stream s)
        {
            var header = s.ReadASCII(4);

            return(header == "BM88" || header == "PBMP");
        }
Exemple #25
0
            public LvlPackage(Stream s, string filename, IReadOnlyFileSystem context)
            {
                stream = s;
                Name   = filename;

                var lvlLookup  = new Dictionary <string, string>();
                var lookupPath = $"archives/{Path.GetFileName(filename)}.yaml";

                Stream s2;

                if (context.TryOpen(lookupPath, out s2))
                {
                    lvlLookup = MiniYaml.FromStream(s2).ToDictionary(x => x.Key, x => x.Value.Value);
                }

                var fileTypeListOffset = s.ReadInt32();

                s.Position = fileTypeListOffset;

                int firstFileListOffset = 0;

                for (var i = 0; s.Position < s.Length; i++)
                {
                    s.Position = fileTypeListOffset + i * 8;

                    var fileType       = s.ReadASCII(4);
                    var fileListOffset = s.ReadInt32();

                    // List terminator reached.
                    if (fileListOffset == 0)
                    {
                        break;
                    }

                    // We need this to calculate the last fileLength.
                    if (firstFileListOffset == 0)
                    {
                        firstFileListOffset = fileListOffset;
                    }

                    // To determine when this list ends, check the next entry
                    s.Position += 4;
                    var fileListEndOffset = s.ReadInt32();

                    // List terminator reached, so assume the list goes on till the fileTypeList starts.
                    if (fileListEndOffset == 0)
                    {
                        fileListEndOffset = fileTypeListOffset;
                    }

                    s.Position = fileListOffset;

                    for (var j = 0; s.Position < fileListEndOffset; j++)
                    {
                        var fileOffset = s.ReadInt32();

                        // Removed file, still increments fileId.
                        if (fileOffset == 0)
                        {
                            continue;
                        }

                        // As the fileLength is nowhere stored, but files always follow in order, calculate the previous fileLength.
                        if (index.Count > 0)
                        {
                            var entry = index.ElementAt(index.Count - 1).Value;
                            entry[1] = fileOffset - entry[0];
                        }

                        var assetFileName = $"{j}.{fileType.ToLower()}";

                        // Lookup assumed original filename for better readability in yaml files.
                        if (lvlLookup.ContainsKey(assetFileName))
                        {
                            assetFileName = lvlLookup[assetFileName];
                        }
                        else
                        {
                            lvlLookup.Add(assetFileName, assetFileName);
                        }

                        index.Add(assetFileName, new int[] { fileOffset, 0 });
                    }
                }

                if (index.Count <= 0)
                {
                    return;
                }

                // Calculate the last fileLength.
                var lastEntry = index.ElementAt(index.Count - 1).Value;

                lastEntry[1] = firstFileListOffset - lastEntry[0];
            }
Exemple #26
0
        public static bool LoadSound(Stream s, out Func <Stream> result, out short channels, out int sampleBits, out int sampleRate)
        {
            result     = null;
            channels   = -1;
            sampleBits = -1;
            sampleRate = -1;

            var type = s.ReadASCII(4);

            if (type != "RIFF")
            {
                return(false);
            }

            s.ReadInt32();             // File-size
            var format = s.ReadASCII(4);

            if (format != "WAVE")
            {
                return(false);
            }

            WaveType audioType        = 0;
            var      dataOffset       = -1L;
            var      dataSize         = -1;
            short    blockAlign       = -1;
            int      uncompressedSize = -1;

            while (s.Position < s.Length)
            {
                if ((s.Position & 1) == 1)
                {
                    s.ReadByte();                     // Alignment
                }
                if (s.Position == s.Length)
                {
                    break;                     // Break if we aligned with end of stream
                }
                var blockType = s.ReadASCII(4);
                switch (blockType)
                {
                case "fmt ":
                    var fmtChunkSize = s.ReadInt32();
                    var audioFormat  = s.ReadInt16();
                    audioType = (WaveType)audioFormat;

                    if (!Enum.IsDefined(typeof(WaveType), audioType))
                    {
                        throw new NotSupportedException("Compression type {0} is not supported.".F(audioFormat));
                    }

                    channels   = s.ReadInt16();
                    sampleRate = s.ReadInt32();
                    s.ReadInt32();                             // Byte Rate
                    blockAlign = s.ReadInt16();
                    sampleBits = s.ReadInt16();

                    s.ReadBytes(fmtChunkSize - 16);
                    break;

                case "fact":
                    var chunkSize = s.ReadInt32();
                    uncompressedSize = s.ReadInt32();
                    s.ReadBytes(chunkSize - 4);
                    break;

                case "data":
                    dataSize    = s.ReadInt32();
                    dataOffset  = s.Position;
                    s.Position += dataSize;
                    break;

                case "LIST":
                case "cue ":
                    var listCueChunkSize = s.ReadInt32();
                    s.ReadBytes(listCueChunkSize);
                    break;

                default:
                    s.Position = s.Length;                             // Skip to end of stream
                    break;
                }
            }

            if (audioType == WaveType.ImaAdpcm)
            {
                sampleBits = 16;
            }

            var chan = channels;

            result = () =>
            {
                var audioStream = SegmentStream.CreateWithoutOwningStream(s, dataOffset, dataSize);
                if (audioType == WaveType.ImaAdpcm)
                {
                    return(new WavStream(audioStream, dataSize, blockAlign, chan, uncompressedSize));
                }

                return(audioStream);                // Data is already PCM format.
            };

            return(true);
        }
Exemple #27
0
            public VolFile(Stream stream, string filename)
            {
                Name        = filename;
                this.stream = stream;

                var magicByte = stream.ReadASCII(4);

                if (magicByte != "VOL ")
                {
                    return;
                }

                var unknown1 = stream.ReadUInt32();

                var header = stream.ReadASCII(4);
                var zero   = stream.ReadUInt32();

                if (header != "volh" && zero != 0)
                {
                    return;
                }

                var volumeSection = stream.ReadASCII(4);

                if (volumeSection != "vols")
                {
                    return;
                }

                var unknown2        = stream.ReadUInt32();
                var directoryOffset = stream.ReadUInt32();

                var entryFilenames = new List <string>();

                while (true)
                {
                    var entryFilename = stream.ReadASCIIZ();
                    if (string.IsNullOrEmpty(entryFilename))
                    {
                        break;
                    }

                    entryFilenames.Add(entryFilename);
                }

                while (true)
                {
                    if (stream.ReadByte() != 0)
                    {
                        break;
                    }
                }

                stream.Seek(-1, SeekOrigin.Current);

                var volumeIndex = stream.ReadASCII(4);

                if (volumeIndex != "voli")
                {
                    return;
                }

                var totalSize = stream.ReadUInt32();

                foreach (var entryFilename in entryFilenames)
                {
                    var filenameIndex = stream.ReadUInt32();
                    var offset        = stream.ReadUInt32();
                    var size          = stream.ReadUInt32();
                    var compression   = stream.ReadByte();
                    var valid         = stream.ReadByte();
                    if (valid != 0 && valid != 1)
                    {
                        throw new InvalidDataException("Check byte contains invalid values");
                    }

                    // Ignore duplicate files
                    if (index.ContainsKey(entryFilename))
                    {
                        continue;
                    }

                    var info = new VolEntry()
                    {
                        Filename    = entryFilename,
                        Offset      = offset + 8,
                        Size        = size,
                        Compression = compression,
                    };

                    if (compression != 0)
                    {
                        throw new NotImplementedException("'RLE', 'LZ', 'LZH' are not yet supported.");
                    }

                    index.Add(entryFilename, info);
                }
            }
Exemple #28
0
        public bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata)
        {
            var start = s.Position;

            var signature = s.ReadASCII(2);

            if (signature != "BM")
            {
                s.Position = start;
                metadata   = null;
                frames     = null;
                return(false);
            }

            var size      = s.ReadUInt32();
            var reserved1 = s.ReadUInt16();
            var reserved2 = s.ReadUInt16();
            var dataStart = s.ReadUInt32();

            var prt = Game.ModData.DefaultFileSystem.Open("op2_art.prt");

            framePalettes = LoadPalettes(prt);
            prtFile       = LoadImageHeader(prt, out var palettes);
            var frameList = new List <ISpriteFrame>();

            // Populate art data
            const byte shadowTileIndex = 1;
            var        imgIndex        = 0;

            foreach (var img in prtFile.ImageHeader)
            {
                var isShadow = img.ImageType == 4 || img.ImageType == 5;

                var dataSize  = new Size((int)img.PaddedWidth, (int)img.Height);
                var frameSize = new Size((int)img.Width, (int)img.Height);
                s.Seek(dataStart + img.DataOffset, SeekOrigin.Begin);

                byte[] data;
                var    numBytes = (int)(img.PaddedWidth * img.Height);

                if (isShadow)
                {
                    var       newSize       = (int)(img.PaddedWidth * img.Height);
                    var       rowSize       = (int)Math.Pow(2, Math.Ceiling(Math.Log(img.Width) / Math.Log(2)));
                    var       hasExtraRow   = rowSize == (int)img.PaddedWidth;
                    var       tempData      = s.ReadBytes(numBytes);
                    var       bits          = new BitArray(tempData);
                    var       processedData = new byte[newSize * 8];
                    var       paddedWidth   = img.Width;
                    const int bitsInAByte   = 8;
                    var       numRows       = (int)img.Height * 2;         // TODO: This is a hack. Not sure why we need to double this
                    if (hasExtraRow)
                    {
                        numRows *= 2;
                    }

                    // HACK: HACK HACK HACK
                    // Obviously our rowSize calculation is borked, so correct some things here
                    if (rowSize < 32)
                    {
                        rowSize = 32;
                    }

                    if (img.ImageType == 5)
                    {
                        if (rowSize == 128)
                        {
                            rowSize = 96;
                        }
                        else if (rowSize == 256)
                        {
                            rowSize = 128;
                        }
                    }

                    for (var y = 0; y < numRows; y++)
                    {
                        for (var x = 0; x < img.Width; x++)
                        {
                            var i = (int)((y * paddedWidth) + x);
                            var reversedBitIndex = 7 - (i % bitsInAByte);
                            var byteFloor        = i - (i % bitsInAByte);

                            var lookupIndex = byteFloor + reversedBitIndex;
                            processedData[i] = (byte)(bits[lookupIndex] ? shadowTileIndex : 0);
                        }
                    }

                    var paddedDiff = (int)(img.PaddedWidth - img.Width);
                    var newData    = new List <byte>();

                    for (var i = 0; i < img.Height; i++)
                    {
                        var startIndex = i * rowSize;

                        var firstX = processedData.Skip(startIndex).Take((int)img.Width).ToArray();
                        newData.AddRange(firstX);
                        newData.AddRange(Enumerable.Repeat <byte>(0, paddedDiff));

                        // if (imgIndex == 1758)
                        // {
                        //  var ss = imgIndex;
                        // }
                    }

                    if (img.PaddedWidth * img.Height > newData.Count)
                    {
                        throw new ArgumentException("Image size did not match number of bytes.");
                    }

                    data = newData.ToArray();
                }
                else
                {
                    data = s.ReadBytes(numBytes);
                }

                img.SpriteFrame = new BitmapSpriteFrame
                {
                    Size      = dataSize,
                    FrameSize = frameSize,
                    Data      = data,
                    Type      = SpriteFrameType.Indexed,
                };
                frameList.Add(img.SpriteFrame);

                imgIndex++;
            }

            metadata = new TypeDictionary {
                new EmbeddedSpritePalette(framePalettes: palettes)
            };

            frames = frameList.ToArray();

            return(true);
        }
Exemple #29
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));
                }
            }
        }
Exemple #30
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));
				}
			}
		}
Exemple #31
0
		public VqaReader(Stream stream)
		{
			this.stream = stream;

			// Decode FORM chunk
			if (stream.ReadASCII(4) != "FORM")
				throw new InvalidDataException("Invalid vqa (invalid FORM section)");
			/*var length = */stream.ReadUInt32();

			if (stream.ReadASCII(8) != "WVQAVQHD")
				throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
			/*var length2 = */stream.ReadUInt32();

			/*var version = */stream.ReadUInt16();
			videoFlags = stream.ReadUInt16();
			Frames = stream.ReadUInt16();
			Width = stream.ReadUInt16();
			Height = stream.ReadUInt16();

			blockWidth = stream.ReadUInt8();
			blockHeight = stream.ReadUInt8();
			Framerate = stream.ReadUInt8();
			chunkBufferParts = stream.ReadUInt8();
			blocks = new int2(Width / blockWidth, Height / blockHeight);

			numColors = stream.ReadUInt16();
			/*var maxBlocks = */stream.ReadUInt16();
			/*var unknown1 = */stream.ReadUInt16();
			/*var unknown2 = */stream.ReadUInt32();

			// Audio
			sampleRate = stream.ReadUInt16();
			audioChannels = stream.ReadByte();
			sampleBits = stream.ReadByte();

			/*var unknown3 =*/stream.ReadUInt32();
			/*var unknown4 =*/stream.ReadUInt16();
			/*maxCbfzSize =*/stream.ReadUInt32(); // Unreliable

			/*var unknown5 =*/stream.ReadUInt32();

			var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));

			if (IsHqVqa)
			{
				cbfBuffer = new byte[maxCbfzSize];
				cbf = new byte[maxCbfzSize * 3];
				origData = new byte[maxCbfzSize];
			}
			else
			{
				cbfBuffer = new byte[Width * Height];
				cbf = new byte[Width * Height];
				cbp = new byte[Width * Height];
				origData = new byte[2 * blocks.X * blocks.Y];
			}

			palette = new uint[numColors];
			frameData = new uint[frameSize, frameSize];
			var type = stream.ReadASCII(4);
			while (type != "FINF")
			{
				// Sub type is a file tag
				if (type[3] == 'F')
				{
					var jmp = int2.Swap(stream.ReadUInt32());
					stream.Seek(jmp, SeekOrigin.Current);
					type = stream.ReadASCII(4);
				}
				else
					throw new NotSupportedException("Vqa uses unknown Subtype: {0}".F(type));
			}

			/*var length = */stream.ReadUInt16();
			/*var unknown4 = */stream.ReadUInt16();

			// Frame offsets
			offsets = new uint[Frames];
			for (var i = 0; i < Frames; i++)
			{
				offsets[i] = stream.ReadUInt32();
				if (offsets[i] > 0x40000000)
					offsets[i] -= 0x40000000;
				offsets[i] <<= 1;
			}

			CollectAudioData();

			Reset();
		}
Exemple #32
0
        // VQA Frame
        public void DecodeVQFR(Stream s, string parentType = "VQFR")
        {
            // The CBP chunks each contain 1/8th of the full lookup table
            // Annoyingly, the complete table is not applied until the frame
            // *after* the one that contains the 8th chunk.
            // Do we have a set of partial lookup tables ready to apply?
            if (currentChunkBuffer == chunkBufferParts && chunkBufferParts != 0)
            {
                if (!cbpIsCompressed)
                {
                    cbf = (byte[])cbp.Clone();
                }
                else
                {
                    LCWDecodeInto(cbp, cbf);
                }

                chunkBufferOffset = currentChunkBuffer = 0;
            }

            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 = LCWDecodeInto(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":
                    var bytes = s.ReadBytes(subchunkLength);
                    bytes.CopyTo(cbp, chunkBufferOffset);
                    chunkBufferOffset += subchunkLength;
                    currentChunkBuffer++;
                    cbpIsCompressed = type == "CBPZ";
                    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);
                        paletteBytes[i * 4]     = b;
                        paletteBytes[i * 4 + 1] = g;
                        paletteBytes[i * 4 + 2] = r;
                        paletteBytes[i * 4 + 3] = 255;
                    }

                    break;

                // Frame data
                case "VPTZ":
                    LCWDecodeInto(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 = LCWDecodeInto(fileBuffer, origData);
                    }
                    else
                    {
                        LCWDecodeInto(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 {type}");
                }
            }
        }
Exemple #33
0
        public VqaReader(Stream stream)
        {
            this.stream = stream;

            // Decode FORM chunk
            if (stream.ReadASCII(4) != "FORM")
            {
                throw new InvalidDataException("Invalid vqa (invalid FORM section)");
            }
            /*var length = */ stream.ReadUInt32();

            if (stream.ReadASCII(8) != "WVQAVQHD")
            {
                throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
            }
            /* var length = */ stream.ReadUInt32();

            /*var version = */ stream.ReadUInt16();
            /*var flags = */ stream.ReadUInt16();
            Frames = stream.ReadUInt16();
            Width  = stream.ReadUInt16();
            Height = stream.ReadUInt16();

            blockWidth  = stream.ReadUInt8();
            blockHeight = stream.ReadUInt8();
            Framerate   = stream.ReadUInt8();
            cbParts     = stream.ReadUInt8();
            blocks      = new int2(Width / blockWidth, Height / blockHeight);

            numColors = stream.ReadUInt16();
            /*var maxBlocks = */ stream.ReadUInt16();
            /*var unknown1 = */ stream.ReadUInt16();
            /*var unknown2 = */ stream.ReadUInt32();

            // Audio
            /*var freq = */ stream.ReadUInt16();
            /*var channels = */ stream.ReadByte();
            /*var bits = */ stream.ReadByte();
            /*var unknown3 = */ stream.ReadBytes(14);

            var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));

            cbf       = new byte[Width * Height];
            cbp       = new byte[Width * Height];
            palette   = new uint[numColors];
            origData  = new byte[2 * blocks.X * blocks.Y];
            frameData = new uint[frameSize, frameSize];

            var type = stream.ReadASCII(4);

            if (type != "FINF")
            {
                stream.Seek(27, SeekOrigin.Current);
                type = stream.ReadASCII(4);
            }

            /*var length = */ stream.ReadUInt16();
            /*var unknown4 = */ stream.ReadUInt16();

            // Frame offsets
            offsets = new UInt32[Frames];
            for (int i = 0; i < Frames; i++)
            {
                offsets[i] = stream.ReadUInt32();
                if (offsets[i] > 0x40000000)
                {
                    offsets[i] -= 0x40000000;
                }
                offsets[i] <<= 1;
            }

            CollectAudioData();

            Reset();
        }
Exemple #34
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);
                var 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 (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;
                    default:
                        throw new InvalidDataException("Unknown sub-chunk {0}".F(type));
                }
            }
        }
Exemple #35
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 = LCWCompression.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
                        {
                            LCWCompression.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":
                    LCWCompression.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 = LCWCompression.DecodeInto(fileBuffer, origData);
                    }
                    else
                    {
                        LCWCompression.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));
                }
            }
        }
Exemple #36
0
        bool LoadSound(Stream s)
        {
            var type = s.ReadASCII(4);

            if (type != "RIFF")
            {
                return(false);
            }

            FileSize = s.ReadInt32();
            Format   = s.ReadASCII(4);
            if (Format != "WAVE")
            {
                return(false);
            }

            while (s.Position < s.Length)
            {
                if ((s.Position & 1) == 1)
                {
                    s.ReadByte();                     // Alignment
                }
                type = s.ReadASCII(4);
                switch (type)
                {
                case "fmt ":
                    FmtChunkSize = s.ReadInt32();
                    AudioFormat  = s.ReadInt16();
                    Type         = (WaveType)AudioFormat;

                    if (Type != WaveType.Pcm && Type != WaveType.ImaAdpcm)
                    {
                        throw new NotSupportedException("Compression type is not supported.");
                    }

                    Channels      = s.ReadInt16();
                    SampleRate    = s.ReadInt32();
                    ByteRate      = s.ReadInt32();
                    BlockAlign    = s.ReadInt16();
                    BitsPerSample = s.ReadInt16();

                    s.ReadBytes(FmtChunkSize - 16);
                    break;

                case "fact":
                {
                    var chunkSize = s.ReadInt32();
                    UncompressedSize = s.ReadInt32();
                    s.ReadBytes(chunkSize - 4);
                }

                break;

                case "data":
                    DataSize  = s.ReadInt32();
                    RawOutput = s.ReadBytes(DataSize);
                    break;

                default:
                    // Ignore unknown chunks
                {
                    var chunkSize = s.ReadInt32();
                    s.ReadBytes(chunkSize);
                }

                break;
                }
            }

            if (Type == WaveType.ImaAdpcm)
            {
                RawOutput     = DecodeImaAdpcmData();
                BitsPerSample = 16;
            }

            return(true);
        }
Exemple #37
0
            public DdfPackage(Stream ddfBase, Stream aniBase, string filename)
            {
                ddfStream = ddfBase;
                aniStream = aniBase;
                Name      = filename;

                var numFiles = ddfStream.ReadUInt32();

                ddfStream.ReadUInt16(); // 768
                ddfStream.ReadUInt16(); // 256
                palettePosition = ddfStream.Position;
                filesList.Add("SWARM_ASSAULT.PAL");
                ddfStream.Position += 256 * 4; // Palette

                for (var i = 0; i < numFiles; i++)
                {
                    var fileName = ddfStream.ReadASCII(32).Replace("\0", string.Empty);

                    if (!ddfIndex.ContainsKey(fileName))
                    {
                        ddfIndex.Add(fileName, ddfStream.Position);
                        filesList.Add(fileName + ".DDF");
                    }

                    ddfStream.Position += 20;
                }

                var numImages = aniStream.ReadUInt32();

                for (var i = 0; i < numImages; i++)
                {
                    var fileName = aniStream.ReadASCII(32).Replace("\0", string.Empty);

                    if (!metaIndex.ContainsKey(fileName))
                    {
                        metaIndex.Add(fileName, aniStream.Position);
                    }

                    aniStream.Position += 32 + 4 * 5;
                    var numUnkB   = aniStream.ReadUInt32();
                    var numPoints = aniStream.ReadUInt32();
                    aniStream.Position += numUnkB * (32 + 32 + 4 * 4);
                    aniStream.Position += numPoints * (32 + 32 + 4 * 2);
                }

                var numAnimations = aniStream.ReadUInt32();

                for (var i = 0; i < numAnimations; i++)
                {
                    var fileName = aniStream.ReadASCII(32).Replace("\0", string.Empty);

                    if (!aniIndex.ContainsKey(fileName))
                    {
                        aniIndex.Add(fileName, aniStream.Position);
                        filesList.Add(fileName + ".ANI");
                    }

                    var numFrames = aniStream.ReadUInt32();

                    for (var j = 0; j < numFrames; j++)
                    {
                        aniStream.Position += 32 + 4 * 2;
                        var numScripts = aniStream.ReadUInt32();
                        aniStream.Position += 32 * numScripts;
                    }
                }
            }
Exemple #38
0
        void CollectAudioData()
        {
            var audio1     = new MemoryStream();         // left channel / mono
            var audio2     = new MemoryStream();         // right channel
            var adpcmIndex = 0;
            var compressed = false;

            for (var i = 0; i < Frames; i++)
            {
                stream.Seek(offsets[i], SeekOrigin.Begin);
                var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length;

                while (stream.Position < end)
                {
                    var type = stream.ReadASCII(4);
                    if (type == "SN2J")
                    {
                        var jmp = int2.Swap(stream.ReadUInt32());
                        stream.Seek(jmp, SeekOrigin.Current);
                        type = stream.ReadASCII(4);
                    }

                    var length = int2.Swap(stream.ReadUInt32());

                    switch (type)
                    {
                    case "SND0":
                    case "SND2":
                        if (audioChannels == 0)
                        {
                            throw new NotSupportedException();
                        }
                        else if (audioChannels == 1)
                        {
                            var rawAudio = stream.ReadBytes((int)length);
                            audio1.Write(rawAudio);
                        }
                        else
                        {
                            var rawAudio = stream.ReadBytes((int)length / 2);
                            audio1.Write(rawAudio);
                            rawAudio = stream.ReadBytes((int)length / 2);
                            audio2.Write(rawAudio);
                            if (length % 2 != 0)
                            {
                                stream.ReadBytes(2);
                            }
                        }

                        compressed = type == "SND2";
                        break;

                    default:
                        if (length + stream.Position > stream.Length)
                        {
                            throw new NotSupportedException("Vqa uses unknown Subtype: {0}".F(type));
                        }
                        stream.ReadBytes((int)length);
                        break;
                    }

                    // Chunks are aligned on even bytes; advance by a byte if the next one is null
                    if (stream.Peek() == 0)
                    {
                        stream.ReadByte();
                    }
                }
            }

            if (audioChannels == 1)
            {
                audioData = compressed ? AudReader.LoadSound(audio1.ToArray(), ref adpcmIndex) : audio1.ToArray();
            }
            else
            {
                byte[] leftData, rightData;
                if (!compressed)
                {
                    leftData  = audio1.ToArray();
                    rightData = audio2.ToArray();
                }
                else
                {
                    adpcmIndex = 0;
                    leftData   = AudReader.LoadSound(audio1.ToArray(), ref adpcmIndex);
                    adpcmIndex = 0;
                    rightData  = AudReader.LoadSound(audio2.ToArray(), ref adpcmIndex);
                }

                audioData = new byte[rightData.Length + leftData.Length];
                var rightIndex = 0;
                var leftIndex  = 0;
                for (var i = 0; i < audioData.Length;)
                {
                    audioData[i++] = leftData[leftIndex++];
                    audioData[i++] = leftData[leftIndex++];
                    audioData[i++] = rightData[rightIndex++];
                    audioData[i++] = rightData[rightIndex++];
                }
            }

            hasAudio = audioData.Length > 0;
        }
Exemple #39
0
 public static VocFileHeader Read(Stream s)
 {
     VocFileHeader vfh;
     vfh.Description = s.ReadASCII(20);
     vfh.DatablockOffset = s.ReadUInt16();
     vfh.Version = s.ReadUInt16();
     vfh.ID = s.ReadUInt16();
     return vfh;
 }
Exemple #40
0
        public VqaReader(Stream stream)
        {
            this.stream = stream;

            // Decode FORM chunk
            if (stream.ReadASCII(4) != "FORM")
            {
                throw new InvalidDataException("Invalid vqa (invalid FORM section)");
            }
            /*var length = */ stream.ReadUInt32();

            if (stream.ReadASCII(8) != "WVQAVQHD")
            {
                throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
            }
            /*var length2 = */ stream.ReadUInt32();

            /*var version = */ stream.ReadUInt16();
            videoFlags = stream.ReadUInt16();
            Frames     = stream.ReadUInt16();
            Width      = stream.ReadUInt16();
            Height     = stream.ReadUInt16();

            blockWidth       = stream.ReadUInt8();
            blockHeight      = stream.ReadUInt8();
            Framerate        = stream.ReadUInt8();
            chunkBufferParts = stream.ReadUInt8();
            blocks           = new int2(Width / blockWidth, Height / blockHeight);

            numColors = stream.ReadUInt16();
            /*var maxBlocks = */ stream.ReadUInt16();
            /*var unknown1 = */ stream.ReadUInt16();
            /*var unknown2 = */ stream.ReadUInt32();

            // Audio
            sampleRate    = stream.ReadUInt16();
            audioChannels = stream.ReadByte();
            sampleBits    = stream.ReadByte();

            /*var unknown3 =*/ stream.ReadUInt32();
            /*var unknown4 =*/ stream.ReadUInt16();
            /*maxCbfzSize =*/ stream.ReadUInt32();            // Unreliable

            /*var unknown5 =*/ stream.ReadUInt32();

            var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));

            if (IsHqVqa)
            {
                cbfBuffer = new byte[maxCbfzSize];
                cbf       = new byte[maxCbfzSize * 3];
                origData  = new byte[maxCbfzSize];
            }
            else
            {
                cbfBuffer = new byte[Width * Height];
                cbf       = new byte[Width * Height];
                cbp       = new byte[Width * Height];
                origData  = new byte[2 * blocks.X * blocks.Y];
            }

            palette   = new uint[numColors];
            frameData = new uint[frameSize, frameSize];
            var type = stream.ReadASCII(4);

            while (type != "FINF")
            {
                // Sub type is a file tag
                if (type[3] == 'F')
                {
                    var jmp = int2.Swap(stream.ReadUInt32());
                    stream.Seek(jmp, SeekOrigin.Current);
                    type = stream.ReadASCII(4);
                }
                else
                {
                    throw new NotSupportedException("Vqa uses unknown Subtype: {0}".F(type));
                }
            }

            /*var length = */ stream.ReadUInt16();
            /*var unknown4 = */ stream.ReadUInt16();

            // Frame offsets
            offsets = new uint[Frames];
            for (var i = 0; i < Frames; i++)
            {
                offsets[i] = stream.ReadUInt32();
                if (offsets[i] > 0x40000000)
                {
                    offsets[i] -= 0x40000000;
                }
                offsets[i] <<= 1;
            }

            CollectAudioData();

            Reset();
        }
Exemple #41
0
        private bool IsPrt(Stream s)
        {
            var start = s.Position;
            var h     = new PrtFile()
            {
                ID       = s.ReadASCII(4),
                PalCount = s.ReadInt32(),
            };

            if (h.ID != "CPAL")
            {
                s.Position = start;
                return(false);
            }

            h.PalData = new Ppal[h.PalCount];

            // Parse palettes
            for (var i = 0; i < h.PalCount; i++)
            {
                var ppal = new Ppal
                {
                    ID            = s.ReadASCII(4),
                    Size          = s.ReadInt32(),
                    HeadID        = s.ReadASCII(4),
                    BytesPerEntry = s.ReadInt32(),
                    Unknown       = s.ReadInt32(),
                    DataID        = s.ReadASCII(4),
                    PalSize       = s.ReadInt32()
                };

                if (ppal.ID != "PPAL" || ppal.HeadID != "head" || ppal.DataID != "data")
                {
                    s.Position = start;
                    return(false);
                }

                var numPaletteEntries = ppal.PalSize / ppal.BytesPerEntry;

                ppal.PaletteData = new RgbQuad[numPaletteEntries];

                // Populate palette
                for (var j = 0; j < numPaletteEntries; j++)
                {
                    var rgba = new RgbQuad
                    {
                        Red      = s.ReadByte(),
                        Green    = s.ReadByte(),
                        Blue     = s.ReadByte(),
                        Reserved = s.ReadByte(),
                    };

                    ppal.PaletteData[j] = rgba;
                }

                h.PalData[i] = ppal;
            }

            h.ImageCount  = s.ReadInt32();
            h.ImageHeader = new Op2Image[h.ImageCount];

            for (var i = 0; i < h.ImageCount; i++)
            {
                var img = new Op2Image
                {
                    SizeScanline = s.ReadInt32(),
                };

                img.ImgData      = s.ReadBytes(img.SizeScanline);
                img.SizeX        = s.ReadInt32();
                img.SizeY        = s.ReadInt32();
                img.Unknown      = s.ReadInt16();
                img.Palette      = s.ReadInt16();
                h.ImageHeader[i] = img;
            }

            h.AllGroupCount   = s.ReadInt32();
            h.AllFrameCount   = s.ReadInt32();
            h.AllPicCount     = s.ReadInt32();
            h.AllExtInfoCount = s.ReadInt32();
            h.Groups          = new ImageGroup[h.AllGroupCount];

            for (var i = 0; i < h.AllGroupCount; i++)
            {
                var img = new ImageGroup
                {
                    Unknown1   = s.ReadInt32(),
                    SelLeft    = s.ReadInt32(),
                    SelTop     = s.ReadInt32(),
                    SelRight   = s.ReadInt32(),
                    SelBottom  = s.ReadInt32(),
                    CenterX    = s.ReadInt32(),
                    CenterY    = s.ReadInt32(),
                    Unknown8   = s.ReadInt32(),
                    FrameCount = s.ReadInt32()
                };

                img.Frames = new Op2Frame[img.FrameCount];

                for (var j = 0; j < img.FrameCount; j++)
                {
                    var frame = new Op2Frame
                    {
                        PicCount = s.ReadUInt8(),
                        Unknown  = s.ReadUInt8(),
                    };

                    frame.ExtUnknown1 = new BytePair[frame.PicCount >> 7];
                    for (var k = 0; k < frame.PicCount >> 7; k++)
                    {
                        var bp = new BytePair
                        {
                            Byte1 = s.ReadUInt8(),
                            Byte2 = s.ReadUInt8(),
                        };

                        frame.ExtUnknown1[k] = bp;
                    }

                    frame.ExtUnknown2 = new BytePair[frame.Unknown >> 7];
                    for (var k = 0; k < frame.Unknown >> 7; k++)
                    {
                        var bp = new BytePair
                        {
                            Byte1 = s.ReadUInt8(),
                            Byte2 = s.ReadUInt8(),
                        };

                        frame.ExtUnknown2[k] = bp;
                    }

                    frame.Pictures = new Op2Picture[frame.PicCount & 0x7F];
                    for (var k = 0; k < frame.Pictures.Length; k++)
                    {
                        var pic = new Op2Picture
                        {
                            ImgNumber = s.ReadInt16(),
                            Reserved  = s.ReadUInt8(),
                            PicOrder  = s.ReadUInt8(),
                            PosX      = s.ReadInt16(),
                            PosY      = s.ReadInt16()
                        };

                        frame.Pictures[k] = pic;
                    }

                    img.Frames[j] = frame;
                }

                img.GroupExtCount = s.ReadInt32();
                img.Extended      = new GroupExt[img.GroupExtCount];

                for (var j = 0; j < img.GroupExtCount; j++)
                {
                    var ext = new GroupExt
                    {
                        Unknown1 = s.ReadInt32(),
                        Unknown2 = s.ReadInt32(),
                        Unknown3 = s.ReadInt32(),
                        Unknown4 = s.ReadInt32(),
                    };

                    img.Extended[j] = ext;
                }

                h.Groups[i] = img;
            }

            file = h;

            return(true);
        }
Exemple #42
0
        public VqaReader(Stream stream)
        {
            this.stream = stream;

            // Decode FORM chunk
            if (stream.ReadASCII(4) != "FORM")
                throw new InvalidDataException("Invalid vqa (invalid FORM section)");
            /*var length = */ stream.ReadUInt32();

            if (stream.ReadASCII(8) != "WVQAVQHD")
                throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
            /* var length = */stream.ReadUInt32();

            /*var version = */stream.ReadUInt16();
            /*var flags = */stream.ReadUInt16();
            Frames = stream.ReadUInt16();
            Width = stream.ReadUInt16();
            Height = stream.ReadUInt16();

            blockWidth = stream.ReadUInt8();
            blockHeight = stream.ReadUInt8();
            Framerate = stream.ReadUInt8();
            cbParts = stream.ReadUInt8();
            blocks = new int2(Width / blockWidth, Height / blockHeight);

            numColors = stream.ReadUInt16();
            /*var maxBlocks = */stream.ReadUInt16();
            /*var unknown1 = */stream.ReadUInt16();
            /*var unknown2 = */stream.ReadUInt32();

            // Audio
            /*var freq = */stream.ReadUInt16();
            /*var channels = */stream.ReadByte();
            /*var bits = */stream.ReadByte();
            /*var unknown3 = */stream.ReadBytes(14);

            var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));
            cbf = new byte[Width*Height];
            cbp = new byte[Width*Height];
            palette = new uint[numColors];
            origData = new byte[2*blocks.X*blocks.Y];
            frameData = new uint[frameSize, frameSize];

            var type = stream.ReadASCII(4);
            if (type != "FINF")
            {
                stream.Seek(27, SeekOrigin.Current);
                type = stream.ReadASCII(4);
            }

            /*var length = */stream.ReadUInt16();
            /*var unknown4 = */stream.ReadUInt16();

            // Frame offsets
            offsets = new UInt32[Frames];
            for (var i = 0; i < Frames; i++)
            {
                offsets[i] = stream.ReadUInt32();
                if (offsets[i] > 0x40000000)
                    offsets[i] -= 0x40000000;
                offsets[i] <<= 1;
            }

            CollectAudioData();

            Reset();
        }
Exemple #43
0
        bool IsWave(Stream s)
        {
            var start = s.Position;
            var type = s.ReadASCII(4);
            s.Position += 4;
            var format = s.ReadASCII(4);
            s.Position = start;

            return type == "RIFF" && format == "WAVE";
        }
Exemple #44
0
        private static bool IsRaw(Stream s)
        {
            var header = s.ReadASCII(4);

            return(header == "????");
        }
        void ParseFile(Stream s, string dirName)
        {
            s.Position += 7;
            var compressedSize = s.ReadUInt32();
            s.Position += 12;
            var chunkSize = s.ReadUInt16();
            s.Position += 4;
            var nameLength = s.ReadByte();
            var fileName = dirName + "\\" + s.ReadASCII(nameLength);

            // Use index syntax to overwrite any duplicate entries with the last value
            index[fileName] = new Entry(accumulatedData, compressedSize);
            accumulatedData += compressedSize;

            // Skip to the end of the chunk
            s.Position += chunkSize - nameLength - 30;
        }