public void Deserialize(Stream input) { var version = input.ReadValueU16(); if (version < 2 || version > 5) { throw new FormatException("unsupported cfs version"); } var header = new Sprite.Header(); if (version >= 5) { header = input.ReadStructure <Sprite.Header>(); } else if (version >= 4) { var oldHeader = input.ReadStructure <Sprite.OldHeader4>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; header.Category = oldHeader.Category; header.BlitMode = oldHeader.BlitMode; header.RowMeaning = oldHeader.RowMeaning; header.YSortAdjust = oldHeader.YSortAdjust; header.SortTransform = oldHeader.SortTransform; header.UserPaletteStart = oldHeader.UserPaletteStart; header.UserPalette = oldHeader.UserPalette; header.Description = oldHeader.Description; } else if (version >= 3) { var oldHeader = input.ReadStructure <Sprite.OldHeader3>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; header.Category = oldHeader.Category; header.BlitMode = oldHeader.BlitMode; header.RowMeaning = oldHeader.RowMeaning; header.YSortAdjust = oldHeader.YSortAdjust; header.SortTransform = oldHeader.SortTransform; header.UserPaletteStart = oldHeader.UserPaletteStart; header.UserPalette = oldHeader.UserPalette; } else if (version >= 1) { var oldHeader = input.ReadStructure <Sprite.OldHeader2>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; } if (header.LightCount != 0 && header.LightCount != 32) { throw new FormatException(); } if (header.ShadowCount != 0 && header.ShadowCount != 8) { throw new FormatException(); } this.AnimationTime = header.AnimationTime; this.Width = header.Width; this.Height = header.Height; this.RowCount = header.RowCount; this.ColumnCount = header.ColumnCount; this.ShadowCount = header.ShadowCount; this.LightCount = header.LightCount; this.MaxSolidIndex = header.MaxSolidIndex; this.CompressionFlags = header.CompressionFlags; this.Category = header.Category; this.Description = header.Description; for (int i = 0; i < this.Palette.Length; i++) { this.Palette[i] = input.ReadValueU32(); } this.UserData = new byte[header.UserDataSize]; if (input.Read(this.UserData, 0, this.UserData.Length) != this.UserData.Length) { throw new FormatException(); } var infos = new Sprite.FrameInfo[header.FrameCount]; for (int i = 0; i < infos.Length; i++) { infos[i] = input.ReadStructure <Sprite.FrameInfo>(); } var compressionFlags = (uint)header.CompressionFlags; if ((compressionFlags & ~0x1FFu) != 0) { throw new FormatException("unknown compression flags"); } if (header.Unknown20 != 0 && header.Unknown20 != 3) { // WHAT DOES THIS VALUE MEAN AUGH throw new NotSupportedException(); } if ((header.CompressionFlags & Sprite.CompressionFlags.NoCompression) != 0) { if ((header.CompressionFlags & ~(Sprite.CompressionFlags.NoPixels | Sprite.CompressionFlags.NoCompression)) != 0) { throw new FormatException("other compression flags set with NoCompression flag"); } } using (var data = input.ReadToMemoryStream(header.DataSize)) { this.Frames = new Sprite.Frame[header.FrameCount]; for (int i = 0; i < header.FrameCount; i++) { var info = infos[i]; data.Seek(info.Offset, SeekOrigin.Begin); var frame = this.Frames[i] = new Sprite.Frame(); frame.X = info.X; frame.Y = info.Y; frame.Width = Math.Abs(info.Width); frame.Height = Math.Abs(info.Height); frame.Pixels = new byte[frame.Width * frame.Height]; if ((header.CompressionFlags & Sprite.CompressionFlags.NoCompression) != 0) { // uncompressed data data.Read(frame.Pixels, 0, frame.Pixels.Length); } else { // compressed data var lengths = new int[frame.Height]; var max = 0; for (int y = 0; y < frame.Height; y++) { int length = data.ReadValueU8(); if (length == 0xFF) { length = data.ReadValueU16(); } lengths[y] = length; max = Math.Max(max, length); } var scanline = new byte[max]; for (int y = 0, offset = 0; y < frame.Height; y++, offset = y * frame.Width) { var length = lengths[y]; if (data.Read(scanline, 0, length) != length) { throw new FormatException(); } for (int x = 0; x < length;) { offset += (scanline[x] >> 4) & 0xF; // transparent var literalCount = scanline[x] & 0xF; if (literalCount > 0) { Array.Copy(scanline, x + 1, frame.Pixels, offset, literalCount); } offset += literalCount; x += 1 + literalCount; } } } // flip horizontal if (info.Width < 0) { for (int y = 0, offset = 0; y < frame.Height; y++, offset += frame.Width) { Array.Reverse(frame.Pixels, offset, frame.Width); } } // flip vertical if (info.Height < 0) { var scanline = new byte[frame.Height]; for (int x = 0; x < frame.Width; x++) { for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width) { scanline[y] = frame.Pixels[offset]; } for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width) { frame.Pixels[offset] = scanline[frame.Height - 1 - y]; } } } } } }
public void Deserialize(Stream input) { var version = input.ReadValueU16(); if (version < 2 || version > 5) { throw new FormatException("unsupported cfs version"); } var header = new Sprite.Header(); if (version >= 5) { header = input.ReadStructure<Sprite.Header>(); } else if (version >= 4) { var oldHeader = input.ReadStructure<Sprite.OldHeader4>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; header.Category = oldHeader.Category; header.BlitMode = oldHeader.BlitMode; header.RowMeaning = oldHeader.RowMeaning; header.YSortAdjust = oldHeader.YSortAdjust; header.SortTransform = oldHeader.SortTransform; header.UserPaletteStart = oldHeader.UserPaletteStart; header.UserPalette = oldHeader.UserPalette; header.Description = oldHeader.Description; } else if (version >= 3) { var oldHeader = input.ReadStructure<Sprite.OldHeader3>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; header.Category = oldHeader.Category; header.BlitMode = oldHeader.BlitMode; header.RowMeaning = oldHeader.RowMeaning; header.YSortAdjust = oldHeader.YSortAdjust; header.SortTransform = oldHeader.SortTransform; header.UserPaletteStart = oldHeader.UserPaletteStart; header.UserPalette = oldHeader.UserPalette; } else if (version >= 1) { var oldHeader = input.ReadStructure<Sprite.OldHeader2>(); header.FrameCount = oldHeader.FrameCount; header.AnimationTime = oldHeader.AnimationTime; header.Width = oldHeader.Width; header.Height = oldHeader.Height; header.RowCount = oldHeader.RowCount; header.ColumnCount = oldHeader.ColumnCount; header.ShadowCount = oldHeader.ShadowCount; header.LightCount = oldHeader.LightCount; header.UserDataSize = oldHeader.UserDataSize; header.CompressionFlags = (Sprite.CompressionFlags)oldHeader.CompressionFlags; header.MaxSolidIndex = oldHeader.MaxSolidIndex; header.DataSize = oldHeader.DataSize; } if (header.LightCount != 0 && header.LightCount != 32) { throw new FormatException(); } if (header.ShadowCount != 0 && header.ShadowCount != 8) { throw new FormatException(); } this.AnimationTime = header.AnimationTime; this.Width = header.Width; this.Height = header.Height; this.RowCount = header.RowCount; this.ColumnCount = header.ColumnCount; this.ShadowCount = header.ShadowCount; this.LightCount = header.LightCount; this.MaxSolidIndex = header.MaxSolidIndex; this.CompressionFlags = header.CompressionFlags; for (int i = 0; i < this.Palette.Length; i++) { this.Palette[i] = input.ReadValueU32(); } this.UserData = new byte[header.UserDataSize]; if (input.Read(this.UserData, 0, this.UserData.Length) != this.UserData.Length) { throw new FormatException(); } var infos = new Sprite.FrameInfo[header.FrameCount]; for (int i = 0; i < infos.Length; i++) { infos[i] = input.ReadStructure<Sprite.FrameInfo>(); } var compressionFlags = (uint)header.CompressionFlags; if ((compressionFlags & ~0x1FFu) != 0) { throw new FormatException("unknown compression flags"); } if (header.Unknown20 != 0 && header.Unknown20 != 3) { // WHAT DOES THIS VALUE MEAN AUGH throw new NotSupportedException(); } if ((header.CompressionFlags & Sprite.CompressionFlags.NoCompression) != 0) { if ((header.CompressionFlags & ~(Sprite.CompressionFlags.NoPixels | Sprite.CompressionFlags.NoCompression)) != 0) { throw new FormatException("other compression flags set with NoCompression flag"); } } using (var data = input.ReadToMemoryStream(header.DataSize)) { this.Frames = new Sprite.Frame[header.FrameCount]; for (int i = 0; i < header.FrameCount; i++) { var info = infos[i]; data.Seek(info.Offset, SeekOrigin.Begin); var frame = this.Frames[i] = new Sprite.Frame(); frame.X = info.X; frame.Y = info.Y; frame.Width = Math.Abs(info.Width); frame.Height = Math.Abs(info.Height); frame.Pixels = new byte[frame.Width * frame.Height]; if ((header.CompressionFlags & Sprite.CompressionFlags.NoCompression) != 0) { // uncompressed data data.Read(frame.Pixels, 0, frame.Pixels.Length); } else { // compressed data var lengths = new int[frame.Height]; var max = 0; for (int y = 0; y < frame.Height; y++) { int length = data.ReadValueU8(); if (length == 0xFF) { length = data.ReadValueU16(); } lengths[y] = length; max = Math.Max(max, length); } var scanline = new byte[max]; for (int y = 0, offset = 0; y < frame.Height; y++, offset = y * frame.Width) { var length = lengths[y]; if (data.Read(scanline, 0, length) != length) { throw new FormatException(); } for (int x = 0; x < length;) { offset += (scanline[x] >> 4) & 0xF; // transparent var literalCount = scanline[x] & 0xF; if (literalCount > 0) { Array.Copy(scanline, x + 1, frame.Pixels, offset, literalCount); } offset += literalCount; x += 1 + literalCount; } } } // flip horizontal if (info.Width < 0) { for (int y = 0, offset = 0; y < frame.Height; y++, offset += frame.Width) { Array.Reverse(frame.Pixels, offset, frame.Width); } } // flip vertical if (info.Height < 0) { var scanline = new byte[frame.Height]; for (int x = 0; x < frame.Width; x++) { for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width) { scanline[y] = frame.Pixels[offset]; } for (int y = 0, offset = x; y < frame.Height; y++, offset += frame.Width) { frame.Pixels[offset] = scanline[frame.Height - 1 - y]; } } } } } }