Start to implement the Secret Files SPR data format
This commit is contained in:
parent
459468ff68
commit
724b1fd1eb
@ -0,0 +1,326 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UniversalEditor.Accessors;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.FileSystem;
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.DeepSilver.SecretFiles
|
||||
{
|
||||
public class SPRDataFormat : DataFormat
|
||||
{
|
||||
private static DataFormatReference _dfr = null;
|
||||
public override DataFormatReference MakeReference()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = base.MakeReference();
|
||||
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
|
||||
_dfr.ExportOptions.Add(new CustomOptionNumber("EncryptionDomain", "Encryption &domain:", 0xbebe2, Int32.MaxValue, Int32.MinValue));
|
||||
_dfr.ExportOptions.Add(new CustomOptionNumber("EncryptionSeed", "Encryption &seed:", 0, Int32.MaxValue, Int32.MinValue));
|
||||
_dfr.Filters.Add("Secret Files: Tunguska SPR archive", new byte?[][] { new byte?[] { (byte)'S', (byte)'P', (byte)'C', (byte)'D' } }, new string[] { "*.spr" });
|
||||
_dfr.Sources.Add("http://wiki.xentax.com/index.php?title=Secret_Files:_Tunguska_%28Demo%29_SPR");
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
private int mvarEncryptionDomain = 0xbebe2;
|
||||
public int EncryptionDomain { get { return mvarEncryptionDomain; } set { mvarEncryptionDomain = value; } }
|
||||
|
||||
private int mvarEncryptionSeed = 0;
|
||||
public int EncryptionSeed { get { return mvarEncryptionSeed; } set { mvarEncryptionSeed = value; } }
|
||||
|
||||
private byte[] EncryptDecrypt(byte[] input)
|
||||
{
|
||||
byte[] output = (input.Clone() as byte[]);
|
||||
|
||||
int KeyDomain = mvarEncryptionDomain * mvarEncryptionSeed;
|
||||
int Key = ((mvarEncryptionSeed << 8) | ((~mvarEncryptionSeed) & 0xff));
|
||||
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
Key = (Key * Key) % KeyDomain;
|
||||
output[i] = (byte)(output[i] ^ (Key & 0xFF));
|
||||
Key = (Key + output[i] + 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null) throw new ObjectModelNotSupportedException();
|
||||
|
||||
Reader reader = base.Accessor.Reader;
|
||||
string signature = reader.ReadFixedLengthString(4);
|
||||
if (signature != "SPCD") throw new InvalidDataFormatException("File does not begin with 'SPCD'");
|
||||
|
||||
uint unknown1 = reader.ReadUInt32();
|
||||
uint unknown2 = reader.ReadUInt32();
|
||||
mvarEncryptionSeed = reader.ReadInt32();
|
||||
uint unknown3 = reader.ReadUInt32();
|
||||
uint unknown4 = reader.ReadUInt32();
|
||||
uint stringTableEntryCount = reader.ReadUInt32();
|
||||
uint stringTableOffset = reader.ReadUInt32();
|
||||
uint stringTableLength = reader.ReadUInt32();
|
||||
uint fileTableEntryCount = reader.ReadUInt32();
|
||||
uint fileTableOffset = reader.ReadUInt32();
|
||||
uint fileTableLength = reader.ReadUInt32();
|
||||
uint unknown5 = reader.ReadUInt32();
|
||||
uint directoryTableEntryCount = reader.ReadUInt32();
|
||||
uint directoryTableOffset = reader.ReadUInt32();
|
||||
uint directoryTableLength = reader.ReadUInt32();
|
||||
|
||||
List<string> stringTableEntries = new List<string>();
|
||||
#region String Table
|
||||
{
|
||||
reader.Seek(stringTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(stringTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
ushort[] stringLengths = new ushort[stringTableEntryCount];
|
||||
for (int i = 0; i < stringTableEntryCount; i++)
|
||||
{
|
||||
stringLengths[i] = reader.ReadUInt16();
|
||||
}
|
||||
for (int i = 0; i < stringTableEntryCount; i++)
|
||||
{
|
||||
string value = reader.ReadFixedLengthString(stringLengths[i]);
|
||||
stringTableEntries.Add(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Directory Table
|
||||
{
|
||||
reader.Seek(directoryTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(directoryTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
for (int i = 0; i < directoryTableEntryCount; i++)
|
||||
{
|
||||
uint directoryNameIndex = reader.ReadUInt32();
|
||||
uint parentDirectoryIndex = reader.ReadUInt32(); // 0x1effffff for root
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region File Table
|
||||
{
|
||||
reader.Seek(fileTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(fileTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
for (int i = 0; i < fileTableEntryCount; i++)
|
||||
{
|
||||
uint parentDirectoryIndex = reader.ReadUInt32(); // 0x1effffff for root
|
||||
uint fileNamePrefixIndex = reader.ReadUInt32(); // index into string table
|
||||
uint fileNameSuffixIndex = reader.ReadUInt32();
|
||||
uint crc32 = reader.ReadUInt32();
|
||||
|
||||
#region File date
|
||||
ushort year = reader.ReadUInt16();
|
||||
ushort month = reader.ReadUInt16();
|
||||
ushort dayOfWeek = reader.ReadUInt16();
|
||||
ushort day = reader.ReadUInt16();
|
||||
ushort hour = reader.ReadUInt16();
|
||||
ushort minute = reader.ReadUInt16();
|
||||
ushort second = reader.ReadUInt16();
|
||||
ushort millisecond = reader.ReadUInt16();
|
||||
|
||||
DateTime fileDate = new DateTime(year, month, day, hour, minute, second, millisecond);
|
||||
#endregion
|
||||
|
||||
uint decompressedLength = reader.ReadUInt32();
|
||||
|
||||
// 0xffffffff if file is not compressed
|
||||
uint compressionHeaderOffset = reader.ReadUInt32();
|
||||
|
||||
// zero if file is not compressed
|
||||
uint compressionHeaderLength = reader.ReadUInt32();
|
||||
|
||||
uint fileDataOffset = reader.ReadUInt32();
|
||||
uint fileDataLength = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
|
||||
if (fsom == null) throw new ObjectModelNotSupportedException();
|
||||
|
||||
Writer writer = base.Accessor.Writer;
|
||||
writer.WriteFixedLengthString("SPCD");
|
||||
|
||||
writer.WriteUInt32(0);
|
||||
writer.WriteUInt32(0);
|
||||
|
||||
writer.WriteInt32(mvarEncryptionSeed);
|
||||
|
||||
writer.WriteUInt32(0);
|
||||
writer.WriteUInt32(0);
|
||||
|
||||
File[] files = fsom.GetAllFiles();
|
||||
uint baseOffset = 54;
|
||||
for (uint i = 0; i < files.Length; i++)
|
||||
{
|
||||
baseOffset += (uint)files[i].Size;
|
||||
}
|
||||
|
||||
#region String Table Data
|
||||
{
|
||||
List<string> stringTableEntries = new List<string>();
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor();
|
||||
Writer bwst = new Writer(ma);
|
||||
foreach (string s in stringTableEntries)
|
||||
{
|
||||
bwst.WriteUInt16((ushort)s.Length);
|
||||
}
|
||||
foreach (string s in stringTableEntries)
|
||||
{
|
||||
bwst.WriteFixedLengthString(s);
|
||||
}
|
||||
bwst.Flush();
|
||||
bwst.Close();
|
||||
byte[] stringTableData = ma.ToArray();
|
||||
stringTableData = EncryptDecrypt(stringTableData);
|
||||
|
||||
uint stringTableOffset = baseOffset;
|
||||
writer.WriteUInt32((uint)stringTableEntries.Count);
|
||||
writer.WriteUInt32(stringTableOffset);
|
||||
writer.WriteUInt32((uint)stringTableData.Length);
|
||||
}
|
||||
#endregion
|
||||
#region Directory Table Data
|
||||
{
|
||||
List<SPRDirectoryInfo> directoryTableEntries = new List<SPRDirectoryInfo>();
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor();
|
||||
Writer bwst = new Writer(ma);
|
||||
foreach (SPRDirectoryInfo s in directoryTableEntries)
|
||||
{
|
||||
bwst.WriteUInt16((ushort)s.Length);
|
||||
}
|
||||
foreach (string s in stringTableEntries)
|
||||
{
|
||||
bwst.WriteFixedLengthString(s);
|
||||
}
|
||||
bwst.Flush();
|
||||
bwst.Close();
|
||||
byte[] stringTableData = ma.ToArray();
|
||||
stringTableData = EncryptDecrypt(stringTableData);
|
||||
|
||||
uint stringTableOffset = baseOffset;
|
||||
writer.WriteUInt32((uint)stringTableEntries.Count);
|
||||
writer.WriteUInt32(stringTableOffset);
|
||||
writer.WriteUInt32((uint)stringTableData.Length);
|
||||
}
|
||||
#endregion
|
||||
|
||||
uint fileTableEntryCount = reader.ReadUInt32();
|
||||
uint fileTableOffset = reader.ReadUInt32();
|
||||
uint fileTableLength = reader.ReadUInt32();
|
||||
uint unknown5 = reader.ReadUInt32();
|
||||
uint directoryTableEntryCount = reader.ReadUInt32();
|
||||
uint directoryTableOffset = reader.ReadUInt32();
|
||||
uint directoryTableLength = reader.ReadUInt32();
|
||||
|
||||
List<string> stringTableEntries = new List<string>();
|
||||
#region String Table
|
||||
{
|
||||
reader.Seek(stringTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(stringTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
ushort[] stringLengths = new ushort[stringTableEntryCount];
|
||||
for (int i = 0; i < stringTableEntryCount; i++)
|
||||
{
|
||||
stringLengths[i] = reader.ReadUInt16();
|
||||
}
|
||||
for (int i = 0; i < stringTableEntryCount; i++)
|
||||
{
|
||||
string value = reader.ReadFixedLengthString(stringLengths[i]);
|
||||
stringTableEntries.Add(value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Directory Table
|
||||
{
|
||||
reader.Seek(directoryTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(directoryTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
for (int i = 0; i < directoryTableEntryCount; i++)
|
||||
{
|
||||
uint directoryNameIndex = reader.ReadUInt32();
|
||||
uint parentDirectoryIndex = reader.ReadUInt32(); // 0x1effffff for root
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region File Table
|
||||
{
|
||||
reader.Seek(fileTableOffset, SeekOrigin.Begin);
|
||||
byte[] data = reader.ReadBytes(fileTableLength);
|
||||
data = EncryptDecrypt(data);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(data);
|
||||
Reader rdr = new Reader(ma);
|
||||
|
||||
for (int i = 0; i < fileTableEntryCount; i++)
|
||||
{
|
||||
uint parentDirectoryIndex = reader.ReadUInt32(); // 0x1effffff for root
|
||||
uint fileNamePrefixIndex = reader.ReadUInt32(); // index into string table
|
||||
uint fileNameSuffixIndex = reader.ReadUInt32();
|
||||
uint crc32 = reader.ReadUInt32();
|
||||
|
||||
#region File date
|
||||
ushort year = reader.ReadUInt16();
|
||||
ushort month = reader.ReadUInt16();
|
||||
ushort dayOfWeek = reader.ReadUInt16();
|
||||
ushort day = reader.ReadUInt16();
|
||||
ushort hour = reader.ReadUInt16();
|
||||
ushort minute = reader.ReadUInt16();
|
||||
ushort second = reader.ReadUInt16();
|
||||
ushort millisecond = reader.ReadUInt16();
|
||||
|
||||
DateTime fileDate = new DateTime(year, month, day, hour, minute, second, millisecond);
|
||||
#endregion
|
||||
|
||||
uint decompressedLength = reader.ReadUInt32();
|
||||
|
||||
// 0xffffffff if file is not compressed
|
||||
uint compressionHeaderOffset = reader.ReadUInt32();
|
||||
|
||||
// zero if file is not compressed
|
||||
uint compressionHeaderLength = reader.ReadUInt32();
|
||||
|
||||
uint fileDataOffset = reader.ReadUInt32();
|
||||
uint fileDataLength = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.DeepSilver.SecretFiles
|
||||
{
|
||||
internal struct SPRDirectoryInfo
|
||||
{
|
||||
public int directoryNameIndex;
|
||||
public int parentDirectoryIndex;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace UniversalEditor.DataFormats.FileSystem.DeepSilver.SecretFiles
|
||||
{
|
||||
internal struct SPRFileInfo
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -77,6 +77,8 @@
|
||||
<Compile Include="DataFormats\FileSystem\CPIO\CPIODataFormat.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\CPIO\CPIOEncoding.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\DeepSilver\SecretFiles\SPRDataFormat.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\DeepSilver\SecretFiles\SPRDirectoryInfo.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\DeepSilver\SecretFiles\SPRFileInfo.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\Dreamfall\PAKDataFormat.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\Eighting\FPK\FPKDataFormat.cs" />
|
||||
<Compile Include="DataFormats\FileSystem\ElectronicArts\BIGFDataFormat.cs" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user