Initial commit
This commit is contained in:
2798
C#/CodeWalker.Core/GameFiles/Utils/DDSIO.cs
Normal file
2798
C#/CodeWalker.Core/GameFiles/Utils/DDSIO.cs
Normal file
File diff suppressed because it is too large
Load Diff
483
C#/CodeWalker.Core/GameFiles/Utils/Data.cs
Normal file
483
C#/CodeWalker.Core/GameFiles/Utils/Data.cs
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
Copyright(c) 2015 Neodymium
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//shamelessly stolen
|
||||
|
||||
|
||||
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public enum Endianess
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
}
|
||||
|
||||
public enum DataType
|
||||
{
|
||||
Byte = 0,
|
||||
Int16 = 1,
|
||||
Int32 = 2,
|
||||
Int64 = 3,
|
||||
Uint16 = 4,
|
||||
Uint32 = 5,
|
||||
Uint64 = 6,
|
||||
Float = 7,
|
||||
Double = 8,
|
||||
String = 9,
|
||||
}
|
||||
|
||||
public class DataReader
|
||||
{
|
||||
private Stream baseStream;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endianess of the underlying stream.
|
||||
/// </summary>
|
||||
public Endianess Endianess
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the underlying stream.
|
||||
/// </summary>
|
||||
public virtual long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the underlying stream.
|
||||
/// </summary>
|
||||
public virtual long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
baseStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new data reader for the specified stream.
|
||||
/// </summary>
|
||||
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
||||
{
|
||||
this.baseStream = stream;
|
||||
this.Endianess = endianess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the underlying stream. This is the only method that directly accesses
|
||||
/// the data in the underlying stream.
|
||||
/// </summary>
|
||||
protected virtual byte[] ReadFromStream(int count, bool ignoreEndianess = false)
|
||||
{
|
||||
var buffer = new byte[count];
|
||||
baseStream.Read(buffer, 0, count);
|
||||
|
||||
// handle endianess
|
||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
||||
{
|
||||
Array.Reverse(buffer);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte.
|
||||
/// </summary>
|
||||
public byte ReadByte()
|
||||
{
|
||||
return ReadFromStream(1)[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of bytes.
|
||||
/// </summary>
|
||||
public byte[] ReadBytes(int count)
|
||||
{
|
||||
return ReadFromStream(count, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a signed 16-bit value.
|
||||
/// </summary>
|
||||
public short ReadInt16()
|
||||
{
|
||||
return BitConverter.ToInt16(ReadFromStream(2), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a signed 32-bit value.
|
||||
/// </summary>
|
||||
public int ReadInt32()
|
||||
{
|
||||
return BitConverter.ToInt32(ReadFromStream(4), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a signed 64-bit value.
|
||||
/// </summary>
|
||||
public long ReadInt64()
|
||||
{
|
||||
return BitConverter.ToInt64(ReadFromStream(8), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an unsigned 16-bit value.
|
||||
/// </summary>
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
return BitConverter.ToUInt16(ReadFromStream(2), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an unsigned 32-bit value.
|
||||
/// </summary>
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
return BitConverter.ToUInt32(ReadFromStream(4), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an unsigned 64-bit value.
|
||||
/// </summary>
|
||||
public ulong ReadUInt64()
|
||||
{
|
||||
return BitConverter.ToUInt64(ReadFromStream(8), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single precision floating point value.
|
||||
/// </summary>
|
||||
public float ReadSingle()
|
||||
{
|
||||
return BitConverter.ToSingle(ReadFromStream(4), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a double precision floating point value.
|
||||
/// </summary>
|
||||
public double ReadDouble()
|
||||
{
|
||||
return BitConverter.ToDouble(ReadFromStream(8), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string.
|
||||
/// </summary>
|
||||
public string ReadString()
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
var temp = ReadFromStream(1)[0];
|
||||
while (temp != 0)
|
||||
{
|
||||
bytes.Add(temp);
|
||||
temp = ReadFromStream(1)[0];
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(bytes.ToArray());
|
||||
}
|
||||
|
||||
|
||||
public Vector3 ReadVector3()
|
||||
{
|
||||
Vector3 v = new Vector3();
|
||||
v.X = ReadSingle();
|
||||
v.Y = ReadSingle();
|
||||
v.Z = ReadSingle();
|
||||
return v;
|
||||
}
|
||||
public Vector4 ReadVector4()
|
||||
{
|
||||
Vector4 v = new Vector4();
|
||||
v.X = ReadSingle();
|
||||
v.Y = ReadSingle();
|
||||
v.Z = ReadSingle();
|
||||
v.W = ReadSingle();
|
||||
return v;
|
||||
}
|
||||
|
||||
public Matrix ReadMatrix()
|
||||
{
|
||||
Matrix m = new Matrix();
|
||||
m.M11 = ReadSingle();
|
||||
m.M21 = ReadSingle();
|
||||
m.M31 = ReadSingle();
|
||||
m.M41 = ReadSingle();
|
||||
m.M12 = ReadSingle();
|
||||
m.M22 = ReadSingle();
|
||||
m.M32 = ReadSingle();
|
||||
m.M42 = ReadSingle();
|
||||
m.M13 = ReadSingle();
|
||||
m.M23 = ReadSingle();
|
||||
m.M33 = ReadSingle();
|
||||
m.M43 = ReadSingle();
|
||||
m.M14 = ReadSingle();
|
||||
m.M24 = ReadSingle();
|
||||
m.M34 = ReadSingle();
|
||||
m.M44 = ReadSingle();
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//TODO: put this somewhere else...
|
||||
public static uint SizeOf(DataType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case DataType.Byte: return 1;
|
||||
case DataType.Int16: return 2;
|
||||
case DataType.Int32: return 4;
|
||||
case DataType.Int64: return 8;
|
||||
case DataType.Uint16: return 2;
|
||||
case DataType.Uint32: return 4;
|
||||
case DataType.Uint64: return 8;
|
||||
case DataType.Float: return 4;
|
||||
case DataType.Double: return 8;
|
||||
case DataType.String: return 0; //how long is a string..?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class DataWriter
|
||||
{
|
||||
private Stream baseStream;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endianess of the underlying stream.
|
||||
/// </summary>
|
||||
public Endianess Endianess
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the underlying stream.
|
||||
/// </summary>
|
||||
public virtual long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position within the underlying stream.
|
||||
/// </summary>
|
||||
public virtual long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
baseStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new data writer for the specified stream.
|
||||
/// </summary>
|
||||
public DataWriter(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
||||
{
|
||||
this.baseStream = stream;
|
||||
this.Endianess = endianess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the underlying stream. This is the only method that directly accesses
|
||||
/// the data in the underlying stream.
|
||||
/// </summary>
|
||||
protected virtual void WriteToStream(byte[] value, bool ignoreEndianess = false)
|
||||
{
|
||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
||||
{
|
||||
var buffer = (byte[])value.Clone();
|
||||
Array.Reverse(buffer);
|
||||
baseStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
baseStream.Write(value, 0, value.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
WriteToStream(new byte[] { value });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes.
|
||||
/// </summary>
|
||||
public void Write(byte[] value)
|
||||
{
|
||||
WriteToStream(value, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a signed 16-bit value.
|
||||
/// </summary>
|
||||
public void Write(short value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a signed 32-bit value.
|
||||
/// </summary>
|
||||
public void Write(int value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a signed 64-bit value.
|
||||
/// </summary>
|
||||
public void Write(long value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an unsigned 16-bit value.
|
||||
/// </summary>
|
||||
public void Write(ushort value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an unsigned 32-bit value.
|
||||
/// </summary>
|
||||
public void Write(uint value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an unsigned 64-bit value.
|
||||
/// </summary>
|
||||
public void Write(ulong value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single precision floating point value.
|
||||
/// </summary>
|
||||
public void Write(float value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a double precision floating point value.
|
||||
/// </summary>
|
||||
public void Write(double value)
|
||||
{
|
||||
WriteToStream(BitConverter.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string.
|
||||
/// </summary>
|
||||
public void Write(string value)
|
||||
{
|
||||
foreach (var c in value)
|
||||
Write((byte)c);
|
||||
Write((byte)0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Write(Vector3 value)
|
||||
{
|
||||
Write(value.X);
|
||||
Write(value.Y);
|
||||
Write(value.Z);
|
||||
}
|
||||
public void Write(Vector4 value)
|
||||
{
|
||||
Write(value.X);
|
||||
Write(value.Y);
|
||||
Write(value.Z);
|
||||
Write(value.W);
|
||||
}
|
||||
|
||||
public void Write(Matrix value)
|
||||
{
|
||||
Write(value.M11);
|
||||
Write(value.M21);
|
||||
Write(value.M31);
|
||||
Write(value.M41);
|
||||
Write(value.M12);
|
||||
Write(value.M22);
|
||||
Write(value.M32);
|
||||
Write(value.M42);
|
||||
Write(value.M13);
|
||||
Write(value.M23);
|
||||
Write(value.M33);
|
||||
Write(value.M43);
|
||||
Write(value.M14);
|
||||
Write(value.M24);
|
||||
Write(value.M34);
|
||||
Write(value.M44);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
429
C#/CodeWalker.Core/GameFiles/Utils/GTACrypto.cs
Normal file
429
C#/CodeWalker.Core/GameFiles/Utils/GTACrypto.cs
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
Copyright(c) 2015 Neodymium
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//shamelessly stolen
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public class GTACrypto
|
||||
{
|
||||
|
||||
|
||||
public static byte[] DecryptAES(byte[] data)
|
||||
{
|
||||
return DecryptAESData(data, GTA5Keys.PC_AES_KEY);
|
||||
}
|
||||
public static byte[] EncryptAES(byte[] data)
|
||||
{
|
||||
return EncryptAESData(data, GTA5Keys.PC_AES_KEY);
|
||||
}
|
||||
|
||||
public static byte[] DecryptAESData(byte[] data, byte[] key, int rounds = 1)
|
||||
{
|
||||
var rijndael = Rijndael.Create();
|
||||
rijndael.KeySize = 256;
|
||||
rijndael.Key = key;
|
||||
rijndael.BlockSize = 128;
|
||||
rijndael.Mode = CipherMode.ECB;
|
||||
rijndael.Padding = PaddingMode.None;
|
||||
|
||||
var buffer = (byte[])data.Clone();
|
||||
var length = data.Length - data.Length % 16;
|
||||
|
||||
// decrypt...
|
||||
if (length > 0)
|
||||
{
|
||||
var decryptor = rijndael.CreateDecryptor();
|
||||
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
|
||||
decryptor.TransformBlock(buffer, 0, length, buffer, 0);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
public static byte[] EncryptAESData(byte[] data, byte[] key, int rounds = 1)
|
||||
{
|
||||
var rijndael = Rijndael.Create();
|
||||
rijndael.KeySize = 256;
|
||||
rijndael.Key = key;
|
||||
rijndael.BlockSize = 128;
|
||||
rijndael.Mode = CipherMode.ECB;
|
||||
rijndael.Padding = PaddingMode.None;
|
||||
|
||||
var buffer = (byte[])data.Clone();
|
||||
var length = data.Length - data.Length % 16;
|
||||
|
||||
// encrypt...
|
||||
if (length > 0)
|
||||
{
|
||||
var encryptor = rijndael.CreateEncryptor();
|
||||
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
|
||||
encryptor.TransformBlock(buffer, 0, length, buffer, 0);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte[] GetNGKey(string name, uint length)
|
||||
{
|
||||
uint hash = GTA5Hash.CalculateHash(name);
|
||||
uint keyidx = (hash + length + (101 - 40)) % 0x65;
|
||||
return GTA5Keys.PC_NG_KEYS[keyidx];
|
||||
}
|
||||
|
||||
|
||||
public static byte[] DecryptNG(byte[] data, string name, uint length)
|
||||
{
|
||||
byte[] key = GetNGKey(name, length);
|
||||
return DecryptNG(data, key);
|
||||
}
|
||||
|
||||
public static byte[] DecryptNG(byte[] data, byte[] key)
|
||||
{
|
||||
var decryptedData = new byte[data.Length];
|
||||
|
||||
var keyuints = new uint[key.Length / 4];
|
||||
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
|
||||
|
||||
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
|
||||
{
|
||||
var encryptedBlock = new byte[16];
|
||||
Array.Copy(data, 16 * blockIndex, encryptedBlock, 0, 16);
|
||||
var decryptedBlock = DecryptNGBlock(encryptedBlock, keyuints);
|
||||
Array.Copy(decryptedBlock, 0, decryptedData, 16 * blockIndex, 16);
|
||||
}
|
||||
|
||||
if (data.Length % 16 != 0)
|
||||
{
|
||||
var left = data.Length % 16;
|
||||
Buffer.BlockCopy(data, data.Length - left, decryptedData, data.Length - left, left);
|
||||
}
|
||||
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
public static byte[] DecryptNGBlock(byte[] data, uint[] key)
|
||||
{
|
||||
var buffer = data;
|
||||
|
||||
// prepare key...
|
||||
var subKeys = new uint[17][];
|
||||
for (int i = 0; i < 17; i++)
|
||||
{
|
||||
subKeys[i] = new uint[4];
|
||||
subKeys[i][0] = key[4 * i + 0];
|
||||
subKeys[i][1] = key[4 * i + 1];
|
||||
subKeys[i][2] = key[4 * i + 2];
|
||||
subKeys[i][3] = key[4 * i + 3];
|
||||
}
|
||||
|
||||
buffer = DecryptNGRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
|
||||
buffer = DecryptNGRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_DECRYPT_TABLES[1]);
|
||||
for (int k = 2; k <= 15; k++)
|
||||
buffer = DecryptNGRoundB(buffer, subKeys[k], GTA5Keys.PC_NG_DECRYPT_TABLES[k]);
|
||||
buffer = DecryptNGRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_DECRYPT_TABLES[16]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// round 1,2,16
|
||||
public static byte[] DecryptNGRoundA(byte[] data, uint[] key, uint[][] table)
|
||||
{
|
||||
var x1 =
|
||||
table[0][data[0]] ^
|
||||
table[1][data[1]] ^
|
||||
table[2][data[2]] ^
|
||||
table[3][data[3]] ^
|
||||
key[0];
|
||||
var x2 =
|
||||
table[4][data[4]] ^
|
||||
table[5][data[5]] ^
|
||||
table[6][data[6]] ^
|
||||
table[7][data[7]] ^
|
||||
key[1];
|
||||
var x3 =
|
||||
table[8][data[8]] ^
|
||||
table[9][data[9]] ^
|
||||
table[10][data[10]] ^
|
||||
table[11][data[11]] ^
|
||||
key[2];
|
||||
var x4 =
|
||||
table[12][data[12]] ^
|
||||
table[13][data[13]] ^
|
||||
table[14][data[14]] ^
|
||||
table[15][data[15]] ^
|
||||
key[3];
|
||||
|
||||
var result = new byte[16];
|
||||
Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// round 3-15
|
||||
public static byte[] DecryptNGRoundB(byte[] data, uint[] key, uint[][] table)
|
||||
{
|
||||
var x1 =
|
||||
table[0][data[0]] ^
|
||||
table[7][data[7]] ^
|
||||
table[10][data[10]] ^
|
||||
table[13][data[13]] ^
|
||||
key[0];
|
||||
var x2 =
|
||||
table[1][data[1]] ^
|
||||
table[4][data[4]] ^
|
||||
table[11][data[11]] ^
|
||||
table[14][data[14]] ^
|
||||
key[1];
|
||||
var x3 =
|
||||
table[2][data[2]] ^
|
||||
table[5][data[5]] ^
|
||||
table[8][data[8]] ^
|
||||
table[15][data[15]] ^
|
||||
key[2];
|
||||
var x4 =
|
||||
table[3][data[3]] ^
|
||||
table[6][data[6]] ^
|
||||
table[9][data[9]] ^
|
||||
table[12][data[12]] ^
|
||||
key[3];
|
||||
|
||||
//var result = new byte[16];
|
||||
//Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
|
||||
//Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
|
||||
//Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
|
||||
//Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
|
||||
//return result;
|
||||
|
||||
var result = new byte[16];
|
||||
result[0] = (byte)((x1 >> 0) & 0xFF);
|
||||
result[1] = (byte)((x1 >> 8) & 0xFF);
|
||||
result[2] = (byte)((x1 >> 16) & 0xFF);
|
||||
result[3] = (byte)((x1 >> 24) & 0xFF);
|
||||
result[4] = (byte)((x2 >> 0) & 0xFF);
|
||||
result[5] = (byte)((x2 >> 8) & 0xFF);
|
||||
result[6] = (byte)((x2 >> 16) & 0xFF);
|
||||
result[7] = (byte)((x2 >> 24) & 0xFF);
|
||||
result[8] = (byte)((x3 >> 0) & 0xFF);
|
||||
result[9] = (byte)((x3 >> 8) & 0xFF);
|
||||
result[10] = (byte)((x3 >> 16) & 0xFF);
|
||||
result[11] = (byte)((x3 >> 24) & 0xFF);
|
||||
result[12] = (byte)((x4 >> 0) & 0xFF);
|
||||
result[13] = (byte)((x4 >> 8) & 0xFF);
|
||||
result[14] = (byte)((x4 >> 16) & 0xFF);
|
||||
result[15] = (byte)((x4 >> 24) & 0xFF);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte[] EncryptNG(byte[] data, string name, uint length)
|
||||
{
|
||||
byte[] key = GetNGKey(name, length);
|
||||
return EncryptNG(data, key);
|
||||
}
|
||||
|
||||
public static byte[] EncryptNG(byte[] data, byte[] key)
|
||||
{
|
||||
if ((GTA5Keys.PC_NG_ENCRYPT_TABLES == null) || (GTA5Keys.PC_NG_ENCRYPT_LUTs == null))
|
||||
{
|
||||
throw new Exception("Unable to encrypt - tables not loaded.");
|
||||
}
|
||||
|
||||
var encryptedData = new byte[data.Length];
|
||||
|
||||
var keyuints = new uint[key.Length / 4];
|
||||
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
|
||||
|
||||
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
|
||||
{
|
||||
byte[] decryptedBlock = new byte[16];
|
||||
Array.Copy(data, 16 * blockIndex, decryptedBlock, 0, 16);
|
||||
byte[] encryptedBlock = EncryptBlock(decryptedBlock, keyuints);
|
||||
Array.Copy(encryptedBlock, 0, encryptedData, 16 * blockIndex, 16);
|
||||
}
|
||||
|
||||
if (data.Length % 16 != 0)
|
||||
{
|
||||
var left = data.Length % 16;
|
||||
Buffer.BlockCopy(data, data.Length - left, encryptedData, data.Length - left, left);
|
||||
}
|
||||
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public static byte[] EncryptBlock(byte[] data, uint[] key)
|
||||
{
|
||||
var buffer = data;
|
||||
|
||||
// prepare key...
|
||||
var subKeys = new uint[17][];
|
||||
for (int i = 0; i < 17; i++)
|
||||
{
|
||||
subKeys[i] = new uint[4];
|
||||
subKeys[i][0] = key[4 * i + 0];
|
||||
subKeys[i][1] = key[4 * i + 1];
|
||||
subKeys[i][2] = key[4 * i + 2];
|
||||
subKeys[i][3] = key[4 * i + 3];
|
||||
}
|
||||
|
||||
buffer = EncryptRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_ENCRYPT_TABLES[16]);
|
||||
for (int k = 15; k >= 2; k--)
|
||||
buffer = EncryptRoundB_LUT(buffer, subKeys[k], GTA5Keys.PC_NG_ENCRYPT_LUTs[k]);
|
||||
buffer = EncryptRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_ENCRYPT_TABLES[1]);
|
||||
buffer = EncryptRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_ENCRYPT_TABLES[0]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundA(byte[] data, uint[] key, uint[][] table)
|
||||
{
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
|
||||
var x1 =
|
||||
table[0][data[0] ^ xorbuf[0]] ^
|
||||
table[1][data[1] ^ xorbuf[1]] ^
|
||||
table[2][data[2] ^ xorbuf[2]] ^
|
||||
table[3][data[3] ^ xorbuf[3]];
|
||||
var x2 =
|
||||
table[4][data[4] ^ xorbuf[4]] ^
|
||||
table[5][data[5] ^ xorbuf[5]] ^
|
||||
table[6][data[6] ^ xorbuf[6]] ^
|
||||
table[7][data[7] ^ xorbuf[7]];
|
||||
var x3 =
|
||||
table[8][data[8] ^ xorbuf[8]] ^
|
||||
table[9][data[9] ^ xorbuf[9]] ^
|
||||
table[10][data[10] ^ xorbuf[10]] ^
|
||||
table[11][data[11] ^ xorbuf[11]];
|
||||
var x4 =
|
||||
table[12][data[12] ^ xorbuf[12]] ^
|
||||
table[13][data[13] ^ xorbuf[13]] ^
|
||||
table[14][data[14] ^ xorbuf[14]] ^
|
||||
table[15][data[15] ^ xorbuf[15]];
|
||||
|
||||
var buf = new byte[16];
|
||||
Array.Copy(BitConverter.GetBytes(x1), 0, buf, 0, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x2), 0, buf, 4, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x3), 0, buf, 8, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x4), 0, buf, 12, 4);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundA_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
|
||||
{
|
||||
var data = (byte[])dataOld.Clone();
|
||||
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
data[y] ^= xorbuf[y];
|
||||
}
|
||||
|
||||
return new byte[] {
|
||||
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0))
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundB_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
|
||||
{
|
||||
var data = (byte[])dataOld.Clone();
|
||||
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
data[y] ^= xorbuf[y];
|
||||
}
|
||||
|
||||
return new byte[] {
|
||||
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0))};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
1470
C#/CodeWalker.Core/GameFiles/Utils/GTAKeys.cs
Normal file
1470
C#/CodeWalker.Core/GameFiles/Utils/GTAKeys.cs
Normal file
File diff suppressed because it is too large
Load Diff
265
C#/CodeWalker.Core/GameFiles/Utils/Jenk.cs
Normal file
265
C#/CodeWalker.Core/GameFiles/Utils/Jenk.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
|
||||
public class JenkHash
|
||||
{
|
||||
public JenkHashInputEncoding Encoding { get; set; }
|
||||
public string Text { get; set; }
|
||||
public int HashInt { get; set; }
|
||||
public uint HashUint { get; set; }
|
||||
public string HashHex { get; set; }
|
||||
|
||||
public JenkHash(string text, JenkHashInputEncoding encoding)
|
||||
{
|
||||
Encoding = encoding;
|
||||
Text = text;
|
||||
HashUint = GenHash(text, encoding);
|
||||
HashInt = (int)HashUint;
|
||||
HashHex = "0x" + HashUint.ToString("X");
|
||||
}
|
||||
|
||||
|
||||
public static uint GenHash(string text, JenkHashInputEncoding encoding)
|
||||
{
|
||||
uint h = 0;
|
||||
byte[] chars;
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
default:
|
||||
case JenkHashInputEncoding.UTF8:
|
||||
chars = UTF8Encoding.UTF8.GetBytes(text);
|
||||
break;
|
||||
case JenkHashInputEncoding.ASCII:
|
||||
chars = ASCIIEncoding.ASCII.GetBytes(text);
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < chars.Length; i++)
|
||||
{
|
||||
h += chars[i];
|
||||
h += (h << 10);
|
||||
h ^= (h >> 6);
|
||||
}
|
||||
h += (h << 3);
|
||||
h ^= (h >> 11);
|
||||
h += (h << 15);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public static uint GenHash(string text)
|
||||
{
|
||||
if (text == null) return 0;
|
||||
uint h = 0;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
h += (byte)text[i];
|
||||
h += (h << 10);
|
||||
h ^= (h >> 6);
|
||||
}
|
||||
h += (h << 3);
|
||||
h ^= (h >> 11);
|
||||
h += (h << 15);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public static uint GenHash(byte[] data)
|
||||
{
|
||||
uint h = 0;
|
||||
for (uint i = 0; i < data.Length; i++)
|
||||
{
|
||||
h += data[i];
|
||||
h += (h << 10);
|
||||
h ^= (h >> 6);
|
||||
}
|
||||
h += (h << 3);
|
||||
h ^= (h >> 11);
|
||||
h += (h << 15);
|
||||
return h;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum JenkHashInputEncoding
|
||||
{
|
||||
UTF8 = 0,
|
||||
ASCII = 1,
|
||||
}
|
||||
|
||||
|
||||
public class JenkIndMatch
|
||||
{
|
||||
public string Hash { get; set; }
|
||||
public string Value { get; set; }
|
||||
public double Score { get; set; }
|
||||
|
||||
public JenkIndMatch(string hash, string val)
|
||||
{
|
||||
Hash = hash;
|
||||
Value = val;
|
||||
CalculateScore();
|
||||
}
|
||||
|
||||
public void CalculateScore()
|
||||
{
|
||||
|
||||
int wordlength = 0;
|
||||
int wordrank = 0;
|
||||
|
||||
string okwordsymbs = " _-.";
|
||||
string goodwordsymbs = "_";
|
||||
|
||||
for (int i = 0; i < Value.Length; i++)
|
||||
{
|
||||
char c = Value[i];
|
||||
|
||||
bool wordchar = (char.IsLetter(c) || char.IsDigit(c) || goodwordsymbs.Contains(c));
|
||||
|
||||
if (wordchar)
|
||||
{
|
||||
wordlength++;
|
||||
}
|
||||
else if (okwordsymbs.Contains(c))
|
||||
{
|
||||
//wordlength++; //don't add this to the score, but allow it to continue the chain
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wordlength > 2)
|
||||
{
|
||||
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
|
||||
}
|
||||
wordlength = 0;
|
||||
}
|
||||
|
||||
//wordrank += wordlength; //each sequential letter in a word contributes more to the rank, ie. 1+2+3+4+...
|
||||
}
|
||||
if (wordlength > 2)
|
||||
{
|
||||
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
|
||||
}
|
||||
|
||||
|
||||
if (Value.Length > 0)
|
||||
{
|
||||
//the max value for a given length when 1+2+3+4+5+..n = n(n+1)/2
|
||||
//double n = (double)Value.Length;
|
||||
//double maxscore = n * (n + 1.0) * 0.5;
|
||||
|
||||
double n = (double)Value.Length;
|
||||
Score = (((double)wordrank) / n);
|
||||
//Score = (((double)wordrank));
|
||||
}
|
||||
else
|
||||
{
|
||||
Score = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} -> {1} ({2:0.##})", Hash, Value, Score);
|
||||
}
|
||||
}
|
||||
|
||||
public class JenkIndProblem
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
public string Excuse { get; set; }
|
||||
public int Line { get; set; }
|
||||
|
||||
public JenkIndProblem(string filepath, string excuse, int line)
|
||||
{
|
||||
Filename = Path.GetFileName(filepath);
|
||||
Excuse = excuse;
|
||||
Line = line;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} : {1} at line {2}", Filename, Excuse, Line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class JenkIndex
|
||||
{
|
||||
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
|
||||
private static object syncRoot = new object();
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
Index.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Ensure(string str)
|
||||
{
|
||||
uint hash = JenkHash.GenHash(str);
|
||||
if (hash == 0) return true;
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (!Index.ContainsKey(hash))
|
||||
{
|
||||
Index.Add(hash, str);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string GetString(uint hash)
|
||||
{
|
||||
string res;
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (!Index.TryGetValue(hash, out res))
|
||||
{
|
||||
res = hash.ToString();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public static string TryGetString(uint hash)
|
||||
{
|
||||
string res;
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (!Index.TryGetValue(hash, out res))
|
||||
{
|
||||
res = string.Empty;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static string[] GetAllStrings()
|
||||
{
|
||||
string[] res = null;
|
||||
lock (syncRoot)
|
||||
{
|
||||
res = Index.Values.ToArray();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user