From bf1968297996fa8e2a5f004d60b83e516840a632 Mon Sep 17 00:00:00 2001 From: KuroiIeWa5Da Date: Thu, 26 Jan 2012 06:22:29 -0600 Subject: Made several large upgrades to Music Disassembler hg-commit-id: 0b180a6e2ec5 --- music/pokeredmusicdisasm/AbstractData.h | 6 +- music/pokeredmusicdisasm/Parser.cpp | 186 ++++++++++++++++++++------------ music/pokeredmusicdisasm/Parser.h | 37 ++++--- music/pokeredmusicdisasm/UnkCode.cpp | 67 ++++++++++++ music/pokeredmusicdisasm/UnkCode.h | 29 +++++ music/pokeredmusicdisasm/UnkEB.cpp | 69 ++++++++++++ music/pokeredmusicdisasm/UnkEB.h | 29 +++++ 7 files changed, 341 insertions(+), 82 deletions(-) create mode 100644 music/pokeredmusicdisasm/UnkCode.cpp create mode 100644 music/pokeredmusicdisasm/UnkCode.h create mode 100644 music/pokeredmusicdisasm/UnkEB.cpp create mode 100644 music/pokeredmusicdisasm/UnkEB.h diff --git a/music/pokeredmusicdisasm/AbstractData.h b/music/pokeredmusicdisasm/AbstractData.h index 2a9fbbaf..0b49255d 100644 --- a/music/pokeredmusicdisasm/AbstractData.h +++ b/music/pokeredmusicdisasm/AbstractData.h @@ -10,11 +10,11 @@ public: AbstractData(); virtual std::string GenAsm(); // Generate Assembly Output - virtual bool IsValid(unsigned char* byte); // Check for byte validity virtual bool Parse(unsigned char* byte); // Parse Given Data - virtual unsigned int Arguments(); // Number of arguments taken + virtual bool GetError(); // Get Error (No Write, Error is read only) - virtual bool GetError(); // Get Error (No Write, Error is read only) + virtual bool IsValid(unsigned char* byte); // Check for byte validity + virtual unsigned int Arguments(); // Number of arguments taken protected: bool error; // Whether there's an error in parsing or not diff --git a/music/pokeredmusicdisasm/Parser.cpp b/music/pokeredmusicdisasm/Parser.cpp index 9fa0af7f..4878ee10 100644 --- a/music/pokeredmusicdisasm/Parser.cpp +++ b/music/pokeredmusicdisasm/Parser.cpp @@ -18,6 +18,7 @@ Parser::Parser(std::string filename) fileLength = 0; filePos = 0; stop = false; + stopAddress = 0; SetFilename(filename); } @@ -87,6 +88,8 @@ void Parser::Read() // Read filedata tmpFile.read(rawBytes, fileLength); tmpFile.close(); + + rawBytesFixed = (unsigned char*)rawBytes; } // Code Operations @@ -96,114 +99,165 @@ void Parser::Parse(unsigned int offset) ParseNext(); } +template +bool Parser::ParseData(unsigned int& pos, bool reado) +{ + // Create the class to use if correct and a dummy class for validating + T* tmpC = 0; + T dummy; + + // If the bytes are this data type then create and save it + if(dummy.IsValid(&rawBytesFixed[pos])) + { + // Ensure this whole opperation isn't read-only (just peeking) + if(!reado) + { + // Initialize the class + tmpC = new T(&rawBytesFixed[pos]); + + // Push it onto the stack and it's assembly generation onto the output class + parsedBytes.push_back(tmpC); // + parsedString.push_back(tmpC->GenAsm()); + + // If the class had any arguments, increment the counter that much forward + pos += tmpC->Arguments(); + } + return true; // Let the code know this class was valid + } + + return false; // Let the code know this class wasn't valid +} + void Parser::ParseNext() // Parses the block immidiately following { stringstream tmpStr; - unsigned char* rawBytesFixed = (unsigned char*)rawBytes; stop = false; // Smart generation - bool indent = false; - bool firstNonNote = false; // First byte wasn't a note or octacve switch, add ";Setup" comment - bool firstNote = false; // First note or octave + bool firstNonNote = false; // (unused so far)First byte wasn't a note or octacve switch, add ";Setup" comment + bool firstNote = false; // (unused so far) First note or octave + unsigned char lDataType = DATA_NA; stringstream pos; pos << "; " << hex << uppercase << (unsigned int)filePos; parsedString.push_back(pos.str()); + unsigned int count = 1; // Counter for processed instructions for(unsigned int i = filePos; (i <= fileLength) && (stop == false); i++) { - // There's a way to make this block shorter but for now it does it's job - - // Check to see if it's the correct data type and if so then use it - if(tmpCall.IsValid(&rawBytesFixed[i])) // Should have made IsValid static + // First peek to see what kind of data it is, then perform any pre and post setup + if(ParseData(i, true)) { - // Call data type + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes - // Create data type then move the increment pointer further up as needed - parsedBytes.push_back(new Call(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpCall.Arguments(); // should have made Arguments static + ParseData(i); + lDataType = DATA_CALL; + } + else if(ParseData(i, true)) + { + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes - Call* _tmp = (Call*)parsedBytes[parsedBytes.size() - 1]; + ParseData(i); + lDataType = DATA_DUTY; } - else if(tmpDuty.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Duty data type - parsedBytes.push_back(new Duty(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpDuty.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); + lDataType = DATA_JUMP; } - else if(tmpJump.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Jump data type - parsedBytes.push_back(new Jump(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpJump.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes - Jump* _tmp = (Jump*)parsedBytes[parsedBytes.size() - 1]; + ParseData(i); + lDataType = DATA_MODULATION; } - else if(tmpModulation.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Modulation data type - parsedBytes.push_back(new Modulation(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpModulation.Arguments(); + // Insert a newline after certain types + if((lDataType == DATA_UNKCODE) || + (lDataType == DATA_UNKEB)) parsedString.push_back("\n"); + + // If the previous item was a rest note then insert a new line + else if(lDataType == DATA_NOTE) + { + Note* _tmpNote = (Note*)parsedBytes[parsedBytes.size() - 1]; + if(_tmpNote->GetPitch() == _tmpNote->noteRst) parsedString.push_back("\n"); + } + + ParseData(i); + + // Further indent each note + parsedString[parsedString.size() - 1] = "\t" + parsedString[parsedString.size() - 1]; + lDataType = DATA_NOTE; } - else if(tmpNote.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Note data type - parsedBytes.push_back(new Note(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpNote.Arguments(); + // Insert new-line if previous line isn't a newline + if(parsedString[parsedString.size() - 1] != "\n") parsedString.push_back("\n"); + + ParseData(i); + lDataType = DATA_OCTAVE; } - else if(tmpOctave.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Octave data type - parsedBytes.push_back(new Octave(&rawBytesFixed[i])); - parsedString.push_back("\n" + parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpOctave.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); + lDataType = DATA_TEMPO; } - else if(tmpStop.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Stop data type - parsedBytes.push_back(new Stop(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpStop.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes - stop = true; // Stop all further processing, we've reached the end of the song + ParseData(i); + lDataType = DATA_VELOCITY; } - else if(tmpTempo.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Tempo data type - parsedBytes.push_back(new Tempo(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpTempo.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); + lDataType = DATA_VOLUME; } - else if(tmpVelocity.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) // The opcode is 0xEB which is unknown and takes a 1-byte argument { - // Velocity data type - parsedBytes.push_back(new Velocity(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpVelocity.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); + lDataType = DATA_UNKEB; } - else if(tmpVolume.IsValid(&rawBytesFixed[i])) + else if(ParseData(i, true)) { - // Volume data type - parsedBytes.push_back(new Volume(&rawBytesFixed[i])); - parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm()); - i += tmpVolume.Arguments(); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); + stop = true; // Raise the stop flag informing the parser to stop + lDataType = DATA_STOP; } else { - // Unknown code - stringstream unkCode; - short tmpByte = (short)rawBytesFixed[i]; - unkCode << "db $" << hex << uppercase << (short)rawBytesFixed[i]; - parsedString.push_back(unkCode.str()); + if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes + + ParseData(i); // The opcode is unknown - process the raw byte and move on + lDataType = DATA_UNKCODE; + } + + // Put everything tabbed over at least 1 time to fix some weird RGBDS bug by pre-pending a tab character + parsedString[parsedString.size() - 1] = "\t" + parsedString[parsedString.size() - 1]; + + // Append File Position in hexidecimal at end of line every 5 instructions + if((count % 5) == 0) + { + stringstream _tmpCount; + _tmpCount << hex << uppercase << i; + parsedString[parsedString.size() - 1] = parsedString[parsedString.size() - 1] + "; " + _tmpCount.str(); } filePos = i; + count++; // If the stop address parameter is set, break when we get there if( (stopAddress != 0) && (i >= stopAddress) ) break; diff --git a/music/pokeredmusicdisasm/Parser.h b/music/pokeredmusicdisasm/Parser.h index 515d07ad..20af39a7 100644 --- a/music/pokeredmusicdisasm/Parser.h +++ b/music/pokeredmusicdisasm/Parser.h @@ -13,11 +13,12 @@ #include "Modulation.h" #include "Note.h" #include "Octave.h" -#include "Parser.h" #include "Stop.h" #include "Tempo.h" #include "Velocity.h" #include "Volume.h" +#include "UnkCode.h" +#include "UnkEB.h" // This is the final class, it takes all of the data types, abstract class, and helper functions and uses them // for parsing @@ -49,30 +50,40 @@ public: void Parse(unsigned int offset); void ParseNext(); // Parses the block immidiately following + // Templates + template + bool ParseData(unsigned int& pos, bool reado = false); + + const enum dataType : unsigned char + { + DATA_NA, + DATA_CALL, + DATA_DUTY, + DATA_JUMP, + DATA_MODULATION, + DATA_NOTE, + DATA_OCTAVE, + DATA_STOP, + DATA_TEMPO, + DATA_UNKCODE, + DATA_UNKEB, + DATA_VELOCITY, + DATA_VOLUME + }; + private: std::string filename; std::vector parsedBytes; std::vector parsedString; char* rawBytes; + unsigned char* rawBytesFixed; unsigned int fileLength; unsigned int filePos; bool stop; // Optional Settings unsigned int stopAddress; - - // A lot of tmp classes - Call tmpCall; - Duty tmpDuty; - Jump tmpJump; - Modulation tmpModulation; - Note tmpNote; - Octave tmpOctave; - Stop tmpStop; - Tempo tmpTempo; - Velocity tmpVelocity; - Volume tmpVolume; }; #endif \ No newline at end of file diff --git a/music/pokeredmusicdisasm/UnkCode.cpp b/music/pokeredmusicdisasm/UnkCode.cpp new file mode 100644 index 00000000..93c74f66 --- /dev/null +++ b/music/pokeredmusicdisasm/UnkCode.cpp @@ -0,0 +1,67 @@ +#include + +#include "Call.h" +#include "Duty.h" +#include "Jump.h" +#include "Modulation.h" +#include "Note.h" +#include "Octave.h" +#include "Stop.h" +#include "Tempo.h" +#include "Velocity.h" +#include "Volume.h" + +#include "UnkCode.h" + +using namespace std; + +UnkCode::UnkCode() +{ + code = 0; +} + +UnkCode::UnkCode(unsigned char* byte) +{ + code = 0; + Parse(byte); +} + +UnkCode::UnkCode(unsigned char code, bool) +{ + SetCode(code); +} + +// Getters / Setters +unsigned char UnkCode::GetCode() +{ + return code; +} + +void UnkCode::SetCode(unsigned char value) +{ + code = value; +} + +// Re-implemented +string UnkCode::GenAsm() +{ + stringstream tmpAsmOut; + tmpAsmOut << "db $" << hex << (short)code; + return tmpAsmOut.str(); +} + +bool UnkCode::Parse(unsigned char* byte) +{ + code = byte[0]; + return true; +} + +bool UnkCode::IsValid(unsigned char* byte) +{ + return true; +} + +unsigned int UnkCode::Arguments() +{ + return 0; +} \ No newline at end of file diff --git a/music/pokeredmusicdisasm/UnkCode.h b/music/pokeredmusicdisasm/UnkCode.h new file mode 100644 index 00000000..28204448 --- /dev/null +++ b/music/pokeredmusicdisasm/UnkCode.h @@ -0,0 +1,29 @@ +#ifndef UNKCODE_H +#define UNKCODE_H + +#include "AbstractData.h" + +// Represents an unknown opcode +class UnkCode : public AbstractData +{ +public: + // Constructors + UnkCode(); + UnkCode(unsigned char* byte); // Parse Immidiately + UnkCode(unsigned char code, bool); // Set Value + + // Getters / Setters + unsigned char GetCode(); + void SetCode(unsigned char value); + + // Re-implemented + virtual std::string GenAsm(); + virtual bool Parse(unsigned char* byte); + virtual bool IsValid(unsigned char* byte); + virtual unsigned int Arguments(); + +private: + unsigned char code; +}; + +#endif \ No newline at end of file diff --git a/music/pokeredmusicdisasm/UnkEB.cpp b/music/pokeredmusicdisasm/UnkEB.cpp new file mode 100644 index 00000000..c8db595f --- /dev/null +++ b/music/pokeredmusicdisasm/UnkEB.cpp @@ -0,0 +1,69 @@ +#include + +#include "Call.h" +#include "Duty.h" +#include "Jump.h" +#include "Modulation.h" +#include "Note.h" +#include "Octave.h" +#include "Stop.h" +#include "Tempo.h" +#include "Velocity.h" +#include "Volume.h" + +#include "UnkEB.h" + +using namespace std; + +UnkEB::UnkEB() +{ + param = 0; +} + +UnkEB::UnkEB(unsigned char* byte) +{ + param = 0; + Parse(byte); +} + +UnkEB::UnkEB(unsigned char code, bool) +{ + SetParam(code); +} + +// Getters / Setters +unsigned char UnkEB::GetParam() +{ + return param; +} + +void UnkEB::SetParam(unsigned char value) +{ + param = value; +} + +// Re-implemented +string UnkEB::GenAsm() +{ + stringstream tmpAsmOut; + tmpAsmOut << hex << "db $" << (short)0xEB << ", $" << (short)param; + return tmpAsmOut.str(); +} + +bool UnkEB::Parse(unsigned char* byte) +{ + param = byte[1]; + return true; +} + +bool UnkEB::IsValid(unsigned char* byte) +{ + if(byte[0] == 0xEB) return true; + else return false; +} + +unsigned int UnkEB::Arguments() +{ + // 1 1-Byte param + return 1; +} \ No newline at end of file diff --git a/music/pokeredmusicdisasm/UnkEB.h b/music/pokeredmusicdisasm/UnkEB.h new file mode 100644 index 00000000..ab11a655 --- /dev/null +++ b/music/pokeredmusicdisasm/UnkEB.h @@ -0,0 +1,29 @@ +#ifndef UNKEB_H +#define UNKEB_H + +#include "AbstractData.h" + +// Represents an unknown opcode +class UnkEB : public AbstractData +{ +public: + // Constructors + UnkEB(); + UnkEB(unsigned char* byte); // Parse Immidiately + UnkEB(unsigned char code, bool); // Set Value + + // Getters / Setters + unsigned char GetParam(); + void SetParam(unsigned char value); + + // Re-implemented + virtual std::string GenAsm(); + virtual bool Parse(unsigned char* byte); + virtual bool IsValid(unsigned char* byte); + virtual unsigned int Arguments(); + +private: + unsigned char param; +}; + +#endif \ No newline at end of file -- cgit v1.2.3