Skip to content

Commit

Permalink
Fix repacking large QAR files
Browse files Browse the repository at this point in the history
- Rewrote QarEntry to use streams
- Still uses a temporary file for the 1/2 of the steps
  • Loading branch information
Atvaark committed Mar 2, 2018
1 parent 40ab0e4 commit 7ef900a
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 232 deletions.
14 changes: 9 additions & 5 deletions GzsTool.Core/Common/FileSystemDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@ public FileSystemDirectory(string baseDirectoryPath)

public byte[] ReadFile(string filePath)
{
string inputFilePath = Path.Combine(_baseDirectoryPath, filePath);
using (FileStream input = new FileStream(inputFilePath, FileMode.Open))
using (var stream = ReadFileStream(filePath))
{
byte[] data = new byte[input.Length];
input.Read(data, 0, data.Length);
return data;
return stream.ToArray();
}
}

public Stream ReadFileStream(string filePath)
{
string inputFilePath = Path.Combine(_baseDirectoryPath, filePath);
FileStream stream = new FileStream(inputFilePath, FileMode.Open);
return stream;
}

public void WriteFile(string filePath, Func<Stream> fileContentStream)
{
string outputFilePath = Path.Combine(_baseDirectoryPath, filePath);
Expand Down
1 change: 1 addition & 0 deletions GzsTool.Core/Common/Interfaces/IDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public interface IDirectory : IFileSystemEntry
{
IEnumerable<IFileSystemEntry> Entries { get; }
byte[] ReadFile(string filePath);
Stream ReadFileStream(string filePath);
void WriteFile(string filePath, Func<Stream> fileContentStream);
}
}
13 changes: 11 additions & 2 deletions GzsTool.Core/Common/VirtualFileSystemDirectory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,25 @@ public string Name
}

public byte[] ReadFile(string filePath)
{
using (var stream = ReadFileStream(filePath))
{
byte[] content = stream.ToArray();
return content;
}
}

public Stream ReadFileStream(string filePath)
{
int index = filePath.IndexOf(DirectorySeparator, StringComparison.Ordinal);
if (index == -1)
{
return _files.Single(f => f.Name == filePath).Content;
return _files.Single(f => f.Name == filePath).ContentStream;
}
string subDirectory = filePath.Substring(0, index);
string subDirectoryFilePath = filePath.Substring(index + DirectorySeparator.Length,
filePath.Length - index - DirectorySeparator.Length);
return _directories.Single(d => d.Name == subDirectory).ReadFile(subDirectoryFilePath);
return _directories.Single(d => d.Name == subDirectory).ReadFileStream(subDirectoryFilePath);
}

public void WriteFile(string filePath, Func<Stream> fileContentStream)
Expand Down
141 changes: 0 additions & 141 deletions GzsTool.Core/Crypto/Cryptography.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using System;
using System.Linq;

namespace GzsTool.Core.Crypto
{
internal class Cryptography
Expand All @@ -23,143 +20,5 @@ public static int GetHeaderSize(uint encryption)

return headerSize;
}

public static void Decrypt1(byte[] sectionData, uint hashLow, uint version, byte[] dataHash)
{
// TODO: Use a ulong array instead.
uint[] decryptionTable =
{
0xBB8ADEDB,
0x65229958,
0x08453206,
0x88121302,
0x4C344955,
0x2C02F10C,
0x4887F823,
0xF3818583,
//0x40C90FDB,
//0x3FC90FDB,
//0x3F490FDB,
//0x3EA2F983,
//0x3C8EFA35,
//0x42652EE0,
//0x40C90FDB,
//0x3FC90FDB,
//0x3F490FDB,
//0x3EA2F983,
//0x3C8EFA35,
//0x42652EE0
};

int blocks = sectionData.Length / sizeof(ulong);
if (version != 2)
{
for (int i = 0; i < blocks; i++)
{
int offset1 = i * sizeof(ulong);
int offset2 = i * sizeof(ulong) + sizeof(uint);
int index = (int)(2 * ((hashLow + offset1 / 11) % 4));
uint u1 = BitConverter.ToUInt32(sectionData, offset1) ^ decryptionTable[index];
uint u2 = BitConverter.ToUInt32(sectionData, offset2) ^ decryptionTable[index + 1];
Buffer.BlockCopy(BitConverter.GetBytes(u1), 0, sectionData, offset1, sizeof(uint));
Buffer.BlockCopy(BitConverter.GetBytes(u2), 0, sectionData, offset2, sizeof(uint));
}

int remaining = sectionData.Length % sizeof(ulong);
for (int i = 0; i < remaining; i++)
{
int offset = blocks * sizeof(long) + i * sizeof(byte);
int index = (int)(2 * ((hashLow + (offset - (offset % sizeof(long))) / 11) % 4));
int decryptionIndex = offset % sizeof(long);
uint xorMask = decryptionIndex < 4 ? decryptionTable[index] : decryptionTable[index + 1];
byte xorMaskByte = (byte)((xorMask >> (8 * decryptionIndex)) & 0xff);
byte b1 = (byte)(sectionData[offset] ^ xorMaskByte);
sectionData[offset] = b1;
}
}
else
{
ulong seed = BitConverter.ToUInt64(dataHash, (int)(hashLow % 2) * 8);
uint seedLow = (uint)seed & 0xFFFFFFFF;
uint seedHigh = (uint)(seed >> 32);
for (int i = 0; i < blocks; i++)
{
int offset1 = i * sizeof(ulong);
int offset2 = i * sizeof(ulong) + sizeof(uint);
int index = 2 * (int)((hashLow + seed + (ulong)(offset1 / 11)) % 4);
uint u1 = BitConverter.ToUInt32(sectionData, offset1) ^ decryptionTable[index] ^ seedLow;
uint u2 = BitConverter.ToUInt32(sectionData, offset2) ^ decryptionTable[index + 1] ^ seedHigh;
Buffer.BlockCopy(BitConverter.GetBytes(u1), 0, sectionData, offset1, sizeof(uint));
Buffer.BlockCopy(BitConverter.GetBytes(u2), 0, sectionData, offset2, sizeof(uint));
}

int remaining = sectionData.Length % sizeof(ulong);
for (int i = 0; i < remaining; i++)
{
int offset = blocks * sizeof(long) + i * sizeof(byte);
int offsetBlock = offset - (offset % sizeof(long));
int index = 2 * (int)((hashLow + seed + (ulong)(offsetBlock / 11)) % 4);
int decryptionIndex = offset % sizeof(long);
uint xorMask = decryptionIndex < 4 ? decryptionTable[index] : decryptionTable[index + 1];
byte xorMaskByte = (byte)((xorMask >> (8 * (decryptionIndex % 4))) & 0xff);
uint seedMask = decryptionIndex < 4 ? seedLow : seedHigh;
byte seedByte = (byte)((seedMask >> (8 * (decryptionIndex % 4))) & 0xff);
sectionData[offset] = (byte)(sectionData[offset] ^ (byte)(xorMaskByte ^ seedByte));
}
}
}

public static unsafe void Decrypt2(byte[] input, uint key)
{
int size = input.Length;
uint currentKey = key | ((key ^ 25974) << 16);

byte[] output = input.ToArray();
fixed (byte* pDestBase = output, pSrcBase = input)
{
uint* pDest = (uint*) pDestBase;
uint* pSrc = (uint*) pSrcBase;
uint i = 278 * key;
for (; size >= 64; size -= 64)
{
uint j = 16;
do
{
*pDest = currentKey ^ *pSrc;
currentKey = i + 48828125 * currentKey;

--j;
pDest++;
pSrc++;
} while (j > 0);
}

for (; size >= 16; pSrc += 4)
{
*pDest = currentKey ^ *pSrc;
uint v7 = i + 48828125 * currentKey;
*(pDest + 1) = v7 ^ *(pSrc + 1);
uint v8 = i + 48828125 * v7;
*(pDest + 2) = v8 ^ *(pSrc + 2);
uint v9 = i + 48828125 * v8;
*(pDest + 3) = v9 ^ *(pSrc + 3);

currentKey = i + 48828125 * v9;
size -= 16;
pDest += 4;
}

for (; size >= 4; pSrc++)
{
*pDest = currentKey ^ *pSrc;

currentKey = i + 48828125 * currentKey;
size -= 4;
pDest++;
}
}

Buffer.BlockCopy(output, 0, input, 0, input.Length);
}
}
}
29 changes: 18 additions & 11 deletions GzsTool.Core/Crypto/Decrypt1Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,30 @@ namespace GzsTool.Core.Crypto
public class Decrypt1Stream : Stream
{
private readonly Stream _input;

private int _position;


private readonly int _size;

private readonly int _version;

private readonly uint _hashLow;


private readonly StreamMode _streamMode;

private readonly ulong _seed;

private readonly uint _seedLow;

private readonly uint _seedHigh;

public Decrypt1Stream(Stream input, int version, int size, byte[] dataHash, uint hashLow)
private int _position;

public Decrypt1Stream(Stream input, int version, int size, byte[] dataHash, uint hashLow, StreamMode streamMode)
{
_input = input;

_version = version;

_size = size;

_hashLow = hashLow;
_streamMode = streamMode;
_seed = BitConverter.ToUInt64(dataHash, (int)(hashLow % 2) * 8);
_seedLow = (uint)_seed & 0xFFFFFFFF;
_seedHigh = (uint)(_seed >> 32);
Expand Down Expand Up @@ -74,14 +74,21 @@ public override int Read(byte[] buffer, int offset, int count)

public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
if (offset != 0)
{
throw new NotSupportedException();
}

Decrypt1(buffer);
_input.Write(buffer, offset, count);
_position += count;
}

public override bool CanRead
{
get
{
return true;
return _streamMode == StreamMode.Read;
}
}

Expand All @@ -97,7 +104,7 @@ public override bool CanWrite
{
get
{
return false;
return _streamMode == StreamMode.Write;
}
}

Expand Down
20 changes: 15 additions & 5 deletions GzsTool.Core/Crypto/Decrypt2Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ public class Decrypt2Stream : Stream
private readonly Stream _input;

private readonly int _size;

private readonly uint _key;

private readonly StreamMode _streamMode;

private int _position;

private uint _blockKey;

public Decrypt2Stream(Stream input, int size, uint key)
public Decrypt2Stream(Stream input, int size, uint key, StreamMode streamMode)
{
_input = input;
_size = size;
_streamMode = streamMode;
_key = 278 * key;
_blockKey = key | ((key ^ 25974) << 16);
}
Expand Down Expand Up @@ -63,14 +66,21 @@ public override int Read(byte[] buffer, int offset, int count)

public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
if (offset != 0)
{
throw new NotSupportedException();
}

Decrypt2(buffer, count);
_input.Write(buffer, offset, count);
_position += count;
}

public override bool CanRead
{
get
{
return true;
return _streamMode == StreamMode.Read;
}
}

Expand All @@ -86,7 +96,7 @@ public override bool CanWrite
{
get
{
return false;
return _streamMode == StreamMode.Write;
}
}

Expand Down
Loading

0 comments on commit 7ef900a

Please sign in to comment.