You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FiestaOnlineEditor/FiestaOnlineEditor/SHNFileDecryptor.h

535 lines
14 KiB

#pragma once
#include <vector>
#include <cstddef>
#include <fstream>
#include <iostream>
#include <string>
#include <chrono>
#include <sstream>
//typedef std::std::byte std::byte;
typedef char sbyte;
class SHNFile{
std::vector<std::byte>ReadBytes(std::ifstream&file);
std::vector<std::byte>ReadBytes(std::ifstream&file,int bytes);
void WriteBytes(std::ofstream&file,std::vector<std::byte>&data);
int ReadInt32(std::ifstream&file);
void Encrypt();
void Decrypt();
std::vector<std::byte>&ReadBytes(int bytes);
std::byte ReadByte();
void WriteByte(std::ofstream&f,std::byte b);
void WriteSByte(std::ofstream&f,sbyte b);
uint16_t ReadUInt16();
void WriteUInt16(std::ofstream&f,uint16_t val);
int16_t ReadInt16();
void WriteInt16(std::ofstream&f,int16_t val);
uint32_t ReadUInt32();
void WriteUInt32(std::ofstream&f,uint32_t val);
int Read();
int32_t ReadInt32();
void WriteInt32(std::ofstream&f,int32_t val);
std::string ReadString(int bytes);
void WriteString(std::ofstream&f,std::string str,int bytes);
float ReadSingle();
void WriteSingle(std::ofstream&f,float n);
sbyte ReadSByte();
std::string ReadString();
uint32_t GetRecordLength();
public:
enum class DataType:int{
BYTE=1,
SBYTE=7,
UINT16=2,
INT16=6,
UINT32=3,
INT32=8,
FLOAT=4,
STRING=5
};
struct Data{
std::shared_ptr<void>data;
DataType type=DataType::BYTE;
Data(std::byte b);
Data(sbyte b);
Data(uint16_t n);
Data(int16_t n);
Data(uint32_t n);
Data(int32_t n);
Data(float n);
Data(std::string str);
template<typename T>
T Get();
template<typename T>
void Set(T b);
std::string GetDisplayText();
};
private:
friend std::ostream&operator<<(std::ostream&out,SHNFile::Data&d){
out<<d.GetDisplayText();
return out;
}
struct Column{
std::string name;
uint32_t type=0;
int length=0;
};
int marker=0;
std::vector<std::byte>cryptHeader;
std::vector<std::byte>data,rawData;
uint32_t header=0,recordCount=0,defaultRecordLength=0,columnCount=0;
std::vector<Column>columns;
std::vector<std::vector<Data>>contents;
std::string filename;
std::vector<std::byte>readArr;
std::byte*fileMarker=0;
public:
void Load(std::string file);
void Save();
void Write(int row,int col,std::byte val);
void Write(int row,int col,sbyte val);
void Write(int row,int col,int16_t val);
void Write(int row,int col,uint16_t val);
void Write(int row,int col,int32_t val);
void Write(int row,int col,uint32_t val);
void Write(int row,int col,float val);
void Write(int row,int col,std::string val);
const SHNFile::Data Get(int row,int col)const;
SHNFile();
};
#ifdef OLC_PGEX_SHNFile
std::vector<std::byte>SHNFile::ReadBytes(std::ifstream&file){
std::vector<std::byte>byteArr;
while(!file.eof()){
byteArr.push_back(std::byte(file.get()));
}
return byteArr;
}
std::vector<std::byte>SHNFile::ReadBytes(std::ifstream&file,int bytes){
std::vector<std::byte>byteArr;
for(int i=0;i<bytes;i++){
if(!file.eof()){
byteArr.push_back(std::byte(file.get()));
} else {
break;
}
}
return byteArr;
}
void SHNFile::WriteBytes(std::ofstream&file,std::vector<std::byte>&data){
for(int i=0;i<data.size();i++){
file<<unsigned char(data[i]);
}
}
int SHNFile::ReadInt32(std::ifstream&file){
std::vector<std::byte>intBytes=ReadBytes(file,4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb;
}
void SHNFile::Encrypt(){
Decrypt();
}
void SHNFile::Decrypt(){
std::byte num = std::byte(data.size());
for(int i=data.size()-1;i>=0;i--){
data[i] = std::byte(data[i]^num);
std::byte num3 = std::byte(i);
num3 = std::byte(num3&std::byte(15));
num3 = std::byte(int(num3)+0x55);
num3 = std::byte(num3 ^ (std::byte((int(std::byte(i))*11))));
num3 = std::byte(num3^num);
num3 = std::byte(int(num3)^170);
num = num3;
}
}
std::vector<std::byte>&SHNFile::ReadBytes(int bytes){
readArr.clear();
std::copy(data.begin()+marker,data.begin()+marker+bytes,std::back_inserter(readArr));
marker+=bytes;
return readArr;
}
std::byte SHNFile::ReadByte(){
std::vector<std::byte>&b=ReadBytes(1);
if(b.size()>0){
return b[0];
} else {
return std::byte(0);
}
}
void SHNFile::WriteByte(std::ofstream&f,std::byte b){
f<<unsigned char(b);
}
void SHNFile::WriteSByte(std::ofstream&f,sbyte b){
f<<char(b);
}
uint16_t SHNFile::ReadUInt16(){
std::vector<std::byte>&intBytes=ReadBytes(2);
uint16_t numb = uint16_t(intBytes[1])<<8|uint16_t(intBytes[0]);
return numb;
}
void SHNFile::WriteUInt16(std::ofstream&f,uint16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
int16_t SHNFile::ReadInt16(){
std::vector<std::byte>&intBytes=ReadBytes(2);
int16_t numb = int16_t(intBytes[1])<<8|int16_t(intBytes[0]);
return numb;
}
void SHNFile::WriteInt16(std::ofstream&f,int16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
uint32_t SHNFile::ReadUInt32(){
std::vector<std::byte>&intBytes=ReadBytes(4);
uint32_t numb = uint32_t(intBytes[3])<<24|uint32_t(intBytes[2])<<16|uint32_t(intBytes[1])<<8|uint32_t(intBytes[0]);
return numb;
}
void SHNFile::WriteUInt32(std::ofstream&f,uint32_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF)<<unsigned char((val>>16)&0xFF)<<unsigned char((val>>24)&0xFF);
}
int SHNFile::Read(){
std::vector<std::byte>&intBytes=ReadBytes(4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb;
}
int32_t SHNFile::ReadInt32(){
std::vector<std::byte>&intBytes=ReadBytes(4);
int32_t numb = int32_t(intBytes[3])<<24|int32_t(intBytes[2])<<16|int32_t(intBytes[1])<<8|uint32_t(intBytes[0]);
return numb;
}
void SHNFile::WriteInt32(std::ofstream&f,int32_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF)<<unsigned char((val>>16)&0xFF)<<unsigned char((val>>24)&0xFF);
}
std::string SHNFile::ReadString(int bytes){
std::vector<std::byte>&strBytes=ReadBytes(bytes);
std::string str="";
for(int i=0;i<strBytes.size();i++){
if(strBytes[i]!=std::byte(0)){
str+=unsigned char(strBytes[i]);
}
}
return str;
}
void SHNFile::WriteString(std::ofstream&f,std::string str,int bytes){
for(int i=0;i<bytes;i++){
if(i<str.length()){
f<<unsigned char(str[i]);
} else {
f<<unsigned char(0x00);
}
}
if(bytes==-1){
//We use this to append a 0 for unknown length strings (of the shn file)
f<<unsigned char(0x00);
}
}
float SHNFile::ReadSingle(){
std::vector<std::byte>strBytes=ReadBytes(4);
std::byte bytes[]={strBytes[0],strBytes[1],strBytes[2],strBytes[3]};
float f;
memcpy(&f,&bytes,4);
return f;
}
void SHNFile::WriteSingle(std::ofstream&f,float n){
std::byte bytes[4]={};
memcpy(&n,&bytes,4);
for(int i=0;i<4;i++){
f<<unsigned char(bytes[i]);
}
}
sbyte SHNFile::ReadSByte(){
return sbyte(ReadBytes(1)[0]);
}
std::string SHNFile::ReadString(){
std::string str="";
while(true){
std::vector<std::byte>byteArr=ReadBytes(1);
if(byteArr.size()>0&&byteArr[0]!=std::byte(0)){
str+=unsigned char(byteArr[0]);
}else{
break;
}
}
return str;
}
uint32_t SHNFile::GetRecordLength(){
uint32_t start=2;
for(Column&col:columns){
start+=uint32_t(col.length);
}
return start;
}
SHNFile::Data::Data(std::byte b){
std::shared_ptr<std::byte>ptr=std::make_shared<std::byte>(std::byte(b));
data=ptr;
type=DataType::BYTE;
}
SHNFile::Data::Data(sbyte b){
std::shared_ptr<sbyte>ptr=std::make_shared<sbyte>(sbyte(b));
data=ptr;
type=DataType::SBYTE;
}
SHNFile::Data::Data(uint16_t n){
std::shared_ptr<uint16_t>ptr=std::make_shared<uint16_t>(uint16_t(n));
data=ptr;
type=DataType::UINT16;
}
SHNFile::Data::Data(int16_t n){
std::shared_ptr<int16_t>ptr=std::make_shared<int16_t>(int16_t(n));
data=ptr;
type=DataType::INT16;
}
SHNFile::Data::Data(uint32_t n){
std::shared_ptr<uint32_t>ptr=std::make_shared<uint32_t>(uint32_t(n));
data=ptr;
type=DataType::UINT32;
}
SHNFile::Data::Data(int32_t n){
std::shared_ptr<int32_t>ptr=std::make_shared<int32_t>(int32_t(n));
data=ptr;
type=DataType::INT32;
}
SHNFile::Data::Data(float n){
std::shared_ptr<float>ptr=std::make_shared<float>(float(n));
data=ptr;
type=DataType::FLOAT;
}
SHNFile::Data::Data(std::string str){
std::shared_ptr<std::string>ptr=std::make_shared<std::string>(str);
data=ptr;
type=DataType::STRING;
}
template <typename T>
T SHNFile::Data::Get(){
return *std::static_pointer_cast<T>(data);
}
template<typename T>
void SHNFile::Data::Set(T b){
data=std::make_shared<T>(b);
}
std::string SHNFile::Data::GetDisplayText(){
switch(type){
case DataType::BYTE:{
return std::to_string(int(Get<std::byte>()));
}break;
case DataType::SBYTE:{
return std::to_string(int(Get<sbyte>()));
}break;
case DataType::UINT16:{
return std::to_string(Get<uint16_t>());
}break;
case DataType::INT16:{
return std::to_string(Get<int16_t>());
}break;
case DataType::UINT32:{
return std::to_string(Get<uint32_t>());
}break;
case DataType::INT32:{
return std::to_string(Get<int32_t>());
}break;
case DataType::FLOAT:{
return std::to_string(Get<float>());
}break;
case DataType::STRING:{
return Get<std::string>();
}break;
}
}
void SHNFile::Load(std::string file){
header=recordCount=defaultRecordLength=columnCount=0;
columns.clear();
contents.clear();
rawData.clear();
marker=0;
std::chrono::time_point<std::chrono::high_resolution_clock>timer=std::chrono::high_resolution_clock::now();
filename=file;
//FILE OPERATIONS!
std::ifstream f(filename,std::ios::binary);
//Since we don't just read in the entire file raw, we have to do some additional work here as the header provides us with some basic info on how to decrypt this file.
//The backup itself needs all the data from the original file, so we're appending it to rawData as we continue reading it.
cryptHeader=ReadBytes(f,0x20);
int readAmt=ReadInt32(f);
rawData.push_back(std::byte(readAmt&0xFF));
rawData.push_back(std::byte((readAmt>>8)&0xFF));
rawData.push_back(std::byte((readAmt>>16)&0xFF));
rawData.push_back(std::byte((readAmt>>24)&0xFF));
data=ReadBytes(f,readAmt-0x24);
std::copy(data.begin(),data.end(),std::back_inserter(rawData));
Decrypt();
header=ReadUInt32();
recordCount=ReadUInt32();
defaultRecordLength=ReadUInt32();
columnCount=ReadUInt32();
int num2=2;
for(int i=0;i<columnCount;i++){
Column columnData;
columnData.name=ReadString(0x30);
columnData.type=ReadUInt32();
columnData.length=ReadInt32();
num2+=columnData.length;
columns.push_back(columnData);
}
for(int i=0;i<recordCount;i++){
ReadUInt16();
std::vector<Data>row;
for(int j=0;j<columns.size();j++){
switch(columns[j].type){
case 1:
case 12:
case 0x10:{
row.push_back(ReadByte());
}break;
case 2:{
row.push_back(ReadUInt16());
}break;
case 3:
case 11:
case 0x12:
case 0x1b:{
row.push_back(ReadUInt32());
}break;
case 5:{
row.push_back(ReadSingle());
}break;
case 9:
case 0x18:{
row.push_back(ReadString(columns[j].length));
}break;
case 13:
case 0x15:{
row.push_back(ReadInt16());
}break;
case 20:{
row.push_back(ReadSByte());
}break;
case 0x16:{
row.push_back(ReadInt32());
}break;
case 0x1a:{
row.push_back(ReadString());
}break;
}
}
contents.push_back(row);
}
std::chrono::duration<float>dur=std::chrono::high_resolution_clock::now()-timer;
std::cout<<"Loaded "<<contents.size()<<" rows, "<<contents.size()*columnCount<<" columns, "<<dur.count()<<"s"<<std::endl;
}
void SHNFile::Save(){
std::ofstream fBackup(filename+".bak",std::ios::binary);
std::cout<<"Saving a backup to "<<filename+".bak"<<std::endl;
for(int i=0;i<rawData.size();i++){
fBackup<<unsigned char(rawData[i]);
}
/*//Decoded version only required for debugging.
std::ofstream fDecodedBackup(filename+"_decoded.bak",std::ios::binary);
std::cout<<"Saving a backup to "<<filename+"_decoded.bak"<<std::endl;
for(int i=0;i<data.size();i++){
fDecodedBackup<<unsigned char(data[i]);
}*/
std::cout<<"Saving new file..."<<std::endl;
std::ofstream f(filename,std::ios::binary);
WriteUInt32(f,header);
WriteUInt32(f,contents.size());
WriteUInt32(f,GetRecordLength());
WriteUInt32(f,columnCount);
for(int i=0;i<columnCount;i++){
WriteString(f,columns[i].name,0x30);
WriteUInt32(f,columns[i].type);
WriteInt32(f,columns[i].length);
}
for(std::vector<Data>&row:contents){
std::streampos marker = f.tellp();
WriteUInt16(f,uint16_t(0));
int colNum=0;
for(Data&col:row){
switch(columns[colNum].type){
case 1:
case 12:
case 0x10:{
WriteByte(f,col.Get<std::byte>());
}break;
case 2:{
WriteUInt16(f,col.Get<uint16_t>());
}break;
case 3:
case 11:
case 0x12:
case 0x1b:{
WriteUInt32(f,col.Get<uint32_t>());
}break;
case 5:{
WriteSingle(f,col.Get<float>());
}break;
case 9:
case 0x18:{
WriteString(f,std::string(col.Get<std::string>()),columns[colNum].length);
}break;
case 13:
case 0x15:{
WriteInt16(f,col.Get<uint16_t>());
}break;
case 20:{
WriteSByte(f,col.Get<sbyte>());
}break;
case 0x16:{
WriteInt32(f,col.Get<int32_t>());
}break;
case 0x1a:{
WriteString(f,col.Get<std::string>(),-1);
}break;
}
colNum++;
}
std::streampos offset = f.tellp() - marker;
std::streampos newMarker = f.tellp();
f.seekp(marker);
WriteUInt16(f,uint16_t(offset));
f.seekp(newMarker);
}
f.close();
std::ifstream finishedFile(filename,std::ios::binary);
data=ReadBytes(finishedFile);
std::ofstream encryptedFile(filename,std::ios::binary);
std::cout<<"Encrypting..."<<std::endl;
Encrypt();
WriteBytes(encryptedFile,cryptHeader);
WriteInt32(encryptedFile,int32_t(data.size()+0x24));
WriteBytes(encryptedFile,data);
std::cout<<"File "<<filename<<" Saved!"<<std::endl;
}
const SHNFile::Data SHNFile::Get(int row,int col)const{
return contents[row][col];
};
void SHNFile::Write(int row,int col,std::byte val){
contents[row][col].Set<std::byte>(val);
}
void SHNFile::Write(int row,int col,sbyte val){
contents[row][col].Set<sbyte>(val);
}
void SHNFile::Write(int row,int col,int16_t val){
contents[row][col].Set<int16_t>(val);
}
void SHNFile::Write(int row,int col,uint16_t val){
contents[row][col].Set<uint16_t>(val);
}
void SHNFile::Write(int row,int col,int32_t val){
contents[row][col].Set<int32_t>(val);
}
void SHNFile::Write(int row,int col,uint32_t val){
contents[row][col].Set<uint32_t>(val);
}
void SHNFile::Write(int row,int col,float val){
contents[row][col].Set<float>(val);
}
void SHNFile::Write(int row,int col,std::string val){
contents[row][col].Set<std::string>(val);
}
SHNFile::SHNFile(){
readArr.reserve(64000);
}
#endif