-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
1,095 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.IO; | ||
using System.IO.Compression; | ||
using System.Buffers; | ||
using System.Buffers.Binary; | ||
|
||
using Syroot.BinaryData; | ||
using Syroot.BinaryData.Core; | ||
using Syroot.BinaryData.Memory; | ||
using ICSharpCode.SharpZipLib.Zip.Compression; | ||
using ICSharpCode.SharpZipLib.Zip.Compression.Streams; | ||
|
||
using System.Security.Cryptography; | ||
|
||
namespace GTPSPUnpacker | ||
{ | ||
public class Compression | ||
{ | ||
/// <summary> | ||
/// Decompresses a file (in memory, unsuited for large files). | ||
/// </summary> | ||
/// <param name="data"></param> | ||
/// <param name="outSize"></param> | ||
/// <param name="deflatedData"></param> | ||
/// <returns></returns> | ||
public unsafe static bool TryInflateInMemory(Span<byte> data, uint outSize, out byte[] deflatedData) | ||
{ | ||
deflatedData = Array.Empty<byte>(); | ||
if (outSize > uint.MaxValue) | ||
return false; | ||
|
||
// Inflated is always little | ||
var sr = new SpanReader(data, Endian.Little); | ||
uint zlibMagic = sr.ReadUInt32(); | ||
uint sizeComplement = sr.ReadUInt32(); | ||
|
||
if ((long)zlibMagic != 0xFFF7EEC5) | ||
return false; | ||
|
||
if (outSize + sizeComplement != 0) | ||
return false; | ||
|
||
const int headerSize = 8; | ||
if (sr.Length <= headerSize) // Header size, if it's under, data is missing | ||
return false; | ||
|
||
deflatedData = new byte[(int)outSize]; | ||
fixed (byte* pBuffer = &sr.Span.Slice(headerSize)[0]) // Vol Header Size | ||
{ | ||
using var ums = new UnmanagedMemoryStream(pBuffer, sr.Span.Length - headerSize); | ||
using var ds = new DeflateStream(ums, CompressionMode.Decompress); | ||
ds.Read(deflatedData, 0, (int)outSize); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/// <summary> | ||
/// Compresses input data (PS2ZIP-like) and encrypts it from one stream to another. | ||
/// </summary> | ||
/// <param name="data"></param> | ||
/// <returns>Length of the compressed data.</returns> | ||
public static uint PS2ZIPCompressEncrypt(Stream input, Stream output) | ||
{ | ||
long basePos = output.Position; | ||
Span<byte> header = stackalloc byte[8]; | ||
BinaryPrimitives.WriteUInt32BigEndian(header, 0xC5EEF7FFu); | ||
BinaryPrimitives.WriteInt32LittleEndian(header[4..], -(int)input.Length); | ||
|
||
VolumeCrypto.EncryptFile((uint)output.Position, header, 8); | ||
output.Write(header); | ||
|
||
var buffer = new byte[input.Length]; | ||
input.Read(buffer); | ||
|
||
var d = new Deflater(Deflater.DEFAULT_COMPRESSION, true); | ||
d.SetInput(buffer); | ||
d.Finish(); | ||
|
||
int count = d.Deflate(buffer); | ||
VolumeCrypto.EncryptFile((uint)output.Position, buffer, buffer.Length); | ||
output.Write(buffer, 0, count); | ||
|
||
return (uint)(output.Position - basePos); | ||
} | ||
|
||
/// <summary> | ||
/// Encrypts a file stream to an output stream. | ||
/// </summary> | ||
/// <param name="data"></param> | ||
/// <returns>Length of the compressed data.</returns> | ||
public static void Encrypt(Stream input, Stream output) | ||
{ | ||
const int bufferSize = 0x20000; | ||
var buffer = ArrayPool<byte>.Shared.Rent(bufferSize); | ||
|
||
uint rem = (uint)input.Length; | ||
|
||
while (rem > 0) | ||
{ | ||
uint size = Math.Min(rem, bufferSize); | ||
input.Read(buffer, 0, (int)size); | ||
VolumeCrypto.EncryptFile((uint)output.Position, buffer, buffer.Length); | ||
output.Write(buffer, 0, (int)size); | ||
|
||
rem -= size; | ||
} | ||
|
||
ArrayPool<byte>.Shared.Return(buffer); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Diagnostics; | ||
|
||
using PDTools.Utils; | ||
|
||
namespace GTPSPUnpacker.Packing | ||
{ | ||
public class IndexWriter | ||
{ | ||
public const int BTREE_SEGMENT_SIZE = 0x1000; | ||
|
||
public int CurrentDataLength = 0; | ||
|
||
public byte SegmentCount = 0; | ||
private List<VolumeEntry> _indices { get; set; } = new(); | ||
|
||
public bool IsEmpty | ||
=> _indices.Count == 0; | ||
|
||
public IndexWriter() | ||
{ | ||
|
||
} | ||
|
||
public void AddIndex(VolumeEntry entry) | ||
{ | ||
_indices.Add(entry); | ||
} | ||
|
||
public void Write(ref BitStream stream) | ||
{ | ||
BitStream entryWriter = new BitStream(BitStreamMode.Write, endian: BitStreamSignificantBitOrder.MSB); | ||
List<int> entryOffsets = new List<int>(); | ||
|
||
for (int i = 0; i < _indices.Count; i++) | ||
{ | ||
if (i != 0) | ||
entryOffsets.Add(entryWriter.Position); | ||
|
||
entryWriter.WriteByte((byte)(_indices[i].EntriesLocationSegmentIndex >> 8)); // Major 8 bits | ||
entryWriter.WriteVarPrefixString(_indices[i].Name); | ||
entryWriter.WriteByte((byte)(_indices[i].EntriesLocationSegmentIndex & 0xFF)); // Minor 8 bits | ||
} | ||
|
||
stream.WriteBoolBit(true); // Index Block | ||
|
||
Debug.Assert((ulong)_indices.Count < Utils.GetMaxValueForBitCount(11), | ||
$"IndexWriter: Index Count was larger that could fit 11 bits ({_indices.Count} < {Utils.GetMaxValueForBitCount(11)})"); | ||
stream.WriteBits((ulong)_indices.Count, 11); | ||
|
||
for (int i = 0; i < entryOffsets.Count; i++) | ||
{ | ||
uint tocSize = (uint)Utils.MeasureBytesTakenByBits(12 + (entryOffsets.Count * 12)); | ||
|
||
Debug.Assert((ulong)(tocSize + entryOffsets[i]) < Utils.GetMaxValueForBitCount(12), | ||
$"IndexWriter: Index offset was larger that could fit 12 bits ({(ulong)(tocSize + entryOffsets[i])} < {Utils.GetMaxValueForBitCount(12)})"); | ||
stream.WriteBits((ulong)(tocSize + entryOffsets[i]), 12); | ||
} | ||
|
||
stream.WriteByteData(entryWriter.GetSpan()); | ||
stream.Align(0x40); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.