-
Notifications
You must be signed in to change notification settings - Fork 131
/
granny2wrapper.cpp
106 lines (87 loc) · 3.85 KB
/
granny2wrapper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#pragma once
#include <Windows.h>
#include "granny2wrapper.h"
namespace LSLib {
namespace Native {
typedef bool(__stdcall * GrannyDecompressDataProc)(int Format, bool FileIsByteReversed, int CompressedBytesSize, void *CompressedBytes, int Stop0, int Stop1, int Stop2, void *DecompressedBytes);
typedef void *(__stdcall * GrannyBeginFileDecompressionProc)(int Format, bool FileIsByteReversed, int DecompressedBytesSize, void *DecompressedBytes, int WorkMemSize, void *WorkMemBuffer);
typedef bool(__stdcall * GrannyDecompressIncrementalProc)(void *State, int CompressedBytesSize, void *CompressedBytes);
typedef bool(__stdcall * GrannyEndFileDecompressionProc)(void *State);
array<byte> ^ Granny2Compressor::Decompress(Int32 format, array<byte> ^ compressed, Int32 decompressedSize, Int32 stop0, Int32 stop1, Int32 stop2)
{
pin_ptr<byte> inputPin(&compressed[compressed->GetLowerBound(0)]);
byte * input = inputPin;
array<byte> ^ decompressed = gcnew array<byte>(decompressedSize);
pin_ptr<byte> decompPtr(&decompressed[decompressed->GetLowerBound(0)]);
byte * decomp = decompPtr;
// Load Granny2 library
HMODULE hGranny = LoadLibraryA("granny2.dll");
if (!hGranny)
{
throw gcnew System::IO::InvalidDataException("Granny2.dll is required for compressed GR2 files.");
}
auto decompressProc = (GrannyDecompressDataProc)GetProcAddress(hGranny, "_GrannyDecompressData@32");
if (!decompressProc)
{
throw gcnew System::IO::InvalidDataException("GrannyDecompressData export not found in Granny2.dll.");
}
bool ok = decompressProc(format, false, compressed->Length, input, stop0, stop1, stop2, decomp);
if (!ok)
{
throw gcnew System::IO::InvalidDataException("Failed to decompress Oodle compressed section.");
}
FreeModule(hGranny);
return decompressed;
}
array<byte> ^ Granny2Compressor::Decompress4(array<byte> ^ compressed, Int32 decompressedSize)
{
pin_ptr<byte> inputPin(&compressed[compressed->GetLowerBound(0)]);
byte * input = inputPin;
array<byte> ^ decompressed = gcnew array<byte>(decompressedSize);
pin_ptr<byte> decompPtr(&decompressed[decompressed->GetLowerBound(0)]);
byte * decomp = decompPtr;
// Load Granny2 library
HMODULE hGranny = LoadLibraryA("granny2.dll");
if (!hGranny)
{
throw gcnew System::IO::InvalidDataException("Granny2.dll is required for compressed GR2 files.");
}
auto beginDecompressProc = (GrannyBeginFileDecompressionProc)GetProcAddress(hGranny, "GrannyBeginFileDecompression");
if (!beginDecompressProc)
{
throw gcnew System::IO::InvalidDataException("GrannyBeginFileDecompression export not found in Granny2.dll.");
}
auto decompressProc = (GrannyDecompressIncrementalProc)GetProcAddress(hGranny, "GrannyDecompressIncremental");
if (!decompressProc)
{
throw gcnew System::IO::InvalidDataException("GrannyDecompressIncremental export not found in Granny2.dll.");
}
auto endDecompressProc = (GrannyEndFileDecompressionProc)GetProcAddress(hGranny, "GrannyEndFileDecompression");
if (!endDecompressProc)
{
throw gcnew System::IO::InvalidDataException("GrannyEndFileDecompression export not found in Granny2.dll.");
}
void * workMem = malloc(0x4000);
void * state = beginDecompressProc(4, false, decompressedSize, decomp, 0x4000, workMem);
int pos = 0;
while (pos < compressed->Length)
{
int chunkSize = min(compressed->Length - pos, 0x2000);
bool incrementOk = decompressProc(state, chunkSize, input + pos);
if (!incrementOk)
{
throw gcnew System::IO::InvalidDataException("Failed to decompress GR2 section increment.");
}
pos += chunkSize;
}
bool ok = endDecompressProc(state);
if (!ok)
{
throw gcnew System::IO::InvalidDataException("Failed to finish GR2 section decompression.");
}
free(workMem);
FreeModule(hGranny);
return decompressed;
}
}
}