1
0
mirror of synced 2026-01-21 01:47:24 +00:00
2020-09-09 15:11:45 -07:00

181 lines
5.0 KiB
C++

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "utils.h"
#include <iostream>
/*
offset 0x00: 0x00000078
offset 0x04 : 0x0080
offset 0x06 : UNICOS padded to 16 bytes <--directory name
offset 0x16 : UNICOS padded to 16 bytes <--file name
offset 0x26 : 06 / 14 / 88 <--Creation date
offset 0x2e : 08 : 48 : 29 <--Creation time
offset 0x36 : 0xdfa50400 <--changes a lot for every file
offset 0x3a : 0x6400 <--Constant(maybe flags of sort ? )
offset 0x3c : 0x00000000
offset 0x40 : 0x5302 0x0100 0x0100
offset 0x42 : 0x0001 0x0100 0x0100
offset 0x44 : 0x163b 0x693d 0x6a3d
offset 0x46 : 0x5302 0x0100 0x0100
offset 0x48 : 0x00000000
offset 0x4c : 0x00000000
offset 0x50 : 0x00000000
offset 0x54 : 0x00000000
offset 0x58 : 0x00000000
offset 0x5c : 0x00000000
offset 0x60 : 0x00000000
offset 0x64 : 0x00000000
offset 0x68 : 0x00000000
offset 0x6c : 0x00000000
offset 0x70 : 0x00000000
offset 0x74 : 0x00000000
offset 0x78 : 0x00000000
offset 0x7c : 0x00000078
*/
struct FileHader_s {
char DirName[17];
char FileName[17];
};
FileHader_s ReadFileHader(FILE *aFile) {
uint32_t UIntBuffer;
char Buffer[16];
FileHader_s RetVal;
fread(&UIntBuffer, 1, 4, aFile); // Magic
if (UIntBuffer != 0x78) throw Generic_x("Invalid header magic in file header");
fread(Buffer, 1, 2, aFile);
fread(&RetVal.DirName, 1, 16, aFile);
RetVal.DirName[16] = 0;
fread(&RetVal.FileName, 1, 16, aFile);
RetVal.FileName[16] = 0;
fread(&Buffer, 1, 8, aFile); // Date
fread(&Buffer, 1, 8, aFile); // Time
fread(&Buffer, 1, 4, aFile);
fread(&Buffer, 1, 2, aFile);
fread(&Buffer, 1, 4, aFile);
fread(&Buffer, 1, 2, aFile);
fread(&Buffer, 1, 2, aFile);
fread(&Buffer, 1, 2, aFile);
fread(&Buffer, 1, 2, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile);
fread(&UIntBuffer, 1, 4, aFile); // Magic
if (UIntBuffer != 0x78) throw Generic_x("Invalid trailer magic in file header");
return RetVal;
}
struct BlockHeader_s {
uint32_t PrevSize;
uint32_t CurSize;
};
BlockHeader_s ReadBlockHeader(FILE *aFile, bool aSkipPrev = false) {
BlockHeader_s RetVal;
if (!aSkipPrev) {
fread(&RetVal.PrevSize, 1, 4, aFile);
}
else {
RetVal.PrevSize = 0;
}
fread(&RetVal.CurSize, 1, 4, aFile);
return RetVal;
}
int PrintUsage(const char *aExecName, const char *ErrorStr = nullptr) {
std::cout << "Usage: " << aExecName << " <image file> -s <output file name>" << std::endl;
return 1;
}
int main(int argc, const char* argv[])
{
CommandLine_c CommandLine(argc, argv);
bool SingleFileMode = false;
std::string OutputFileName;
std::string InFileName;
try {
while (CommandLine.HasMoreParams()) {
std::string CurParam = CommandLine.GetNextParam();
if (CurParam.length() == 0) continue;
if (CurParam == "-s") {
OutputFileName = CommandLine.GetNextParam();
SingleFileMode = true;
}
else {
if (InFileName.empty()) {
InFileName = CurParam;
}
else {
throw Generic_x("Unkown command line parameter");
}
}
}
if (InFileName.empty()) throw Generic_x("Input file name must be specified");
}
catch (std::exception &Ex) {
return PrintUsage(argv[0], Ex.what());
}
errno = 0;
FILE *Input = fopen(InFileName.c_str(),"rb");
FILE *Output = nullptr;
if (Input == nullptr) {
std::cout << "Can't open input file: " << InFileName << std::endl;
return 1;
}
try {
while (!feof(Input)) {
if (!SingleFileMode) {
FileHader_s FileHeader;
FileHeader = ReadFileHader(Input);
OutputFileName = FileHeader.FileName;
std::cout << "Found file " << OutputFileName << " in directory " << FileHeader.DirName << std::endl;
}
BlockHeader_s BlockHeader = ReadBlockHeader(Input, SingleFileMode);
if (BlockHeader.PrevSize != 0) throw Generic_x("Invalid first block header: prev should be 0");
Output = fopen(OutputFileName.c_str(), "wb");
if (Output == nullptr) throw Generic_x("Can't create output file");
while (BlockHeader.CurSize != 0) {
char Buffer[4096];
if (BlockHeader.CurSize > sizeof(Buffer)) throw Generic_x("Current block size is too large");
fread(Buffer, 1, BlockHeader.CurSize, Input);
fwrite(Buffer, 1, BlockHeader.CurSize, Output);
BlockHeader_s NewHeader = ReadBlockHeader(Input);
if (NewHeader.PrevSize != BlockHeader.CurSize) throw Generic_x("Block header libnk error");
BlockHeader = NewHeader;
}
fclose(Output);
Output = nullptr;
if (SingleFileMode) break;
}
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
if (Input != nullptr) fclose(Input);
if (Output != nullptr) fclose(Output);
return 1;
}
if (Input != nullptr) fclose(Input);
if (Output != nullptr) fclose(Output);
return 0;
}