Files
gMod/source/uMod_File.cpp
T
DubbleClick a7e36fc965 rename to gmod, drop gui (#1)
* remove GUI parts as those will not be updated

* move to header/source

* add cmakelist to create solution

* Change Readme

* Implement modlist.txt loading

* Setup versioning and CD pipeline

* Setup DirectX in pipeline

* Make uMod load from uMod.dll directory

* Fix file loading

* Remove break

* Fix CD pipeline (#1)

* Test cd pipeline

* See what's in Lib directory

* See inside lib/x86

* Manually adjust the build environment

* Disable CD pipeline in PRs
Create CI pipeline

* Fix slashes in path

* Fix build call

* Attempt to fix paths

* Copy dx headers inside the /header folder

* Use ps

* Change cache location

* Path changes

* Improve CMake to look for lib and header files

* Fix missing Lib folder

* Move changes to CD pipeline

* Disable CI on merge and fix CD (#2)

* Fix CD tag (#4)

* Hijack existing DirectX calls (#5)

* Create a dll without listener (#6)

* Fix asset creation in CD pipeline (#7)

* Setup file loading

* create necessary files

* merge latest changes, set output dir

* Change main to master in pipelines
Add fallback for DX libs in CMakeLists

* Setup new generator

* formatting

* remove listener

* Change CD to pick the dll from bin
Change release name to gMod

* more formatting

* add editorconfig

* Setup versioning

* Remove CODEOWNERS

---------

Co-authored-by: Alex Macocian <amacocian@yahoo.com>
2023-11-10 17:40:30 +01:00

486 lines
12 KiB
C++

#include "uMod_Main.h"
#include "unzip.h"
#include "uMod_File.h"
#include "utils.h"
#include "uMod_Texture.h"
#include <fstream>
#include <sstream>
#include <vector>
#ifdef __CDT_PARSER__
#define FindZipItem(...) 0
#define UnzipItem(...) 0
#define CloseZip(...) 0
#define GetZipItem(...) 0
#endif
uMod_File::uMod_File()
{
Loaded = false;
XORed = false;
FileInMemory = static_cast<char*>(nullptr);
MemoryLength = 0u;
FileLen = 0u;
}
uMod_File::uMod_File(const std::string file)
{
Loaded = false;
XORed = false;
FileInMemory = static_cast<char*>(nullptr);
MemoryLength = 0u;
FileLen = 0u;
SetFile(file);
}
uMod_File::~uMod_File()
{
if (FileInMemory != static_cast<char*>(nullptr)) {
delete[] FileInMemory;
}
}
bool uMod_File::FileSupported()
{
const std::string file_type = GetFileExtension(FileName);
if (file_type == "zip") {
return true;
}
if (file_type == "tpf") {
return true;
}
if (file_type == "bmp") {
return true;
}
if (file_type == "jpg") {
return true;
}
if (file_type == "tga") {
return true;
}
if (file_type == "png") {
return true;
}
if (file_type == "dds") {
return true;
}
if (file_type == "ppm") {
return true;
}
return false;
}
bool uMod_File::PackageFile()
{
const std::string file_type = GetFileExtension(FileName);
if (file_type == "zip") {
return true;
}
if (file_type == "tpf") {
return true;
}
return false;
}
bool uMod_File::SingleFile()
{
const std::string file_type = GetFileExtension(FileName);
if (file_type == "bmp") {
return true;
}
if (file_type == "jpg") {
return true;
}
if (file_type == "tga") {
return true;
}
if (file_type == "png") {
return true;
}
if (file_type == "dds") {
return true;
}
if (file_type == "ppm") {
return true;
}
return false;
}
int uMod_File::GetContent()
{
const std::string file_type = GetFileExtension(FileName);
if (file_type == "zip") {
AddZip();
}
else if (file_type == "tpf") {
AddTpf();
}
else if (SingleFile()) {
AddFile();
}
else {
printf(FileName.c_str());
printf(" Not supported\n");
return -1;
}
return 0;
}
int uMod_File::ReadFile()
{
if (Loaded) {
return 0;
}
XORed = false;
const auto name = FileName;
std::ifstream inputFile(name, std::ios::binary);
if (!inputFile ||
!inputFile.is_open()) {
printf(name.c_str());
printf(" Could not open\n");
return -1;
}
const std::vector<char> buffer(std::istreambuf_iterator<char>(inputFile), {});
if (FileInMemory) {
delete[] FileInMemory;
}
FileInMemory = new char[buffer.size()];
for (auto i = 0; i < buffer.size(); i++) {
FileInMemory[i] = buffer[i];
}
FileLen = buffer.size();
inputFile.close();
FileInMemory[FileLen] = 0;
printf(name.c_str());
printf("%d\n", FileLen);
Loaded = true;
return 0;
}
int uMod_File::UnXOR()
{
if (XORed) {
return 0;
}
/*
*
* BIG THANKS TO Tonttu
* (TPFcreate 1.5)
*
*/
const auto buff = (unsigned int*)FileInMemory;
const unsigned int TPF_XOR = 0x3FA43FA4u;
const unsigned int size = FileLen / 4u;
for (unsigned int i = 0; i < size; i++) {
buff[i] ^= TPF_XOR;
}
for (unsigned int i = size * 4u; i < size * 4u + FileLen % 4u; i++) {
((unsigned char*)FileInMemory)[i] ^= static_cast<unsigned char>(TPF_XOR);
}
unsigned int pos = FileLen - 1;
while (pos > 0u && FileInMemory[pos]) {
pos--;
}
if (pos > 0u && pos < FileLen - 1) {
FileLen = pos + 1;
}
XORed = true;
/*
* original code by Tonttu
* The last bytes are not revealed correctly
unsigned int j=0;
while ( j <= result - 4 )
{
*( unsigned int* )( &buffer[j] ) ^= TPF_XOR;
j += 4;
}
while ( j < result )
{
buffer[j] ^= (unsigned char )( TPF_XOR >> 24 );
TPF_XOR <<= 4;
j++;
}
*/
return 0;
}
int uMod_File::AddFile()
{
DWORD64 temp_hash;
std::string name = AfterLast(FileName, '_');
name = BeforeLast(name, '.');
try {
// Convert hexadecimal string to unsigned long long
temp_hash = std::stoull(name, nullptr, 16);
}
catch (const std::invalid_argument& e) {
printf("Encountered error");
printf(e.what());
}
catch (const std::out_of_range& e) {
printf("Encountered error");
printf(e.what());
}
if (const int ret = ReadFile()) {
return ret;
}
FileHash = temp_hash;
return 0;
}
int uMod_File::AddZip()
{
if (const int ret = ReadFile()) {
return ret;
}
return AddContent(nullptr);
}
int uMod_File::AddTpf()
{
if (const int ret = ReadFile()) {
return ret;
}
UnXOR();
constexpr char pw[] = {
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(0xBD),
0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F,
0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74,
0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41,
0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B,
0x46, 0x6F, '\0'
};
return AddContent(pw);
}
int uMod_File::AddContent(const char* pw)
{
// Thats is really nasty code, but atm I am happy that it works. I should try an other unzip api,
// This one seems to behave very strange.
// I know, that also a bug in my code could be reason for the crashes, but UnzipItem( ... ) unzipes wrong files
// and GetZipItem( ... ) returns garbage as file names, and the next call of GetZipItem( ... ) blows up the program.
//
// I have commented line 3519 in unzip.cpp.
// It was stated this is a bug, but it did not solve my problems.
//
// closing and reopen the zip handle did the trick.
//
const auto& name = FileName;
HZIP ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
if (ZIP_Handle == static_cast<HZIP>(nullptr)) {
printf(name.c_str());
printf(" Failed to unzip file\n");
return -1;
}
ZIPENTRY ze;
int index;
FindZipItem(ZIP_Handle, "texmod.def", false, &index, &ze);
if (index >= 0) //if texmod.def is present in the zip file
{
printf(name.c_str());
printf(" Unzipping based on texmod.def of size %d\n", ze.unc_size);
char* def;
int len = ze.unc_size;
try { def = new char[len + 1]; }
catch (...) {
printf(name.c_str());
printf(" Memory error\n");
return -1;
}
ZRESULT zr = UnzipItem(ZIP_Handle, index, def, len);
if (zr != ZR_OK && zr != ZR_MORE) {
delete[] def;
return -1;
}
def[len] = 0;
std::stringstream tokenStream(def);
std::string token;
DWORD64 temp_hash;
std::string entry;
std::string file;
while (std::getline(tokenStream, token)) {
entry = token;
printf(name.c_str());
printf(" Parsing token %s\n", token.c_str());
file = BeforeFirst(token, '|');
try {
temp_hash = std::stoull(file, nullptr, 16);
// Successful conversion; can continue processing...
}
catch (const std::invalid_argument&) {
// Handle invalid argument
printf(name.c_str());
printf(" Invalid hash\n");
continue; // Skip the rest of the current loop iteration
}
catch (const std::out_of_range&) {
// Handle out of range
printf(name.c_str());
printf(" Invalid hash\n");
continue; // Skip the rest of the current loop iteration
}
file = AfterFirst(entry, '|');
ReplaceAll(file, "\r", "");
while ((!file.empty() && file[0] == '.' && (file.size() > 1 && (file[1] == '/' || file[1] == '\\')))
|| (!file.empty() && (file[0] == '/' || file[0] == '\\'))) {
file.erase(0, 1);
}
FindZipItem(ZIP_Handle, file.c_str(), false, &index, &ze); // look for texture
if (index >= 0) {
std::vector<char> data;
UModTexture texture;
data.resize(ze.unc_size);
ZRESULT rz = UnzipItem(ZIP_Handle, index, data.data(), ze.unc_size);
if (rz != ZR_OK && rz != ZR_MORE) {
printf(name.c_str());
printf(" Unzip error\n");
}
else {
texture.hash = temp_hash;
texture.data = data;
texture.name = file;
Textures.push_back(texture);
printf(name.c_str());
printf(" Added texture of size %d %s\n", data.size(), file.c_str());
}
}
else {
printf(name.c_str());
printf(" Unzip error\n");
CloseZip(ZIP_Handle); //somehow we need to close and to reopen the zip handle, otherwise the program crashes
ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
}
}
delete[] def;
CloseZip(ZIP_Handle);
if (Textures.size() == 0) {
printf(name.c_str());
printf(" No textures parsed\n");
return -1;
}
return 0;
}
//we load each dds file
{
printf(name.c_str());
printf(" Unzipping without texmode.def\n");
CloseZip(ZIP_Handle); //somehow we need to close and to reopen the zip handle, otherwise the program crashes
ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
if (ZIP_Handle == static_cast<HZIP>(nullptr)) {
printf(name.c_str());
printf(" Failed to unzip file");
return -1;
}
std::string file;
GetZipItem(ZIP_Handle, -1, &ze); //ask for number of entries
int num = ze.index;
DWORD64 temp_hash;
for (int i = 0; i < num; i++) {
if (GetZipItem(ZIP_Handle, i, &ze) != ZR_OK) {
continue; //ask for name and size
}
int len = ze.unc_size;
printf(name.c_str());
printf(" Parsing token %s\n", ze.name);
std::vector<char> data;
UModTexture texture;
data.resize(ze.unc_size);
ZRESULT rz = UnzipItem(ZIP_Handle, i, data.data(), len);
if (rz != ZR_OK && rz != ZR_MORE) {
printf(name.c_str());
printf(" Unzip error\n");
continue;
}
file = ze.name;
if (file.size() == 0) {
continue;
}
if (file == "Comment.txt") // skip comment
{
continue;
}
auto entryName = AfterLast(file, '.');
if (entryName != "dds") {
continue;
}
entryName = AfterLast(file, L'_');
entryName = BeforeLast(entryName, L'.');
try {
temp_hash = std::stoull(entryName, nullptr, 16); // Convert hex string to number
}
catch (const std::invalid_argument& e) {
printf(name.c_str());
printf(" Invalid hash\n");
continue;
}
catch (const std::out_of_range& e) {
printf(name.c_str());
printf(" Invalid hash\n");
continue;
}
texture.hash = temp_hash;
texture.name = entryName;
texture.data = data;
Textures.push_back(texture);
printf(name.c_str());
printf(" Added texture of size %d %s\n", data.size(), entryName.c_str());
}
CloseZip(ZIP_Handle);
if (Textures.size() == 0) {
printf(name.c_str());
printf(" No textures parsed\n");
return -1;
}
return 0;
}
return 0;
}