summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuroiIeWa5Da <tyuki@adu.me>2012-01-26 06:22:29 -0600
committerKuroiIeWa5Da <tyuki@adu.me>2012-01-26 06:22:29 -0600
commitbf1968297996fa8e2a5f004d60b83e516840a632 (patch)
tree5ae653257dc979e098c4a7aaac3996cdb42138d3
parent25e09f50668a6a90620522bacd9bfaba2b6f6ee5 (diff)
Made several large upgrades to Music Disassembler
hg-commit-id: 0b180a6e2ec5
-rw-r--r--music/pokeredmusicdisasm/AbstractData.h6
-rw-r--r--music/pokeredmusicdisasm/Parser.cpp186
-rw-r--r--music/pokeredmusicdisasm/Parser.h37
-rw-r--r--music/pokeredmusicdisasm/UnkCode.cpp67
-rw-r--r--music/pokeredmusicdisasm/UnkCode.h29
-rw-r--r--music/pokeredmusicdisasm/UnkEB.cpp69
-rw-r--r--music/pokeredmusicdisasm/UnkEB.h29
7 files changed, 341 insertions, 82 deletions
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<class T>
+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<Call>(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<Call>(i);
+ lDataType = DATA_CALL;
+ }
+ else if(ParseData<Duty>(i, true))
+ {
+ if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
- Call* _tmp = (Call*)parsedBytes[parsedBytes.size() - 1];
+ ParseData<Duty>(i);
+ lDataType = DATA_DUTY;
}
- else if(tmpDuty.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Jump>(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<Jump>(i);
+ lDataType = DATA_JUMP;
}
- else if(tmpJump.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Modulation>(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<Modulation>(i);
+ lDataType = DATA_MODULATION;
}
- else if(tmpModulation.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Note>(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<Note>(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<Octave>(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<Octave>(i);
+ lDataType = DATA_OCTAVE;
}
- else if(tmpOctave.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Tempo>(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<Tempo>(i);
+ lDataType = DATA_TEMPO;
}
- else if(tmpStop.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Velocity>(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<Velocity>(i);
+ lDataType = DATA_VELOCITY;
}
- else if(tmpTempo.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Volume>(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<Volume>(i);
+ lDataType = DATA_VOLUME;
}
- else if(tmpVelocity.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<UnkEB>(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<UnkEB>(i);
+ lDataType = DATA_UNKEB;
}
- else if(tmpVolume.IsValid(&rawBytesFixed[i]))
+ else if(ParseData<Stop>(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<Stop>(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<UnkCode>(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<class T>
+ 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<AbstractData*> parsedBytes;
std::vector<std::string> 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 <sstream>
+
+#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 <sstream>
+
+#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