///WELCOME TO MCDIRGE: COMMAND LINE EDITION VERSION 0.1
///Currently only tested and confirmed with file 'cfg000'
#include <iostream>
#include <fstream>
using namespace std;
///DECLARING THE KEY BLOCKS IN GLOBAL SPACE TO BE AVAILABLE EVERYWHERE
uint8_t KeyBlocksArray[32][8] =
{
{0x45, 0x48, 0x79, 0xEC, 0x35, 0x82, 0x1B, 0xC6},
{0x59, 0x69, 0x5E, 0x9E, 0x0D, 0x8B, 0x89, 0xDE},
{0xBD, 0x0E, 0xD8, 0x17, 0x44, 0xB7, 0xAF, 0x58},
{0xB1, 0x49, 0x38, 0x77, 0x54, 0x94, 0x6E, 0xBB},
{0x75, 0x70, 0x19, 0x54, 0xA6, 0xE5, 0x28, 0xA9},
{0x49, 0x32, 0x7F, 0xA4, 0x3F, 0x7C, 0xCC, 0x4D},
{0x6D, 0xFB, 0x7B, 0x36, 0x3E, 0x6D, 0xFE, 0x84},
{0x21, 0xE9, 0x6B, 0x10, 0x37, 0x22, 0xF8, 0x98},
{0xA5, 0x8D, 0x1B, 0x52, 0x13, 0xAB, 0xD8, 0xFC},
{0x39, 0xC4, 0x89, 0x9A, 0x60, 0x57, 0x3B, 0xF0},
{0x1D, 0xD5, 0xB0, 0x04, 0xE3, 0xB4, 0x28, 0xB1},
{0x91, 0x29, 0x74, 0x17, 0x6F, 0x88, 0xCB, 0x75},
{0xD5, 0xCF, 0x44, 0x75, 0x2B, 0xAA, 0xF9, 0x4C},
{0x29, 0x0F, 0x58, 0x4A, 0xD9, 0x52, 0xE0, 0x80},
{0xCD, 0x4B, 0xB8, 0x73, 0x3E, 0x9E, 0x61, 0x84},
{0x01, 0x7B, 0x99, 0x42, 0x38, 0x17, 0xE8, 0x95},
{0x05, 0x67, 0xFF, 0x4C, 0x19, 0x74, 0x88, 0xED},
{0x19, 0x03, 0xFD, 0x80, 0x7E, 0x44, 0xAA, 0xA3},
{0x7D, 0x0F, 0xF1, 0x84, 0x78, 0x56, 0x53, 0x32},
{0x71, 0x4D, 0xB5, 0x98, 0x5A, 0xB0, 0xA0, 0xFB},
{0x35, 0x83, 0x8A, 0xFB, 0xC4, 0x71, 0x23, 0xEA},
{0x09, 0x90, 0xB4, 0xE9, 0xD8, 0x38, 0xB1, 0x92},
{0x2D, 0xD0, 0x86, 0x90, 0x3C, 0x1C, 0x76, 0xDD},
{0xE1, 0x10, 0xA2, 0xD2, 0x2E, 0x8D, 0x4E, 0x53},
{0x65, 0x54, 0x2A, 0x1D, 0xEA, 0xC1, 0x88, 0xA0},
{0xF9, 0xA5, 0xD3, 0x91, 0x92, 0xC9, 0xAB, 0x22},
{0xDD, 0x3D, 0x22, 0xD9, 0xDC, 0xEF, 0x5A, 0xAD},
{0x51, 0x35, 0xAB, 0x3D, 0x50, 0xAF, 0xC6, 0x62},
{0x95, 0x0A, 0x58, 0x34, 0x91, 0x6C, 0xE1, 0xED},
{0xE9, 0x34, 0xB8, 0x05, 0xD6, 0x1E, 0x67, 0xA5},
{0x8D, 0x08, 0x99, 0x1C, 0x2E, 0x9A, 0x03, 0x3B},
{0xC1, 0x2A, 0xFD, 0x8E, 0xE6, 0x02, 0x12, 0x27},
};
///Prototyping smaller functions.
uint32_t LittleEndianToBigEndian (char Byte1, char Byte2, char Byte3, char Byte4);
uint32_t LittleEndianToBigEndian_unsignedchar (uint8_t Byte1, uint8_t Byte2, uint8_t Byte3, uint8_t Byte4);
///DECODER
void OpenDecodeAndCopyFile (string Filename)
{
///OPENING ENCODED FILE AND COPYING CONTENTS INTO EncodeToDecodeMemBlock
streampos size;
char *EncodeToDecodeMemBlock;
ifstream ReadingEncodedFile;
ReadingEncodedFile.open (Filename, ios::in | ios::binary | ios::ate);
size = ReadingEncodedFile.tellg();
ReadingEncodedFile.seekg(0, ios::beg);
EncodeToDecodeMemBlock = new char [size];
ReadingEncodedFile.read (EncodeToDecodeMemBlock, size);
ReadingEncodedFile.close();
///CONTENTS ARE NOW COPIED ONTO EncodeToDecodeMemBlock
cout << std::hex << std::uppercase << "All 0x" << size << " bytes of " << Filename << " are now in the memory block.\n" << endl;
///DECODING THE ENCODED INFORMATION NOW IN EncodeToDecodeMemBlock
static uint32_t ByteCounter, BlockCounter, KeyBlockCtr;
static uint32_t Gear1, Gear2;
static uint32_t TBlockA, TBlockB, KBlockA, KBlockB;
static bool CarryFlag1, CarryFlag2;
static uint8_t IntermediateCarrier;
static uint8_t OldMemblockValue;
///OUTERMOST LOOP OF THE DECODER
for ( ; ByteCounter < size; BlockCounter++, KeyBlockCtr++)
{
if(KeyBlockCtr > 31)
KeyBlockCtr = 0;
Gear1 = (ByteCounter << 0x14) | (ByteCounter << 0x0A) | ByteCounter;
if (Gear1 > ~0xA1652347)
CarryFlag1 = 1;
else
CarryFlag1 = 0;
Gear1 = Gear1 + 0xA1652347;
Gear2 = BlockCounter*2+CarryFlag1;
///THE INNER LOOP OF THE DECODER
for(int iterate(0), BlockwiseByteCounter(0); BlockwiseByteCounter < 8; )
{
if(iterate==0 && BlockwiseByteCounter==0)
{
OldMemblockValue = EncodeToDecodeMemBlock[ByteCounter];
EncodeToDecodeMemBlock[ByteCounter] = 0x45 ^ BlockCounter ^ EncodeToDecodeMemBlock[ByteCounter];
iterate++;
}
else if(iterate==0 && BlockwiseByteCounter < 8)
{
IntermediateCarrier = EncodeToDecodeMemBlock[ByteCounter] ^ OldMemblockValue;
OldMemblockValue = EncodeToDecodeMemBlock[ByteCounter];
EncodeToDecodeMemBlock[ByteCounter] = IntermediateCarrier;
iterate++;
}
else if(iterate < 9 && BlockwiseByteCounter < 8)
{EncodeToDecodeMemBlock[ByteCounter] = 0x78 + EncodeToDecodeMemBlock[ByteCounter] - KeyBlocksArray[KeyBlockCtr][iterate-1];
iterate++;}
else if(iterate==9)
{iterate = 0;
ByteCounter++;
BlockwiseByteCounter++;}
}
///EXITING THE INNER LOOP OF THE DECOER
///RESUMING THE OUTER LOOP
ByteCounter -=8;
TBlockA = LittleEndianToBigEndian (EncodeToDecodeMemBlock[ByteCounter], EncodeToDecodeMemBlock[ByteCounter+1], EncodeToDecodeMemBlock[ByteCounter+2], EncodeToDecodeMemBlock[ByteCounter+3]);
TBlockB = LittleEndianToBigEndian (EncodeToDecodeMemBlock[ByteCounter+4], EncodeToDecodeMemBlock[ByteCounter+5], EncodeToDecodeMemBlock[ByteCounter+6], EncodeToDecodeMemBlock[ByteCounter+7]);
KBlockA = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][0], KeyBlocksArray[KeyBlockCtr][1], KeyBlocksArray[KeyBlockCtr][2], KeyBlocksArray[KeyBlockCtr][3]);
KBlockB = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][4], KeyBlocksArray[KeyBlockCtr][5], KeyBlocksArray[KeyBlockCtr][6], KeyBlocksArray[KeyBlockCtr][7]);
if (TBlockA < KBlockA)
CarryFlag2 = 1;
else
CarryFlag2 = 0;
TBlockA = TBlockA - KBlockA;
TBlockB = TBlockB - KBlockB - CarryFlag2;
TBlockA = TBlockA ^ Gear1;
TBlockB = TBlockB ^ Gear2;
TBlockA = KBlockA ^ TBlockA;
TBlockB = KBlockB ^ TBlockB;
EncodeToDecodeMemBlock[ByteCounter] = (TBlockB & 0x000000FF);
EncodeToDecodeMemBlock[ByteCounter+1] = (TBlockB & 0x0000FF00) >> 8;
EncodeToDecodeMemBlock[ByteCounter+2] = (TBlockB & 0x00FF0000) >> 16;
EncodeToDecodeMemBlock[ByteCounter+3] = (TBlockB & 0xFF000000) >> 24;
EncodeToDecodeMemBlock[ByteCounter+4] = (TBlockA & 0x000000FF);
EncodeToDecodeMemBlock[ByteCounter+5] = (TBlockA & 0x0000FF00) >> 8;
EncodeToDecodeMemBlock[ByteCounter+6] = (TBlockA & 0x00FF0000) >> 16;
EncodeToDecodeMemBlock[ByteCounter+7] = (TBlockA & 0xFF000000) >> 24;
ByteCounter +=8;
}
///EXITING THE OUTER LOOP. cfg000 HAS NOW BEEN FULLY DECODED.
///CREATING A FILE COPY OF THE DECODED INFORMATION FOR USE IN OTHER FUNCTIONS
string Filecopy = Filename + "_decoded";
ofstream CopyingDecodedFile;
CopyingDecodedFile.open (Filecopy, ios::out | ios::trunc | ios::binary);
CopyingDecodedFile.write (EncodeToDecodeMemBlock, size);
CopyingDecodedFile.close();
delete[] EncodeToDecodeMemBlock;
}
///ENCODER
void ChangeValuesAndEncodeFile (string Filename)
{
///USER INPUT: EDIT VALUE OF PARTICULAR ADDRESSES
///ENCODER
///OPENING THE DECODED FILE AND COPYING IT INTO MEMBLOCK
string Filecopy = Filename + "_decoded";
char *DecodeToEncodeMemBlock;
static uint32_t FileAddressToEdit;
static uint16_t AddressValuetoEdit;
streampos size;
ifstream ReadingDecodedFile;
ReadingDecodedFile.open (Filecopy, ios::in | ios::binary | ios::ate);
size = ReadingDecodedFile.tellg();
ReadingDecodedFile.seekg(0, ios::beg);
DecodeToEncodeMemBlock = new char [size];
ReadingDecodedFile.read (DecodeToEncodeMemBlock, size);
ReadingDecodedFile.close();
///THE DECODED DATA IS NOW IN MEMBLOCK
string YesOrNo;
loop:
cout << std::hex << std::uppercase << "\nWhich address do you wish to change the value of?" << endl;
cout << "\t[Enter a hex value in the range of 0x0 to 0x" << size - 9 << "]" << endl;
cin >> std::hex >> FileAddressToEdit;
cout << "What value do you want 0x" << FileAddressToEdit << " to have?" << endl;
cout << "\t[Enter a hex value in the range 0x0 to 0xFF]" << endl;
cin >> std::hex >> AddressValuetoEdit;
DecodeToEncodeMemBlock[FileAddressToEdit] = AddressValuetoEdit;
cout << "\nDo you wish to change another offset? (Y/N)" << endl;
cin >> YesOrNo;
if (YesOrNo == "Y" || YesOrNo == "y" || YesOrNo == "1") goto loop;
///CHECKSUM CALCULATOR
cout << "Values of the given addresses have been changed. Updating checksum and re-encoding " << Filename << "." << endl;
static uint32_t Checksum, MemBlockConverter;
for (int iterate(0); iterate < (size-8); iterate+=4)
{
MemBlockConverter = DecodeToEncodeMemBlock[iterate];
if(MemBlockConverter > 0x7F)
MemBlockConverter = MemBlockConverter & 0x000000FF;
Checksum = Checksum + MemBlockConverter;
}
///CHECKSUM CALCULATED
///INSERTING CHECKSUM INTO END PORTION OF FILE
DecodeToEncodeMemBlock[size-4] = (Checksum & 0x000000FF);
DecodeToEncodeMemBlock[size-3] = (Checksum & 0x0000FF00) >> 8;
DecodeToEncodeMemBlock[size-2] = (Checksum & 0x00FF0000) >> 16;
DecodeToEncodeMemBlock[size-1] = (Checksum & 0xFF000000) >> 24;
///CHECKSUM INSERTED
///ENCODE the file, now that all the changes have been made and the checksum has been updated.
static uint32_t ByteCounter, BlockCounter, KeyBlockCtr;
static uint32_t Gear1, Gear2, Gear3;
static uint32_t TBlockA, TBlockB, KBlockA, KBlockB;
static bool CarryFlag1, CarryFlag2;
static uint8_t OldMemblockValue;
///OUTERMOST LOOP OF THE ENCODER
for ( ; ByteCounter < size; BlockCounter++, KeyBlockCtr++)
{
if(KeyBlockCtr > 31)
KeyBlockCtr = 0;
Gear1 = (ByteCounter << 0x14) | (ByteCounter << 0x0A) | ByteCounter;
if (Gear1 > ~0xA1652347)
CarryFlag1 = 1;
else
CarryFlag1 = 0;
Gear1 = Gear1 + 0xA1652347;
Gear2 = BlockCounter*2+CarryFlag1;
TBlockB = LittleEndianToBigEndian (DecodeToEncodeMemBlock[ByteCounter], DecodeToEncodeMemBlock[ByteCounter+1], DecodeToEncodeMemBlock[ByteCounter+2], DecodeToEncodeMemBlock[ByteCounter+3]);
TBlockA = LittleEndianToBigEndian (DecodeToEncodeMemBlock[ByteCounter+4], DecodeToEncodeMemBlock[ByteCounter+5], DecodeToEncodeMemBlock[ByteCounter+6], DecodeToEncodeMemBlock[ByteCounter+7]);
KBlockA = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][0], KeyBlocksArray[KeyBlockCtr][1], KeyBlocksArray[KeyBlockCtr][2], KeyBlocksArray[KeyBlockCtr][3]);
KBlockB = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][4], KeyBlocksArray[KeyBlockCtr][5], KeyBlocksArray[KeyBlockCtr][6], KeyBlocksArray[KeyBlockCtr][7]);
TBlockB = KBlockB ^ TBlockB;
TBlockA = KBlockA ^ TBlockA;
TBlockB = TBlockB ^ Gear2;
TBlockA = TBlockA ^ Gear1;
if (TBlockA > ~KBlockA) ///Reverse of TBlockA < KBlockA from the Decoder.
CarryFlag2 = 1;
else
CarryFlag2 = 0;
/// /// /// ///
TBlockB = TBlockB + KBlockB + CarryFlag2; ///Reversed from subtraction to addition.
TBlockA = TBlockA + KBlockA; ///Reversed from subtraction to addition.
DecodeToEncodeMemBlock[ByteCounter] = (TBlockA & 0x000000FF);
DecodeToEncodeMemBlock[ByteCounter+1] = (TBlockA & 0x0000FF00) >> 8;
DecodeToEncodeMemBlock[ByteCounter+2] = (TBlockA & 0x00FF0000) >> 16;
DecodeToEncodeMemBlock[ByteCounter+3] = (TBlockA & 0xFF000000) >> 24;
DecodeToEncodeMemBlock[ByteCounter+4] = (TBlockB & 0x000000FF);
DecodeToEncodeMemBlock[ByteCounter+5] = (TBlockB & 0x0000FF00) >> 8;
DecodeToEncodeMemBlock[ByteCounter+6] = (TBlockB & 0x00FF0000) >> 16;
DecodeToEncodeMemBlock[ByteCounter+7] = (TBlockB & 0xFF000000) >> 24;
///INNER LOOP OF ENCODER
for(int iterate(8), BlockwiseByteCounter(0); BlockwiseByteCounter < 8; )
{
if(iterate != 0 && BlockwiseByteCounter < 8)
{DecodeToEncodeMemBlock[ByteCounter] = DecodeToEncodeMemBlock[ByteCounter] + KeyBlocksArray[KeyBlockCtr][iterate-1] - 0x78;
iterate--;}
else if(iterate == 0 && BlockwiseByteCounter==0)
{
DecodeToEncodeMemBlock[ByteCounter] = 0x45 ^ BlockCounter ^ DecodeToEncodeMemBlock[ByteCounter];
OldMemblockValue = DecodeToEncodeMemBlock[ByteCounter];
BlockwiseByteCounter++;
ByteCounter++;
iterate = 8;
}
else if(iterate == 0 && BlockwiseByteCounter < 8)
{
DecodeToEncodeMemBlock[ByteCounter] = DecodeToEncodeMemBlock[ByteCounter] ^ OldMemblockValue;
OldMemblockValue = DecodeToEncodeMemBlock[ByteCounter];
iterate = 8;
BlockwiseByteCounter++;
ByteCounter++;
}
}
///EXITING INNER LOOP OF ENCODER
}
///EXITING OUTER LOOP
///ENCODING FINISHED
///ENTERING RE-ENCODED DATA INTO THE FILE
ofstream SavingEncodedFile;
SavingEncodedFile.open (Filename, ios::out | ios::trunc | ios::binary);
SavingEncodedFile.write (DecodeToEncodeMemBlock, size);
SavingEncodedFile.close();
delete[] DecodeToEncodeMemBlock;
///FINISHED ENTERING RE-ENCODED DATA INTO THE FILE
}
int main()
{
string YesOrNo;
string filename;
cout << "\n Welcome to the prototype of McDirge: The Dirge of Cerberus save editor." << endl;
cout << " Command line version 0.1\n\t Open file cfg000? <Y/N>" << endl;
cin >> YesOrNo;
if (YesOrNo == "N" || YesOrNo == "n" || YesOrNo == "NO" || YesOrNo == "no" || YesOrNo == "0")
{cout << "\ You have selected to not open cfg000. Exiting program." << endl;
return 0;}
else
{
filename = "cfg000";
OpenDecodeAndCopyFile (filename);
cout << filename << " has now been decoded and a copy named '" << filename << "_decoded' has been created." << endl;
ChangeValuesAndEncodeFile (filename);
cout << "\nAll changes have been saved and '" << filename << "' has been re-encoded." << endl;
cout << " Thank you for using McDirge: The Dirge of Cerberus save editor!\n Exiting program." << endl;
return 0;
}
return 0;
}
///FUNCTIONS FOR BYTE CONVERSION FROM 4-BYTE BLOCKS. FUNCTIONS PROTOTYPED AT THE TOP OF THE PROGRAM.
uint32_t LittleEndianToBigEndian (char Byte1, char Byte2, char Byte3, char Byte4)
{
static uint32_t BigEndianBlock, ConvertByte4, ConvertByte3, ConvertByte2, ConvertByte1;
ConvertByte4 = (Byte4 << 24) & 0xFF000000;
ConvertByte3 = (Byte3 << 16) & 0x00FF0000;
ConvertByte2 = (Byte2 << 8) & 0x0000FF00;
ConvertByte1 = Byte1 & 0x000000FF;
BigEndianBlock = ConvertByte4 + ConvertByte3 + ConvertByte2 + ConvertByte1;
return BigEndianBlock;
}
uint32_t LittleEndianToBigEndian_unsignedchar (uint8_t Byte1, uint8_t Byte2, uint8_t Byte3, uint8_t Byte4)
{
static uint32_t BigEndianBlock, ConvertByte4, ConvertByte3, ConvertByte2, ConvertByte1;
ConvertByte4 = Byte4 << 24;
ConvertByte3 = Byte3 << 16;
ConvertByte2 = Byte2 << 8;
ConvertByte1 = Byte1;
BigEndianBlock = ConvertByte4 + ConvertByte3 + ConvertByte2 + ConvertByte1;
return BigEndianBlock;
}