From dbe3d98c4e7b882d7b31e85ecf442fbdca550646 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Tue, 12 Nov 2019 19:14:24 -0500 Subject: [PATCH] add Slightly Mad Studios BFF - requires XMemLZX decompression but it is unavailable at the moment --- .../FileSystem/SlightlyMadStudiosBFF.uexml | 25 ++ ...lEditor.Content.PlatformIndependent.csproj | 1 + .../SlightlyMadStudios/BFFCompressionType.cs | 31 ++ .../SlightlyMadStudios/BFFDataFormat.cs | 399 ++++++++++++++++++ .../UniversalEditor.Plugins.FileSystem.csproj | 3 + 5 files changed, 459 insertions(+) create mode 100644 CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/FileSystem/SlightlyMadStudiosBFF.uexml create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFCompressionType.cs create mode 100644 CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFDataFormat.cs diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/FileSystem/SlightlyMadStudiosBFF.uexml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/FileSystem/SlightlyMadStudiosBFF.uexml new file mode 100644 index 00000000..8ab7f8a8 --- /dev/null +++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/FileSystem/SlightlyMadStudiosBFF.uexml @@ -0,0 +1,25 @@ + + + + + + + + *.bff + + + + KAP + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj index 0d4678c1..4bf7a4f3 100644 --- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj +++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj @@ -648,6 +648,7 @@ + diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFCompressionType.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFCompressionType.cs new file mode 100644 index 00000000..520888dc --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFCompressionType.cs @@ -0,0 +1,31 @@ +// +// BFFCompressionType.cs +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace UniversalEditor.DataFormats.FileSystem.SlightlyMadStudios +{ + public enum BFFCompressionType : byte + { + None = 0, + Zlib = 1, + XMemDecompress = 2, + Oodle = 3 + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFDataFormat.cs new file mode 100644 index 00000000..9aba8256 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/DataFormats/FileSystem/SlightlyMadStudios/BFFDataFormat.cs @@ -0,0 +1,399 @@ +// +// BFFDataFormat.cs - Slightly Mad Studios BFF archive (transcribed from BMS 0.2.5) +// Used in Need for Speed: Shift 1 and 2, Project Cars, Project Cars 2, Test Drive: Ferrari Racing Legends, etc. +// +// Author: +// Mike Becker +// +// Copyright (c) 2019 Mike Becker +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using UniversalEditor.Accessors; +using UniversalEditor.IO; +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.FileSystem.SlightlyMadStudios +{ + public class BFFDataFormat : DataFormat + { + int PCARS_ERROR = 0; + int PCARS_KEY_SET = 0; + int X12d = 0; + int PCARS_NUM = 0; + + public int FormatVersion { get; set; } = 0; + + private static DataFormatReference _dfr = null; + protected override DataFormatReference MakeReferenceInternal() + { + if (_dfr == null) + { + _dfr = base.MakeReferenceInternal(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + } + return _dfr; + } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + Reader reader = Accessor.Reader; + string signature = reader.ReadFixedLengthString(4); + if (signature == "PAK ") + { + // big-endian + reader.Endianness = Endianness.BigEndian; + } + else if (signature == " KAP") + { + // little-endian + reader.Endianness = Endianness.LittleEndian; + } + + FormatVersion = reader.ReadInt32(); + FormatVersion &= 0xff; + int fileCount = reader.ReadInt32(); + + Accessor.Seek(0x118, SeekOrigin.Begin); + int X118 = reader.ReadInt32(); + Accessor.Seek(0x120, SeekOrigin.Begin); + int X120 = reader.ReadInt32(); + X120 -= 0x308; // 24547 + Accessor.Seek(0x12d, SeekOrigin.Begin); + X12d = reader.ReadInt32(); + + if (X12d == 1) + { + throw new NotSupportedException("X12d equal to %X12d% has not been tested"); + } + + PCARS_NUM = 0; + int TMP_OFF = 0; + if (FormatVersion == 4) + { + // lame scanner for Project Cars, sorry... + if (signature == "PAK ") + { + TMP_OFF = 0x8; + } + else + { + TMP_OFF = 0xc; + } + + int ZERO = 0; + for (PCARS_NUM = 0; PCARS_NUM < 0x16; PCARS_NUM++) + { + X12dset(); + + if (PCARS_ERROR != 0) + { + PCARS_NUM = -1; + PCARS_KEY_SET += 1; + ZERO = 1; + } + else + { + // log MEMORY_FILE 0x130 0x10 + reader.Seek(0x130, SeekOrigin.Begin); + byte[] m_file = reader.ReadBytes(0x10); + MemoryAccessor ma_file = new MemoryAccessor(m_file); + + // getvarchr DEST SRC OFFSET [TYPE=byte] + // i.e. SRC.Seek(OFFSET); DEST = SRC.Read(); + // getvarchr ZERO MEMORY_FILE TMP_OFF long + ma_file.Seek(TMP_OFF, SeekOrigin.Begin); + ZERO = ma_file.Reader.ReadInt32(); + } + + if (ZERO == 0) + { + break; + } + } + } + + X12dset(); + + int X120OFFSET = 0; + + reader.Seek(0x130, SeekOrigin.Begin); + byte[] m_file1 = reader.ReadBytes(X118); + MemoryAccessor ma_file1 = new MemoryAccessor(m_file1); + + byte[] m_file2 = null; + MemoryAccessor ma_file2 = null; + + if (FormatVersion == 4) // Project Cars + { + // names are not supported because they use a boring + // and chaotic obfuscation method (no rc4), if one + // day I will have time and desire maybe I will look + // at them + X120OFFSET = 0; + } + else + { + X12dset(); + + X120OFFSET = 0x438; + + X120OFFSET += X118; + + reader.Seek(X120OFFSET, SeekOrigin.Begin); + m_file2 = reader.ReadBytes(X120); + ma_file2 = new MemoryAccessor(m_file2); + } + + // goto 0 MEMORY_FILE + for (int i = 0; i < fileCount; i++) + { + // encryption "" "" // reset here instead to do it after each *log + int dummy1 = ma_file1.Reader.ReadInt32(); + int dummy2 = ma_file1.Reader.ReadInt32(); + long offset = ma_file1.Reader.ReadInt64(); + int zsize = ma_file1.Reader.ReadInt32(); + int size = ma_file1.Reader.ReadInt32(); + int dummy3 = ma_file1.Reader.ReadInt32(); + int dummy4 = ma_file1.Reader.ReadInt32(); + BFFCompressionType TYPE = (BFFCompressionType) ma_file1.Reader.ReadByte(); + byte dummy5 = ma_file1.Reader.ReadByte(); + int crc = ma_file1.Reader.ReadInt32(); + string FILEEXT = ma_file1.Reader.ReadFixedLengthString(4); + string NAME = null; + if (X120OFFSET != 0) + { + long NAMEOFF = ma_file2.Reader.ReadInt64(); + int dummy21 = ma_file2.Reader.ReadInt32(); + int dummy22 = ma_file2.Reader.ReadInt32(); + + long tmp = ma_file2.Reader.Accessor.Position; + NAMEOFF -= X120OFFSET; + + ma_file2.Reader.Seek(NAMEOFF, SeekOrigin.Begin); + byte NAMESZ = ma_file2.Reader.ReadByte(); + + NAME = ma_file2.Reader.ReadFixedLengthString(NAMESZ); + + ma_file2.Seek(tmp, SeekOrigin.Begin); + } + else + { + NAME = String.Format("{0}.{1}", offset, FILEEXT); + } + + File f = fsom.AddFile(NAME); + f.Size = size; + f.Properties.Add("size", size); + f.Properties.Add("zsize", zsize); + f.Properties.Add("offset", offset); + f.Properties.Add("compressionMethod", TYPE); + f.DataRequest += f_DataRequest; + + X12dset(); + } + } + + void f_DataRequest(object sender, DataRequestEventArgs e) + { + File f = (File)sender; + int size = (int)f.Properties["size"]; + int zsize = (int)f.Properties["zsize"]; + long offset = (long)f.Properties["offset"]; + BFFCompressionType TYPE = (BFFCompressionType)f.Properties["compressionMethod"]; + + Accessor.Reader.Seek(offset, SeekOrigin.Begin); + byte[] compressedData = Accessor.Reader.ReadBytes(zsize); + byte[] decompressedData = compressedData; + + switch (TYPE) + { + case BFFCompressionType.None: + { + break; + } + case BFFCompressionType.Zlib: + { + // comtype zlib; + // clog NAME OFFSET ZSIZE SIZE; + break; + } + case BFFCompressionType.XMemDecompress: + { + // comtype XMemDecompress + // clog NAME OFFSET ZSIZE SIZE + decompressedData = Compression.CompressionModule.FromKnownCompressionMethod(Compression.CompressionMethod.XMemLZX).Decompress(compressedData, size); + break; + } + case BFFCompressionType.Oodle: + { + // comtype oodle + // clog NAME OFFSET ZSIZE SIZE + break; + } + default: + { + throw new NotSupportedException(String.Format("compression type {0} not supported", TYPE)); + } + } + + e.Data = decompressedData; + } + + + void X12dset() + { + if (X12d == 1) // ignored at the moment + { + // TMPSZ += 0xf; + // TMPSZ &= 0xfffffff0; + } + if (X12d == 2) + { + // encryption rc4("@lLy0urRaC3ar3bE"); + } + if (FormatVersion == 4) // Project Cars + { + if (X12d == 0) + { + // nothing: World of Speed and Redbull Air Race + } + else + { + PROJECTCARS_KEY(); + } + } + } + + void PROJECTCARS_KEY() + { + PCARS_ERROR = 1; + + StringAccessor maKey = null; + if (PCARS_KEY_SET == -1) + { + // nothing, just a placeholder + } + else if (PCARS_KEY_SET == 0) // pCars patch 10.0 + { + maKey = new StringAccessor("\xe3\xf4\xd1\xd5\xeb\xcc\xcf\xbc\xa1\xcd\xeb\xf9\xf7\xeb\xec\xc3\x9c\xe4\xdd\x94\xb5\xcb\xe6\xe6\x00\x4b\x00\x9f\xfd\xe2\x80\x81\xe3\xea\x81\xd5\x9d\xe2\xf3\xd2\xb9\xfc\xf3\xf7\xc8\xde\x8d\x00\x39\x45\x51\x2b\x3f\x00\x86\xad\xa9\xc4\x80\xe4\x94\xbf\xe5\xe1\xe6\xe1\x8d\xa4\xf2\xf6\xf3\x00\x70\x3d\x41\x6d\x75\x39\x61\x70\x00\xfe\xa9\xe7\xd1\x84\xc1\xe6\xfa\xbb\xd2\xf4\xbc\x8f\x97\xe0\x8f\x81\xd2\x00\x39\x5f\x75\x38\x65\x32\x72\x00\xcf\xa4\xd4\xe6\xff\xc7\xc4\xfa\xde\xcc\xa0\xa2\xe5\x8f\xb4\x84\x8c\xda\xfc\xe9\xdc\xf3\xb1\xfb\xd8\xbc\x00\xe4\xbb\xdd\xf4\x9e\xa5\xd8\xb1\xe1\x86\x97\xc4\xfc\xf1\xd0\xff\xb9\xf1\xc6\xaf\xdf\x9e\x83\x00\x2a\x75\x00\x95\xb9\xd0\x96\xb7\xaf\xd2\x92\xff\xe5\x88\xed\xeb\xa6\xd2\x8b\xed\xfd\xe2\x8b\xdb\xcb\x88\xb5\x00\x53\x00\xf4\xfd\xe0\xe4\x87\xf7\x80\xf6\xcb\x81\xe6\xc8\xef\xf8\xca\x88\xa6\xb0\x9f\x00\x52\x75\x6b\x45\x64\x72\x00\x80\xa6\xd0\x82\x82\xab\xd7\xa2\xf6\xe2\x95\xbd\xea\xa0\xcc\xe8\xb0\xb5\xdd\xaa\x00\x75\x21\x65\x52\x65\x00\xe5\xe4\xea\x92\x89\xf9\xdb\xa4\xfc\xca\xa5\xa1\xf6\x93\xa6\xdc\xbe\xbb\x9b\xac\xf2\xce\x00\x2d\x61\x66\x00\xdc\xfd\xfa\xfe\x84\xae\xd9\xeb\xc8\xd1\xbf\xd6\x8b\xf0\xfd\xed\xe4\xd7\xf2\xab\xc8\xd8\xbd\xf0\x00\x33\x00\xd5\x81\xa5\x9b\xfa\xa8\xf7\xfc\xde\xf3\x91\xc5\xf5\x95\xc5\xfb\xfe\xcc\xec\x93\x00\x61\x74\x68\x65\x3f\x00\x99\xbf\xfd\xd4\xaf\xd0\x80\xbd\xb6\x8f\xfe\xf3\xf8\x91\xb8\x8b\xb7\xc3\x8f\x94\xab\xe8\x00\x70\x2b\x73\x00\xe1\xa3\xe2\x94\xb7\xd6\xff\xa9\xd1\xe2\x8d\xd2\xe6\x93\xa7\xc5\x88\xde\x89\xec\xbf\x00\x65\x6a\x61\x77\x00\xda\xfa\xef\xc9\xe4\xd2\x8f\xf3\xc5\x93\xb2\xf8\x9f\xfd\xf4\xe7\xb9\xa7\x88\xbe\xf6\xc5\xf3\xfe\xc4\x00\x00\xe4\x81\xbc\xd7\x90\xf5\xe4\xb7\xcc\xce\xbb\xaa\xf7\x94\xe4\xde\x91\xf6\xe5\xef\xa7\xe8\xef\xab\x00\x53\x00\xe1\xf4\xc9\xef\x97\xc6\xf9\x91\xa0\xf1\xf6\xd0\xce\xaa\xeb\x8d\xbe\xc4\x99\xb7\xfd\x97\xfa\xc6\x97\x00\x00\xca\xb9\xb4\x9d\x99\xce\xe8\x95\xae\xc2\xe3\xd3\xd8\x88\xf4\xf9\x8c\xa2\xd0\xfa\xd0\xd6\x00\x75\x77\x65\x00"); + } + else if (PCARS_KEY_SET == 1) // pCars + { + maKey = new StringAccessor("\xe3\xf4\xd1\xd5\xeb\xcc\xcf\xbc\xa1\xcd\xeb\xf9\xf7\xeb\xec\xc3\x9c\xe4\xdd\x94\xb5\xcb\xe6\xe6\x00\x4b\x00\x9f\xfd\xe2\x80\x81\xe3\xea\x81\xd5\x9d\xe2\xf3\xd2\xb9\xfc\xf3\xf7\xc8\xde\x8d\x00\x39\x45\x51\x2b\x3f\x00\x86\xad\xa9\xc4\x80\xe4\x94\xbf\xe5\xe1\xe6\xe1\x8d\xa4\xf2\xf6\xf3\x00\x70\x3d\x41\x6d\x75\x39\x61\x70\x00\xfe\xa9\xe7\xd1\x84\xc1\xe6\xfa\xbb\xd2\xf4\xbc\x8f\x97\xe0\x8f\x81\xd2\x00\x39\x5f\x75\x38\x65\x32\x72\x00\xcf\xa4\xd4\xe6\xff\xc7\xc4\xfa\xde\xcc\xa0\xa2\xe5\x8f\xb4\x84\x8c\xda\xfc\xe9\xdc\xf3\xb1\xfb\xd8\xbc\x00\xe4\xbb\xdd\xf4\x9e\xa5\xd8\xb1\xe1\x86\x97\xc4\xfc\xf1\xd0\xff\xb9\xf1\xc6\xaf\xdf\x9e\x83\x00\x2a\x75\x00\x95\xb9\xd0\x96\xb7\xaf\xd2\x92\xff\xe5\x88\xed\xeb\xa6\xd2\x8b\xed\xfd\xe2\x8b\xdb\xcb\x88\xb5\x00\x53\x00\xf4\xfd\xe0\xe4\x87\xf7\x80\xf6\xcb\x81\xe6\xc8\xef\xf8\xca\x88\xa6\xb0\x9f\x00\x52\x75\x6b\x45\x64\x72\x00\x80\xa6\xd0\x82\x82\xab\xd7\xa2\xf6\xe2\x95\xbd\xea\xa0\xcc\xe8\xb0\xb5\xdd\xaa\x00\x75\x21\x65\x52\x65\x00\xe5\xe4\xea\x92\x89\xf9\xdb\xa4\xfc\xca\xa5\xa1\xf6\x93\xa6\xdc\xbe\xbb\x9b\xac\xf2\xce\x00\x2d\x61\x66\x00\xdc\xfd\xfa\xfe\x84\xae\xd9\xeb\xc8\xd1\xbf\xd6\x8b\xf0\xfd\xed\xe4\xd7\xf2\xab\xc8\xd8\xbd\xf0\x00\x33\x00\xd5\x81\xa5\x9b\xfa\xa8\xf7\xfc\xde\xf3\x91\xc5\xf5\x95\xc5\xfb\xfe\xcc\xec\x93\x00\x61\x74\x68\x65\x3f\x00\x99\xbf\xfd\xd4\xaf\xd0\x80\xbd\xb6\x8f\xfe\xf3\xf8\x91\xb8\x8b\xb7\xc3\x8f\x94\xab\xe8\x00\x70\x2b\x73\x00\xe1\xa3\xe2\x94\xb7\xd6\xff\xa9\xd1\xe2\x8d\xd2\xe6\x93\xa7\xc5\x88\xde\x89\xec\xbf\x00\x65\x6a\x61\x77\x00\x99\xff\xb4\x93\xf2\xdc\x8d\xa2\xf4\xc9\xb0\xcb\xfe\x88\xf6\xd9\x9e\xba\xe6\x00\x70\x52\x65\x64\x72\x65\x00\xe4\x81\xbc\xd7\x90\xf5\xe4\xb7\xcc\xce\xbb\xaa\xf7\x94\xe4\xde\x91\xf6\xe5\xef\xa7\xe8\xef\xab\x00\x53\x00\xe1\xf4\xc9\xef\x97\xc6\xf9\x91\xa0\xf1\xf6\xd0\xce\xaa\xeb\x8d\xbe\xc4\x99\xb7\xfd\x97\xfa\xc6\x97\x00\x00\xca\xb9\xb4\x9d\x99\xce\xe8\x95\xae\xc2\xe3\xd3\xd8\x88\xf4\xf9\x8c\xa2\xd0\xfa\xd0\xd6\x00\x75\x77\x65\x00"); + } + else if (PCARS_KEY_SET == 2) // Test Drive: Ferrari Racing Legends + { + maKey = new StringAccessor("\x87\xaf\xa2\x84\xaf\xb0\xc1\x8d\xe5\xda\xef\xef\x95\x97\xef\xeb\x82\xa5\xcb\xf1\xbd\xf2\x00\x53\x30\x4b\x00\x8d\x89\xa8\xce\xa4\xeb\xc7\xa6\xc7\xe9\xa2\xc4\xdb\xb7\xb2\xf9\xf0\xfd\xd1\xaa\x00\x39\x45\x51\x2b\x3f\x00\x9d\x91\xc2\xe2\xff\xfa\x82\xbd\xfe\xc6\x84\xf8\xd7\xaf\xae\xea\x8e\xd7\xc5\xad\xfb\xe4\x00\x39\x61\x70\x00\xce\xee\xe6\xe6\xa1\xe1\xcd\xe4\xa7\xd0\x8b\xdb\x86\xa2\xd0\x82\x97\xda\x9d\xaf\xf4\x00\x38\x65\x32\x72\x00\xc8\xba\xe8\xc9\x80\xbb\xc0\xb7\xc4\xe2\xa5\xa5\x87\xf3\xec\x81\x94\xcb\x00\x41\x2b\x65\x70\x65\x74\x3f\x00\x95\xf6\xe0\xc8\xbf\xd0\xc5\xbd\xcc\xd4\xb0\xd0\xd1\x88\xfc\xeb\x8a\xa0\x8d\x80\xcf\x00\x50\x41\x2a\x75\x00\xc8\xfa\xcf\xfe\x89\xe6\x86\x85\xf6\x80\xad\xe9\xf9\x96\xff\xff\xb5\xdf\xfc\xb6\xc4\xee\xf5\x00\x45\x53\x00\xef\xae\xe1\xf2\xfa\xa7\xf6\xa4\xa9\xc3\xb9\xcf\xcf\xbf\xe3\xc0\x00\x68\x75\x57\x52\x75\x6b\x45\x64\x72\x00\xde\xfd\xfa\x9b\xbc\xfa\xca\x90\xf8\x80\x83\xd9\xfa\xa1\xa1\x94\x95\xc1\xfe\xff\xac\xe7\x8d\x00\x52\x65\x00\x99\x83\xc8\xf5\xfc\xbb\x9b\xe4\xcb\x99\x97\xeb\xff\x84\xcb\xd4\x00\x40\x75\x73\x50\x61\x2d\x2d\x61\x66\x00\xca\xb3\xd2\xd1\xb2\xac\x9a\xf1\xc6\xf2\xa0\xff\xcb\x88\xbc\xc4\x9f\xfc\xc9\xbc\xbc\xe3\x90\x00\x2a\x33\x00\xfa\xb9\xe6\x8d\xb2\xe7\x99\xef\xdc\xdc\xae\xc9\xca\xf6\xb0\xcd\x00\x61\x6e\x65\x6d\x61\x74\x68\x65\x3f\x00\x99\xbe\xb0\xca\x8c\xa3\xe3\xf0\xe5\x95\xf2\xd5\x97\xf8\xbc\xf7\x9f\xa2\x00\x76\x65\x34\x55\x70\x2b\x73\x00\xd2\xa3\xc9\x94\xe3\xf9\xe5\xa7\xd4\xf6\xec\xb8\xeb\xa6\xa3\xed\xbc\x00\x42\x72\x45\x5a\x65\x6a\x61\x77\x00\x81\x86\xf1\x98\xa9\xfd\xc3\xfc\xb9\x96\x8e\xc6\x85\xa1\xea\xc0\xa6\xfd\x85\xad\xfc\x00\x65\x64\x72\x65\x00\xdd\xfa\xc0\x93\xe9\xf2\xdb\xae\xa6\xca\x8e\xb2\xc5\xe4\xf5\xec\xfa\xbd\x00\x54\x61\x23\x55\x70\x23\x53\x00\x87\x92\xc4\x8d\x92\xfa\x8d\x90\xe0\xe6\xf6\xa0\xc0\x96\xc3\x98\xf6\xd2\xcc\x00\x61\x6d\x61\x73\x74\x61\x00\x94\x96\xc7\x80\xa2\xa3\x9e\x8e\xd0\xc4\xad\xe0\xd1\xa5\xf0\xee\xf8\xf7\x97\x00\x38\x40\x79\x75\x77\x65\x00\xe1\xab\xac\xe8\x99\xc0\xc0\x8c\xc5\xf7\x86\xba\xfd\x83\xa1\x87\xa5\xd9\xf5\xfc\xd7\x00\x63\x68\x24\x26\x00"); + } + else if (PCARS_KEY_SET == 3) // pCars 2 + { + maKey = new StringAccessor("\xee\xf3\xdb\x82\xe0\xf8\xca\xf2\xed\xc7\xad\xa6\xd7\x8a\xc3\xfa\xf2\xf5\xef\xf2\xa8\xf9\xb3\xc6\xe3\xe3\x00\xe8\xea\xa6\x8b\x91\xba\xc1\xf0\xde\xcd\x86\xc7\xef\x85\xa5\x86\xf6\xdb\xc8\x89\xa9\xe1\xe4\xd0\x00\x3f\x00\xd1\xba\xe4\xc8\x93\xd7\x9c\xe0\xa0\xc1\xba\xbc\xf8\xf2\xf7\x8b\x87\xa6\x87\xf2\x00\x6d\x75\x39\x61\x70\x00\xe4\x86\xde\xea\xbf\xeb\xe7\xbd\xe9\xe5\x8d\xd2\xf9\xf2\xb2\x87\x8c\xb5\xfc\xa3\xfa\xc4\xf7\xf8\x00\x72\x00\x99\xaa\xe8\x9f\xad\xd5\x8b\xe4\xa3\xf4\x8a\xfc\x85\x8b\xe3\x96\xf7\xe3\x99\x89\xa7\xcc\x00\x65\x74\x3f\x00\xd2\xf7\xed\xf1\xf8\xbc\xd1\xea\xac\xc5\xed\xd4\xfe\xba\xd2\x95\xac\xd4\xe3\xfc\xeb\xf3\xf8\x00\x2a\x75\x00\xdc\xee\xe2\xfb\xa1\xe1\xe3\xad\xc1\x94\xe4\xa7\x8d\xf2\xdc\xe8\xa2\xa9\x9a\xa6\xcf\x86\xe3\xa8\xef\x00\x00\x8d\x90\xfd\xfd\xaf\xbd\xc1\x97\xa8\xc4\xa5\xfc\x98\x84\xa5\x97\x82\xfc\xda\xef\xa6\xfb\xbe\xcf\xe7\x93\x00\x81\xf4\xa0\xe6\xe6\xc6\xd5\x85\xfa\xce\x91\xf5\xe8\xe8\xf8\xc1\x83\xbc\x8f\xf7\xda\x00\x21\x65\x52\x65\x00\xc6\xf6\xe5\x9e\xea\xa0\xfc\x89\xb5\xc8\x8e\xf1\x93\xea\xce\xd1\x87\xa4\x9f\x92\xa6\xfd\x00\x2d\x61\x66\x00\x93\xae\xa1\xd5\x99\xc7\x91\x80\xda\xe1\xac\xd1\xed\xf5\xbc\xfc\xf5\xdc\x85\x84\xf5\xf0\xee\xab\x00\x33\x00\x93\x86\xa4\x9e\xf1\xec\xe4\xbb\xba\xd9\xf3\xf0\x93\xf3\xa9\x91\xfa\xba\x94\x97\xce\xcb\x00\x68\x65\x3f\x00\xfb\xb3\xc7\xde\xff\xa3\xe4\xac\xc6\xd8\xa6\xa0\xd9\xa5\xcc\xd4\xf3\xe8\xe8\xf6\xa5\x00\x55\x70\x2b\x73\x00\xef\xbe\xc3\xc6\x93\xc1\xea\xa3\xf5\xda\x97\xcb\x97\xb6\xf9\x9a\xe9\xfa\xf0\x98\xb8\x00\x65\x6a\x61\x77\x00\xd8\xf8\xba\x9a\x96\xd0\xca\x8a\xb0\x91\xe9\xa2\x94\xed\xb0\x98\xaa\xf9\x87\x81\xd2\xed\x84\xac\xc8\x00\x00\xe5\xb5\xec\xdc\xb5\xb0\xd6\xaa\xfc\xd2\xbf\xf7\xe2\xa3\xfd\x9c\xef\xae\x9d\x8e\xa7\x86\x00\x70\x23\x53\x00\x8f\xea\xc4\xe1\xf5\xce\xc3\xbe\xc3\x9d\x8d\xc3\xe0\x87\xe4\xec\x86\xa0\x93\x88\xeb\xd5\xbd\xb2\x00\x61\x00\xe4\xff\xfc\x9d\xb6\xce\x86\xb6\xf3\x81\x8b\xe9\x82\x95\xd6\x9f\x97\xfe\xec\xfc\xc6\xe9\x00\x75\x77\x65\x00"); + } + else if (PCARS_KEY_SET == 4) // pCars 197 + { + maKey = new StringAccessor("\xE8\xEC\xF0\xFF\xF2\xA9\xC4\x87\xA2\xE5\xA1\xEA\x8B\xAF\xD4\xEE\x00\x57\x4F\x66\x59\x34\x71\x53\x30\x4B\x00\xEB\xF3\xBC\xEF\xFD\xE1\xC5\x97\xB0\xE5\x9A\xAC\xC6\xB4\xBB\xD7\xB2\xBD\x9D\x89\xD5\x80\xFC\xE2\xEB\x00\x00\xCC\xEC\xA9\xE1\x83\xD4\xEA\x90\xE4\xC9\xFA\xA0\x94\x88\xBA\xCB\xF0\xEF\x80\xAE\xAC\x00\x75\x39\x61\x70\x00\xCC\x8A\xE1\x8D\xE9\xBF\x88\xB0\xC2\xD9\xA7\xA0\xEB\xE2\xF3\x99\x87\xD9\xCF\xB3\xAE\xDC\xA9\xF5\xDC\x00\x00\xC6\xF6\xB5\xC2\xED\xF3\xEC\x91\xC2\xC3\x81\xCA\x89\xF1\xA1\xDB\x92\xC6\xEF\xE9\xF9\xD6\xBD\x00\x74\x3F\x00\x94\x8E\xD0\xD4\x8C\xA8\x96\xBA\xB9\x87\xE9\xFE\xE4\xF1\xD1\x86\x94\xC7\x00\x67\x35\x73\x50\x41\x2A\x75\x00\x88\x93\xAE\x8D\xE6\xB8\xEA\x89\xDE\x95\x92\xD6\xD0\xB0\xB2\xD7\xA6\xDD\x9B\xF7\xF5\x00\x73\x35\x45\x53\x00\xF8\x8F\xF9\xC6\xB9\xAC\xC6\xA4\xF4\xED\xB0\xDE\x81\xF3\xC7\xED\x8D\xAB\xE3\xB4\x00\x75\x6B\x45\x64\x72\x00\xFA\xA0\xA6\xF5\x93\xCF\xCA\xFA\xDF\xDA\x81\xB9\xDA\x87\xFA\xD4\xA8\xD0\x00\x66\x3F\x75\x21\x65\x52\x65\x00\xD1\xF1\xA3\xCF\xAE\xFC\x93\xE3\xAC\xF2\xA5\xEA\x82\xAD\xDA\xF6\xA5\xF4\x84\xBF\xBC\xCC\x00\x2D\x61\x66\x00\xEF\x8E\xAB\xFC\xF6\xC1\xC4\x98\xE1\x89\xFD\xA0\xCC\x91\xEF\x95\xF0\xFE\x84\xFF\xFB\xE6\x91\xB2\xDE\x91\x00\xDD\xA6\xAC\xDC\xF4\xC7\xFE\x81\xDD\xD7\xBD\xF8\xDB\xFA\xA7\xD5\xF8\xC4\xF7\xF1\xF1\xDE\xA0\x00\x65\x3F\x00\xFB\x98\xDF\xE4\xA5\xDD\xFB\x80\xC8\xF3\xBB\xA4\xD8\x86\xB9\xED\xE2\xCE\x82\xAF\xC8\x88\xA3\xFD\x00\x73\x00\xE2\xEB\xD4\xFF\xF8\xF3\x89\xE2\xFC\xD4\xBB\xB5\xD7\xE6\xCA\xF6\x8A\xFD\xCC\xAC\xA1\xF6\x00\x6A\x61\x77\x00\xE0\xF4\xFD\xCF\xB9\xED\xF1\x86\xF0\x97\x81\xEC\xC1\xF3\xD3\x82\x95\xD9\xF1\xEC\x00\x52\x65\x64\x72\x65\x00\xE3\xA2\xC0\xCD\xED\xA3\xDF\xAB\xFA\xF2\x92\xE8\x9C\xB6\xFE\xC5\xB2\xE1\x82\xBD\xD5\x00\x55\x70\x23\x53\x00\xD2\x8B\xF3\xFD\xE6\xC9\xFF\xF4\xEC\x88\x97\xA1\x93\xB2\xE0\xF5\x8E\xCB\x99\x88\xAB\xCE\x99\xB8\x00\x61\x00\xED\xEB\xC4\xDC\xEF\xC7\xCF\x81\xE8\x8F\xA1\xFB\xC4\xE4\xBB\xCF\x9C\xB2\xEC\x95\xBB\xC8\xF0\xCB\x86\x00\x00"); + } + else if (PCARS_KEY_SET == 5) // pCars before 197 + { + maKey = new StringAccessor("\xfe\xb5\xaa\xe7\x8b\xe2\xcc\xb1\xd8\x9e\xa3\xe0\xde\xbf\xbf\x87\x00\x57\x4f\x66\x59\x34\x71\x53\x30\x4b\x00\x99\xaf\xda\x8f\x92\xcd\xf1\xa2\xdc\x94\x9b\xaa\x94\xf2\xce\xca\xed\xf2\xe4\x00\x65\x39\x45\x51\x2b\x3f\x00\xf6\x9a\xd1\x9f\xad\xe0\x87\xe3\xbd\xd1\x86\xfc\xed\x84\xf9\xdf\xb4\xba\xe1\xa8\xe5\xd8\xf2\xff\x00\x70\x00\x9d\x8f\xca\x9e\x85\xea\xdc\xf6\xaa\xe2\x9c\xc6\xce\x97\xae\x91\x96\xf5\xda\xf2\xa4\x84\x00\x65\x32\x72\x00\xc0\x93\xd8\xd7\xf0\xa2\xc5\xec\xa3\xc2\xe4\xb2\xce\xec\xdf\xc1\x8a\x00\x51\x41\x2b\x65\x70\x65\x74\x3f\x00\xe5\x89\xe7\xfd\x86\xdc\xc3\xa2\xc9\xe8\xb2\xd1\xeb\xbb\xb9\x84\x89\xa5\xd8\x00\x35\x73\x50\x41\x2a\x75\x00\xd8\x9d\xa7\xcb\x81\xaa\x84\xe0\xfd\x9c\xb5\xcf\x84\xaa\xe0\x99\x85\x00\x72\x65\x4a\x65\x73\x35\x45\x53\x00\xde\xef\xce\xef\x82\xa6\x94\xf3\xdc\x94\xe4\xe4\xd1\xbf\xd1\x93\x00\x68\x75\x57\x52\x75\x6b\x45\x64\x72\x00\xef\x8d\xe3\xf6\xf4\xc9\xeb\x9c\xbe\xf3\xb2\xa0\xda\x88\xf3\xde\x95\xbc\xe6\x9f\x00\x75\x21\x65\x52\x65\x00\xd2\x91\xeb\xe3\x96\xc0\xd6\xb1\xe9\xfe\xa8\xe3\xe1\xaa\xab\xf0\x97\xd1\xda\xa9\xd0\xe3\xe9\xbc\xec\x00\x00\x9b\xb5\xe8\xd8\xf7\xf1\xc3\x8c\xd3\x98\xb5\xc0\xd4\xb7\xe6\xf5\x8a\xf4\x92\xf4\xe9\xc3\xaa\x00\x2a\x33\x00\xd4\x80\xb2\x86\xe0\xbe\xe3\xf5\xe8\xcc\xbf\xc7\xdf\xf8\xf5\xfd\x96\xbd\x8b\x83\xf3\x00\x74\x68\x65\x3f\x00\x89\x82\xc4\xdb\xab\xb2\xc1\xf0\xcf\x92\xfd\xa2\xed\x93\xc9\xeb\xfe\xf1\xe8\xef\xa2\x00\x55\x70\x2b\x73\x00\x92\x89\xfa\xcd\x91\xd4\xd1\xb7\xec\x87\xbf\xec\xcf\x9e\xcd\xfc\xf4\x00\x42\x72\x45\x5a\x65\x6a\x61\x77\x00\xdf\xaf\xfe\xfb\x8f\xa5\x9d\xec\xf6\xe9\xa1\xc6\xc6\x8d\xeb\xd5\x00\x53\x57\x65\x70\x52\x65\x64\x72\x65\x00\xd6\xb4\xbf\xf1\x85\xe3\xf9\xa9\xaf\xcc\xe9\xa0\xe3\x95\xd8\x85\xbb\xaa\xe7\xee\x00\x23\x55\x70\x23\x53\x00\xd7\xa8\xd5\xea\xeb\xa6\xe6\x8f\xae\xf2\x91\xac\xdd\xf4\xa0\x82\xb9\xb5\x87\x8d\xab\x9d\xea\xd8\x9b\x00\x00\x88\xb1\xc8\xfa\xfe\xf3\xcf\xbd\xc0\xe0\xa3\xda\xd7\xec\xe9\xd0\xb3\xd0\xe5\xa0\xfb\xe1\xf1\xfd\x99\x00\x00"); + } + else if (PCARS_KEY_SET == 6) // pCars 2 + { + maKey = new StringAccessor("\x99\x89\xcb\xf7\x9f\xb8\xf2\x83\xea\xdb\xb2\xa0\xce\x98\xae\xf1\x87\xa3\xf8\x8f\xa5\xed\x00\x53\x30\x4b\x00\xce\x91\xa5\xf9\xe6\xd9\xf6\x80\xc8\xca\xa3\xc7\xed\x9f\xba\xf5\xef\xa7\xd9\xaa\xa5\xff\x00\x51\x2b\x3f\x00\xe2\xb1\xf0\xda\xae\xa7\x8d\x8a\xfb\xef\x83\xa2\xce\x90\xf7\xfa\x88\xa1\xed\x8c\xe7\x9c\x00\x39\x61\x70\x00\xee\xf2\xa6\xd7\x92\xdf\xd2\x82\xc0\x85\xa2\xbc\x94\xec\xb4\xfa\x86\xd9\x98\xf5\xf8\x86\x00\x65\x32\x72\x00\xc8\x88\xf4\xcf\xbf\xe3\xd8\x96\xdb\xfd\xa5\xd8\xc3\xbf\xd3\xe0\x91\xda\xdc\xf0\xf4\xfc\x00\x65\x74\x3f\x00\xeb\xa3\xde\xca\x84\xf8\xca\xa3\xa3\xff\xab\xdc\xfa\x8f\xeb\xf9\xbd\xe8\xe4\xa4\xf4\xe5\x00\x41\x2a\x75\x00\xc6\x97\xa7\xde\xa5\xbb\x8f\xf1\xae\x86\xb0\xe0\xe0\xbc\xeb\xdd\xf8\xde\xe4\xf6\xb5\xff\x00\x35\x45\x53\x00\xc7\x82\xe4\xc7\xf5\xf6\xdb\x84\xf9\xed\x96\xc8\x9e\x8d\xe7\xc4\xb7\xff\xdf\x81\xa0\xee\x00\x45\x64\x72\x00\xd9\x9d\xc5\xcb\xbd\xfa\xe3\xac\xc6\xf4\x9e\xfe\xda\x93\xc9\xdd\x83\xe1\xe6\x8b\xff\xd8\x00\x65\x52\x65\x00\xfe\xf2\xd7\xe4\x82\xd9\x95\x95\xa6\xeb\xa2\xa3\xeb\x96\xfa\xc0\xaf\xe9\xe1\x81\xff\xc0\x00\x2d\x61\x66\x00\xc4\xf7\xd5\xdb\xf6\xcb\xdf\xe3\xe8\x84\x9d\xc1\xd8\x9a\xd3\xec\x83\xdd\xfa\x8d\xa9\xdd\x00\x66\x2a\x33\x00\xf6\xba\xf2\x82\xab\xba\x89\xac\xfb\x9f\xff\xc8\x98\xb7\xd2\xfd\x98\xa1\xcc\xf5\xa7\xd4\x00\x68\x65\x3f\x00\xed\xf3\xc3\xc1\x8b\xe8\xc0\xf3\xdb\xe6\x85\xf2\xdf\x91\xe3\x9b\xb1\xa7\xe3\xad\xc6\xda\x00\x70\x2b\x73\x00\xe7\x90\xe6\x94\x9f\xc0\xdd\x95\xe1\xfb\xb0\xc2\xf5\x80\xd2\xf6\xbf\xc2\xe5\xbf\xfe\xda\x00\x6a\x61\x77\x00\xf4\xbe\xfb\x8f\x8f\xfa\xc9\x83\xcc\xd8\xf8\xe5\x9f\xed\xdc\xff\xae\xff\x9a\x8b\xb0\x94\x00\x64\x72\x65\x00\xd4\xfe\xc0\x87\xbf\xa1\x87\xa0\xa7\xda\xe9\xa8\xd0\xa1\xbc\xce\x8c\xc1\x9e\x83\xd5\xc7\x00\x70\x23\x53\x00\xc7\x81\xae\xd0\x95\xfc\x9d\x9c\xd5\xfd\x8c\xf7\x84\xf1\xb5\xde\xed\xbc\xf1\xbe\xf3\xd7\x00\x73\x74\x61\x00\xfa\x82\xfe\xc6\x81\xa7\xd7\x81\xc0\x9a\xb7\xf5\xdb\x9c\xce\xd0\xa1\xbd\xe7\xa7\xb5\xfa\x00\x75\x77\x65\x00"); + } + else + { + throw new NotSupportedException(String.Format("unavailable key for key set {0}", PCARS_KEY_SET)); + } + + int PCARS_OFF = PCARS_NUM; + PCARS_OFF *= 0x1b; + + int PCARS_MEM_SIZE = (int)maKey.Length; + + if (PCARS_MEM_SIZE >= PCARS_OFF) + { + PCARS_MEM_SIZE -= PCARS_OFF; + if (PCARS_MEM_SIZE >= 0x1b) + { + PCARS_ERROR = 0; + + maKey.Seek(PCARS_OFF, SeekOrigin.Begin); + string PCARS_KEY = maKey.Reader.ReadFixedLengthString(0x1b); + int PCARS_KEYSZ = PCARS_KEY.Length; + + // xor 0x1b and 3 are multiples so no need of byte per byte xor + // encryption xor "\xac\xc7\x91"; + int TMP = (int)maKey.Length; + + + // log MEMORY_FILE3 0 TMP MEMORY_FILE3 + + // reverse short + int j = PCARS_OFF; + + for (int x = PCARS_KEYSZ; x > 1; x-=2) + { + // getvarchr TMP MEMORY_FILE3 j short + + // reverseshort TMP + + // putvarchr MEMORY_FILE3 j TMP short + + j += 2; + } + + // get key + maKey.Seek(PCARS_OFF, SeekOrigin.Begin); + PCARS_KEY = maKey.Reader.ReadFixedLengthString(PCARS_KEYSZ); + + // encryption key + // encryption rc4 PCARS_KEY "" 0 PCARS_KEYSZ + + // other pre-built keys used somewhere else: + // encryption rc4 "QgT~(x/x}yON{0Db02,M?_1g_W+FuI}kGE[sZ" + // encryption rc4 "4!spu3eyEpED?+ud6E4etHe=7?!fa" + // encryption rc4 "9TEXU+u#U*h+D=efUcRudach$&" + // encryption rc4 "jetracR--acr_t-tr*7*dadrab" + // encryption rc4 "j@yutranemuwece9Azatra?wa*" + // encryption rc4 "pUphe-apru=UWraBRu7@SW-xa#" + // encryption rc4 "d+!ugapH=stephacUchucresUC" + // encryption rc4 "we$r8truSpaT7aT7Edasw7sPap" + // encryption rc4 "+h5@u7!a7h9w8aCaqeya&rutac" + // encryption rc4 "PrEthAk$ke5RaxudrEKunAVabE" + // encryption rc4 "quwa?7@tew8era!EcRE@uf+FRu" + // encryption rc4 "j*qabaqu#7ufr7y=trUb!P@afe" + // encryption rc4 "B5u3AS6eQUwruY&?!u-rA4*te6" + // encryption rc4 "sPE32u2aS!ezEyakawuKE7uhes" + // encryption rc4 "fr2BaPujuwekasa$e5ap*te2ax" + // encryption rc4 "tuth6&r=swexe6uCedabr#vefa" + } + } + } + + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj index 4f3d0fa3..5ff1d0e7 100644 --- a/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj +++ b/CSharp/Plugins/UniversalEditor.Plugins.FileSystem/UniversalEditor.Plugins.FileSystem.csproj @@ -230,6 +230,8 @@ + + @@ -267,6 +269,7 @@ +