diff --git a/IPFBrowser/Extensions.cs b/IPFBrowser/Extensions.cs
new file mode 100644
index 0000000..a006cd7
--- /dev/null
+++ b/IPFBrowser/Extensions.cs
@@ -0,0 +1,139 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace IPFBrowser
+{
+ ///
+ /// Extensions for BinaryReader and BinaryWriter to make working with
+ /// IES files easier.
+ ///
+ public static class BinaryReaderWriterExtensions
+ {
+ private const int XorKey = 1;
+
+ ///
+ /// XORs buffer and returns it as a string in the given encoding.
+ ///
+ /// Buffer to XOR.
+ private static void XorBuffer(ref byte[] buffer)
+ {
+ for (var i = 0; i < buffer.Length; ++i)
+ {
+ if (buffer[i] == 0)
+ break;
+
+ buffer[i] = (byte)(buffer[i] ^ XorKey);
+ }
+ }
+
+ ///
+ /// Reads ushort-length-prefixed, XORed UTF8 string from reader and
+ /// returns it.
+ ///
+ ///
+ ///
+ public static string ReadXoredLpString(this BinaryReader reader)
+ {
+ var length = reader.ReadUInt16();
+ return ReadXoredFixedString(reader, length);
+ }
+
+ ///
+ /// Reads XORed UTF8 string with given length from reader and
+ /// returns it.
+ ///
+ ///
+ ///
+ ///
+ public static string ReadXoredFixedString(this BinaryReader reader, int length)
+ {
+ if (length <= 0)
+ return "";
+
+ var buffer = reader.ReadBytes(length);
+ XorBuffer(ref buffer);
+ var index = Array.IndexOf(buffer, (byte)0);
+
+ if (index != -1)
+ length = index;
+
+ return Encoding.UTF8.GetString(buffer, 0, length);
+ }
+
+ ///
+ /// Reads XORed UTF8 string with given length from reader and
+ /// returns it.
+ ///
+ ///
+ ///
+ ///
+ public static string ReadFixedString(this BinaryReader reader, int length)
+ {
+ if (length <= 0)
+ return "";
+
+ var buffer = reader.ReadBytes(length);
+ var index = Array.IndexOf(buffer, (byte)0);
+
+ if (index != -1)
+ length = index;
+
+ return Encoding.UTF8.GetString(buffer, 0, length);
+ }
+
+ ///
+ /// Writes UTF8 string to the writer, prefixed with a length.
+ /// The string is XORed.
+ ///
+ ///
+ ///
+ ///
+ public static void WriteXoredLpString(this BinaryWriter writer, string value)
+ {
+ var length = Encoding.UTF8.GetByteCount(value);
+ writer.Write((ushort)length);
+ WriteXoredFixedString(writer, value, length);
+ }
+
+ ///
+ /// Writes UTF8 string with a fixed length to the writer. String
+ /// is cut off if it's to long and extended with null bytes if
+ /// too short. The actual string is XORed.
+ ///
+ ///
+ ///
+ ///
+ public static void WriteXoredFixedString(this BinaryWriter writer, string value, int length)
+ {
+ var buffer = Encoding.UTF8.GetBytes(value);
+ var writeLength = (buffer.Length > length ? length : buffer.Length);
+
+ XorBuffer(ref buffer);
+
+ writer.Write(buffer, 0, writeLength);
+
+ for (; writeLength < length; ++writeLength)
+ writer.Write((byte)0);
+ }
+
+ ///
+ /// Writes UTF8 string with a fixed length to the writer. String
+ /// is cut off if it's to long and extended with null bytes if
+ /// too short.
+ ///
+ ///
+ ///
+ ///
+ public static void WriteFixedString(this BinaryWriter writer, string value, int length)
+ {
+ var buffer = Encoding.UTF8.GetBytes(value);
+ var writeLength = (buffer.Length > length ? length : buffer.Length);
+
+ writer.Write(buffer, 0, writeLength);
+
+ for (; writeLength < length; ++writeLength)
+ writer.Write((byte)0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/IPFBrowser/FileFormats/IES/IesFile.cs b/IPFBrowser/FileFormats/IES/IesFile.cs
index b69b309..714718e 100644
--- a/IPFBrowser/FileFormats/IES/IesFile.cs
+++ b/IPFBrowser/FileFormats/IES/IesFile.cs
@@ -14,7 +14,10 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text;
+using System.Windows.Forms;
+using IPFBrowser;
namespace IPFBrowser.FileFormats.IES
{
@@ -24,7 +27,11 @@ public class IesFile : IDisposable
private BinaryReader _reader;
private byte _xorKey;
- public List Columns { get; private set; }
+ private const int HeaderNameLengths = 0x40;
+ private const int ColumnSize = 136;
+ private const int SizesPos = (2 * HeaderNameLengths + 2 * sizeof(short));
+
+ public List Columns { get; private set; }
public IesHeader Header { get; private set; }
public List Rows { get; private set; }
@@ -73,8 +80,9 @@ private void ReadColumns()
item.Name = this.DecryptString(_reader.ReadBytes(0x40), null);
item.Name2 = this.DecryptString(_reader.ReadBytes(0x40), null);
item.Type = (ColumnType)_reader.ReadUInt16();
- _reader.ReadUInt32();
- item.Position = _reader.ReadUInt16();
+ item.Access = (PropertyAccess)_reader.ReadUInt16();
+ item.Sync = _reader.ReadUInt16();
+ item.Position = _reader.ReadUInt16();
// Duplicates
var old = item.Name;
@@ -88,14 +96,16 @@ private void ReadColumns()
private void ReadHeader()
{
- this.Header = new IesHeader();
+ this.Header = new IesHeader();
this.Header.Name = Encoding.UTF8.GetString(_reader.ReadBytes(0x80));
- _reader.ReadUInt32();
- this.Header.DataOffset = _reader.ReadUInt32();
+ this.Header.Version = _reader.ReadUInt16();
+ _reader.ReadUInt16(); // padding
+ this.Header.DataOffset = _reader.ReadUInt32();
this.Header.ResourceOffset = _reader.ReadUInt32();
this.Header.FileSize = _reader.ReadUInt32();
- _reader.ReadUInt16();
- this.Header.RowCount = _reader.ReadUInt16();
+ this.Header.UseClassId = (_reader.ReadByte() != 0);
+ _reader.ReadByte(); // padding
+ this.Header.RowCount = _reader.ReadUInt16();
this.Header.ColumnCount = _reader.ReadUInt16();
this.Header.NumberColumnCount = _reader.ReadUInt16();
this.Header.StringColumnCount = _reader.ReadUInt16();
@@ -109,11 +119,14 @@ private void ReadRows()
this.Rows = new List();
for (int i = 0; i < this.Header.RowCount; ++i)
{
- _reader.ReadUInt32();
- var count = _reader.ReadUInt16();
- _reader.ReadBytes(count);
+ var item = new IesRow();
- var item = new IesRow();
+ item.ClassId = _reader.ReadInt32();
+ item.ClassName = _reader.ReadXoredLpString();
+ //var count = _reader.ReadUInt16();
+ //_reader.ReadBytes(count);
+
+
for (int j = 0; j < this.Columns.Count; ++j)
{
var column = this.Columns[j];
@@ -121,20 +134,7 @@ private void ReadRows()
if (column.IsNumber)
{
var nan = _reader.ReadSingle();
- var maxValue = uint.MaxValue;
- try
- {
- maxValue = (uint)nan;
- }
- catch
- {
- nan = float.NaN;
- }
-
- if (Math.Abs((float)(nan - maxValue)) < float.Epsilon)
- item.Add(column.Name, maxValue);
- else
- item.Add(column.Name, nan);
+ item.Add(column.Name, nan);
}
else
{
@@ -151,13 +151,122 @@ private void ReadRows()
_reader.BaseStream.Seek((long)this.Header.StringColumnCount, SeekOrigin.Current);
}
}
- }
+ ///
+ /// Saves this instance's data to IES file.
+ ///
+ ///
+ public byte[] ToBytes()
+ {
+ var columns = this.Columns.ToList();
+ var sortedColumns = columns.OrderBy(a => a.IsNumber ? 0 : 1).ThenBy(a => a.Position);
+ var rows = this.Rows;
+
+ var rowCount = rows.Count;
+ var colCount = columns.Count;
+ var numberColCount = columns.Count(a => a.IsNumber);
+ var stringColCount = colCount - numberColCount;
+
+ MemoryStream ms = new MemoryStream();
+
+ using (var bw = new BinaryWriter(ms))
+ {
+ bw.WriteFixedString(this.Header.Name, HeaderNameLengths * 2);
+ bw.Write((ushort)this.Header.Version);
+ bw.Write((ushort)0); // padding
+ bw.Write((uint)this.Header.DataOffset);
+ bw.Write((uint)this.Header.ResourceOffset);
+ bw.Write((uint)this.Header.FileSize);
+ bw.Write(this.Header.UseClassId ? (byte)1 : (byte)0);
+ bw.Write((byte)0); // padding
+ bw.Write((ushort)rowCount);
+ bw.Write((ushort)colCount);
+ bw.Write((ushort)numberColCount);
+ bw.Write((ushort)stringColCount);
+ bw.Write((ushort)0); // padding
+
+ foreach (var column in columns)
+ {
+ bw.WriteXoredFixedString(column.Name, HeaderNameLengths);
+ bw.WriteXoredFixedString(column.Name2, HeaderNameLengths);
+ bw.Write((ushort)column.Type);
+ bw.Write((ushort)column.Access);
+ bw.Write((ushort)column.Sync);
+ bw.Write((ushort)column.Position);
+ }
+
+ var rowsStart = bw.BaseStream.Position;
+ foreach (var row in rows)
+ {
+ // Find the ClassId and ClassName
+ // If these are part of the table, we write these instead of whatever
+ // values we might have here, in case the user changed them
+ if (row.TryGetValue("ClassID", out var classId))
+ {
+ bw.Write((int)(float)classId);
+ }
+ else
+ {
+ bw.Write(row.ClassId);
+ }
+
+ if (row.TryGetValue("ClassName", out var className))
+ {
+ bw.WriteXoredLpString((String)className);
+ }
+ else
+ {
+ bw.WriteXoredLpString(row.ClassName ?? "");
+ }
+
+ foreach (var column in sortedColumns)
+ {
+ if (!row.TryGetValue(column.Name, out var value))
+ {
+ if (column.IsNumber)
+ bw.Write(0f);
+ else
+ bw.Write((ushort)0);
+ }
+ else
+ {
+ if (column.IsNumber)
+ bw.Write((float)value);
+ else
+ bw.WriteXoredLpString((string)value);
+ }
+ }
+
+ foreach (var column in sortedColumns.Where(a => !a.IsNumber))
+ {
+ if (row.UseScr.TryGetValue(column.Name, out var value))
+ bw.Write(value ? (byte)1 : (byte)0);
+ else
+ bw.Write((byte)0);
+ }
+ }
+
+ this.Header.DataOffset = (uint)(columns.Count * ColumnSize);
+ this.Header.ResourceOffset = (uint)(bw.BaseStream.Position - rowsStart);
+ this.Header.FileSize = (uint)bw.BaseStream.Position;
+
+ bw.BaseStream.Seek(SizesPos, SeekOrigin.Begin);
+ bw.Write((uint)this.Header.DataOffset);
+ bw.Write((uint)this.Header.ResourceOffset);
+ bw.Write((uint)this.Header.FileSize);
+ bw.BaseStream.Seek(0, SeekOrigin.End);
+ }
+
+ return ms.ToArray();
+ }
+ }
public class IesHeader
{
- public uint DataOffset { get; set; }
+ public int Version { get; set; }
+ public uint DataOffset { get; set; }
public uint ResourceOffset { get; set; }
public uint FileSize { get; set; }
+ public bool UseClassId { get; set; }
public string Name { get; set; }
public ushort ColumnCount { get; set; }
public ushort RowCount { get; set; }
@@ -171,8 +280,9 @@ public class IesColumn : IComparable
public string Name2 { get; set; }
public ColumnType Type { get; set; }
public ushort Position { get; set; }
-
- public bool IsNumber { get { return (this.Type == ColumnType.Float); } }
+ public PropertyAccess Access { get; set; } = PropertyAccess.SP;
+ public int Sync { get; set; }
+ public bool IsNumber { get { return (this.Type == ColumnType.Float); } }
public int CompareTo(IesColumn other)
{
@@ -193,9 +303,21 @@ public enum ColumnType
String2
}
- public class IesRow : Dictionary
+ public enum PropertyAccess : byte
+ {
+ EP,
+ CP,
+ VP,
+ SP,
+ CT,
+ }
+
+ public class IesRow : Dictionary
{
- public float GetFloat(string name)
+ public int ClassId { get; set; }
+ public string ClassName { get; set; }
+ public Dictionary UseScr { get; } = new Dictionary();
+ public float GetFloat(string name)
{
if (!ContainsKey(name))
throw new ArgumentException("Unknown field: " + name);
diff --git a/IPFBrowser/FileFormats/IPF/Ipf.cs b/IPFBrowser/FileFormats/IPF/Ipf.cs
index e46630a..177d714 100644
--- a/IPFBrowser/FileFormats/IPF/Ipf.cs
+++ b/IPFBrowser/FileFormats/IPF/Ipf.cs
@@ -11,10 +11,16 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+using IPFBrowser.FileFormats.IES;
+using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+using System.Windows.Forms;
+using System.Xml.Linq;
namespace IPFBrowser.FileFormats.IPF
{
@@ -24,16 +30,16 @@ public class Ipf
private readonly Stream _stream;
private readonly BinaryReader _br;
- public string FilePath { get; private set; }
+ public string FilePath { get; private set; }
public List Files { get; private set; }
public IpfFooter Footer { get; private set; }
public Ipf(string filePath)
{
_stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
- _br = new BinaryReader(_stream);
+ _br = new BinaryReader(_stream);
- this.FilePath = filePath;
+ this.FilePath = filePath;
this.Load();
}
@@ -44,7 +50,7 @@ public void Close()
if (_br != null)
_br.Dispose();
- }
+ }
public void Load()
{
@@ -52,14 +58,14 @@ public void Load()
this.Footer = new IpfFooter();
this.Footer.FileCount = _br.ReadUInt16();
- var fileTableOffset = _br.ReadUInt32();
- _br.ReadUInt16();
- _br.ReadUInt32();
- _br.ReadUInt32(); // compression
- this.Footer.PatchVersion = _br.ReadUInt32();
+ this.Footer.FileTableOffset = _br.ReadUInt32();
+ this.Footer.Val1 = _br.ReadUInt16();
+ this.Footer.Val2 = _br.ReadUInt32();
+ this.Footer.Compression = _br.ReadUInt32();
+ this.Footer.PatchVersion = _br.ReadUInt32();
this.Footer.NewVersion = _br.ReadUInt32();
- _stream.Position = fileTableOffset;
+ _stream.Position = this.Footer.FileTableOffset;
this.Files = new List();
for (int i = 0; i < this.Footer.FileCount; i++)
@@ -67,7 +73,7 @@ public void Load()
var ipfFile = new IpfFile(this);
var pathLength = _br.ReadUInt16();
- _br.ReadUInt32(); // crc32
+ ipfFile.Checksum = _br.ReadUInt32();
ipfFile.SizeCompressed = _br.ReadUInt32();
ipfFile.SizeUncompressed = _br.ReadUInt32();
ipfFile.Offset = _br.ReadUInt32();
@@ -78,11 +84,122 @@ public void Load()
var path = new string(_br.ReadChars(pathLength));
ipfFile.Path = path.Replace("\\", "/");
ipfFile.FullPath = Path.Combine(ipfFile.PackFileName, path).Replace("\\", "/");
-
+
this.Files.Add(ipfFile);
}
}
+ public bool Save(string filePath)
+ {
+ var tempPath = Path.GetDirectoryName(filePath) + "\\~" + Path.GetFileName(filePath);
+
+ if (File.Exists(tempPath))
+ {
+ File.Delete(tempPath);
+ }
+
+ try
+ {
+ var outputStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
+ var bw = new BinaryWriter(outputStream);
+
+ uint currentPosition = 0;
+
+ foreach (var file in this.Files)
+ {
+ if (!file.isModified)
+ {
+ bw.Write(ReadData(file.Offset, (int)file.SizeCompressed));
+ bw.Flush();
+
+ // update the offset for use in writing the file table later, nothing else needs to be changed
+ file.Offset = currentPosition;
+ currentPosition += file.SizeCompressed;
+ }
+ else
+ {
+ file.SizeUncompressed = (uint)file.GetData().Length;
+
+ var compressedData = file.Compress();
+ file.SizeCompressed = (uint)compressedData.Length;
+ file.Checksum = CRC32.crc32(0, compressedData);
+
+ bw.Write(compressedData);
+ bw.Flush();
+
+ file.Offset = currentPosition;
+ currentPosition += file.SizeCompressed;
+ }
+ }
+
+ IpfFooter newFooter = new IpfFooter();
+ newFooter.FileCount = (ushort)this.Files.Count;
+ newFooter.FileTableOffset = currentPosition;
+ newFooter.Val1 = this.Footer.Val1;
+ newFooter.Val2 = this.Footer.Val2;
+ newFooter.Compression = this.Footer.Compression;
+ newFooter.PatchVersion = this.Footer.PatchVersion;
+ newFooter.NewVersion = this.Footer.NewVersion;
+
+ // Now we write the file table
+
+ foreach (var file in this.Files)
+ {
+ bw.Write((ushort)file.Path.Length);
+ bw.Write((uint)file.Checksum);
+ bw.Write((uint)file.SizeCompressed);
+ bw.Write((uint)file.SizeUncompressed);
+ bw.Write((uint)file.Offset);
+ bw.Write((ushort)file.PackFileName.Length);
+ bw.WriteFixedString(file.PackFileName, file.PackFileName.Length);
+ bw.WriteFixedString(file.Path, file.Path.Length);
+ bw.Flush();
+ }
+
+ // Finally we write the footer
+
+ bw.Write((ushort)newFooter.FileCount);
+ bw.Write((uint)newFooter.FileTableOffset);
+ bw.Write((ushort)newFooter.Val1);
+ bw.Write((uint)newFooter.Val2);
+ bw.Write((uint)newFooter.Compression);
+ bw.Write((uint)newFooter.PatchVersion);
+ bw.Write((uint)newFooter.NewVersion);
+ bw.Flush();
+ bw.Close();
+
+ if (filePath == this.FilePath)
+ {
+ // Overwriting the open file, have to reopen the file
+ _br.Close();
+ _stream.Close();
+ }
+
+ if (File.Exists(filePath))
+ {
+ File.Delete(filePath);
+ }
+ File.Move(tempPath, filePath);
+
+ return filePath == this.FilePath;
+ }
+ catch (IOException ex)
+ {
+ MessageBox.Show("Cannot save to this file. This file may be open in another application.");
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Unable to save the file");
+ }
+
+ if (File.Exists(tempPath))
+ {
+ File.Delete(tempPath);
+ }
+
+ return false;
+ }
+
public byte[] ReadData(long offset, int length)
{
byte[] data;
@@ -99,7 +216,7 @@ public byte[] ReadData(long offset, int length)
public class IpfFile
{
- private readonly string[] _noCompression = new[] { ".jpg", ".jpg", ".fsb", ".mp3" };
+ private readonly string[] _noCompression = new[] { ".jpg", ".jpeg", ".fsb", ".mp3" };
public Ipf Ipf { get; set; }
public string PackFileName { get; set; }
@@ -108,24 +225,37 @@ public class IpfFile
public uint Offset { get; set; }
public uint SizeCompressed { get; set; }
public uint SizeUncompressed { get; set; }
+ public uint Checksum { get; set; }
+
+ public bool isModified;
- public IpfFile(Ipf ipf)
+ public byte[] content;
+
+ public IpfFile(Ipf ipf)
{
this.Ipf = ipf;
+ isModified = false;
}
-
public byte[] GetData()
{
- var ext = System.IO.Path.GetExtension(this.Path);
- var data = this.Ipf.ReadData(this.Offset, (int)this.SizeCompressed);
-
- if (_noCompression.Contains(ext.ToLowerInvariant()))
- return data;
-
- return this.Decompress(data);
- }
+ if (isModified)
+ {
+ return content;
+ }
+ else
+ {
+ var ext = System.IO.Path.GetExtension(this.Path);
+ var data = this.Ipf.ReadData(this.Offset, (int)this.SizeCompressed);
+
+ if (_noCompression.Contains(ext.ToLowerInvariant()))
+ {
+ return data;
+ }
+ return Decompress(data);
+ }
+ }
- private byte[] Decompress(byte[] data)
+ private byte[] Decompress(byte[] data)
{
if (this.Ipf.Footer.NewVersion > 11000 || this.Ipf.Footer.NewVersion == 0)
{
@@ -141,13 +271,122 @@ private byte[] Decompress(byte[] data)
return msOut.ToArray();
}
}
- }
- public class IpfFooter
+ public byte[] Compress()
+ {
+ if (!isModified)
+ {
+ // data is already compressed, just return the data
+ return this.Ipf.ReadData(this.Offset, (int)this.SizeCompressed);
+ }
+
+ var ext = System.IO.Path.GetExtension(this.Path);
+ if (_noCompression.Contains(ext.ToLowerInvariant()))
+ {
+ // does not require compression or encryption
+ return content;
+ }
+
+ byte[] bytes = null;
+
+ using (var ms = new MemoryStream())
+ {
+ using (var deflate = new DeflateStream(ms, CompressionMode.Compress, true))
+ {
+ deflate.Write(content, 0, content.Length);
+ }
+
+ bytes = ms.ToArray();
+ }
+
+ byte[] encryptedBytes = null;
+
+ if (this.Ipf.Footer.NewVersion > 11000 || this.Ipf.Footer.NewVersion == 0)
+ {
+ var pkw = new PkwareTraditionalEncryptionData("ofO1a0ueXA? [\xFFs h %?");
+ encryptedBytes = pkw.Encrypt(bytes, bytes.Length);
+ }
+
+ return encryptedBytes;
+ }
+ }
+
+
+ public static class CRC32
+ {
+ static readonly uint[] crc32_tab = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ };
+
+
+ ///
+ /// Calculate the crc32 checksum of the given memory block.
+ ///
+ /// The start value for the crc
+ /// Pointer to the memory block
+ /// Number of bytes
+ public static unsafe uint crc32(uint crc, byte[] buf)
+ {
+ crc = crc ^ ~0U; //0xFFFFFFFF
+ foreach (byte b in buf)
+ crc = crc32_tab[(crc ^ b) & 0xFF] ^ (crc >> 8);
+
+ return crc ^ ~0U; //0xFFFFFFFF
+ }
+ }
+
+ public class IpfFooter
{
public ushort FileCount { get; set; }
public uint NewVersion { get; set; }
public uint PatchVersion { get; set; }
- }
+ public uint FileTableOffset { get; set; }
+ public uint Val1 { get; set; }
+ public uint Val2 { get; set; }
+ public uint Compression { get; set; }
+
+ }
}
diff --git a/IPFBrowser/FileFormats/IPF/PkwareTraditionalEncryptionData.cs b/IPFBrowser/FileFormats/IPF/PkwareTraditionalEncryptionData.cs
index 235a74a..a1ea394 100644
--- a/IPFBrowser/FileFormats/IPF/PkwareTraditionalEncryptionData.cs
+++ b/IPFBrowser/FileFormats/IPF/PkwareTraditionalEncryptionData.cs
@@ -60,9 +60,16 @@ public byte[] Encrypt(byte[] plainText, int length)
var cipherText = new byte[length];
for (int i = 0; i < length; i++)
{
- byte C = plainText[i];
- cipherText[i] = (byte)(plainText[i] ^ MagicByte);
- UpdateKeys(C);
+ if ((i % 2) != 0)
+ {
+ cipherText[i] = plainText[i];
+ }
+ else
+ {
+ byte C = plainText[i];
+ cipherText[i] = (byte)(plainText[i] ^ MagicByte);
+ UpdateKeys(C);
+ }
}
return cipherText;
}
diff --git a/IPFBrowser/FrmMain.Designer.cs b/IPFBrowser/FrmMain.Designer.cs
index 9de97bf..ca0a7b5 100644
--- a/IPFBrowser/FrmMain.Designer.cs
+++ b/IPFBrowser/FrmMain.Designer.cs
@@ -28,389 +28,425 @@ protected override void Dispose(bool disposing)
///
private void InitializeComponent()
{
- this.components = new System.ComponentModel.Container();
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain));
- this.SplMain = new System.Windows.Forms.SplitContainer();
- this.TreeFolders = new System.Windows.Forms.TreeView();
- this.imageList1 = new System.Windows.Forms.ImageList(this.components);
- this.SplFiles = new System.Windows.Forms.SplitContainer();
- this.LstFiles = new System.Windows.Forms.ListView();
- this.GridPreview = new System.Windows.Forms.DataGridView();
- this.PnlImagePreview = new System.Windows.Forms.Panel();
- this.ImgPreview = new System.Windows.Forms.PictureBox();
- this.TxtPreview = new ScintillaNET.Scintilla();
- this.LblPreview = new System.Windows.Forms.Label();
- this.OfdIpfFile = new System.Windows.Forms.OpenFileDialog();
- this.StatusStrip = new System.Windows.Forms.StatusStrip();
- this.LblVersion = new System.Windows.Forms.ToolStripStatusLabel();
- this.LblFileName = new System.Windows.Forms.ToolStripStatusLabel();
- this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
- this.menuItem1 = new System.Windows.Forms.MenuItem();
- this.BtnMenuOpen = new System.Windows.Forms.MenuItem();
- this.BtnExit = new System.Windows.Forms.MenuItem();
- this.menuItem3 = new System.Windows.Forms.MenuItem();
- this.BtnAbout = new System.Windows.Forms.MenuItem();
- this.SavExtractFile = new System.Windows.Forms.SaveFileDialog();
- this.FbdExtractPack = new Ookii.Dialogs.VistaFolderBrowserDialog();
- this.toolStrip1 = new System.Windows.Forms.ToolStrip();
- this.BtnOpen = new System.Windows.Forms.ToolStripButton();
- this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
- this.BtnExtractClient = new System.Windows.Forms.ToolStripButton();
- this.BtnExtractPack = new System.Windows.Forms.ToolStripButton();
- this.BtnExtractFile = new System.Windows.Forms.ToolStripButton();
- this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
- this.BtnPreview = new System.Windows.Forms.ToolStripButton();
- ((System.ComponentModel.ISupportInitialize)(this.SplMain)).BeginInit();
- this.SplMain.Panel1.SuspendLayout();
- this.SplMain.Panel2.SuspendLayout();
- this.SplMain.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.SplFiles)).BeginInit();
- this.SplFiles.Panel1.SuspendLayout();
- this.SplFiles.Panel2.SuspendLayout();
- this.SplFiles.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.GridPreview)).BeginInit();
- this.PnlImagePreview.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.ImgPreview)).BeginInit();
- this.StatusStrip.SuspendLayout();
- this.toolStrip1.SuspendLayout();
- this.SuspendLayout();
- //
- // SplMain
- //
- this.SplMain.Dock = System.Windows.Forms.DockStyle.Fill;
- this.SplMain.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
- this.SplMain.IsSplitterFixed = true;
- this.SplMain.Location = new System.Drawing.Point(0, 41);
- this.SplMain.Name = "SplMain";
- //
- // SplMain.Panel1
- //
- this.SplMain.Panel1.Controls.Add(this.TreeFolders);
- this.SplMain.Panel1MinSize = 250;
- //
- // SplMain.Panel2
- //
- this.SplMain.Panel2.Controls.Add(this.SplFiles);
- this.SplMain.Size = new System.Drawing.Size(964, 535);
- this.SplMain.SplitterDistance = 250;
- this.SplMain.TabIndex = 0;
- //
- // TreeFolders
- //
- this.TreeFolders.Dock = System.Windows.Forms.DockStyle.Fill;
- this.TreeFolders.HideSelection = false;
- this.TreeFolders.ImageIndex = 2;
- this.TreeFolders.ImageList = this.imageList1;
- this.TreeFolders.Location = new System.Drawing.Point(0, 0);
- this.TreeFolders.Name = "TreeFolders";
- this.TreeFolders.PathSeparator = "/";
- this.TreeFolders.SelectedImageIndex = 2;
- this.TreeFolders.Size = new System.Drawing.Size(250, 535);
- this.TreeFolders.TabIndex = 0;
- this.TreeFolders.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeFolders_AfterSelect);
- //
- // imageList1
- //
- this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
- this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
- this.imageList1.Images.SetKeyName(0, "folder_page_white.png");
- this.imageList1.Images.SetKeyName(1, "folder_page.png");
- this.imageList1.Images.SetKeyName(2, "folder.png");
- this.imageList1.Images.SetKeyName(3, "compress.png");
- this.imageList1.Images.SetKeyName(4, "page_white_text.png");
- this.imageList1.Images.SetKeyName(5, "page_white_code.png");
- this.imageList1.Images.SetKeyName(6, "page_white.png");
- this.imageList1.Images.SetKeyName(7, "image.png");
- this.imageList1.Images.SetKeyName(8, "table.png");
- //
- // SplFiles
- //
- this.SplFiles.Dock = System.Windows.Forms.DockStyle.Fill;
- this.SplFiles.Location = new System.Drawing.Point(0, 0);
- this.SplFiles.Name = "SplFiles";
- this.SplFiles.Orientation = System.Windows.Forms.Orientation.Horizontal;
- //
- // SplFiles.Panel1
- //
- this.SplFiles.Panel1.Controls.Add(this.LstFiles);
- //
- // SplFiles.Panel2
- //
- this.SplFiles.Panel2.Controls.Add(this.GridPreview);
- this.SplFiles.Panel2.Controls.Add(this.PnlImagePreview);
- this.SplFiles.Panel2.Controls.Add(this.TxtPreview);
- this.SplFiles.Panel2.Controls.Add(this.LblPreview);
- this.SplFiles.Size = new System.Drawing.Size(710, 535);
- this.SplFiles.SplitterDistance = 231;
- this.SplFiles.TabIndex = 0;
- //
- // LstFiles
- //
- this.LstFiles.Dock = System.Windows.Forms.DockStyle.Fill;
- this.LstFiles.HideSelection = false;
- this.LstFiles.Location = new System.Drawing.Point(0, 0);
- this.LstFiles.MultiSelect = false;
- this.LstFiles.Name = "LstFiles";
- this.LstFiles.Size = new System.Drawing.Size(710, 231);
- this.LstFiles.SmallImageList = this.imageList1;
- this.LstFiles.TabIndex = 0;
- this.LstFiles.UseCompatibleStateImageBehavior = false;
- this.LstFiles.View = System.Windows.Forms.View.List;
- this.LstFiles.SelectedIndexChanged += new System.EventHandler(this.LstFiles_SelectedIndexChanged);
- //
- // GridPreview
- //
- this.GridPreview.AllowUserToDeleteRows = false;
- this.GridPreview.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
- this.GridPreview.Location = new System.Drawing.Point(456, 25);
- this.GridPreview.Name = "GridPreview";
- this.GridPreview.ReadOnly = true;
- this.GridPreview.Size = new System.Drawing.Size(240, 150);
- this.GridPreview.TabIndex = 6;
- //
- // PnlImagePreview
- //
- this.PnlImagePreview.AutoScroll = true;
- this.PnlImagePreview.Controls.Add(this.ImgPreview);
- this.PnlImagePreview.Location = new System.Drawing.Point(239, 11);
- this.PnlImagePreview.Name = "PnlImagePreview";
- this.PnlImagePreview.Size = new System.Drawing.Size(211, 164);
- this.PnlImagePreview.TabIndex = 5;
- //
- // ImgPreview
- //
- this.ImgPreview.Location = new System.Drawing.Point(0, 0);
- this.ImgPreview.Name = "ImgPreview";
- this.ImgPreview.Size = new System.Drawing.Size(156, 100);
- this.ImgPreview.TabIndex = 4;
- this.ImgPreview.TabStop = false;
- //
- // TxtPreview
- //
- this.TxtPreview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
- this.TxtPreview.Location = new System.Drawing.Point(33, 75);
- this.TxtPreview.Name = "TxtPreview";
- this.TxtPreview.ReadOnly = true;
- this.TxtPreview.ScrollWidth = 100;
- this.TxtPreview.Size = new System.Drawing.Size(200, 100);
- this.TxtPreview.TabIndex = 2;
- this.TxtPreview.UseTabs = false;
- //
- // LblPreview
- //
- this.LblPreview.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.LblPreview.ForeColor = System.Drawing.Color.Silver;
- this.LblPreview.Location = new System.Drawing.Point(27, 11);
- this.LblPreview.Name = "LblPreview";
- this.LblPreview.Size = new System.Drawing.Size(122, 61);
- this.LblPreview.TabIndex = 1;
- this.LblPreview.Text = "Preview";
- this.LblPreview.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
- //
- // OfdIpfFile
- //
- this.OfdIpfFile.Filter = "IPF-files|*.ipf";
- //
- // StatusStrip
- //
- this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.LblVersion,
- this.LblFileName});
- this.StatusStrip.Location = new System.Drawing.Point(0, 576);
- this.StatusStrip.Name = "StatusStrip";
- this.StatusStrip.Size = new System.Drawing.Size(964, 24);
- this.StatusStrip.TabIndex = 3;
- //
- // LblVersion
- //
- this.LblVersion.AutoSize = false;
- this.LblVersion.Name = "LblVersion";
- this.LblVersion.Size = new System.Drawing.Size(118, 19);
- this.LblVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
- //
- // LblFileName
- //
- this.LblFileName.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
- this.LblFileName.BorderStyle = System.Windows.Forms.Border3DStyle.Etched;
- this.LblFileName.Name = "LblFileName";
- this.LblFileName.Size = new System.Drawing.Size(4, 19);
- this.LblFileName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
- //
- // mainMenu1
- //
- this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
- this.menuItem1,
- this.menuItem3});
- //
- // menuItem1
- //
- this.menuItem1.Index = 0;
- this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
- this.BtnMenuOpen,
- this.BtnExit});
- this.menuItem1.Text = "File";
- //
- // BtnMenuOpen
- //
- this.BtnMenuOpen.Index = 0;
- this.BtnMenuOpen.Text = "Open...";
- this.BtnMenuOpen.Click += new System.EventHandler(this.BtnOpen_Click);
- //
- // BtnExit
- //
- this.BtnExit.Index = 1;
- this.BtnExit.Text = "Exit";
- //
- // menuItem3
- //
- this.menuItem3.Index = 1;
- this.menuItem3.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
- this.BtnAbout});
- this.menuItem3.Text = "?";
- //
- // BtnAbout
- //
- this.BtnAbout.Index = 0;
- this.BtnAbout.Text = "About";
- this.BtnAbout.Click += new System.EventHandler(this.BtnAbout_Click);
- //
- // SavExtractFile
- //
- this.SavExtractFile.Filter = "All files|*.*";
- //
- // toolStrip1
- //
- this.toolStrip1.AutoSize = false;
- this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
- this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.BtnOpen,
- this.toolStripSeparator1,
- this.BtnExtractClient,
- this.BtnExtractPack,
- this.BtnExtractFile,
- this.toolStripSeparator2,
- this.BtnPreview});
- this.toolStrip1.Location = new System.Drawing.Point(0, 0);
- this.toolStrip1.Name = "toolStrip1";
- this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
- this.toolStrip1.Size = new System.Drawing.Size(964, 41);
- this.toolStrip1.TabIndex = 1;
- this.toolStrip1.Text = "toolStrip1";
- //
- // BtnOpen
- //
- this.BtnOpen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
- this.BtnOpen.Image = ((System.Drawing.Image)(resources.GetObject("BtnOpen.Image")));
- this.BtnOpen.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.BtnOpen.ImageTransparentColor = System.Drawing.Color.Magenta;
- this.BtnOpen.Name = "BtnOpen";
- this.BtnOpen.Size = new System.Drawing.Size(36, 38);
- this.BtnOpen.Text = "Open IPF file";
- this.BtnOpen.Click += new System.EventHandler(this.BtnOpen_Click);
- //
- // toolStripSeparator1
- //
- this.toolStripSeparator1.Name = "toolStripSeparator1";
- this.toolStripSeparator1.Size = new System.Drawing.Size(6, 41);
- //
- // BtnExtractClient
- //
- this.BtnExtractClient.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
- this.BtnExtractClient.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractClient.Image")));
- this.BtnExtractClient.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.BtnExtractClient.ImageTransparentColor = System.Drawing.Color.Magenta;
- this.BtnExtractClient.Name = "BtnExtractClient";
- this.BtnExtractClient.Size = new System.Drawing.Size(36, 38);
- this.BtnExtractClient.Text = "Extract all client IPFs";
- this.BtnExtractClient.Click += new System.EventHandler(this.BtnExtractClient_Click);
- //
- // BtnExtractPack
- //
- this.BtnExtractPack.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
- this.BtnExtractPack.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractPack.Image")));
- this.BtnExtractPack.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.BtnExtractPack.ImageTransparentColor = System.Drawing.Color.Magenta;
- this.BtnExtractPack.Name = "BtnExtractPack";
- this.BtnExtractPack.Size = new System.Drawing.Size(36, 38);
- this.BtnExtractPack.Text = "Extract open IPF file";
- this.BtnExtractPack.Click += new System.EventHandler(this.BtnExtractPack_Click);
- //
- // BtnExtractFile
- //
- this.BtnExtractFile.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
- this.BtnExtractFile.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractFile.Image")));
- this.BtnExtractFile.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.BtnExtractFile.ImageTransparentColor = System.Drawing.Color.Magenta;
- this.BtnExtractFile.Name = "BtnExtractFile";
- this.BtnExtractFile.Size = new System.Drawing.Size(36, 38);
- this.BtnExtractFile.Text = "Extract selected file";
- this.BtnExtractFile.Click += new System.EventHandler(this.BtnExtractFile_Click);
- //
- // toolStripSeparator2
- //
- this.toolStripSeparator2.Name = "toolStripSeparator2";
- this.toolStripSeparator2.Size = new System.Drawing.Size(6, 41);
- //
- // BtnPreview
- //
- this.BtnPreview.Checked = true;
- this.BtnPreview.CheckOnClick = true;
- this.BtnPreview.CheckState = System.Windows.Forms.CheckState.Checked;
- this.BtnPreview.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
- this.BtnPreview.Image = ((System.Drawing.Image)(resources.GetObject("BtnPreview.Image")));
- this.BtnPreview.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
- this.BtnPreview.ImageTransparentColor = System.Drawing.Color.Magenta;
- this.BtnPreview.Name = "BtnPreview";
- this.BtnPreview.Size = new System.Drawing.Size(36, 38);
- this.BtnPreview.Text = "Show Preview";
- this.BtnPreview.Click += new System.EventHandler(this.BtnPreview_Click);
- //
- // FrmMain
- //
- this.AllowDrop = true;
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(964, 600);
- this.Controls.Add(this.SplMain);
- this.Controls.Add(this.toolStrip1);
- this.Controls.Add(this.StatusStrip);
- this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
- this.Menu = this.mainMenu1;
- this.Name = "FrmMain";
- this.Text = "IPF Browser";
- this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmMain_FormClosing);
- this.DragDrop += new System.Windows.Forms.DragEventHandler(this.FrmMain_DragDrop);
- this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FrmMain_DragEnter);
- this.SplMain.Panel1.ResumeLayout(false);
- this.SplMain.Panel2.ResumeLayout(false);
- ((System.ComponentModel.ISupportInitialize)(this.SplMain)).EndInit();
- this.SplMain.ResumeLayout(false);
- this.SplFiles.Panel1.ResumeLayout(false);
- this.SplFiles.Panel2.ResumeLayout(false);
- ((System.ComponentModel.ISupportInitialize)(this.SplFiles)).EndInit();
- this.SplFiles.ResumeLayout(false);
- ((System.ComponentModel.ISupportInitialize)(this.GridPreview)).EndInit();
- this.PnlImagePreview.ResumeLayout(false);
- ((System.ComponentModel.ISupportInitialize)(this.ImgPreview)).EndInit();
- this.StatusStrip.ResumeLayout(false);
- this.StatusStrip.PerformLayout();
- this.toolStrip1.ResumeLayout(false);
- this.toolStrip1.PerformLayout();
- this.ResumeLayout(false);
- this.PerformLayout();
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain));
+ this.SplMain = new System.Windows.Forms.SplitContainer();
+ this.TreeFolders = new System.Windows.Forms.TreeView();
+ this.imageList1 = new System.Windows.Forms.ImageList(this.components);
+ this.SplFiles = new System.Windows.Forms.SplitContainer();
+ this.LstFiles = new System.Windows.Forms.ListView();
+ this.GridPreview = new System.Windows.Forms.DataGridView();
+ this.PnlImagePreview = new System.Windows.Forms.Panel();
+ this.ImgPreview = new System.Windows.Forms.PictureBox();
+ this.TxtPreview = new ScintillaNET.Scintilla();
+ this.LblPreview = new System.Windows.Forms.Label();
+ this.OfdIpfFile = new System.Windows.Forms.OpenFileDialog();
+ this.SfdIpfFile = new System.Windows.Forms.SaveFileDialog();
+ this.StatusStrip = new System.Windows.Forms.StatusStrip();
+ this.LblVersion = new System.Windows.Forms.ToolStripStatusLabel();
+ this.LblFileName = new System.Windows.Forms.ToolStripStatusLabel();
+ this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
+ this.menuItem1 = new System.Windows.Forms.MenuItem();
+ this.BtnMenuOpen = new System.Windows.Forms.MenuItem();
+ this.BtnMenuSave = new System.Windows.Forms.MenuItem();
+ this.BtnExit = new System.Windows.Forms.MenuItem();
+ this.menuItem3 = new System.Windows.Forms.MenuItem();
+ this.BtnAbout = new System.Windows.Forms.MenuItem();
+ this.SavExtractFile = new System.Windows.Forms.SaveFileDialog();
+ this.FbdExtractPack = new Ookii.Dialogs.VistaFolderBrowserDialog();
+ this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+ this.BtnOpen = new System.Windows.Forms.ToolStripButton();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.BtnExtractClient = new System.Windows.Forms.ToolStripButton();
+ this.BtnExtractPack = new System.Windows.Forms.ToolStripButton();
+ this.BtnExtractFile = new System.Windows.Forms.ToolStripButton();
+ this.BtnSavePack = new System.Windows.Forms.ToolStripButton();
+ this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.BtnPreview = new System.Windows.Forms.ToolStripButton();
+ ((System.ComponentModel.ISupportInitialize)(this.SplMain)).BeginInit();
+ this.SplMain.Panel1.SuspendLayout();
+ this.SplMain.Panel2.SuspendLayout();
+ this.SplMain.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.SplFiles)).BeginInit();
+ this.SplFiles.Panel1.SuspendLayout();
+ this.SplFiles.Panel2.SuspendLayout();
+ this.SplFiles.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.GridPreview)).BeginInit();
+ this.PnlImagePreview.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.ImgPreview)).BeginInit();
+ this.StatusStrip.SuspendLayout();
+ this.toolStrip1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // SplMain
+ //
+ this.SplMain.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.SplMain.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
+ this.SplMain.IsSplitterFixed = true;
+ this.SplMain.Location = new System.Drawing.Point(0, 41);
+ this.SplMain.Name = "SplMain";
+ //
+ // SplMain.Panel1
+ //
+ this.SplMain.Panel1.Controls.Add(this.TreeFolders);
+ this.SplMain.Panel1MinSize = 250;
+ //
+ // SplMain.Panel2
+ //
+ this.SplMain.Panel2.Controls.Add(this.SplFiles);
+ this.SplMain.Size = new System.Drawing.Size(964, 535);
+ this.SplMain.SplitterDistance = 250;
+ this.SplMain.TabIndex = 0;
+ //
+ // TreeFolders
+ //
+ this.TreeFolders.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.TreeFolders.HideSelection = false;
+ this.TreeFolders.ImageIndex = 2;
+ this.TreeFolders.ImageList = this.imageList1;
+ this.TreeFolders.Location = new System.Drawing.Point(0, 0);
+ this.TreeFolders.Name = "TreeFolders";
+ this.TreeFolders.PathSeparator = "/";
+ this.TreeFolders.SelectedImageIndex = 2;
+ this.TreeFolders.Size = new System.Drawing.Size(250, 535);
+ this.TreeFolders.TabIndex = 0;
+ this.TreeFolders.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeFolders_AfterSelect);
+ this.TreeFolders.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TreeFolders_KeyDown);
+ //
+ // imageList1
+ //
+ this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
+ this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
+ this.imageList1.Images.SetKeyName(0, "folder_page_white.png");
+ this.imageList1.Images.SetKeyName(1, "folder_page.png");
+ this.imageList1.Images.SetKeyName(2, "folder.png");
+ this.imageList1.Images.SetKeyName(3, "compress.png");
+ this.imageList1.Images.SetKeyName(4, "page_white_text.png");
+ this.imageList1.Images.SetKeyName(5, "page_white_code.png");
+ this.imageList1.Images.SetKeyName(6, "page_white.png");
+ this.imageList1.Images.SetKeyName(7, "image.png");
+ this.imageList1.Images.SetKeyName(8, "table.png");
+ //
+ // SplFiles
+ //
+ this.SplFiles.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.SplFiles.Location = new System.Drawing.Point(0, 0);
+ this.SplFiles.Name = "SplFiles";
+ this.SplFiles.Orientation = System.Windows.Forms.Orientation.Horizontal;
+ //
+ // SplFiles.Panel1
+ //
+ this.SplFiles.Panel1.Controls.Add(this.LstFiles);
+ //
+ // SplFiles.Panel2
+ //
+ this.SplFiles.Panel2.Controls.Add(this.GridPreview);
+ this.SplFiles.Panel2.Controls.Add(this.PnlImagePreview);
+ this.SplFiles.Panel2.Controls.Add(this.TxtPreview);
+ this.SplFiles.Panel2.Controls.Add(this.LblPreview);
+ this.SplFiles.Size = new System.Drawing.Size(710, 535);
+ this.SplFiles.SplitterDistance = 231;
+ this.SplFiles.TabIndex = 0;
+ //
+ // LstFiles
+ //
+ this.LstFiles.AllowDrop = true;
+ this.LstFiles.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.LstFiles.HideSelection = false;
+ this.LstFiles.Location = new System.Drawing.Point(0, 0);
+ this.LstFiles.MultiSelect = false;
+ this.LstFiles.Name = "LstFiles";
+ this.LstFiles.Size = new System.Drawing.Size(710, 231);
+ this.LstFiles.SmallImageList = this.imageList1;
+ this.LstFiles.TabIndex = 0;
+ this.LstFiles.UseCompatibleStateImageBehavior = false;
+ this.LstFiles.View = System.Windows.Forms.View.List;
+ this.LstFiles.SelectedIndexChanged += new System.EventHandler(this.LstFiles_SelectedIndexChanged);
+ this.LstFiles.DragDrop += new System.Windows.Forms.DragEventHandler(this.LstFiles_DropFile);
+ this.LstFiles.DragEnter += new System.Windows.Forms.DragEventHandler(this.LstFiles_DragEnter);
+ this.LstFiles.KeyDown += new System.Windows.Forms.KeyEventHandler(this.LstFiles_KeyDown);
+ //
+ // GridPreview
+ //
+ this.GridPreview.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ this.GridPreview.Location = new System.Drawing.Point(456, 25);
+ this.GridPreview.Name = "GridPreview";
+ this.GridPreview.Size = new System.Drawing.Size(240, 150);
+ this.GridPreview.TabIndex = 6;
+ this.GridPreview.RowHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridPreview_InsertRow);
+ this.GridPreview.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.GridPreview_ValueChanged);
+ this.GridPreview.UserDeletedRow += new System.Windows.Forms.DataGridViewRowEventHandler(this.GridPreview_DeleteRow);
+ //
+ // PnlImagePreview
+ //
+ this.PnlImagePreview.AutoScroll = true;
+ this.PnlImagePreview.Controls.Add(this.ImgPreview);
+ this.PnlImagePreview.Location = new System.Drawing.Point(239, 11);
+ this.PnlImagePreview.Name = "PnlImagePreview";
+ this.PnlImagePreview.Size = new System.Drawing.Size(211, 164);
+ this.PnlImagePreview.TabIndex = 5;
+ //
+ // ImgPreview
+ //
+ this.ImgPreview.Location = new System.Drawing.Point(0, 0);
+ this.ImgPreview.Name = "ImgPreview";
+ this.ImgPreview.Size = new System.Drawing.Size(156, 100);
+ this.ImgPreview.TabIndex = 4;
+ this.ImgPreview.TabStop = false;
+ //
+ // TxtPreview
+ //
+ this.TxtPreview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.TxtPreview.Location = new System.Drawing.Point(33, 75);
+ this.TxtPreview.Name = "TxtPreview";
+ this.TxtPreview.ScrollWidth = 100;
+ this.TxtPreview.Size = new System.Drawing.Size(200, 100);
+ this.TxtPreview.TabIndex = 2;
+ this.TxtPreview.UseTabs = false;
+ this.TxtPreview.TextChanged += new System.EventHandler(this.TxtPreview_TextChanged);
+ //
+ // LblPreview
+ //
+ this.LblPreview.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.LblPreview.ForeColor = System.Drawing.Color.Silver;
+ this.LblPreview.Location = new System.Drawing.Point(27, 11);
+ this.LblPreview.Name = "LblPreview";
+ this.LblPreview.Size = new System.Drawing.Size(122, 61);
+ this.LblPreview.TabIndex = 1;
+ this.LblPreview.Text = "Preview";
+ this.LblPreview.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // OfdIpfFile
+ //
+ this.OfdIpfFile.Filter = "IPF-files|*.ipf";
+ //
+ // SfdIpfFile
+ //
+ this.SfdIpfFile.Filter = "IPF-files|*.ipf";
+ //
+ // StatusStrip
+ //
+ this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.LblVersion,
+ this.LblFileName});
+ this.StatusStrip.Location = new System.Drawing.Point(0, 576);
+ this.StatusStrip.Name = "StatusStrip";
+ this.StatusStrip.Size = new System.Drawing.Size(964, 24);
+ this.StatusStrip.TabIndex = 3;
+ //
+ // LblVersion
+ //
+ this.LblVersion.AutoSize = false;
+ this.LblVersion.Name = "LblVersion";
+ this.LblVersion.Size = new System.Drawing.Size(118, 19);
+ this.LblVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.LblVersion.Click += new System.EventHandler(this.LblVersion_Click);
+ //
+ // LblFileName
+ //
+ this.LblFileName.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
+ this.LblFileName.BorderStyle = System.Windows.Forms.Border3DStyle.Etched;
+ this.LblFileName.Name = "LblFileName";
+ this.LblFileName.Size = new System.Drawing.Size(4, 19);
+ this.LblFileName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // mainMenu1
+ //
+ this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.menuItem1,
+ this.menuItem3});
+ //
+ // menuItem1
+ //
+ this.menuItem1.Index = 0;
+ this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.BtnMenuOpen,
+ this.BtnMenuSave,
+ this.BtnExit});
+ this.menuItem1.Text = "File";
+ //
+ // BtnMenuOpen
+ //
+ this.BtnMenuOpen.Index = 0;
+ this.BtnMenuOpen.Text = "Open...";
+ this.BtnMenuOpen.Click += new System.EventHandler(this.BtnOpen_Click);
+ //
+ // BtnMenuSave
+ //
+ this.BtnMenuSave.Index = 1;
+ this.BtnMenuSave.Text = "Save As...";
+ this.BtnMenuSave.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // BtnExit
+ //
+ this.BtnExit.Index = 2;
+ this.BtnExit.Text = "Exit";
+ this.BtnExit.Click += new System.EventHandler(this.BtnExit_Click);
+ //
+ // menuItem3
+ //
+ this.menuItem3.Index = 1;
+ this.menuItem3.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.BtnAbout});
+ this.menuItem3.Text = "Help";
+ //
+ // BtnAbout
+ //
+ this.BtnAbout.Index = 0;
+ this.BtnAbout.Text = "About";
+ this.BtnAbout.Click += new System.EventHandler(this.BtnAbout_Click);
+ //
+ // SavExtractFile
+ //
+ this.SavExtractFile.Filter = "All files|*.*";
+ //
+ // toolStrip1
+ //
+ this.toolStrip1.AutoSize = false;
+ this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
+ this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.BtnOpen,
+ this.toolStripSeparator1,
+ this.BtnExtractClient,
+ this.BtnExtractPack,
+ this.BtnExtractFile,
+ this.BtnSavePack,
+ this.toolStripSeparator2,
+ this.BtnPreview});
+ this.toolStrip1.Location = new System.Drawing.Point(0, 0);
+ this.toolStrip1.Name = "toolStrip1";
+ this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
+ this.toolStrip1.Size = new System.Drawing.Size(964, 41);
+ this.toolStrip1.TabIndex = 1;
+ this.toolStrip1.Text = "toolStrip1";
+ //
+ // BtnOpen
+ //
+ this.BtnOpen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnOpen.Image = ((System.Drawing.Image)(resources.GetObject("BtnOpen.Image")));
+ this.BtnOpen.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnOpen.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnOpen.Name = "BtnOpen";
+ this.BtnOpen.Size = new System.Drawing.Size(36, 38);
+ this.BtnOpen.Text = "Open IPF file";
+ this.BtnOpen.Click += new System.EventHandler(this.BtnOpen_Click);
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(6, 41);
+ //
+ // BtnExtractClient
+ //
+ this.BtnExtractClient.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnExtractClient.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractClient.Image")));
+ this.BtnExtractClient.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnExtractClient.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnExtractClient.Name = "BtnExtractClient";
+ this.BtnExtractClient.Size = new System.Drawing.Size(36, 38);
+ this.BtnExtractClient.Text = "Extract all client IPFs";
+ this.BtnExtractClient.Click += new System.EventHandler(this.BtnExtractClient_Click);
+ //
+ // BtnExtractPack
+ //
+ this.BtnExtractPack.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnExtractPack.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractPack.Image")));
+ this.BtnExtractPack.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnExtractPack.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnExtractPack.Name = "BtnExtractPack";
+ this.BtnExtractPack.Size = new System.Drawing.Size(36, 38);
+ this.BtnExtractPack.Text = "Extract open IPF file";
+ this.BtnExtractPack.Click += new System.EventHandler(this.BtnExtractPack_Click);
+ //
+ // BtnExtractFile
+ //
+ this.BtnExtractFile.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnExtractFile.Image = ((System.Drawing.Image)(resources.GetObject("BtnExtractFile.Image")));
+ this.BtnExtractFile.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnExtractFile.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnExtractFile.Name = "BtnExtractFile";
+ this.BtnExtractFile.Size = new System.Drawing.Size(36, 38);
+ this.BtnExtractFile.Text = "Extract selected file";
+ this.BtnExtractFile.Click += new System.EventHandler(this.BtnExtractFile_Click);
+ //
+ // BtnSavePack
+ //
+ this.BtnSavePack.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnSavePack.Image = ((System.Drawing.Image)(resources.GetObject("BtnSavePack.Image")));
+ this.BtnSavePack.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnSavePack.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnSavePack.Name = "BtnSavePack";
+ this.BtnSavePack.Size = new System.Drawing.Size(36, 38);
+ this.BtnSavePack.Text = "Save Modified IPF File";
+ this.BtnSavePack.ToolTipText = "Save Modified IPF File";
+ this.BtnSavePack.Click += new System.EventHandler(this.BtnSave_Click);
+ //
+ // toolStripSeparator2
+ //
+ this.toolStripSeparator2.Name = "toolStripSeparator2";
+ this.toolStripSeparator2.Size = new System.Drawing.Size(6, 41);
+ //
+ // BtnPreview
+ //
+ this.BtnPreview.Checked = true;
+ this.BtnPreview.CheckOnClick = true;
+ this.BtnPreview.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.BtnPreview.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.BtnPreview.Image = ((System.Drawing.Image)(resources.GetObject("BtnPreview.Image")));
+ this.BtnPreview.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
+ this.BtnPreview.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.BtnPreview.Name = "BtnPreview";
+ this.BtnPreview.Size = new System.Drawing.Size(36, 38);
+ this.BtnPreview.Text = "Show Preview";
+ this.BtnPreview.Click += new System.EventHandler(this.BtnPreview_Click);
+ //
+ // FrmMain
+ //
+ this.AllowDrop = true;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(964, 600);
+ this.Controls.Add(this.SplMain);
+ this.Controls.Add(this.toolStrip1);
+ this.Controls.Add(this.StatusStrip);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Menu = this.mainMenu1;
+ this.Name = "FrmMain";
+ this.Text = "IPF Browser";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmMain_FormClosing);
+ this.DragDrop += new System.Windows.Forms.DragEventHandler(this.FrmMain_DragDrop);
+ this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FrmMain_DragEnter);
+ this.SplMain.Panel1.ResumeLayout(false);
+ this.SplMain.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.SplMain)).EndInit();
+ this.SplMain.ResumeLayout(false);
+ this.SplFiles.Panel1.ResumeLayout(false);
+ this.SplFiles.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.SplFiles)).EndInit();
+ this.SplFiles.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.GridPreview)).EndInit();
+ this.PnlImagePreview.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.ImgPreview)).EndInit();
+ this.StatusStrip.ResumeLayout(false);
+ this.StatusStrip.PerformLayout();
+ this.toolStrip1.ResumeLayout(false);
+ this.toolStrip1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
}
- #endregion
+ #endregion
- private System.Windows.Forms.SplitContainer SplMain;
+ private System.Windows.Forms.SplitContainer SplMain;
private System.Windows.Forms.TreeView TreeFolders;
private System.Windows.Forms.SplitContainer SplFiles;
private System.Windows.Forms.ListView LstFiles;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton BtnOpen;
private System.Windows.Forms.OpenFileDialog OfdIpfFile;
- private System.Windows.Forms.ImageList imageList1;
+ private System.Windows.Forms.SaveFileDialog SfdIpfFile;
+ private System.Windows.Forms.ImageList imageList1;
private System.Windows.Forms.StatusStrip StatusStrip;
private System.Windows.Forms.ToolStripStatusLabel LblVersion;
private System.Windows.Forms.ToolStripStatusLabel LblFileName;
@@ -427,12 +463,14 @@ private void InitializeComponent()
private System.Windows.Forms.DataGridView GridPreview;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
private System.Windows.Forms.ToolStripButton BtnExtractPack;
- private System.Windows.Forms.ToolStripButton BtnExtractFile;
+ private System.Windows.Forms.ToolStripButton BtnExtractFile;
+ private System.Windows.Forms.ToolStripButton BtnSavePack;
private System.Windows.Forms.SaveFileDialog SavExtractFile;
private Ookii.Dialogs.VistaFolderBrowserDialog FbdExtractPack;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
private System.Windows.Forms.ToolStripButton BtnExtractClient;
private System.Windows.Forms.ToolStripButton BtnPreview;
- }
+ private System.Windows.Forms.MenuItem BtnMenuSave;
+ }
}
diff --git a/IPFBrowser/FrmMain.cs b/IPFBrowser/FrmMain.cs
index adf5bff..b3f6088 100644
--- a/IPFBrowser/FrmMain.cs
+++ b/IPFBrowser/FrmMain.cs
@@ -24,10 +24,13 @@
using System.Drawing.Text;
using System.IO;
using System.Linq;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
+using static System.Net.Mime.MediaTypeNames;
namespace IPFBrowser
{
@@ -40,6 +43,10 @@ public partial class FrmMain : Form
private Dictionary _fileTypes = new Dictionary();
+ private IpfFile openIpfFile;
+ private bool openTextFile;
+ private IesFile openIesFile;
+
///
/// Initializes form.
///
@@ -80,9 +87,11 @@ public FrmMain(string[] args)
LblPreview.Dock = DockStyle.Fill;
GridPreview.Dock = DockStyle.Fill;
- // Disable extract buttons by default
+ // Disable extract / save buttons by default
+ BtnMenuSave.Enabled = false;
BtnExtractPack.Enabled = false;
- BtnExtractFile.Enabled = false;
+ BtnExtractFile.Enabled = false;
+ BtnSavePack.Enabled = false;
// Hide empty lists
SplMain.Visible = false;
@@ -160,6 +169,11 @@ private void BtnOpen_Click(object sender, EventArgs e)
///
private void Open(string filePath)
{
+ if (_openedIpf != null)
+ {
+ _openedIpf.Close();
+ }
+
if (Path.GetExtension(filePath) == ".ies")
{
this.ResetPreview();
@@ -183,11 +197,15 @@ private void Open(string filePath)
foreach (var iesColumn in iesFile.Columns)
row.Cells[i++].Value = iesRow[iesColumn.Name];
+ row.Tag = iesRow.ClassName;
+
GridPreview.Rows.Add(row);
}
GridPreview.ResumeDrawing();
+ openIesFile = iesFile;
+
GridPreview.Visible = true;
});
@@ -211,7 +229,6 @@ private void Open(string filePath)
try
{
_openedIpf = new Ipf(filePath);
- _openedIpf.Load();
}
catch (IOException)
{
@@ -242,9 +259,11 @@ private void Open(string filePath)
TreeFolders.SelectedNode.Toggle();
}
- // Show lists and enabled pack extract button
- BtnExtractPack.Enabled = true;
- SplMain.Visible = true;
+ // Show lists and enabled pack extract button
+ BtnMenuSave.Enabled = true;
+ BtnExtractPack.Enabled = true;
+ BtnSavePack.Enabled = true;
+ SplMain.Visible = true;
}
///
@@ -286,7 +305,7 @@ private void PopulateTreeView(TreeView treeView, IEnumerable paths, char
{
node = treeView.Nodes.Add(subPathAgg, subPath);
insertedPaths.Add(subPathAgg, node);
- }
+ }
else
{
node = node.Nodes.Add(subPathAgg, subPath);
@@ -313,23 +332,25 @@ private void LstFiles_SelectedIndexChanged(object sender, EventArgs e)
return;
}
- BtnExtractFile.Enabled = true;
+ BtnExtractFile.Enabled = true;
if (BtnPreview.Checked)
Preview();
}
- ///
- /// Called when selected a node in the tree view,
- /// lists files in node's folder in file list.
- ///
- ///
- ///
- private void TreeFolders_AfterSelect(object sender, TreeViewEventArgs e)
+
+ ///
+ /// Called when selected a node in the tree view,
+ /// lists files in node's folder in file list.
+ ///
+ ///
+ ///
+ private void TreeFolders_AfterSelect(object sender, TreeViewEventArgs e)
{
var path = e.Node.FullPath.Replace('\\', '/') + '/';
- LstFiles.BeginUpdate();
+ ResetPreview();
+ LstFiles.BeginUpdate();
LstFiles.Items.Clear();
List paths;
@@ -342,7 +363,10 @@ private void TreeFolders_AfterSelect(object sender, TreeViewEventArgs e)
var lvi = LstFiles.Items.Add(fileName);
//lvi.SubItems.Add("0 Byte");
- lvi.Tag = filePath;
+
+ lvi.Tag = filePath;
+ if (_files.TryGetValue(filePath, out var ipfFile) && ipfFile.isModified)
+ lvi.ForeColor = Color.Blue;
FileFormat fileType;
if (_fileTypes.TryGetValue(ext, out fileType))
@@ -355,18 +379,74 @@ private void TreeFolders_AfterSelect(object sender, TreeViewEventArgs e)
LstFiles.EndUpdate();
}
- ///
- /// Shows preview for selected file.
- ///
- private void Preview()
+ ///
+ /// Key Pressed on TreeFolders pane, used for deleting folders
+ ///
+ ///
+ ///
+ private void TreeFolders_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Delete)
+ {
+ if (TreeFolders.SelectedNode == null)
+ return;
+
+ ResetPreview();
+
+ DeleteFolder(TreeFolders.SelectedNode);
+ }
+ }
+
+
+ ///
+ /// Attempt to delete a folder, its associated subfolders, and files
+ ///
+ ///
+ private void DeleteFolder(TreeNode folder)
+ {
+ TreeNode[] toRemove = new TreeNode[folder.Nodes.Count];
+ folder.Nodes.CopyTo(toRemove, 0);
+
+ foreach (TreeNode subfolder in toRemove)
+ {
+ DeleteFolder(subfolder);
+ }
+
+ // now remove the files
+
+ var path = folder.FullPath.Replace('\\', '/') + '/';
+
+ if (_folders.TryGetValue(path, out var files))
+ {
+ foreach (var file in files)
+ {
+ if (_files.TryGetValue(file, out var ipfFile))
+ {
+ _openedIpf.Files.Remove(ipfFile);
+ }
+ _files.Remove(file);
+ }
+ }
+
+ _folders.Remove(path);
+ TreeFolders.Nodes.Remove(folder);
+ }
+
+
+ ///
+ /// Shows preview for selected file.
+ ///
+ private void Preview()
{
- if (LstFiles.SelectedIndices.Count == 0)
- return;
+ if (LstFiles.SelectedIndices.Count == 0)
+ return;
var selected = LstFiles.SelectedItems[0];
var fileName = (string)selected.Tag;
var ipfFile = _files[fileName];
var ext = Path.GetExtension(fileName).ToLowerInvariant();
+
+ openIpfFile = ipfFile;
var previewType = PreviewType.None;
var lexer = Lexer.Null;
@@ -392,11 +472,10 @@ private void Preview()
Invoke((MethodInvoker)delegate
{
- TxtPreview.ReadOnly = false;
TxtPreview.Text = text;
- TxtPreview.ReadOnly = true;
TxtPreview.Visible = true;
});
+ openTextFile = true;
break;
case PreviewType.Image:
@@ -405,7 +484,7 @@ private void Preview()
Invoke((MethodInvoker)delegate
{
using (var ms = new MemoryStream(imgData))
- ImgPreview.Image = Image.FromStream(ms);
+ ImgPreview.Image = System.Drawing.Image.FromStream(ms);
ImgPreview.Size = ImgPreview.Image.Size;
PnlImagePreview.Visible = true;
});
@@ -473,6 +552,8 @@ private void Preview()
foreach (var iesColumn in iesFile.Columns)
GridPreview.Columns.Add(iesColumn.Name, iesColumn.Name);
+ int index = 0;
+
foreach (var iesRow in iesFile.Rows)
{
var row = new DataGridViewRow();
@@ -482,11 +563,15 @@ private void Preview()
foreach (var iesColumn in iesFile.Columns)
row.Cells[i++].Value = iesRow[iesColumn.Name];
- GridPreview.Rows.Add(row);
+ row.Tag = "" + index++;
+
+ GridPreview.Rows.Add(row);
}
GridPreview.ResumeDrawing();
+ openIesFile = iesFile;
+
GridPreview.Visible = true;
});
break;
@@ -578,7 +663,7 @@ private void Preview()
private void BtnExit_Click(object sender, EventArgs e)
{
Close();
- }
+ }
///
/// Sets lexer and styles for text preview.
@@ -669,7 +754,12 @@ private void BtnAbout_Click(object sender, EventArgs e)
///
private void ResetPreview()
{
- TxtPreview.Visible = false;
+ if (openIpfFile != null && openIpfFile.isModified)
+ SaveIpfFile();
+
+ openTextFile = false;
+ openIesFile = null;
+ TxtPreview.Visible = false;
TxtPreview.Text = "";
PnlImagePreview.Visible = false;
@@ -735,17 +825,18 @@ private void BtnExtractFile_Click(object sender, EventArgs e)
File.WriteAllBytes(filePath, file);
}
- ///
- /// Called when clicking Extract Client button, extracts selected
- /// TOS client to selected destination.
- ///
- ///
- /// Loads data first, followed by patch, to get the latest version
- /// of all files found.
- ///
- ///
- ///
- private void BtnExtractClient_Click(object sender, EventArgs e)
+
+ ///
+ /// Called when clicking Extract Client button, extracts selected
+ /// TOS client to selected destination.
+ ///
+ ///
+ /// Loads data first, followed by patch, to get the latest version
+ /// of all files found.
+ ///
+ ///
+ ///
+ private void BtnExtractClient_Click(object sender, EventArgs e)
{
FbdExtractPack.Description = "Select TOS folder.";
FbdExtractPack.ShowNewFolderButton = false;
@@ -871,5 +962,362 @@ private void ExtractFiles(IEnumerable ipfFiles, string extractPath)
// blocks the main window.
frmProgress.ShowDialog();
}
- }
+
+ ///
+ /// Value changed for Text Preview
+ ///
+ ///
+ ///
+ private void TxtPreview_TextChanged(object sender, System.EventArgs e)
+ {
+ if (openTextFile) {
+ openIpfFile.isModified = true;
+ LstFiles.SelectedItems[0].ForeColor = Color.Blue;
+ }
+ }
+
+
+ ///
+ /// Value changed for Grid Preview
+ ///
+ ///
+ ///
+ private void GridPreview_ValueChanged(object sender, DataGridViewCellEventArgs e)
+ {
+ if (openIesFile == null)
+ return;
+ var newValue = (string)GridPreview[e.ColumnIndex, e.RowIndex].Value;
+ if (e.RowIndex >= openIesFile.Rows.Count)
+ GridPreview_AddRow();
+ var editedRow = openIesFile.Rows[e.RowIndex];
+ var editedCol = openIesFile.Columns[e.ColumnIndex];
+ if (editedCol.IsNumber)
+ {
+ var newFloat = 0f;
+ if (float.TryParse(newValue, out newFloat))
+ {
+ editedRow[editedCol.Name] = float.Parse(newValue);
+ }
+ else
+ {
+ MessageBox.Show("Value must be numeric");
+ GridPreview[e.ColumnIndex, e.RowIndex].Value = editedRow[editedCol.Name].ToString();
+ }
+ }
+ else
+ {
+ editedRow[editedCol.Name] = newValue;
+ }
+
+ openIpfFile.isModified = true;
+ LstFiles.SelectedItems[0].ForeColor = Color.Blue;
+ }
+
+
+ ///
+ /// Inserting a row in Grid Preview
+ /// This is done by right clicking the row header above where you want to insert, which is
+ /// not ideal, this can probably be moved to a proper context menu eventually
+ ///
+ private void GridPreview_InsertRow(object sender, DataGridViewCellMouseEventArgs e)
+ {
+ if (e.Button != MouseButtons.Right)
+ return;
+
+ var afterRow = e.RowIndex;
+ if (afterRow > openIesFile.Rows.Count)
+ return;
+
+ GridPreview.Rows.Insert(afterRow + 1, 1);
+
+ // Some files have auto-generated classnames rather than having them in the file
+ // Need to shift these down to avoid duplicates
+ // For files which contain the Classid / Classname as part of the file these values aren't used.
+ for (int i = afterRow + 1; i < openIesFile.Rows.Count; i++)
+ {
+ openIesFile.Rows[i].ClassId++;
+ openIesFile.Rows[i].ClassName = "ClassName" + openIesFile.Rows[i].ClassId;
+ }
+
+ var newRow = new IesRow();
+ newRow.ClassId = openIesFile.Rows[afterRow].ClassId + 1;
+ newRow.ClassName = "ClassName" + newRow.ClassId;
+
+ openIesFile.Rows.Insert(afterRow + 1, newRow);
+
+ openIpfFile.isModified = true;
+ LstFiles.SelectedItems[0].ForeColor = Color.Blue;
+ }
+
+
+ ///
+ /// Added a row in Grid Preview
+ ///
+ private void GridPreview_AddRow()
+ {
+ var newRow = new IesRow();
+ newRow.ClassId = openIesFile.Rows[openIesFile.Rows.Count - 1].ClassId + 1;
+ newRow.ClassName = "ClassName" + newRow.ClassId;
+
+ openIesFile.Rows.Add(newRow);
+
+ openIpfFile.isModified = true;
+ LstFiles.SelectedItems[0].ForeColor = Color.Blue;
+ }
+
+
+ ///
+ /// Deleted a row in Grid Preview
+ ///
+ ///
+ ///
+ private void GridPreview_DeleteRow(object sender, DataGridViewRowEventArgs e)
+ {
+ if (openIesFile == null)
+ return;
+
+ int deletedIndex = int.Parse((string)e.Row.Tag);
+
+ openIesFile.Rows.RemoveAt(deletedIndex);
+
+ openIpfFile.isModified = true;
+ LstFiles.SelectedItems[0].ForeColor = Color.Blue;
+ }
+
+
+ ///
+ /// Saves changes to an IPF file
+ ///
+ private void SaveIpfFile()
+ {
+ if (openIesFile != null)
+ {
+ openIpfFile.content = openIesFile.ToBytes();
+ return;
+ }
+
+ if (openTextFile)
+ {
+ int byteCount = Encoding.UTF8.GetByteCount(TxtPreview.Text.ToCharArray(), 0, TxtPreview.TextLength);
+ openIpfFile.content = new byte[byteCount];
+ Encoding.UTF8.GetEncoder().GetBytes(TxtPreview.Text.ToCharArray(), 0, TxtPreview.TextLength, openIpfFile.content, 0, true);
+ }
+ }
+
+
+ ///
+ /// Key Pressed on LstFiles window, used for deleting files
+ ///
+ ///
+ ///
+ private void LstFiles_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Delete)
+ {
+ if (LstFiles.SelectedIndices.Count == 0)
+ return;
+
+ foreach (ListViewItem file in LstFiles.SelectedItems)
+ {
+ var fileName = (string)file.Tag;
+ _openedIpf.Files.Remove(_files[fileName]);
+ _files.Remove(fileName);
+
+ var folderPath = TreeFolders.SelectedNode.FullPath.Replace('\\', '/') + '/';
+
+ if (_folders.TryGetValue(folderPath, out var paths))
+ {
+ paths.Remove(fileName);
+ }
+
+ LstFiles.Items.Remove(file);
+ }
+
+ openIpfFile = null;
+ ResetPreview();
+ }
+ }
+
+
+ ///
+ /// Drag Enter method for the LstFiles window
+ ///
+ ///
+ ///
+ private void LstFiles_DragEnter(object sender, DragEventArgs e)
+ {
+ if (TreeFolders.SelectedNode == null) return;
+
+ if (!e.Data.GetDataPresent(DataFormats.FileDrop))
+ return;
+
+ e.Effect = DragDropEffects.Copy;
+ }
+
+
+ ///
+ /// Called when dropping a file in the LstFiles window
+ ///
+ ///
+ ///
+ private void LstFiles_DropFile(object sender, DragEventArgs e)
+ {
+ if (TreeFolders.SelectedNode == null)
+ return;
+
+ if (!e.Data.GetDataPresent(DataFormats.FileDrop))
+ return;
+
+ string[] files = (string[]) e.Data.GetData(DataFormats.FileDrop);
+ if (files.Length > 1)
+ {
+ MessageBox.Show("Please drop only one file at a time");
+ return;
+ }
+
+ var ext = Path.GetExtension(files[0]);
+
+ FileFormat fileType;
+ if (!_fileTypes.TryGetValue(ext, out fileType))
+ {
+ MessageBox.Show("Can't add this type of file");
+ return;
+ }
+
+ var folderPath = TreeFolders.SelectedNode.FullPath.Replace('\\', '/') + "/";
+ var newFilename = Path.GetFileName(files[0]);
+ var fullFileName = folderPath + newFilename;
+
+ if (_files.Keys.Contains(fullFileName))
+ {
+ var isPreviewedFile = BtnPreview.Checked && openIpfFile != null && _files[fullFileName] == openIpfFile;
+
+ if (isPreviewedFile)
+ ResetPreview();
+
+ _files[fullFileName].isModified = true;
+ _files[fullFileName].content = File.ReadAllBytes(files[0]);
+ foreach (ListViewItem item in LstFiles.Items)
+ {
+ if ((string)item.Tag == fullFileName)
+ {
+ item.ForeColor = Color.Blue;
+ }
+ }
+
+ if (isPreviewedFile)
+ Preview();
+
+ return;
+ }
+
+ IpfFile newFile = new IpfFile(_openedIpf);
+ newFile.Path = newFilename;
+ newFile.PackFileName = folderPath;
+ newFile.FullPath = fullFileName;
+ newFile.isModified = true;
+ newFile.content = File.ReadAllBytes(files[0]);
+
+ if (_folders.TryGetValue(folderPath, out var paths))
+ {
+ paths.Add(fullFileName);
+ }
+ _files.Add(fullFileName, newFile);
+ _openedIpf.Files.Add(newFile);
+
+ var lvi = LstFiles.Items.Add(newFilename);
+
+ lvi.Tag = fullFileName;
+ lvi.ForeColor = Color.Blue;
+ lvi.ImageKey = fileType.Icon;
+ }
+
+
+ ///
+ /// Called when clicking Save, shows save dialog and saves the IPF file
+ ///
+ ///
+ ///
+ private void BtnSave_Click(object sender, EventArgs e)
+ {
+ if (openIpfFile != null && openIpfFile.isModified)
+ SaveIpfFile();
+
+ if (SfdIpfFile.ShowDialog() != DialogResult.OK)
+ return;
+
+ var filePath = SfdIpfFile.FileName;
+ var reopenRequired = _openedIpf.Save(filePath);
+
+ if (reopenRequired)
+ {
+ Open(filePath);
+ }
+ }
+
+
+ ///
+ /// Called when the version label is clicked, lets you change the version
+ ///
+ ///
+ ///
+ private void LblVersion_Click(object sender, EventArgs e)
+ {
+ string newVersion = "" + _openedIpf.Footer.NewVersion;
+ if (ShowInputDialog("New Version", ref newVersion) == DialogResult.OK)
+ {
+ if (uint.TryParse(newVersion, out var result))
+ {
+ _openedIpf.Footer.NewVersion = result;
+ LblVersion.Text = "Version " + newVersion;
+ }
+ else
+ {
+ MessageBox.Show("Value must be numeric");
+ }
+ }
+ }
+
+
+ private static DialogResult ShowInputDialog(string title, ref string value)
+ {
+ System.Drawing.Size size = new System.Drawing.Size(200, 70);
+ Form inputBox = new Form();
+
+ inputBox.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+ inputBox.ShowInTaskbar = false;
+ inputBox.StartPosition = FormStartPosition.CenterParent;
+ inputBox.ClientSize = size;
+ inputBox.Text = title;
+
+ System.Windows.Forms.TextBox textBox = new TextBox();
+ textBox.Size = new System.Drawing.Size(size.Width - 10, 23);
+ textBox.Location = new System.Drawing.Point(5, 5);
+ textBox.Text = value;
+ inputBox.Controls.Add(textBox);
+
+ Button okButton = new Button();
+ okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+ okButton.Name = "okButton";
+ okButton.Size = new System.Drawing.Size(75, 23);
+ okButton.Text = "&OK";
+ okButton.Location = new System.Drawing.Point(size.Width - 80 - 80, 39);
+ inputBox.Controls.Add(okButton);
+
+ Button cancelButton = new Button();
+ cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ cancelButton.Name = "cancelButton";
+ cancelButton.Size = new System.Drawing.Size(75, 23);
+ cancelButton.Text = "&Cancel";
+ cancelButton.Location = new System.Drawing.Point(size.Width - 80, 39);
+ inputBox.Controls.Add(cancelButton);
+
+ inputBox.AcceptButton = okButton;
+ inputBox.CancelButton = cancelButton;
+
+ DialogResult result = inputBox.ShowDialog();
+ value = textBox.Text;
+ return result;
+ }
+ }
}
diff --git a/IPFBrowser/FrmMain.resx b/IPFBrowser/FrmMain.resx
index 490ee25..5326875 100644
--- a/IPFBrowser/FrmMain.resx
+++ b/IPFBrowser/FrmMain.resx
@@ -118,14 +118,14 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- 377, 17
+ 331, 17
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA2
- EQAAAk1TRnQBSQFMAgEBCQEAAdABAAHQAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
+ EQAAAk1TRnQBSQFMAgEBCQEAAYABAQGAAQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAATADAAEBAQABCAYAAQwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
@@ -202,76 +202,79 @@
- 237, 17
+ 225, 17
+
+
+ 17, 17
- 487, 17
+ 442, 17
- 597, 17
+ 552, 17
- 854, 17
+ 670, 17
- 990, 17
+ 796, 17
- 17, 17
+ 120, 17
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- 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
+ 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
- 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
+ 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
@@ -310,58 +313,92 @@
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- 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
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAPJSURBVFhHvZfda1tlHMcfmO5u6IUreOe9oLaoF3VYWWWd
+ CHrrjf/AROaGbnOosZO9UfBGYW4Vy9zadCZpwtbi2Jg42ZhsQvWmvlTbpk1OmjRNbNq8v/z8fp8nO6S0
+ Xc5Zgl/4cJ6mz/P7fp+Xc3Ki6nrEFwyOB0Ih8Y+Nic8VAX0NBINyye8PsZYp6U47WKBVxeNxGfZ6x1Bv
+ mynrXDs5c2pmdk5m58KOYX/qwvCwvsZiMbno9fpR01WIDi4jNReel/D8gswvRJrCfuxPwVSWU2ndtixL
+ RkdHLdR91JRvLjsAiy5Eoo5hfwpLL9lsTuKJJf03Q1zy+aKo7SiEHYAzi0Qtx7A/xQCVSlkymVU7BLfj
+ O4ch7ABRJLcw0CkRK6rHcQsohuBK3N8OHkwc8AQ8HhiiwxcI6AEsGltcdEw0Zulxd+/d0yG4EoTtb+sH
+ k3cYPB43VpvLDhBbjMtiPOEY9l/NrOmxW4mrSw9jtbnsACzKPXSDDlKnMRihWJsexmpz2QESKLi0lGwZ
+ 1iGUqwAcnEwutwXWolwFSKaWcYJTbYG1KFcBUukUSLeJlK7pKkD635W2QrkKsLKSaSuUqwB8lLYTyhdw
+ 8RxYXVt7SLL6EZzN5SWXK+Ba0FcqFJxwHmAtm30IcpLPl6RaRoFanQZdH7/rPEAul3NNIY+ZVkQ8/tek
+ 8yMlXR+DTwzPe5TsOq6k95i6DJ8tX9fsAPl8ERRcUSzCHXoO5r9N75PJv/aDA5pfp/fL1MxB2XNacRV2
+ GLuNsgMUCiVQdEQRfUsw10sPceb/JL6QMzeUfPVDHbTnkmfk1VM6wBPGbqPsAMVyWYqlUlNK6Fer6iG2
+ XsSS/xJ9V87eUXLuZwPbk9Z70ntSB9jyHNgBKpWKlFG8GdWKOWlPH1HauBt7/RK4Ft4tZydhXoft6+Fe
+ eeWYkj6swusDSt74XIfZbqyN7ADValWHaEatagJ8FnxTDl9Vcn5GydC0ksHfYTy1nq/x2Xn8zxtWcvIn
+ JXv61Q14PmasjexXMqpWqzWlUcdDb8n738MIJuf+wKxh2sggPhv6W8mnOBM9H6ib8HsWrDuQHfxV1IoG
+ Jt6WQ9cQAkaDf8IYsyZs09wD85eNeRfYCdbdkh0jIyMZvrtxJbgdTvGPBSUUmpCrV27JO1/2yFGc+m9m
+ YcwgYAhtz4/rzHknbPjRwhfGTrAb9LbA3l0fqrjnppILEUM/9ryZOcVXZobgbdIKT4HuvhMqvRcnnvQc
+ Ubfx2QPN2ylO5EnwAuBq9oBnwP9ifl+Nq8nDxtO+xXeAUv8Bm5NRY4qg1uoAAAAASUVORK5CYII=
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAZ3SURBVFhHzZVpTFRXGIYv0ervJtrqD1e0xq3WFREQxK0o
+ uKcucVdUFNxQBqiCa9kURUBmYZsZWUZQUVwLFAZREQTBkc0BkWUYFLWNWFPjj7ffuTMIF29SJZL0Jk+4
+ ufOd93vOueceuP/t9f79e9wOtUdOsBUxxfz3SzCPCZqCd2//hDn28y7WPDvQCkXKLahI9ST2dZli1XZk
+ HR+Pd62fKcGaZxydQAO34UmaBAUnbFEQMq1L3A+2xpNL+1GS4I5b/qP/W4I1v+E3GqVqN9Rc8UVxmIOZ
+ GYTjF8LGOKDolB1qLntDl+iBa77DSeK1uARrnu5liRL1VtRd9YUucgYeRRCRjnQ/s0uwsXxG+HTUpZNE
+ kjuueA7A3286SXz48AG5Mle0PErH2+rf8UZPVGegtTrzq8CyWCbLflV2A9qojfjnXWu7RGtrK1J3DoGx
+ UIPcI+OgPTQW2sM/EnT/VaAsyszxG4nmBxqkegzC6xZju8DLly+R4jEETQWJuBM41USQNe5+JVgWy7x9
+ fAJNMgkp7gPR3FjXLvDixQucZwL5KuTTzs0Pph3Mdv9JOxR+BVgWy7wbMAnGAjXOk0BTQ61QQOM+FIZ7
+ sR8bF52yh3r3WMTvHI14j1GII9jfeI/RUBKqTrBn7LeOtUoaq9w1hiSm85n5QVZouh8HzY5Bnwok7yCB
+ PDkKqHEhwT4j1e5ReJb4C+rMNCQuR3PiKrxMXE2swSsz7J49Y7+xmrb6Rs0KRGweigenHfjM+yemoemu
+ AsnbSaC+k0DSdhLIjUIR+3apeUn4LFqBMdArF4viFdQHNgEWmBrAYWfQt6I1teeW4ayrJYrPOPKZD0Jt
+ YcyTIslNRCDBzRIGbRgVz0Rx+EyURs6Bas9YPIld+AmSgO8hybZATD2HuEYOPnkc9gb3+aSuRrUYUVtH
+ 4GHELD6z6LQ9jLnhSNg2CIbOAueYQM4plETO5tFJf4bacxwqol0ESAL7wSvLAvKnHBTVJqJrOXhrSSKk
+ r6BWH7cQUreRKD07hzLn4GH4DBIIExdQbyOB7BDoqPgRUSZzQsL+n1CucPmIN2ueQc31HORVHGQVJth9
+ NIl4Z3PwJIm2+qrYBZC5j4Euaq4pN8IRRu1JnNsqIqDaSgJZgXhMM9dJnShgPhK9JqJC5szjG9wfkkwL
+ KFjzSmpcLoQ9iyEJH5LYf/I7foyeJGI8xuGxbB7lOpHEbBizg6DeIiawxRKNmcdQLp+PMqIqxgXJksmo
+ iqLmp/rh1xwLKJ9xiCeBaDbrMiHsGftNXcfh4G2SCOuLMmoau2s8KhTOplyaXNMfv0HtKiKgdB2GpozD
+ qKDG5fT+ntD7S/a2QmWkE2xCe2JaMAc72vG2RzhcrrGGvLQH5CXUnJAR159ZwzGgB1/Daied5FB+di6U
+ npNRGbOA3xPlinlozjoK1WYRgXgmcMuP3ttCVBLV9BlpfKbSe2Pvrp0ZAT2RXbsS8sKekBVQc0JK5NWv
+ hENwT0Ht40gS8LKiySwy5cY4oznjEJSiApuHwXDLF/p4+oaJp+qlOH9gmumz7MB0Eiisl0CR1wtyWmqG
+ NJfDQ4MEdiG9BLWl9OmpJNY0mSV8JltVY+ZBxG8SEYjdRCtwU4Jq1RJ+ADtEUg/a0AnGTrF27Eig3BAG
+ eVZvSDOpORGVwUHfHEYCvQW1xXQCqn1t6TxYapJQLsLzDB/EbhQRiNlIK3Btn1DAj53hQmyDaAX07iip
+ 3kvsM7MXj2r3wPbEN4LaolA7JB6wFwg03/RCzAYRgWgSaEjfRQKmYiZwwd8e+SE2Ag6E98fUQAtMoc3W
+ kcmBHPad6SuoLThhgyQ/xw4Ci9F0fQ+i14sIKEigPm37xxV4ylbA3wF3jk9C3rEJAu4dnYjCI5NRfMSK
+ h92zZ53r7h6fCA0JtGWyjd2U7gGFmIB843DUXXDlV0DPBNRLkOI/Ha8qL+JV1WUizQy7v4zXnWh73rHu
+ r+qr0Bx14mfOMpmEIW0b5OsGfyog20ACKRs+CjDrGjYwbgH9Y3HuEvo4Fz7DtPxmgYubIFsrIiBd/wPq
+ NGtQo17GS5gwiZiWrwu0jTfn1dCnbbiwDtI1IgLyDSPQmLIaDZrlqE/uHlh286V1kK8dIhRoaWlB0uEV
+ OLt6MCJWDEB4N8GyI1cNpLNhAYyG+nYBdpWVlUGr1SIzM7NbycnJgU6nEzZvu9ireP78ebfCepjb0cVx
+ /wJuY5fnBqzZIQAAAABJRU5ErkJggg==
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
- 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
- Dx9jcJyVAAAAAElFTkSuQmCC
+ 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
+ Dpt0eOMpAAAAAElFTkSuQmCC
diff --git a/IPFBrowser/IPFBrowser.csproj b/IPFBrowser/IPFBrowser.csproj
index b82b4f2..e73b7a8 100644
--- a/IPFBrowser/IPFBrowser.csproj
+++ b/IPFBrowser/IPFBrowser.csproj
@@ -63,6 +63,7 @@
+