subrepo:
  subdir:   "OTRGui"
  merged:   "a6066a251"
upstream:
  origin:   "https://github.com/HarbourMasters/otrgui.git"
  branch:   "master"
  commit:   "a6066a251"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
This commit is contained in:
M4xw
2022-03-22 02:53:51 +01:00
parent 442a88f03b
commit f52a2a6406
1018 changed files with 511803 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
#include "baserom_extractor.h"
#include "utils/mutils.h"
#include "yaz0/yaz0.h"
#include <filesystem>
#include <fstream>
#include <cstring>
#ifndef _MSC_VER
#include <byteswap.h>
#endif
namespace fs = std::filesystem;
#define DMA_ENTRY_SIZE 16
#if defined (_MSC_VER)
#define __bswap_32 _byteswap_ulong
#define bswap_32 _byteswap_ulong
#endif
//Rom DMA table start
#define OOT_OFF_NTSC_10_RC 0x7430
#define OOT_OFF_NTSC_10 0x7430
#define OOT_OFF_NTSC_11 0x7430
#define OOT_OFF_PAL_10 0x7950
#define OOT_OFF_NTSC_12 0x7960
#define OOT_OFF_PAL_11 0x7950
#define OOT_OFF_JP_GC 0x7170
#define OOT_OFF_JP_MQ 0x7170
#define OOT_OFF_US_GC 0x7170
#define OOT_OFF_US_MQ 0x7170
#define OOT_OFF_PAL_GC_DBG1 0x12F70
#define OOT_OFF_PAL_MQ_DBG 0x12F70
#define OOT_OFF_PAL_GC_DBG2 0x12F70
#define OOT_OFF_PAL_GC 0x7170
#define OOT_OFF_PAL_MQ 0x7170
#define OOT_OFF_JP_GC_CE 007170
#define OOT_OFF_CN_IQUE 0xB7A0
#define OOT_OFF_TW_IQUE 0xB240
#define MM_OFF_US_10 0x1A500
#define MM_OFF_JP_10 0x1C110
#define MM_OFF_JP_11 0x1C050
#define MM_OFF_DBG 0x24F60
RomVersion GetVersion(FILE* rom) {
RomVersion version;
fseek(rom, 0x10, SEEK_SET);
if (fread(&version.crc, sizeof(uint32_t), 1, rom) != 1) {
version.error = "Could not read rom CRC";
return version;
}
version.crc = __bswap_32(version.crc);
switch (version.crc) {
case OOT_NTSC_10:
version.version = "N64 NTSC 1.0";
version.listPath = "ntsc_oot.txt";
version.offset = OOT_OFF_NTSC_10;
break;
case OOT_NTSC_11:
version.version = "N64 NTSC 1.1";
version.listPath = "ntsc_oot.txt";
version.offset = OOT_OFF_NTSC_11;
break;
case OOT_NTSC_12:
version.version = "N64 NTSC 1.2";
version.listPath = "ntsc_oot.txt";
version.offset = OOT_OFF_NTSC_12;
break;
case OOT_PAL_10:
version.version = "N64 PAL 1.0";
version.listPath = "pal_oot.txt";
version.offset = OOT_OFF_PAL_10;
break;
case OOT_PAL_11:
version.version = "N64 PAL 1.1";
version.listPath = "pal_oot.txt";
version.offset = OOT_OFF_PAL_11;
break;
case OOT_NTSC_JP_GC:
version.version = "JP GameCube (MQ Disk)";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_JP_GC;
break;
case OOT_NTSC_JP_GC_CE:
version.version = "GameCube (Collectors Edition Disk)";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_JP_GC_CE;
break;
case OOT_NTSC_JP_MQ:
version.version = "JP Master Quest";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_MQ:
version.version = "NTSC Master Quest";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_GC:
version.version = "NTSC GameCube";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_US_MQ;
break;
case OOT_PAL_GC:
version.version = "PAL GameCube";
version.listPath = "gamecube_mq.txt";
version.offset = OOT_OFF_PAL_GC;
break;
case OOT_PAL_MQ:
version.version = "PAL Master Quest";
version.listPath = "pal_mq.txt";
version.offset = OOT_OFF_PAL_MQ;
break;
case OOT_PAL_GC_DBG1:
version.version = "GameCube Debug 1.0";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_GC_DBG1;
break;
case OOT_PAL_GC_DBG2:
version.version = "GameCube Debug 2.0";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_GC_DBG2;
break;
case OOT_PAL_GC_MQ_DBG:
version.version = "GameCube MQ-Debug";
version.listPath = "dbg.txt";
version.offset = OOT_OFF_PAL_MQ_DBG;
break;
case OOT_IQUE_CN:
version.version = "OoT IQue";
version.listPath = "ique.txt";
version.offset = OOT_OFF_CN_IQUE;
break;
case OOT_IQUE_TW:
version.version = "TW IQue";
version.listPath = "ique.txt";
version.offset = OOT_OFF_TW_IQUE;
break;
default:
version.error = MoonUtils::format("Unknown CRC %x given: ", version.crc);
}
return version;
}
std::string read(const std::string& file) {
if (std::ifstream in(file, std::ios::in | std::ios::binary); in)
return { std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>() };
return "None";
}
int to_int(char* buffer) {
int a;
memcpy(&a, buffer, sizeof(int));
return a;
}
WriteResult ExtractBaserom(const char* romPath) {
FILE* rom = fopen(romPath, "rb");
RomVersion version = GetVersion(rom);
WriteResult result;
if (rom == nullptr) {
result.error = "Could not open baserom.z64";
return result;
}
fseek(rom, 0, SEEK_END);
const long romSize = ftell(rom);
char* romData = new char[romSize];
rewind(rom);
fread(romData, sizeof(char), romSize, rom);
MoonUtils::mkdir("tmp/baserom/");
const std::vector<std::string> lines = MoonUtils::split(read(MoonUtils::join("assets/extractor/filelists", version.listPath)), '\n');
for (int i = 0; i < lines.size(); i++) {
FILE* outFile = fopen(MoonUtils::join("tmp/baserom", lines[i]).c_str(), "wb");
const int romOffset = version.offset + (DMA_ENTRY_SIZE * i);
const int virtStart = bswap_32(to_int(romData + romOffset));
const int virtEnd = bswap_32(to_int(romData + romOffset + 4));
const int physStart = bswap_32(to_int(romData + romOffset + 8));
const int physEnd = bswap_32(to_int(romData + romOffset + 12));
printf("File: %s vStart: 0x%08X vEnd: 0x%08X pStart: 0x%08X pEnd: 0x%08X\n", lines[i].c_str(), virtStart, virtEnd, physStart, physEnd);
const bool compressed = physEnd != 0;
int size = compressed ? physEnd - physStart : virtEnd - virtStart;
auto outData = new uint8_t[size];
memcpy(outData, romData + physStart, size);
if (compressed) {
std::vector<uint8_t> compressedData = yaz0_encode(outData, size);
outData = compressedData.data();
size = compressedData.size();
}
fwrite(outData, sizeof(char), size, outFile);
fflush(outFile);
fclose(outFile);
}
fclose(rom);
return result;
}

View File

@@ -0,0 +1,39 @@
#ifndef EXTRACT_BASEROM_H_
#define EXTRACT_BASEROM_H_
#define OOT_NTSC_10 0xEC7011B7
#define OOT_NTSC_11 0xD43DA81F
#define OOT_NTSC_12 0x693BA2AE
#define OOT_PAL_10 0xB044B569
#define OOT_PAL_11 0xB2055FBD
#define OOT_NTSC_JP_GC_CE 0xF7F52DB8
#define OOT_NTSC_JP_GC 0xF611F4BA
#define OOT_NTSC_US_GC 0xF3DD35BA
#define OOT_PAL_GC 0x09465AC3
#define OOT_NTSC_JP_MQ 0xF43B45BA
#define OOT_NTSC_US_MQ 0xF034001A
#define OOT_PAL_MQ 0x1D4136F3
#define OOT_PAL_GC_DBG1 0x871E1C92 // 03-21-2002 build
#define OOT_PAL_GC_DBG2 0x87121EFE // 03-13-2002 build
#define OOT_PAL_GC_MQ_DBG 0x917D18F6
#define OOT_IQUE_TW 0x3D81FB3E
#define OOT_IQUE_CN 0xB1E1E07B
#include <cstdio>
#include <string>
struct RomVersion {
std::string version = "None";
std::string error = "None";
std::string listPath = "None";
int offset;
uint32_t crc;
};
struct WriteResult {
std::string error = "None";
};
WriteResult ExtractBaserom(const char* filePath);
RomVersion GetVersion(FILE * rom);
#endif

View File

@@ -0,0 +1,29 @@
#ifndef __READWRITE_H__
#define __READWRITE_H__
#include <stdint.h>
/* variables */
union {
uint32_t u;
float f;
} __u32_f32_union__;
#define U32(x) \
((uint32_t)((((uint8_t*)(x))[0] << 24) | (((uint8_t*)(x))[1] << 16) | \
(((uint8_t*)(x))[2] << 8) | ((uint8_t*)(x))[3]))
#define U16(x) ((uint16_t)(((*((uint8_t*)(x))) << 8) | ((uint8_t*)(x))[1]))
#define U8(x) ((uint8_t)((uint8_t*)(x))[0])
#define S32(x) ((int32_t)(U32(x)))
#define S16(x) ((int16_t)(U16(x)))
#define F32(x) (((__u32_f32_union__.u = U32(x)) & 0) + __u32_f32_union__.f)
#define W32(x, v) \
{ \
*((uint8_t*)x + 3) = ((v)&0xFF); \
*((uint8_t*)x + 2) = (((v) >> 8) & 0xFF); \
*((uint8_t*)x + 1) = (((v) >> 16) & 0xFF); \
*((uint8_t*)x + 0) = (((v) >> 24) & 0xFF); \
}
#endif

View File

@@ -0,0 +1,227 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <list>
#include "readwrite.h"
#include "yaz0.h"
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
/* internal declarations */
int yaz0_encode_internal(const u8* src, int srcSize, u8* Data);
int yaz0_get_size(u8* src) { return U32(src + 0x4); }
u32 toDWORD(u32 d) {
u8 w1 = d & 0xFF;
u8 w2 = (d >> 8) & 0xFF;
u8 w3 = (d >> 16) & 0xFF;
u8 w4 = d >> 24;
return (w1 << 24) | (w2 << 16) | (w3 << 8) | w4;
}
// simple and straight encoding scheme for Yaz0
u32 longest_match_brute(const u8* src, int size, int pos, u32* pMatchPos) {
int startPos = pos - 0x1000;
int max_match_size = size - pos;
u32 best_match_size = 0;
u32 best_match_pos = 0;
if (max_match_size < 3) return 0;
if (startPos < 0) startPos = 0;
if (max_match_size > 0x111) max_match_size = 0x111;
for (int i = startPos; i < pos; i++) {
int current_size;
for (current_size = 0; current_size < max_match_size; current_size++) {
if (src[i + current_size] != src[pos + current_size]) {
break;
}
}
if (current_size > best_match_size) {
best_match_size = current_size;
best_match_pos = i;
if (best_match_size == 0x111) break;
}
}
*pMatchPos = best_match_pos;
return best_match_size;
}
u32 longest_match_rabinkarp(const u8* src, int size, int pos, u32* match_pos) {
int startPos = pos - 0x1000;
int max_match_size = size - pos;
u32 best_match_size = 0;
u32 best_match_pos = 0;
if (max_match_size < 3) return 0;
if (startPos < 0) startPos = 0;
if (max_match_size > 0x111) max_match_size = 0x111;
int find_hash = src[pos] << 16 | src[pos + 1] << 8 | src[pos + 2];
int current_hash = src[startPos] << 16 | src[startPos + 1] << 8 | src[startPos + 2];
for (int i = startPos; i < pos; i++) {
if(current_hash == find_hash) {
int current_size;
for (current_size = 3; current_size < max_match_size; current_size++) {
if (src[i + current_size] != src[pos + current_size]) {
break;
}
}
if (current_size > best_match_size) {
best_match_size = current_size;
best_match_pos = i;
if (best_match_size == 0x111) break;
}
}
current_hash = (current_hash << 8 | src[i + 3]) & 0xFFFFFF;
}
*match_pos = best_match_pos;
return best_match_size;
}
int yaz0_encode_internal(const u8* src, int srcSize, u8* Data) {
int srcPos = 0;
int bitmask = 0x80;
u8 currCodeByte = 0;
int currCodeBytePos = 0;
int pos = currCodeBytePos + 1;
while (srcPos < srcSize) {
u32 numBytes;
u32 matchPos;
numBytes = longest_match_rabinkarp(src, srcSize, srcPos, &matchPos);
//fprintf(stderr, "pos %x len %x pos %x\n", srcPos, (int)numBytes, (int)matchPos);
if (numBytes < 3) {
//fprintf(stderr, "single byte %02x\n", src[srcPos]);
Data[pos++] = src[srcPos++];
currCodeByte |= bitmask;
} else {
// RLE part
u32 dist = srcPos - matchPos - 1;
if (numBytes >= 0x12) // 3 byte encoding
{
Data[pos++] = dist >> 8; // 0R
Data[pos++] = dist & 0xFF; // FF
if (numBytes > 0xFF + 0x12) numBytes = 0xFF + 0x12;
Data[pos++] = numBytes - 0x12;
} else // 2 byte encoding
{
Data[pos++] = ((numBytes - 2) << 4) | (dist >> 8);
Data[pos++] = dist & 0xFF;
}
srcPos += numBytes;
}
bitmask >>= 1;
// write eight codes
if (!bitmask) {
Data[currCodeBytePos] = currCodeByte;
currCodeBytePos = pos++;
currCodeByte = 0;
bitmask = 0x80;
}
}
if (bitmask) {
Data[currCodeBytePos] = currCodeByte;
}
return pos;
}
std::vector<uint8_t> yaz0_encode_fast(const u8* src, int src_size) {
std::vector<uint8_t> buffer;
std::vector<std::list<uint32_t>> lut;
lut.resize(0x1000000);
for (int i = 0; i < src_size - 3; ++i) {
lut[src[i + 0] << 16 | src[i + 1] << 8 | src[i + 2]].push_back(i);
}
return buffer;
}
std::vector<uint8_t> yaz0_encode(const u8* src, int src_size) {
std::vector<uint8_t> buffer(src_size * 10 / 8 + 16);
u8* dst = buffer.data();
// write 4 bytes yaz0 header
memcpy(dst, "Yaz0", 4);
// write 4 bytes uncompressed size
W32(dst + 4, src_size);
// encode
int dst_size = yaz0_encode_internal(src, src_size, dst + 16);
int aligned_size = (dst_size + 31) & -16;
buffer.resize(aligned_size);
#if 0
std::vector<uint8_t> decompressed(src_size);
yaz0_decode(buffer.data(), decompressed.data(), src_size);
if(memcmp(src, decompressed.data(), src_size)) {
fprintf(stderr, "Decompressed buffer is different from original\n");
}
#endif
return buffer;
}
void yaz0_decode(const uint8_t* source, uint8_t* decomp, int32_t decompSize) {
uint32_t srcPlace = 0, dstPlace = 0;
uint32_t i, dist, copyPlace, numBytes;
uint8_t codeByte, byte1, byte2;
uint8_t bitCount = 0;
source += 0x10;
while (dstPlace < decompSize) {
/* If there are no more bits to test, get a new byte */
if (!bitCount) {
codeByte = source[srcPlace++];
bitCount = 8;
}
/* If bit 7 is a 1, just copy 1 byte from source to destination */
/* Else do some decoding */
if (codeByte & 0x80) {
decomp[dstPlace++] = source[srcPlace++];
} else {
/* Get 2 bytes from source */
byte1 = source[srcPlace++];
byte2 = source[srcPlace++];
/* Calculate distance to move in destination */
/* And the number of bytes to copy */
dist = ((byte1 & 0xF) << 8) | byte2;
copyPlace = dstPlace - (dist + 1);
numBytes = byte1 >> 4;
/* Do more calculations on the number of bytes to copy */
if (!numBytes)
numBytes = source[srcPlace++] + 0x12;
else
numBytes += 2;
/* Copy data from a previous point in destination */
/* to current point in destination */
for (i = 0; i < numBytes; i++) decomp[dstPlace++] = decomp[copyPlace++];
}
/* Set up for the next read cycle */
codeByte = codeByte << 1;
bitCount--;
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include <vector>
void yaz0_decode(const uint8_t* src, uint8_t* dest, int32_t destsize);
std::vector<uint8_t> yaz0_encode(const uint8_t* src, int src_size);

View File

@@ -0,0 +1,102 @@
#include "extractor.h"
#include <string>
#include "impl.h"
#include "utils/mutils.h"
#include <thread>
#ifdef _WIN32
#define PLATFORM Platforms::WINDOWS
#else
#define PLATFORM Platforms::LINUX
#endif
namespace Util = MoonUtils;
static int maxResources = 0;
static int extractedResources = 0;
bool buildingOtr = false;
int skipFrames = 0;
bool isWindows() {
return (PLATFORM == Platforms::WINDOWS);
}
void BuildOTR(const std::string output) {
Util::copy("tmp/baserom/Audiobank", "Extract/Audiobank");
Util::copy("tmp/baserom/Audioseq", "Extract/Audioseq");
Util::copy("tmp/baserom/Audiotable", "Extract/Audiotable");
Util::copy("assets/game/", "Extract/assets/");
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out") + " botr -se OTR";
ProcessResult result = NativeFS->LaunchProcess(execStr);
if(result.exitCode != 0) {
std::cout << "\nError when building the OTR file with error code: " << result.exitCode << " !" << std::endl;
std::cout << "Aborting...\n" << std::endl;
}
setCurrentStep("Done!");
if (output == ".") return;
const std::string outputPath = MoonUtils::join(output, "oot.otr");
if(MoonUtils::exists(outputPath)) MoonUtils::rm(outputPath);
MoonUtils::copy("oot.otr", outputPath);
}
void ExtractFile(std::string xmlPath, std::string outPath, std::string outSrcPath) {
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out");
std::string args = Util::format(" e -eh -i %s -b tmp/baserom/ -o %s -osf %s -gsf 1 -rconf assets/extractor/Config.xml -se OTR %s", xmlPath.c_str(), outPath.c_str(), outSrcPath.c_str(), xmlPath.find("overlays") != std::string::npos ? "--static" : "");
ProcessResult result = NativeFS->LaunchProcess(execStr + args);
if (result.exitCode != 0) {
std::cout << "\nError when extracting the ROM with error code: " << result.exitCode << " !" << std::endl;
std::cout << "Aborting...\n" << std::endl;
}
}
void ExtractFunc(std::string fullPath) {
std::vector<std::string> path = Util::split(fullPath, Util::pathSeparator());
std::string outPath = Util::join(Util::join("assets/extractor/xmls/output", path[4]), Util::basename(fullPath));
Util::mkdir(outPath);
ExtractFile(fullPath, outPath, outPath);
setCurrentStep("Extracting: " + Util::basename(fullPath));
extractedResources++;
}
void startWorker() {
std::string path = "assets/extractor/xmls";
std::vector<std::string> files;
Util::dirscan(path, files);
std::vector<std::string> xmlFiles;
for(auto &file : files) {
if (file.find(".xml") != std::string::npos) xmlFiles.push_back(file);
}
for (auto& file : xmlFiles) {
if(single_thread) {
ExtractFunc(file);
} else {
std::thread thread_object(ExtractFunc, file);
thread_object.detach();
}
}
maxResources = xmlFiles.size();
}
void updateWorker(const std::string& output) {
if (maxResources > 0 && !buildingOtr && extractedResources >= maxResources) {
setCurrentStep("Building OTR...");
if (skipFrames < 3) {
skipFrames++;
return;
}
buildingOtr = true;
if (single_thread){
BuildOTR(output);
return;
}
std::thread otr(BuildOTR, output);
otr.detach();
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include <string>
enum Platforms {
WINDOWS, LINUX
};
void startWorker();
void updateWorker(const std::string& output);

View File

@@ -0,0 +1,82 @@
#include "fix_baserom.h"
#include <cstdlib>
#include <cstdio>
#ifndef _MSC_VER
#include <byteswap.h>
#endif
#include "md5/md5.h"
#define ROM_SIZE 0x3600000
#if defined (_MSC_VER)
#define __bswap_32 _byteswap_ulong
#define bswap_32 _byteswap_ulong
#define __bswap_16 _byteswap_ushort
#endif
int fix_baserom(const char* baserom_path, const char* output_path) {
FILE* currentFile = fopen(baserom_path, "rb");
char md5[16];
if (currentFile != nullptr) md5File(currentFile, md5);
currentFile = fopen(baserom_path, "rb");
if (currentFile != NULL) {
uint8_t firstByte = 0x00;
if (fread(&firstByte, sizeof(uint8_t), 1, currentFile) != 1) return 1;
fseek(currentFile, 0, SEEK_SET);
FILE* outFile = fopen(output_path, "wb");
// Little Endian N64 Rom
if (firstByte == 0x40) {
uint32_t currentWord;
for (uint32_t i = 0; i < ROM_SIZE / 4; i++) {
if (fread(&currentWord, sizeof(uint32_t), 1, currentFile) != 1) {
fprintf(stderr, "Failed to read data from rom file\n");
}
currentWord = __bswap_32(currentWord);
if (fwrite(&currentWord, sizeof(uint32_t), 1, outFile) != 1) {
fprintf(stderr, "Failed to write to new rom file.\n");
}
}
} else if (firstByte == 0x37) { // Byte Swapped
uint16_t currentShort;
for (uint32_t i = 0; i < ROM_SIZE / 2; i++) {
if (fread(&currentShort, sizeof(uint16_t), 1, currentFile) != 1) {
fprintf(stderr, "Failed to read data from rom file\n");
return 1;
}
currentShort = __bswap_16(currentShort);
if (fread(&currentShort, sizeof(uint16_t), 1, outFile) != 1) {
fprintf(stderr, "Failed to write to new rom file.\n");
return 1;
}
}
} else { // Big Endian
void* data = malloc(ROM_SIZE);
if (data == NULL) {
fprintf(stderr, "Failed to allocate memory for new baserom.\n");
return 1;
}
if (fread(data, ROM_SIZE, 1, currentFile) != 1) {
fprintf(stderr, "Failed to read data from rom file\n");
return 1;
}
if (fread(data, ROM_SIZE, 1, outFile) != 1) {
fprintf(stderr, "Failed to write to new rom file.\n");
}
free(data);
}
fseek(outFile, 0x3E, SEEK_SET);
fputc('P', outFile); // Patch the rom header to be 'PAL'
fclose(outFile);
fclose(currentFile);
}
}

View File

@@ -0,0 +1,3 @@
#pragma once
int fix_baserom(const char* baserom_path, const char* output_path);

View File

@@ -0,0 +1,307 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#ifndef HAVE_OPENSSL
#include <string.h>
#include "md5.h"
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) (((x) ^ (y)) ^ (z))
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them in a
* properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned memory
* accesses is just an optimization. Nothing will break if it fails to detect
* a suitable architecture.
*
* Unfortunately, this optimization may be a C strict aliasing rules violation
* if the caller's data buffer has effective type that cannot be aliased by
* MD5_u32plus. In practice, this problem may occur if these MD5 routines are
* inlined into a calling function, or with future and dangerously advanced
* link-time optimizations. For the time being, keeping these MD5 routines in
* their own translation unit avoids the problem.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
(*(MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update the bit
* counters. There are no alignment requirements.
*/
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = (const unsigned char *)data;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
void MD5_Init(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
}
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
MD5_u32plus saved_lo;
unsigned long used, available;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
available = 64 - used;
if (size < available) {
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
body(ctx, ctx->buffer, 64);
}
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
#define OUT(dst, src) \
(dst)[0] = (unsigned char)(src); \
(dst)[1] = (unsigned char)((src) >> 8); \
(dst)[2] = (unsigned char)((src) >> 16); \
(dst)[3] = (unsigned char)((src) >> 24);
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
unsigned long used, available;
used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
available = 64 - used;
if (available < 8) {
memset(&ctx->buffer[used], 0, available);
body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->buffer[used], 0, available - 8);
ctx->lo <<= 3;
OUT(&ctx->buffer[56], ctx->lo)
OUT(&ctx->buffer[60], ctx->hi)
body(ctx, ctx->buffer, 64);
OUT(&result[0], ctx->a)
OUT(&result[4], ctx->b)
OUT(&result[8], ctx->c)
OUT(&result[12], ctx->d)
memset(ctx, 0, sizeof(*ctx));
}
#endif
void md5File(FILE* file, char* outBuffer) {
char buffer[1024];
size_t inputSize = 0;
fseek(file, 0, SEEK_SET);
MD5_CTX ctx;
MD5_Init(&ctx);
while ((inputSize = fread(buffer, 1, 1024, file)) > 0) {
MD5_Update(&ctx, (char*)buffer, inputSize);
}
//char buffer2[16];
MD5_Final(outBuffer, &ctx);
}

View File

@@ -0,0 +1,58 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
#ifdef HAVE_OPENSSL
#include <openssl/md5.h>
#elif !defined(_MD5_H)
#define _MD5_H
#include <stdio.h>
#include <stdint.h>
/* Any 32-bit or wider unsigned integer data type will do */
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned int MD5_u32plus;
typedef struct {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
} MD5_CTX;
extern void MD5_Init(MD5_CTX* ctx);
extern void MD5_Update(MD5_CTX* ctx, const void* data, unsigned long size);
extern void MD5_Final(unsigned char* result, MD5_CTX* ctx);
extern void md5File(FILE* inFile, char* outBuffer);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,20 @@
#pragma once
#include <string>
#define NULLSTR "None"
enum class LaunchType {
FILE, FOLDER
};
struct ProcessResult {
int exitCode;
};
class FSBridge {
public:
virtual void InitBridge() = 0;
virtual ProcessResult LaunchProcess(std::string cmd) = 0;
virtual std::string LaunchFileExplorer(LaunchType type) = 0;
};

View File

@@ -0,0 +1,37 @@
#include "fs-linux.h"
#ifndef _WIN32
#include <stdio.h>
#include "utils/mutils.h"
#include "portable-file-dialogs.h"
#define DEFAULT_PATH "~"
void LinuxBridge::InitBridge() {}
ProcessResult LinuxBridge::LaunchProcess(std::string cmd) {
cmd = MoonUtils::normalize(cmd);
std::cout << "Trying to launch: " << cmd << std::endl;
ProcessResult result = { };
result.exitCode = WEXITSTATUS(system(cmd.c_str()));
return result;
}
std::string LinuxBridge::LaunchFileExplorer(LaunchType type) {
if(type == LaunchType::FILE){
auto file = pfd::open_file("Open OoT Baserom", DEFAULT_PATH,
{ "Rom Files (.z64 .n64)", "*.z64 *.n64", "All Files", "*" },
pfd::opt::force_path
);
std::vector<std::string> files = file.result();
if(!files.empty()) return files[0];
}
if(type == LaunchType::FOLDER){
auto dir = pfd::select_folder("Select any directory", DEFAULT_PATH).result();
if(!dir.empty()) return dir;
}
return "None";
}
#endif

View File

@@ -0,0 +1,9 @@
#pragma once
#include "../fs-bridge.h"
class LinuxBridge : public FSBridge {
void InitBridge() override;
ProcessResult LaunchProcess(std::string cmd) override;
std::string LaunchFileExplorer(LaunchType type) override;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
#include "fs-windows.h"
#ifdef _WIN32
#include <direct.h>
#include <Windows.h>
#include <ShObjIdl.h>
#include <stdio.h>
#include "utils/mutils.h"
void WindowsBridge::InitBridge() {}
ProcessResult WindowsBridge::LaunchProcess(std::string cmd) {
cmd = MoonUtils::normalize(cmd);
std::cout << "Trying to launch: " << cmd << std::endl;
ProcessResult result = { };
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD exit_code;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
char cwd[256];
getcwd(cwd, 256);
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
LPSTR(cmd.c_str()), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi
)) {
result.exitCode = GetLastError();
return result;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &exit_code);
result.exitCode = static_cast<int>(exit_code);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return result;
}
std::string WindowsBridge::LaunchFileExplorer(LaunchType type) {
std::string path = "None";
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (!SUCCEEDED(hr)) return path;
IFileOpenDialog* pFileOpen;
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
if (type == LaunchType::FOLDER) {
DWORD dwOptions;
pFileOpen->GetOptions(&dwOptions);
pFileOpen->SetOptions(dwOptions | FOS_PICKFOLDERS);
}
if (!SUCCEEDED(hr)) {
CoUninitialize();
return path;
}
hr = pFileOpen->Show(nullptr);
if (!SUCCEEDED(hr)) {
pFileOpen->Release();
return path;
}
IShellItem* pItem;
hr = pFileOpen->GetResult(&pItem);
if (!SUCCEEDED(hr)) return path;
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
// Display the file name to the user.
if (SUCCEEDED(hr)) {
path = MoonUtils::narrow(std::wstring(pszFilePath));
CoTaskMemFree(pszFilePath);
}
pItem->Release();
return path;
}
#endif

View File

@@ -0,0 +1,9 @@
#pragma once
#include "../fs-bridge.h"
class WindowsBridge : public FSBridge {
void InitBridge() override;
ProcessResult LaunchProcess(std::string cmd) override;
std::string LaunchFileExplorer(LaunchType type) override;
};