diff --git a/src/Syroot.Worms.Test/Program.cs b/src/Syroot.Worms.Test/Program.cs
index d529c54..359569f 100644
--- a/src/Syroot.Worms.Test/Program.cs
+++ b/src/Syroot.Worms.Test/Program.cs
@@ -1,17 +1,52 @@
using System;
+using System.IO;
using Syroot.Worms.Gen2;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
namespace Syroot.Worms.Test
{
+ ///
+ /// Represents the main class of the application containing the program entry point.
+ ///
internal class Program
{
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private static readonly string[] _testPaths = { @"C:\Games\Worms Armageddon 3.7.2.1", @"E:\" };
+
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static void Main(string[] args)
{
- Archive archive = new Archive(@"D:\Archive\Games\Worms\Worms Armageddon\DATA\Gfx\Gfx0.dir");
- archive.Save(@"D:\Pictures\test.dir");
- Archive archive2 = new Archive(@"D:\Pictures\test.dir");
+ //foreach (string dirFile in GetFiles("*.dir"))
+ //{
+ // Console.WriteLine($"Loading {dirFile}...");
+ // Archive archive = new Archive(dirFile);
+ // foreach (string entry in archive.Keys)
+ // {
+ // Console.WriteLine($"\t{entry}");
+ // }
+ //}
+
+ foreach (string imgFile in GetFiles("*.img"))
+ {
+ Console.WriteLine("Loading {imgFile}...");
+ Image image = new Image(imgFile);
+ }
+
+ Console.ReadLine();
+ }
+
+ private static List GetFiles(string wildcard)
+ {
+ List files = new List();
+ foreach (string testPath in _testPaths)
+ {
+ files.AddRange(Directory.GetFiles(testPath, wildcard, SearchOption.AllDirectories));
+ }
+ return files;
}
}
}
\ No newline at end of file
diff --git a/src/Syroot.Worms.sln b/src/Syroot.Worms.sln
index b9a47e3..76d41e2 100644
--- a/src/Syroot.Worms.sln
+++ b/src/Syroot.Worms.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26403.3
+VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
EndProject
diff --git a/src/Syroot.Worms/Core/ByteArrayExtensions.cs b/src/Syroot.Worms/Core/ByteArrayExtensions.cs
index 6b6c2b5..7e5b142 100644
--- a/src/Syroot.Worms/Core/ByteArrayExtensions.cs
+++ b/src/Syroot.Worms/Core/ByteArrayExtensions.cs
@@ -1,17 +1,17 @@
namespace Syroot.Worms.Core
{
///
- /// Represents extension methods for instances.
+ /// Represents extension methods for byte array instances.
///
internal static class ByteArrayExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
///
- /// Returns true if the current instance holds the same values as the given one.
+ /// Returns true if the current byte array instance holds the same values as the given one.
///
- /// The extended instance.
- /// The instance to compare with.
+ /// The extended byte array instance.
+ /// The byte array instance to compare with.
/// true if both instances hold the same values, otherwise false.
internal static bool Compare(this byte[] self, byte[] other)
{
diff --git a/src/Syroot.Worms/Core/Team17Compression.cs b/src/Syroot.Worms/Core/Team17Compression.cs
new file mode 100644
index 0000000..6b523f3
--- /dev/null
+++ b/src/Syroot.Worms/Core/Team17Compression.cs
@@ -0,0 +1,54 @@
+using System.IO;
+
+namespace Syroot.Worms.Core
+{
+ ///
+ /// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
+ /// graphic file formats.
+ /// S. http://worms2d.info/Team17_compression.
+ ///
+ internal static class Team17Compression
+ {
+ public static bool Decompress(BinaryReader b, ref byte[] dStream)
+ {
+ int cmd;
+ int output = 0; //offset of next write
+ while ((cmd = b.ReadByte()) != -1)
+ { //read a byte
+ if ((cmd & 0x80) == 0)
+ { //command: 1 byte (color)
+ dStream[output++] = (byte)cmd;
+ }
+ else
+ {
+ int arg1 = (cmd >> 3) & 0xF; //arg1=bits 2-5
+ int arg2 = b.ReadByte();
+ if (arg2 == -1)
+ return false;
+ arg2 = ((cmd << 8) | arg2) & 0x7FF; //arg2=bits 6-16
+ if (arg1 == 0)
+ {
+ if (arg2 == 0) //command: 0x80 0x00
+ return false;
+ int arg3 = b.ReadByte();
+ if (arg3 == -1)
+ return false;
+ output = CopyData(output, arg2, arg3 + 18, ref dStream); //command: 3 bytes
+ }
+ else
+ {
+ output = CopyData(output, arg2 + 1, arg1 + 2, ref dStream); //command: 2 bytes
+ }
+ }
+ }
+ return true;
+ }
+
+ public static int CopyData(int dOffset, int cOffset, int Repeat, ref byte[] dStream)
+ {
+ for (; Repeat > 0; Repeat--)
+ dStream[dOffset] = dStream[dOffset++ - cOffset];
+ return dOffset;
+ }
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/Archive.cs b/src/Syroot.Worms/Gen2/Archive.cs
index 2bfaf7c..1397f65 100644
--- a/src/Syroot.Worms/Gen2/Archive.cs
+++ b/src/Syroot.Worms/Gen2/Archive.cs
@@ -16,8 +16,8 @@ namespace Syroot.Worms.Gen2
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
- private static readonly int _signature = 0x1A524944;
- private static readonly int _tocSignature = 0x0000000A;
+ private const int _signature = 0x1A524944; // "DIR", 0x1A
+ private const int _tocSignature = 0x0000000A;
private const int _hashBits = 10;
private const int _hashSize = 1 << _hashBits;
@@ -63,7 +63,7 @@ namespace Syroot.Worms.Gen2
int signature = reader.ReadInt32();
if (signature != _signature)
{
- throw new InvalidDataException("Invalid file signature.");
+ throw new InvalidDataException("Invalid DIR file signature.");
}
int fileSize = reader.ReadInt32();
int tocOffset = reader.ReadInt32();
@@ -73,7 +73,7 @@ namespace Syroot.Worms.Gen2
int tocSignature = reader.ReadInt32();
if (tocSignature != _tocSignature)
{
- throw new InvalidDataException("Invalid table of contents signature.");
+ throw new InvalidDataException("Invalid DIR table of contents signature.");
}
// Generate a data dictionary out of the hash table and file entries.
int[] hashTable = reader.ReadInt32s(_hashSize);
diff --git a/src/Syroot.Worms/Gen2/Image.cs b/src/Syroot.Worms/Gen2/Image.cs
index 72715ea..13a7aef 100644
--- a/src/Syroot.Worms/Gen2/Image.cs
+++ b/src/Syroot.Worms/Gen2/Image.cs
@@ -1,10 +1,157 @@
using System;
-using System.Collections.Generic;
+using System.IO;
using System.Text;
+using Syroot.IO;
+using Syroot.Maths;
+using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2
{
- class Image
+ ///
+ /// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
+ /// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
+ ///
+ public class Image
{
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const int _signature = 0x1A474D49; // "IMG", 0x1A
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ ///
+ /// Initializes a new instance of the class, loading the data from the given
+ /// .
+ ///
+ /// The to load the data from.
+ public Image(Stream stream)
+ {
+ Load(stream);
+ }
+
+ ///
+ /// Initializes a new instance of the class, loading the data from the given file.
+ ///
+ /// The name of the file to load the data from.
+ public Image(string fileName)
+ {
+ Load(fileName);
+ }
+
+ // ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ ///
+ /// Gets an optional description of the image contents.
+ ///
+ public string Description { get; private set; }
+
+ ///
+ /// Gets the number of bits required to describe a color per pixel.
+ ///
+ public int BitsPerPixel { get; private set; }
+
+ ///
+ /// Gets the color palette of the image. The first color must always be black.
+ ///
+ public Color[] Palette { get; private set; }
+
+ ///
+ /// Gets the width of the image in pixels.
+ ///
+ public int Width { get; private set; }
+
+ ///
+ /// Gets the height of the image in pixels.
+ ///
+ public int Height { get; private set; }
+
+ ///
+ /// Gets the data of the image pixels.
+ ///
+ public byte[] Data { get; private set; }
+
+ // ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
+
+ ///
+ /// Loads the data from the given .
+ ///
+ /// The to load the data from.
+ public void Load(Stream stream)
+ {
+ using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
+ {
+ // Read the header.
+ int signature = reader.ReadInt32();
+ if (signature != _signature)
+ {
+ throw new InvalidDataException("Invalid IMG file signature.");
+ }
+ int fileSize = reader.ReadInt32();
+
+ // Read an optional string describing the image contents or the bits per pixel.
+ BitsPerPixel = reader.ReadByte();
+ if (BitsPerPixel == 0)
+ {
+ Description = String.Empty;
+ BitsPerPixel = reader.ReadByte();
+ }
+ else if (BitsPerPixel > 32)
+ {
+ Description = (char)BitsPerPixel + reader.ReadString(BinaryStringFormat.ZeroTerminated);
+ BitsPerPixel = reader.ReadByte();
+ }
+
+ // Read image flags describing the format and availability of the following contents.
+ Flags flags = (Flags)reader.ReadByte();
+
+ // Read the image palette if available. The first color of the palette is implicitly black.
+ if (flags.HasFlag(Flags.Palettized))
+ {
+ int colorCount = reader.ReadInt16();
+ Palette = new Color[colorCount + 1];
+ Palette[0] = Color.Black;
+ for (int i = 1; i <= colorCount; i++)
+ {
+ Palette[i] = new Color(reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
+ }
+ }
+
+ Width = reader.ReadInt16();
+ Height = reader.ReadInt16();
+
+ // Read the image data, which might be compressed.
+ byte[] data = new byte[Width * Height * (BitsPerPixel / 8)];
+ if (flags.HasFlag(Flags.Compressed))
+ {
+ Team17Compression.Decompress(reader, ref data);
+ }
+ else
+ {
+ data = reader.ReadBytes(data.Length);
+ }
+ Data = data;
+ }
+ }
+
+ ///
+ /// Loads the data from the given file.
+ ///
+ /// The name of the file to load the data from.
+ public void Load(string fileName)
+ {
+ using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ Load(stream);
+ }
+ }
+
+ // ---- ENUMERATIONS -------------------------------------------------------------------------------------------
+
+ [Flags]
+ private enum Flags
+ {
+ Compressed = 1 << 6,
+ Palettized = 1 << 7
+ }
}
}
diff --git a/src/Syroot.Worms/Syroot.Worms.csproj b/src/Syroot.Worms/Syroot.Worms.csproj
index a5ed3fc..8d2376b 100644
--- a/src/Syroot.Worms/Syroot.Worms.csproj
+++ b/src/Syroot.Worms/Syroot.Worms.csproj
@@ -1,21 +1,35 @@
- netcoreapp1.1
-
-
-
- bin\Release\netcoreapp1.1\Syroot.Worms.xml
+ .NET library to load and modify file formats of Team17 Worms games.
+ MIT
+ Syroot.Worms
+ Worms
+ Syroot
+ 0.1.0
+
+ Syroot.Worms
+ worms;team17
+ Initial alpha release.
+ https://raw.githubusercontent.com/Syroot/Worms/master/res/Logo.png
+ https://github.com/Syroot/Worms
+ https://raw.githubusercontent.com/Syroot/Worms/master/LICENSE
+ git
+ https://github.com/Syroot/Worms
+
+ netstandard1.6
+ true
+
+
+
+
+
-
-
-
-
\ No newline at end of file