Saving shn files now implemented.

master
sigonasr2 1 year ago
parent 89ce51cd6f
commit d5f7cf205d
  1. BIN
      SHNFileDecryptor/AbState.shn
  2. BIN
      SHNFileDecryptor/AbState.shn.bak
  3. BIN
      SHNFileDecryptor/AbState.shn_decoded.bak
  4. 209
      SHNFileDecryptor/SHNFileDecryptor.cpp
  5. BIN
      SHNFileDecryptor/save_AbState.shn

Binary file not shown.

Binary file not shown.

@ -9,6 +9,13 @@ typedef std::byte byte;
typedef char sbyte; typedef char sbyte;
class SHNFile{ class SHNFile{
std::vector<byte>ReadBytes(std::ifstream&file){
std::vector<byte>byteArr;
while(!file.eof()){
byteArr.push_back(byte(file.get()));
}
return byteArr;
}
std::vector<byte>ReadBytes(std::ifstream&file,int bytes){ std::vector<byte>ReadBytes(std::ifstream&file,int bytes){
std::vector<byte>byteArr; std::vector<byte>byteArr;
for(int i=0;i<bytes;i++){ for(int i=0;i<bytes;i++){
@ -20,11 +27,19 @@ class SHNFile{
} }
return byteArr; return byteArr;
} }
void WriteBytes(std::ofstream&file,std::vector<byte>&data){
for(int i=0;i<data.size();i++){
file<<unsigned char(data[i]);
}
}
int ReadInt32(std::ifstream&file){ int ReadInt32(std::ifstream&file){
std::vector<byte>intBytes=ReadBytes(file,4); std::vector<byte>intBytes=ReadBytes(file,4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]); int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb; return numb;
} }
void Encrypt(){
Decrypt();
}
void Decrypt(){ void Decrypt(){
byte num = byte(data.size()); byte num = byte(data.size());
for(int i=data.size()-1;i>=0;i--){ for(int i=data.size()-1;i>=0;i--){
@ -58,26 +73,44 @@ class SHNFile{
return byte(0); return byte(0);
} }
} }
void WriteByte(std::ofstream&f,byte b){
f<<unsigned char(b);
}
void WriteSByte(std::ofstream&f,sbyte b){
f<<char(b);
}
uint16_t ReadUInt16(){ uint16_t ReadUInt16(){
std::vector<byte>intBytes=ReadBytes(2); std::vector<byte>intBytes=ReadBytes(2);
uint16_t numb = uint16_t(intBytes[1])<<8|uint16_t(intBytes[0]); uint16_t numb = uint16_t(intBytes[1])<<8|uint16_t(intBytes[0]);
return numb; return numb;
} }
void WriteUInt16(std::ofstream&f,uint16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
int16_t ReadInt16(){ int16_t ReadInt16(){
std::vector<byte>intBytes=ReadBytes(2); std::vector<byte>intBytes=ReadBytes(2);
int16_t numb = int16_t(intBytes[1])<<8|int16_t(intBytes[0]); int16_t numb = int16_t(intBytes[1])<<8|int16_t(intBytes[0]);
return numb; return numb;
} }
void WriteInt16(std::ofstream&f,int16_t val){
f<<unsigned char(val&0xFF)<<unsigned char((val>>8)&0xFF);
}
uint32_t ReadUInt32(){ uint32_t ReadUInt32(){
std::vector<byte>intBytes=ReadBytes(4); std::vector<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]); uint32_t numb = uint32_t(intBytes[3])<<24|uint32_t(intBytes[2])<<16|uint32_t(intBytes[1])<<8|uint32_t(intBytes[0]);
return numb; return numb;
} }
void 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 ReadInt32(){ int ReadInt32(){
std::vector<byte>intBytes=ReadBytes(4); std::vector<byte>intBytes=ReadBytes(4);
int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]); int numb = int(intBytes[3])<<24|int(intBytes[2])<<16|int(intBytes[1])<<8|int(intBytes[0]);
return numb; return numb;
} }
void 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);
}
struct Column{ struct Column{
std::string name; std::string name;
uint32_t type=0; uint32_t type=0;
@ -93,13 +126,33 @@ class SHNFile{
} }
return str; return str;
} }
void 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 ReadSingle(){ float ReadSingle(){
std::vector<byte>strBytes=ReadBytes(4); std::vector<byte>strBytes=ReadBytes(4);
byte bytes[]={strBytes[0],strBytes[1],strBytes[2],strBytes[3]}; byte bytes[]={strBytes[0],strBytes[1],strBytes[2],strBytes[3]};
float f; float f;
memcpy(&f,&bytes,sizeof(float)); memcpy(&f,&bytes,4);
return f; return f;
} }
void WriteSingle(std::ofstream&f,float n){
byte bytes[4];
memcpy(&n,&bytes,4);
for(int i=0;i<4;i++){
f<<unsigned char(bytes[i]);
}
}
sbyte ReadSByte(){ sbyte ReadSByte(){
return sbyte(ReadBytes(1)[0]); return sbyte(ReadBytes(1)[0]);
} }
@ -115,6 +168,13 @@ class SHNFile{
} }
return str; return str;
} }
uint32_t GetRecordLength(){
uint32_t start=2;
for(Column&col:columns){
start+=uint32_t(col.length);
}
return start;
}
public: public:
struct Data{ struct Data{
std::shared_ptr<void>data; std::shared_ptr<void>data;
@ -238,6 +298,8 @@ public:
//FILE OPERATIONS! //FILE OPERATIONS!
std::ifstream f(filename,std::ios::binary); 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); cryptHeader=ReadBytes(f,0x20);
std::copy(cryptHeader.begin(),cryptHeader.end(),std::back_inserter(rawData)); std::copy(cryptHeader.begin(),cryptHeader.end(),std::back_inserter(rawData));
int readAmt=ReadInt32(f); int readAmt=ReadInt32(f);
@ -269,40 +331,40 @@ public:
std::vector<Data>row; std::vector<Data>row;
for(int j=0;j<columns.size();j++){ for(int j=0;j<columns.size();j++){
switch(columns[j].type){ switch(columns[j].type){
case 1: case 1:
case 12: case 12:
case 0x10:{ case 0x10:{
row.push_back(ReadByte()); row.push_back(ReadByte());
}break; }break;
case 2:{ case 2:{
row.push_back(ReadUInt16()); row.push_back(ReadUInt16());
}break; }break;
case 3: case 3:
case 11: case 11:
case 0x12: case 0x12:
case 0x1b:{ case 0x1b:{
row.push_back(ReadUInt32()); row.push_back(ReadUInt32());
}break; }break;
case 5:{ case 5:{
row.push_back(ReadSingle()); row.push_back(ReadSingle());
}break; }break;
case 9: case 9:
case 0x18:{ case 0x18:{
row.push_back(ReadString(columns[j].length)); row.push_back(ReadString(columns[j].length));
}break; }break;
case 13: case 13:
case 0x15:{ case 0x15:{
row.push_back(ReadInt16()); row.push_back(ReadInt16());
}break; }break;
case 20:{ case 20:{
row.push_back(ReadSByte()); row.push_back(ReadSByte());
}break; }break;
case 0x16:{ case 0x16:{
row.push_back(ReadInt32()); row.push_back(ReadInt32());
}break; }break;
case 0x1a:{ case 0x1a:{
row.push_back(ReadString()); row.push_back(ReadString());
}break; }break;
} }
} }
contents.push_back(row); contents.push_back(row);
@ -316,8 +378,82 @@ public:
for(int i=0;i<rawData.size();i++){ for(int i=0;i<rawData.size();i++){
fBackup<<unsigned char(rawData[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::cout<<"Saving new file..."<<std::endl;
//std::ofstream f("save_"+filename,std::ios::binary); 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.GetByte());
}break;
case 2:{
WriteUInt16(f,col.GetUInt16());
}break;
case 3:
case 11:
case 0x12:
case 0x1b:{
WriteUInt32(f,col.GetUInt32());
}break;
case 5:{
WriteSingle(f,col.GetFloat());
}break;
case 9:
case 0x18:{
WriteString(f,col.GetString(),columns[colNum].length);
}break;
case 13:
case 0x15:{
WriteInt16(f,col.GetInt16());
}break;
case 20:{
WriteSByte(f,col.GetSByte());
}break;
case 0x16:{
WriteInt32(f,col.GetInt32());
}break;
case 0x1a:{
WriteString(f,col.GetString(),-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;
} }
SHNFile(){} SHNFile(){}
}; };
@ -325,6 +461,5 @@ public:
int main(){ int main(){
SHNFile shn; SHNFile shn;
shn.Load("AbState.shn"); shn.Load("AbState.shn");
shn.Load("AbState.shn");
shn.Save(); shn.Save();
} }

Binary file not shown.
Loading…
Cancel
Save