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; } }
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; } }
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); }
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]); } }
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; } }
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); } }
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); }
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)); }
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); } }
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); }
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); }
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); } }
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; } }
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; } }
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()); }
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); } }
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); }
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; }
private static bool IsBmp(Stream s) { var header = s.ReadASCII(4); return(header == "BM88" || header == "PBMP"); }
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]; }
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); }
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); } }
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); }
// 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)); } } }
// 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)); } } }
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(); }
// 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}"); } } }
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(); }
// 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)); } } }
// 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)); } } }
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); }
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; } } }
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; }
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; }
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(); }
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); }
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(); }
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"; }
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; }