shithub: pokered

Download patch

ref: bf1968297996fa8e2a5f004d60b83e516840a632
parent: 25e09f50668a6a90620522bacd9bfaba2b6f6ee5
author: KuroiIeWa5Da <tyuki@adu.me>
date: Thu Jan 26 01:22:29 EST 2012

Made several large upgrades to Music Disassembler

hg-commit-id: 0b180a6e2ec5


--- a/music/pokeredmusicdisasm/AbstractData.h
+++ b/music/pokeredmusicdisasm/AbstractData.h
@@ -10,11 +10,11 @@
     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
--- a/music/pokeredmusicdisasm/Parser.cpp
+++ b/music/pokeredmusicdisasm/Parser.cpp
@@ -18,6 +18,7 @@
 	fileLength = 0;
 	filePos = 0;
 	stop = false;
+	stopAddress = 0;
 
 	SetFilename(filename);
 }
@@ -87,6 +88,8 @@
 	// Read filedata
 	tmpFile.read(rawBytes, fileLength);
 	tmpFile.close();
+
+	rawBytesFixed = (unsigned char*)rawBytes;
 }
 
 // Code Operations
@@ -96,114 +99,165 @@
 	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
+		// First peek to see what kind of data it is, then perform any pre and post setup
+		if(ParseData<Call>(i, true))
+		{
+			if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
 
-		// 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
+			ParseData<Call>(i);
+			lDataType = DATA_CALL;
+		}
+		else if(ParseData<Duty>(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
-
-			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;
--- 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,6 +50,27 @@
 	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;
@@ -55,6 +77,7 @@
 	std::vector<std::string> parsedString;
 
 	char* rawBytes;
+	unsigned char* rawBytesFixed;
 	unsigned int fileLength;
 	unsigned int filePos;
 	bool stop;
@@ -61,18 +84,6 @@
 
 	// 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
--- /dev/null
+++ b/music/pokeredmusicdisasm/UnkCode.cpp
@@ -1,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
--- /dev/null
+++ b/music/pokeredmusicdisasm/UnkCode.h
@@ -1,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
--- /dev/null
+++ b/music/pokeredmusicdisasm/UnkEB.cpp
@@ -1,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
--- /dev/null
+++ b/music/pokeredmusicdisasm/UnkEB.h
@@ -1,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