mirror of
https://github.com/izzy2lost/Diddy-Kong-Racing.git
synced 2026-06-19 01:16:26 -07:00
Removed unecessary files. Added zip_file lib to dkr_assets_tool
This commit is contained in:
+5709
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
#include "DKRCompression.h"
|
||||
|
||||
DKRCompression::DKRCompression()
|
||||
{
|
||||
compressed.SetGame(DKR);
|
||||
}
|
||||
|
||||
DKRCompression::~DKRCompression(void)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DKRCompression::compressBuffer(std::vector<uint8_t>& data)
|
||||
{
|
||||
int uncompressedSize = data.size();
|
||||
int compressedSize = 0;
|
||||
|
||||
uint8_t* compressed = dkr_gzip_compress(&data[0], uncompressedSize, 9, &compressedSize);
|
||||
|
||||
std::vector<uint8_t> dkr_compressed(compressed + 10, compressed + compressedSize - 8);
|
||||
|
||||
dkr_compressed.insert(dkr_compressed.begin(), 0x09); // gzip compression level?
|
||||
dkr_compressed.insert(dkr_compressed.begin(), (uncompressedSize >> 24) & 0xFF);
|
||||
dkr_compressed.insert(dkr_compressed.begin(), (uncompressedSize >> 16) & 0xFF);
|
||||
dkr_compressed.insert(dkr_compressed.begin(), (uncompressedSize >> 8) & 0xFF);
|
||||
dkr_compressed.insert(dkr_compressed.begin(), uncompressedSize & 0xFF);
|
||||
|
||||
while((dkr_compressed.size() & 0xF) != 0) {
|
||||
dkr_compressed.push_back(0); // Pad out compressed file to be 16-byte aligned.
|
||||
}
|
||||
|
||||
return dkr_compressed;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DKRCompression::decompressBuffer(std::vector<uint8_t>& data)
|
||||
{
|
||||
compressed.SetCompressedBuffer(&data[0], data.size());
|
||||
|
||||
int fileSize = 0, fileSizeCompressed = 0;
|
||||
uint8_t* decompressed = compressed.OutputDecompressedBuffer(fileSize, fileSizeCompressed);
|
||||
if(decompressed == NULL) {
|
||||
std::cout << "Error decompressing input" << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
std::vector<uint8_t> out(decompressed, decompressed + fileSize);
|
||||
delete[] decompressed;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool DKRCompression::writeBinaryFile(std::vector<uint8_t>& output, std::string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary);
|
||||
for(int i = 0; i < output.size(); i++)
|
||||
wf.write((char *)&output[i], 1);
|
||||
wf.close();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DKRCompression::readBinaryFile(std::vector<uint8_t>& input, std::string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ifstream is;
|
||||
is.open(filename.c_str(), std::ios::binary);
|
||||
is.seekg(0, std::ios::end);
|
||||
size_t filesize = is.tellg();
|
||||
is.seekg(0, std::ios::beg);
|
||||
input.resize(filesize);
|
||||
is.read((char *)input.data(), filesize);
|
||||
is.close();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "GECompression.h"
|
||||
#include "DKRGzip.h"
|
||||
|
||||
// C++17
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
class DKRCompression
|
||||
{
|
||||
public:
|
||||
DKRCompression();
|
||||
~DKRCompression();
|
||||
|
||||
std::vector<uint8_t> compressBuffer(std::vector<uint8_t>& data);
|
||||
std::vector<uint8_t> decompressBuffer(std::vector<uint8_t>& data);
|
||||
bool readBinaryFile(std::vector<uint8_t>& input, std::string filename);
|
||||
bool writeBinaryFile(std::vector<uint8_t>& output, std::string filename);
|
||||
|
||||
private:
|
||||
GECompression compressed;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This is a custom version of gzip that was made specifically for the
|
||||
* Diddy Kong Racing decompilation project, since I cannot get zlib to
|
||||
* produce matching compressed files.
|
||||
*
|
||||
* The main difference with this version of gzip is that you can pass in
|
||||
* a simple byte array instead of having to use the FILE structure.
|
||||
*
|
||||
* This library can only compress files at the moment.
|
||||
*
|
||||
* Feel free to use it for your own project. The license is the same as gzip.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
unsigned char* dkr_gzip_compress(unsigned char* input, int inputSize, int gzipLevel, int* outputSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,121 +0,0 @@
|
||||
// GE Recompression C++ Class
|
||||
// Painstakingly done by Henry Ford (mrhtford_ps2dev@hotmail.com)
|
||||
// Ported to C++ Class by SubDrag (subdrag@rarewitchproject.com) July 13, 2005
|
||||
// Compression Games Added April 03, 2007
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define maxByteSize 0x800000
|
||||
|
||||
#define GOLDENEYE 0
|
||||
#define PD 1
|
||||
#define BANJOKAZOOIE 2
|
||||
#define KILLERINSTINCT 3
|
||||
#define DONKEYKONG64 4
|
||||
#define BLASTCORPS 5
|
||||
#define BANJOTOOIE 6
|
||||
#define DONKEYKONG64KIOSK 7
|
||||
#define CONKER 8
|
||||
#define TOPGEARRALLY 9
|
||||
#define MILO 10
|
||||
#define JFG 11
|
||||
#define DKR 12
|
||||
#define JFGKIOSK 13
|
||||
#define MICKEYSPEEDWAY 14
|
||||
#define MORTALKOMBAT 15
|
||||
#define STUNTRACER64 16
|
||||
#define ZLB 17
|
||||
#define RESIDENTEVIL2 18
|
||||
|
||||
#define BOOL bool
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#define DWORD int
|
||||
#define CString std::string
|
||||
#define PTSTR std::string
|
||||
#define LPSTR std::string
|
||||
|
||||
struct tableEntry {
|
||||
unsigned long bits;
|
||||
unsigned char flags;
|
||||
int nextIndex;
|
||||
unsigned long wordValue;
|
||||
};
|
||||
|
||||
class GECompression
|
||||
{
|
||||
public:
|
||||
GECompression();
|
||||
~GECompression(void);
|
||||
void SetCompressedBuffer(unsigned char* Buffer, int bufferSize);
|
||||
unsigned char* OutputDecompressedBuffer(int& fileSize, int& compressedSize);
|
||||
//bool CompressGZipFile(CString inputFile, CString outputFile, bool byteFlipCompressed);
|
||||
int game;
|
||||
CString mainFolder;
|
||||
void SetGame(int replaceGame);
|
||||
//void SetPath(CString directory);
|
||||
//old stuff
|
||||
//unsigned char* Compress(int& compressedSize);
|
||||
//unsigned char* OutputCompressed(int compressionType, int& fileSize);
|
||||
//void SetInputBuffer(unsigned char* Buffer, int bufferSize);
|
||||
|
||||
BOOL hiddenExec (PTSTR pCmdLine, CString currentDirectory);
|
||||
BOOL IsFileExist(LPSTR lpszFilename);
|
||||
|
||||
private:
|
||||
static unsigned char bt1Table1[288];
|
||||
static unsigned char bt1Table2[30];
|
||||
|
||||
static unsigned short bt12Table1S[0x20];
|
||||
static unsigned short bt12Table1B[0x20];
|
||||
static unsigned short bt12Table2S[0x20];
|
||||
static unsigned short bt12Table2B[0x20];
|
||||
|
||||
static unsigned char bt2Table1B[0x13];
|
||||
|
||||
tableEntry* unpackTable;
|
||||
int unpackTableIndex;
|
||||
|
||||
unsigned long bitsCache;
|
||||
int bitsRemain;
|
||||
unsigned long bytesIndex;
|
||||
|
||||
//unsigned char* inputBuffer;
|
||||
//int inputBufferSize;
|
||||
unsigned char* compressedBuffer;
|
||||
int compressedBufferSize;
|
||||
|
||||
unsigned long GetNBits(int nBits);
|
||||
unsigned long GetNBitsAndPreserve(int nBits);
|
||||
|
||||
bool UncompressType0(unsigned char* returnBuffer, int& fileSize);
|
||||
bool UncompressType1(unsigned char* returnBuffer, int& fileSize);
|
||||
bool UncompressType2(unsigned char* returnBuffer, int& fileSize);
|
||||
|
||||
void CreateGlobalDecompressionTable(int bit1TableChoice, int size2, int bit12STableSChoice, int bit12BTableChoice, int numBits, bool& returnValue, int& numReturnBits, int& returnStartIndex);
|
||||
bool DecompressBasedOnTable(int startIndex1, int startIndex2, int bitLen1, int bitLen2, unsigned char* returnBuffer, int& fileSize);
|
||||
|
||||
unsigned char variableTable[0x13];
|
||||
unsigned short tableSize;
|
||||
unsigned char fiveBits;
|
||||
unsigned long* wordTable;
|
||||
|
||||
// old stuff
|
||||
/*void FlipBits(unsigned char* indexes, int sizeBytes, int offset);
|
||||
bool* StringToBits(CString bitString, int& lengthBool);
|
||||
static CString dictionaryFirstStr[0x10];
|
||||
static CString dictionarySecondStr[0x10];
|
||||
CString EncodeLZBitPart(int backAmt);
|
||||
CString EncodeRLEBitPart(int repeatAmt);
|
||||
CString HexToBits(int hexNum, int outLength);
|
||||
CString FlipStringBits(CString inputString);*/
|
||||
|
||||
// better compression way
|
||||
|
||||
|
||||
|
||||
unsigned long iterationCounter;
|
||||
};
|
||||
@@ -1,98 +0,0 @@
|
||||
#ifndef THREAD_POOL_H
|
||||
#define THREAD_POOL_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
ThreadPool(size_t);
|
||||
template<class F, class... Args>
|
||||
auto enqueue(F&& f, Args&&... args)
|
||||
-> std::future<typename std::result_of<F(Args...)>::type>;
|
||||
~ThreadPool();
|
||||
private:
|
||||
// need to keep track of threads so we can join them
|
||||
std::vector< std::thread > workers;
|
||||
// the task queue
|
||||
std::queue< std::function<void()> > tasks;
|
||||
|
||||
// synchronization
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
// the constructor just launches some amount of workers
|
||||
inline ThreadPool::ThreadPool(size_t threads)
|
||||
: stop(false)
|
||||
{
|
||||
for(size_t i = 0;i<threads;++i)
|
||||
workers.emplace_back(
|
||||
[this]
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
std::function<void()> task;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
this->condition.wait(lock,
|
||||
[this]{ return this->stop || !this->tasks.empty(); });
|
||||
if(this->stop && this->tasks.empty())
|
||||
return;
|
||||
task = std::move(this->tasks.front());
|
||||
this->tasks.pop();
|
||||
}
|
||||
|
||||
task();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// add new work item to the pool
|
||||
template<class F, class... Args>
|
||||
auto ThreadPool::enqueue(F&& f, Args&&... args)
|
||||
-> std::future<typename std::result_of<F(Args...)>::type>
|
||||
{
|
||||
using return_type = typename std::result_of<F(Args...)>::type;
|
||||
|
||||
auto task = std::make_shared< std::packaged_task<return_type()> >(
|
||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
||||
);
|
||||
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
||||
// don't allow enqueueing after stopping the pool
|
||||
if(stop)
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
|
||||
tasks.emplace([task](){ (*task)(); });
|
||||
}
|
||||
condition.notify_one();
|
||||
return res;
|
||||
}
|
||||
|
||||
// the destructor joins all threads
|
||||
inline ThreadPool::~ThreadPool()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
stop = true;
|
||||
}
|
||||
condition.notify_all();
|
||||
for(std::thread &worker: workers)
|
||||
worker.join();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,308 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
ExtractConfig::ExtractConfig(std::string configsDirectory, std::string filename, std::string outDirectory){
|
||||
std::cout << "Reading config \"" << filename << "\"" << std::endl;
|
||||
configJSON = json::JSON::Load(read_file(configsDirectory + '/' + filename));
|
||||
|
||||
this->outDirectory = outDirectory + "/assets/" + configJSON["subfolder"].ToString();
|
||||
|
||||
this->name = configJSON["config-name"].ToString();
|
||||
this->subfolder = configJSON["subfolder"].ToString();
|
||||
this->md5 = configJSON["checksum-md5"].ToString();
|
||||
this->notSupported = configJSON["not-supported"].ToString() == "true";
|
||||
}
|
||||
|
||||
ExtractConfig::~ExtractConfig(){
|
||||
}
|
||||
|
||||
bool is_binary_type(std::string type) {
|
||||
return type == "Binary" || type == "GameText" || type == "MenuText" || type == "Sprites" || type == "Miscellaneous"
|
||||
|| type == "LevelHeaders" || type == "LevelNames" || type == "ObjectHeaders"
|
||||
|| type == "Audio" || type == "Particles" || type == "ParticleBehaviors" || type == "TTGhosts";
|
||||
}
|
||||
|
||||
bool is_compressed_type(std::string type) {
|
||||
return type == "Compressed" || type == "LevelObjectMap" || type == "LevelModels"
|
||||
|| type == "ObjectModels" || type == "ObjectAnimations";
|
||||
}
|
||||
|
||||
std::string get_extension_from_type(std::string type) {
|
||||
if(is_compressed_type(type)) {
|
||||
return ".cbin";
|
||||
} else if(type == "Textures") {
|
||||
return ".png";
|
||||
} else {
|
||||
return ".bin";
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractConfig::extract_file(ROM& rom, std::string type, std::string folder, std::string filename, std::vector<uint8_t> data) {
|
||||
|
||||
}
|
||||
|
||||
uint32_t get_uint_from_table(std::vector<uint8_t>& table, int index) {
|
||||
return (table[index * 4] << 24) | (table[index * 4 + 1] << 16) | (table[index * 4 + 2] << 8) | table[index * 4 + 3];
|
||||
}
|
||||
|
||||
std::vector<std::vector<uint8_t>> get_section_files(std::vector<uint8_t>& section, std::vector<uint8_t>& table, std::string tableType, json::JSON& outputAsset) {
|
||||
std::vector<std::vector<uint8_t>> out;
|
||||
|
||||
int currentTableIndex = 0;
|
||||
int scale = 1; // Each table entry is 4-bytes long.
|
||||
int offset = 0;
|
||||
|
||||
if(tableType == "MenuText") {
|
||||
outputAsset["text-entry-count"] = get_uint_from_table(table, currentTableIndex);
|
||||
currentTableIndex = 1; // The first entry is the number of text entries for each language.
|
||||
} else if(tableType == "TTGhosts") {
|
||||
scale = 2; // Each table entry is 8-bytes long.
|
||||
offset = 1; // offset by 4 bytes.
|
||||
outputAsset["meta"] = json::Array();
|
||||
} else if (tableType == "GameText") {
|
||||
outputAsset["textTypes"] = json::Array();
|
||||
}
|
||||
|
||||
uint32_t currentTableValue = get_uint_from_table(table, currentTableIndex * scale + offset);
|
||||
uint32_t nextTableValue = get_uint_from_table(table, (currentTableIndex + 1) * scale + offset);
|
||||
|
||||
if (tableType == "Audio") {
|
||||
// The audio table doesn't start at offset 0, so this check will extract
|
||||
// the first actual part of the audio section.
|
||||
std::vector<uint8_t> file(section.begin(), section.begin() + currentTableValue);
|
||||
out.push_back(file);
|
||||
}
|
||||
|
||||
while(nextTableValue != 0xFFFFFFFF) {
|
||||
|
||||
if(tableType == "GameText") {
|
||||
bool isDialog = (currentTableValue & 0x80000000) == 0x80000000;
|
||||
outputAsset["textTypes"].append(isDialog ? 1 : 0);
|
||||
currentTableValue &= 0x7FFFFFFF;
|
||||
nextTableValue &= 0x7FFFFFFF;
|
||||
} else if(tableType == "Miscellaneous") {
|
||||
currentTableValue *= 4;
|
||||
nextTableValue *= 4;
|
||||
} else if (tableType == "TTGhosts") {
|
||||
json::JSON metaObj = json::Object();
|
||||
metaObj["levelID"] = table[currentTableIndex * 8 + 0];
|
||||
metaObj["vehicleID"] = table[currentTableIndex * 8 + 1];
|
||||
outputAsset["meta"].append(metaObj);
|
||||
}
|
||||
|
||||
int length = nextTableValue - currentTableValue;
|
||||
if(length < 0) {
|
||||
std::cout << "Error: Invalid table length: " << length << std::endl;
|
||||
std::cout << std::hex << "currentTableValue: " << currentTableValue << std::dec << std::endl;
|
||||
std::cout << std::hex << "nextTableValue: " << nextTableValue << std::dec << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> file(section.begin() + currentTableValue, section.begin() + nextTableValue);
|
||||
out.push_back(file);
|
||||
|
||||
currentTableIndex++;
|
||||
currentTableValue = get_uint_from_table(table, currentTableIndex * scale + offset);
|
||||
nextTableValue = get_uint_from_table(table, (currentTableIndex + 1) * scale + offset);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void ExtractConfig::extract(ROM& rom, json::JSON& assetsJson) {
|
||||
currentROMOffset = 0;
|
||||
|
||||
/* Extract the code sections */
|
||||
json::JSON codeSections = configJSON["code"]["sections"];
|
||||
int numCodeSections = codeSections.length();
|
||||
for(int i = 0; i < numCodeSections; i++) {
|
||||
json::JSON section = codeSections[i];
|
||||
json::JSON files = section["files"];
|
||||
std::string folder = this->outDirectory + "/" + section["folder"].ToString();
|
||||
if(!fs::is_directory(folder)) {
|
||||
fs::create_directories(folder);
|
||||
}
|
||||
|
||||
std::string type = section["type"].ToString();
|
||||
|
||||
int numFiles = files.length();
|
||||
for(int j = 0; j < numFiles; j++) {
|
||||
json::JSON file = files[j];
|
||||
int length = std::stoul(file["length"].ToString(), nullptr, 16);
|
||||
extractions.push_back(ExtractInfo(type, folder, file["filename"].ToString(),
|
||||
rom.get_bytes_from_range(currentROMOffset, length)));
|
||||
currentROMOffset += length;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the assets section has the correct number of entries. */
|
||||
json::JSON assetSections = configJSON["assets"]["sections"];
|
||||
int numAssetSections = assetSections.length();
|
||||
int numAssetSectionsFromTable = rom.get_uint(currentROMOffset);
|
||||
|
||||
if(numAssetSections != numAssetSectionsFromTable) {
|
||||
std::cout << "Error: Number of asset sections in config does not match ROM." << std::endl;
|
||||
std::cout << "Number of asset sections in Config: " << numAssetSections << std::endl;
|
||||
std::cout << "Number of asset sections in ROM: " << numAssetSectionsFromTable << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
|
||||
currentROMOffset += 4;
|
||||
int tableOffset = currentROMOffset;
|
||||
currentROMOffset += (numAssetSections + 1) * 4;
|
||||
int assetsStart = currentROMOffset;
|
||||
|
||||
std::vector<std::vector<uint8_t>> sectionsData;
|
||||
|
||||
/* Read the main assets look-up table for section lengths */
|
||||
for(int i = 0; i < numAssetSections; i++) {
|
||||
int assetSectionLength = rom.get_uint(tableOffset + ((i + 1) * 4)) - rom.get_uint(tableOffset + (i * 4));
|
||||
sectionsData.push_back(rom.get_bytes_from_range(currentROMOffset, assetSectionLength));
|
||||
currentROMOffset += assetSectionLength;
|
||||
}
|
||||
|
||||
currentROMOffset = assetsStart;
|
||||
|
||||
assetsJson["assets"] = json::Array();
|
||||
|
||||
/* Extract the assets sections */
|
||||
for(int i = 0; i < numAssetSections; i++) {
|
||||
json::JSON section = assetSections[i];
|
||||
std::string folder = this->outDirectory + "/" + section["folder"].ToString();
|
||||
std::string type = section["type"].ToString();
|
||||
|
||||
if(!fs::is_directory(folder)) {
|
||||
fs::create_directories(folder);
|
||||
}
|
||||
|
||||
json::JSON outputAsset = json::Object();
|
||||
outputAsset["type"] = type;
|
||||
|
||||
if(section.hasKey("name")) {
|
||||
outputAsset["name"] = section["name"].ToString();
|
||||
}
|
||||
|
||||
if(type == "Table") {
|
||||
assetsJson["assets"].append(outputAsset);
|
||||
continue;
|
||||
} else if(type == "Textures") {
|
||||
outputAsset["flip-textures"] = section["flip-textures"];
|
||||
}
|
||||
|
||||
outputAsset["folder"] = section["folder"].ToString();
|
||||
outputAsset["filenames"] = json::Array();
|
||||
|
||||
if(section.hasKey("table")) {
|
||||
int tableIndex = section["table"].ToInt();
|
||||
std::vector<std::vector<uint8_t>> sectionFiles
|
||||
= get_section_files(sectionsData[i], sectionsData[tableIndex], type, outputAsset);
|
||||
int numberOfSectionFiles = sectionFiles.size();
|
||||
|
||||
outputAsset["table"] = tableIndex;
|
||||
|
||||
for(int j = 0; j < numberOfSectionFiles; j++) {
|
||||
std::string filename = "";
|
||||
if(section.hasKey("filenames")) {
|
||||
filename = section["filenames"][j].ToString();
|
||||
}
|
||||
if(filename == "") {
|
||||
std::stringstream filenameStream;
|
||||
filenameStream << "unknown_" << i << "_" << j;
|
||||
filename = filenameStream.str();
|
||||
}
|
||||
outputAsset["filenames"].append(filename + get_extension_from_type(type));
|
||||
extractions.push_back(ExtractInfo(type, folder, filename, sectionFiles[j]));
|
||||
}
|
||||
} else {
|
||||
// No lookup table associated, so the section is assumed to be 1 file.
|
||||
std::string filename = "";
|
||||
if(section.hasKey("filenames")) {
|
||||
filename = section["filenames"][0].ToString();
|
||||
}
|
||||
if(filename == "") {
|
||||
std::stringstream filenameStream;
|
||||
filenameStream << "unknown_" << i;
|
||||
filename = filenameStream.str();
|
||||
}
|
||||
outputAsset["filenames"].append(filename + get_extension_from_type(type));
|
||||
extractions.push_back(ExtractInfo(type, folder, filename, sectionsData[i]));
|
||||
}
|
||||
currentROMOffset += sectionsData[i].size();
|
||||
assetsJson["assets"].append(outputAsset);
|
||||
}
|
||||
|
||||
ThreadPool pool(std::thread::hardware_concurrency());
|
||||
|
||||
for(int i = 0; i < extractions.size(); i++) {
|
||||
std::string type = extractions[i].type;
|
||||
std::string folder = extractions[i].folder;
|
||||
std::string filename = extractions[i].filename;
|
||||
std::vector<uint8_t> data = extractions[i].data;
|
||||
pool.enqueue([&rom, type, folder, filename, data] {
|
||||
std::string outFilepath = folder + "/" + filename;
|
||||
|
||||
if(is_binary_type(type)) {
|
||||
ExtractBinary(data, rom, outFilepath + ".bin");
|
||||
} else if(is_compressed_type(type)) {
|
||||
ExtractCompressed(data, rom, outFilepath + ".cbin");
|
||||
} else if(type == "Textures") {
|
||||
ExtractTextures(data, rom, outFilepath + ".png");
|
||||
} else if(type == "Empty") {
|
||||
} else if(type != "NoExtract") {
|
||||
std::cout << "Unknown extraction type: " << type << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ExtractConfig::is_supported(){
|
||||
return !notSupported;
|
||||
}
|
||||
|
||||
std::string ExtractConfig::get_name(){
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string ExtractConfig::get_md5(){
|
||||
return md5;
|
||||
}
|
||||
|
||||
std::string ExtractConfig::get_subfolder(){
|
||||
return subfolder;
|
||||
}
|
||||
|
||||
std::string ExtractConfig::read_file(std::string filename) {
|
||||
std::ifstream t(filename);
|
||||
t.seekg(0, std::ios::end);
|
||||
size_t size = t.tellg();
|
||||
std::string buffer(size, ' ');
|
||||
t.seekg(0);
|
||||
t.read(&buffer[0], size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
// C++17
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
#include "../json/json.hpp"
|
||||
|
||||
#include "rom.h"
|
||||
#include "extract_binary.h"
|
||||
#include "extract_compressed.h"
|
||||
#include "extract_textures.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
struct ExtractInfo {
|
||||
std::string type;
|
||||
std::string folder;
|
||||
std::string filename;
|
||||
std::vector<uint8_t> data;
|
||||
ExtractInfo(std::string type, std::string folder, std::string filename, std::vector<uint8_t> data)
|
||||
: type(type), folder(folder), filename(filename), data(data) {}
|
||||
};
|
||||
|
||||
class ExtractConfig {
|
||||
public:
|
||||
ExtractConfig(std::string configsDirectory, std::string filename, std::string outDirectory);
|
||||
~ExtractConfig();
|
||||
|
||||
void extract(ROM& rom, json::JSON& assetsJson);
|
||||
void extract_file(ROM& rom, std::string type, std::string folder, std::string filename, std::vector<uint8_t> data);
|
||||
|
||||
bool is_supported();
|
||||
std::string get_name();
|
||||
std::string get_md5();
|
||||
std::string get_subfolder();
|
||||
|
||||
|
||||
private:
|
||||
json::JSON configJSON; // Loaded from a config file.
|
||||
|
||||
int currentROMOffset;
|
||||
|
||||
bool notSupported;
|
||||
std::string outDirectory;
|
||||
std::string name;
|
||||
std::string md5;
|
||||
std::string subfolder;
|
||||
|
||||
std::vector<ExtractInfo> extractions;
|
||||
|
||||
std::string read_file(std::string filename);
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "extract.h"
|
||||
|
||||
Extract::Extract(std::vector<uint8_t> data, ROM& rom, std::string outFilepath){
|
||||
}
|
||||
|
||||
Extract::~Extract(){
|
||||
}
|
||||
|
||||
void Extract::write_binary_file(std::vector<uint8_t> data, std::string filepath){
|
||||
std::ofstream wf(filepath.c_str(), std::ios::out | std::ios::binary);
|
||||
for(int i = 0; i < data.size(); i++)
|
||||
wf.write((char *)&data[i], 1);
|
||||
wf.close();
|
||||
}
|
||||
|
||||
void Extract::write_text_file(std::string text, std::string filepath){
|
||||
std::ofstream myfile;
|
||||
myfile.open(filepath);
|
||||
myfile << text;
|
||||
myfile.close();
|
||||
}
|
||||
|
||||
void Extract::print_extracted(std::string outFilepath) {
|
||||
std::stringstream out;
|
||||
out << "Extracted " << outFilepath << std::endl;
|
||||
std::cout << out.str();
|
||||
}
|
||||
|
||||
void Extract::to_lowercase(std::string& input) {
|
||||
for(char& character : input) {
|
||||
character = std::tolower(character);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
#include "../json/json.hpp"
|
||||
|
||||
// C++17
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
class Extract {
|
||||
public:
|
||||
Extract(std::vector<uint8_t> data, ROM& rom, std::string outFilepath);
|
||||
~Extract();
|
||||
|
||||
void write_binary_file(std::vector<uint8_t> data, std::string filepath);
|
||||
void write_text_file(std::string data, std::string filepath);
|
||||
void print_extracted(std::string outFilepath);
|
||||
|
||||
protected:
|
||||
void to_lowercase(std::string& input);
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "extract_binary.h"
|
||||
|
||||
ExtractBinary::ExtractBinary(std::vector<uint8_t> data, ROM& rom, std::string outFilepath)
|
||||
: Extract(data, rom, outFilepath) {
|
||||
write_binary_file(data, outFilepath);
|
||||
print_extracted(outFilepath);
|
||||
}
|
||||
|
||||
ExtractBinary::~ExtractBinary(){
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "extract.h"
|
||||
|
||||
class ExtractBinary : Extract {
|
||||
public:
|
||||
ExtractBinary(std::vector<uint8_t> data, ROM& rom, std::string outFilepath);
|
||||
~ExtractBinary();
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "extract_compressed.h"
|
||||
|
||||
ExtractCompressed::ExtractCompressed(std::vector<uint8_t> data, ROM& rom, std::string outFilepath)
|
||||
: Extract(data, rom, outFilepath) {
|
||||
|
||||
if(data.size() == 0) {
|
||||
std::cout << "Warning: \"" << outFilepath << "\" is empty." << std::endl;
|
||||
write_binary_file(data, outFilepath);
|
||||
print_extracted(outFilepath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Needed padding to prevent errors with decompressing.
|
||||
if(data[data.size() - 1] != 0) {
|
||||
data.push_back(0);
|
||||
data.push_back(0);
|
||||
data.push_back(0);
|
||||
data.push_back(0);
|
||||
}
|
||||
|
||||
DKRCompression compression;
|
||||
data = compression.decompressBuffer(data);
|
||||
|
||||
write_binary_file(data, outFilepath);
|
||||
print_extracted(outFilepath);
|
||||
}
|
||||
|
||||
ExtractCompressed::~ExtractCompressed(){
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "extract.h"
|
||||
#include "../dkr_decompressor_src/DKRCompression.h"
|
||||
|
||||
class ExtractCompressed : Extract {
|
||||
public:
|
||||
ExtractCompressed(std::vector<uint8_t> data, ROM& rom, std::string outFilepath);
|
||||
~ExtractCompressed();
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
#include "extract_textures.h"
|
||||
|
||||
ExtractTextures::ExtractTextures(std::vector<uint8_t> data, ROM& rom, std::string outFilepath)
|
||||
: Extract(data, rom, outFilepath) {
|
||||
std::vector<uint8_t> header(data.begin(), data.begin() + TEX_HEADER_SIZE);
|
||||
std::vector<uint8_t> texData;
|
||||
|
||||
bool isCompressed = (header[0x1D] == 0x01);
|
||||
|
||||
if(isCompressed) {
|
||||
std::vector<uint8_t> compressedData(data.begin() + TEX_HEADER_SIZE, data.end());
|
||||
// Needed padding to prevent errors with decompressing.
|
||||
if(compressedData[compressedData.size() - 1] != 0) {
|
||||
compressedData.push_back(0);
|
||||
compressedData.push_back(0);
|
||||
compressedData.push_back(0);
|
||||
compressedData.push_back(0);
|
||||
}
|
||||
DKRCompression compression;
|
||||
texData = compression.decompressBuffer(compressedData);
|
||||
} else {
|
||||
texData = data;
|
||||
}
|
||||
|
||||
int numTextures = header[0x12];
|
||||
int dataOffset = 0;
|
||||
|
||||
std::vector<uint8_t> combinedTexturesData;
|
||||
|
||||
int totalHeight = 0;
|
||||
for(int i = 0; i < numTextures; i++){
|
||||
int width = texData[dataOffset + 0x00];
|
||||
int height = texData[dataOffset + 0x01];
|
||||
int textureFormat = texData[dataOffset + 0x02] & 0xF;
|
||||
int textureSize = get_texture_size(width, height, textureFormat);
|
||||
|
||||
std::vector<uint8_t> texHeader(texData.begin() + dataOffset, texData.begin() + dataOffset + TEX_HEADER_SIZE);
|
||||
std::vector<uint8_t> texData2(texData.begin() + dataOffset + TEX_HEADER_SIZE, texData.begin() + dataOffset + textureSize);
|
||||
|
||||
process_texture(texHeader, texData2);
|
||||
combinedTexturesData.insert(combinedTexturesData.end(), texData2.begin(), texData2.end());
|
||||
|
||||
dataOffset += textureSize;
|
||||
totalHeight += texHeader[1];
|
||||
}
|
||||
|
||||
int width = header[0];
|
||||
int height = totalHeight;
|
||||
int textureFormat = header[0x02] & 0xF;
|
||||
|
||||
switch(textureFormat) {
|
||||
case TEX_FORMAT_RGBA32:
|
||||
{
|
||||
rgba2png(outFilepath.c_str(), (const rgba*)&combinedTexturesData[0], width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_RGBA16:
|
||||
{
|
||||
rgba* outTex = raw2rgba(&combinedTexturesData[0], width, height, 16);
|
||||
rgba2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I8:
|
||||
{
|
||||
ia* outTex = raw2i(&combinedTexturesData[0], width, height, 8);
|
||||
ia2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I4:
|
||||
{
|
||||
ia* outTex = raw2i(&combinedTexturesData[0], width, height, 4);
|
||||
ia2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA16:
|
||||
{
|
||||
ia* outTex = raw2ia(&combinedTexturesData[0], width, height, 16);
|
||||
ia2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA8:
|
||||
{
|
||||
ia* outTex = raw2ia(&combinedTexturesData[0], width, height, 8);
|
||||
ia2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_IA4:
|
||||
{
|
||||
ia* outTex = raw2ia(&combinedTexturesData[0], width, height, 4);
|
||||
ia2png(outFilepath.c_str(), outTex, width, height);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_CI4:
|
||||
{
|
||||
std::cout << "Error: CI4 texture format is not currently supported." << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
default: // Invalid texture format
|
||||
{
|
||||
std::cout << "Error: Unknown texture format " << textureFormat << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
|
||||
write_binary_file(header, outFilepath + ".header");
|
||||
|
||||
print_extracted(outFilepath);
|
||||
}
|
||||
|
||||
ExtractTextures::~ExtractTextures(){
|
||||
}
|
||||
|
||||
void ExtractTextures::deinterlace(std::vector<uint8_t>& data, int width, int height, int bitDepth, int bufferSize) {
|
||||
uint8_t* temp = new uint8_t[bufferSize];
|
||||
|
||||
int numPixels;
|
||||
if(bitDepth == 4) {
|
||||
numPixels = ((width * height) / 2);
|
||||
} else {
|
||||
numPixels = (width * height * (bitDepth / 8));
|
||||
}
|
||||
|
||||
int stride = bufferSize * 2;
|
||||
|
||||
int size = numPixels / stride;
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
int row;
|
||||
if(bitDepth == 4) {
|
||||
row = (i * stride) / width * 2;
|
||||
} else {
|
||||
row = (i * stride) / width / (bitDepth / 8);
|
||||
}
|
||||
if(row % 2 == 0) continue;
|
||||
for(int j = 0; j < bufferSize; j++) {
|
||||
temp[j] = data[i * stride + j];
|
||||
data[i * stride + j] = data[i * stride + j + bufferSize];
|
||||
data[i * stride + j + bufferSize] = temp[j];
|
||||
}
|
||||
}
|
||||
|
||||
delete[] temp;
|
||||
}
|
||||
|
||||
void ExtractTextures::process_texture(std::vector<uint8_t>& header, std::vector<uint8_t>& data) {
|
||||
int width = header[0];
|
||||
int height = header[1];
|
||||
int textureFormat = header[0x02] & 0xF;
|
||||
bool isInterlaced = ((header[0x06] & 0x04) == 0x04);
|
||||
|
||||
switch(textureFormat) {
|
||||
case TEX_FORMAT_RGBA32:
|
||||
{
|
||||
if(isInterlaced) deinterlace(data, width, height, 32, 8);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_RGBA16:
|
||||
case TEX_FORMAT_IA16:
|
||||
{
|
||||
if(isInterlaced) deinterlace(data, width, height, 16, 4);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I8:
|
||||
case TEX_FORMAT_IA8:
|
||||
{
|
||||
if(isInterlaced) deinterlace(data, width, height, 8, 4);
|
||||
break;
|
||||
}
|
||||
case TEX_FORMAT_I4:
|
||||
case TEX_FORMAT_IA4:
|
||||
{
|
||||
if(isInterlaced) deinterlace(data, width, height, 4, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ExtractTextures::get_texture_size(int width, int height, int textureFormat) {
|
||||
switch(textureFormat) {
|
||||
case TEX_FORMAT_RGBA32:
|
||||
return (width * height * 4) + TEX_HEADER_SIZE;
|
||||
case TEX_FORMAT_RGBA16:
|
||||
case TEX_FORMAT_IA16:
|
||||
return (width * height * 2) + TEX_HEADER_SIZE;
|
||||
case TEX_FORMAT_I8:
|
||||
case TEX_FORMAT_IA8:
|
||||
return (width * height) + TEX_HEADER_SIZE;
|
||||
case TEX_FORMAT_I4:
|
||||
case TEX_FORMAT_IA4:
|
||||
return (width * height / 2) + TEX_HEADER_SIZE;
|
||||
case TEX_FORMAT_CI4:
|
||||
std::cout << "Error: CI4 texture format is not currently supported." << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
|
||||
std::cout << "Error: Invalid texture format " << textureFormat << std::endl;
|
||||
throw 1;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "extract.h"
|
||||
#include "../dkr_decompressor_src/DKRCompression.h"
|
||||
#include "../n64graphics/n64graphics.h"
|
||||
|
||||
#define TEX_FORMAT_RGBA32 0
|
||||
#define TEX_FORMAT_RGBA16 1
|
||||
#define TEX_FORMAT_I8 2
|
||||
#define TEX_FORMAT_I4 3
|
||||
#define TEX_FORMAT_IA16 4
|
||||
#define TEX_FORMAT_IA8 5
|
||||
#define TEX_FORMAT_IA4 6
|
||||
#define TEX_FORMAT_CI4 7
|
||||
|
||||
#define TEX_HEADER_SIZE 0x20
|
||||
|
||||
class ExtractTextures : Extract {
|
||||
public:
|
||||
ExtractTextures(std::vector<uint8_t> data, ROM& rom, std::string outFilepath);
|
||||
~ExtractTextures();
|
||||
|
||||
private:
|
||||
void deinterlace(std::vector<uint8_t>& data, int width, int height, int bitDepth, int bufferSize);
|
||||
void process_texture(std::vector<uint8_t>& header, std::vector<uint8_t>& data);
|
||||
int get_texture_size(int width, int height, int textureFormat);
|
||||
|
||||
};
|
||||
@@ -1,142 +0,0 @@
|
||||
#include "rom.h"
|
||||
|
||||
ROM::ROM(std::string filename){
|
||||
if(!readROMFile(filename)) {
|
||||
// ROM failed to load.
|
||||
throw 1;
|
||||
}
|
||||
romFilename = filename;
|
||||
|
||||
test_endianness();
|
||||
calculate_md5();
|
||||
}
|
||||
|
||||
ROM::~ROM(){
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ROM::get_bytes_from_range(int start, int numBytes){
|
||||
std::vector<uint8_t> subVector(numBytes);
|
||||
std::copy(bytes.begin() + start, bytes.begin() + start + numBytes, subVector.begin());
|
||||
return subVector;
|
||||
}
|
||||
|
||||
uint8_t ROM::get_byte(int romOffset){
|
||||
return bytes[romOffset];
|
||||
}
|
||||
|
||||
uint32_t ROM::get_uint(int romOffset){
|
||||
return (bytes[romOffset] << 24) | (bytes[romOffset + 1] << 16) | (bytes[romOffset + 2] << 8) | bytes[romOffset + 3];
|
||||
}
|
||||
|
||||
std::string ROM::get_md5(){
|
||||
return md5;
|
||||
}
|
||||
|
||||
int ROM::get_size(){
|
||||
return bytes.size();
|
||||
}
|
||||
|
||||
void ROM::test_endianness(){
|
||||
bool convertedToBigEndian = false;
|
||||
if(bytes[0] == 0x80 && bytes[1] == 0x37) { // Big endian
|
||||
// Do nothing
|
||||
} else if(bytes[0] == 0x37 && bytes[1] == 0x80) { // Mixed endian (byteswapped)
|
||||
// Mixed endian, convert to big endian
|
||||
int numBytes = get_size();
|
||||
for(int i = 0; i < numBytes; i+=2) {
|
||||
uint8_t temp = bytes[i];
|
||||
bytes[i] = bytes[i + 1];
|
||||
bytes[i + 1] = temp;
|
||||
}
|
||||
convertedToBigEndian = true;
|
||||
} else if(bytes[0] == 0x40 && bytes[1] == 0x12) { // Little endian
|
||||
// Little endian, convert to big endian
|
||||
int numBytes = get_size();
|
||||
uint8_t temp[4];
|
||||
for(int i = 0; i < numBytes; i+=4) {
|
||||
temp[0] = bytes[i + 0];
|
||||
temp[1] = bytes[i + 1];
|
||||
temp[2] = bytes[i + 2];
|
||||
temp[3] = bytes[i + 3];
|
||||
bytes[i + 0] = temp[3];
|
||||
bytes[i + 1] = temp[2];
|
||||
bytes[i + 2] = temp[1];
|
||||
bytes[i + 3] = temp[0];
|
||||
}
|
||||
convertedToBigEndian = true;
|
||||
} else {
|
||||
// Invalid ROM file
|
||||
throw 1;
|
||||
}
|
||||
|
||||
if(convertedToBigEndian) { // Overwrite ROM file
|
||||
fs::remove(fs::path(romFilename)); // Delete old romfile
|
||||
std::string z64Filename = romFilename.substr(0, romFilename.length() - 4) + ".z64";
|
||||
if(!writeROMFile(z64Filename)) { // Save new big-endian rom.
|
||||
// ROM failed to save.
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ROM::calculate_md5() {
|
||||
uint8_t buffer[0x4000];
|
||||
uint8_t digest[MD5_DIGEST_LENGTH];
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
MD5_CTX md5Context;
|
||||
|
||||
MD5_Init(&md5Context);
|
||||
MD5_Update(&md5Context, &bytes[0], bytes.size());
|
||||
int res = MD5_Final(digest, &md5Context);
|
||||
|
||||
if(res == 0){ // hash failed or raise an exception
|
||||
md5 = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// set up stringstream format
|
||||
ss << std::hex << std::setfill('0');
|
||||
|
||||
|
||||
for(uint8_t uc: digest) {
|
||||
ss << std::setw(2) << (int)uc;
|
||||
}
|
||||
|
||||
md5 = ss.str();
|
||||
}
|
||||
|
||||
bool ROM::readROMFile(std::string filename) {
|
||||
try
|
||||
{
|
||||
std::ifstream is;
|
||||
is.open(filename.c_str(), std::ios::binary);
|
||||
is.seekg(0, std::ios::end);
|
||||
size_t filesize = is.tellg();
|
||||
is.seekg(0, std::ios::beg);
|
||||
bytes.resize(filesize);
|
||||
is.read((char *)bytes.data(), filesize);
|
||||
is.close();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ROM::writeROMFile(std::string filename) {
|
||||
try
|
||||
{
|
||||
std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary);
|
||||
for(int i = 0; i < bytes.size(); i++)
|
||||
wf.write((char *)&bytes[i], 1);
|
||||
wf.close();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
// C++17
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
class ROM {
|
||||
public:
|
||||
ROM(std::string filename);
|
||||
~ROM();
|
||||
|
||||
std::vector<uint8_t> get_bytes_from_range(int start, int numBytes);
|
||||
uint8_t get_byte(int romOffset);
|
||||
uint32_t get_uint(int romOffset);
|
||||
|
||||
std::string get_md5();
|
||||
int get_size();
|
||||
|
||||
private:
|
||||
void test_endianness();
|
||||
void calculate_md5();
|
||||
bool readROMFile(std::string filename);
|
||||
bool writeROMFile(std::string filename);
|
||||
|
||||
std::vector<uint8_t> bytes;
|
||||
std::string md5;
|
||||
std::string romFilename;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user