From 4f0f7636d5c0647d51fda62ad8a01ff840579b7b Mon Sep 17 00:00:00 2001
From: Josh Kropf <josh@slashdev.ca>
Date: Sun, 1 Feb 2009 13:15:45 -0500
Subject: [PATCH 3/4] Added save module command to javaloader

---
 src/m_javaloader.cc  |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/m_javaloader.h   |    2 +
 src/packet.cc        |    6 +++
 src/packet.h         |    1 +
 src/protocol.h       |    1 +
 tools/bjavaloader.cc |   47 ++++++++++++++++++++++++++
 6 files changed, 145 insertions(+), 0 deletions(-)

diff --git a/src/m_javaloader.cc b/src/m_javaloader.cc
index 308486a..1702c93 100644
--- a/src/m_javaloader.cc
+++ b/src/m_javaloader.cc
@@ -815,5 +815,93 @@ void JavaLoader::ClearEventlog()
 	}
 }
 
+void JavaLoader::SaveData(JLPacket &packet, uint16_t id, std::ostream &output)
+{
+	packet.SaveModule(id);
+	m_socket->Packet(packet);
+	
+	if( packet.Command() != SB_COMMAND_JL_ACK ) {
+		ThrowJLError("JavaLoader::SaveData", packet.Command());
+	}
+	
+	// get total size of cod file or this sibling cod file
+	Data &response = packet.GetReceive();
+	m_socket->Receive(response);
+	Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint32_t));
+	MAKE_JLPACKET(jpack, response);
+	uint32_t total_size = be_btohl(jpack->u.cod_size);
+	
+	for( ;; ) {
+		packet.GetData();
+		m_socket->Packet(packet);
+
+		if( packet.Command() == SB_COMMAND_JL_ACK )
+			return;
+
+		if( packet.Command() != SB_COMMAND_JL_GET_DATA_ENTRY ) {
+			ThrowJLError("JavaLoader::SaveData", packet.Command());
+		}
+
+		// expected size of data in resonse packet
+		unsigned int expect = packet.Size();
+
+		m_socket->Receive(response);
+		Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + expect);
+		
+		output.write((const char *)response.GetData() + SB_JLPACKET_HEADER_SIZE, expect);
+	}
+}
+
+void JavaLoader::Save(const std::string &cod_name, std::ostream &output)
+{
+	Data command(-1, 8), data(-1, 8), response;
+
+	JLPacket packet(command, data, response);
+
+	// set filename, device responds with an ID
+	packet.SetCodFilename(cod_name);
+	m_socket->Packet(packet);
+	
+	if( packet.Command() == SB_COMMAND_JL_COD_NOT_FOUND ) {
+		throw Error(string("JavaLoader::Save: module ") + cod_name + " not found");
+	}
+	
+	if( packet.Command() != SB_COMMAND_JL_ACK ) {
+		ThrowJLError("JavaLoader::Save", packet.Command());
+	}
+	
+	// make sure there is an ID coming
+	if( packet.Size() != 2 )
+		throw Error("JavaLoader::Save: expected module ID");
+
+	// get ID
+	m_socket->Receive(response);
+	Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint16_t));
+	MAKE_JLPACKET(jpack, response);
+	uint16_t id = be_btohs(jpack->u.id);
+	
+	// get list of sibling modules
+	packet.GetSubDir(id);
+	m_socket->Packet(packet);
+	
+	if( packet.Command() != SB_COMMAND_JL_ACK ) {
+		ThrowJLError("JavaLoader::Save", packet.Command());
+	}
+	
+	// expected number of module ID's
+	unsigned int expect = packet.Size();
+	
+	// get list of sibling module ID's
+	m_socket->Receive(response);
+	Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + expect);
+	
+	uint16_t *ids = (uint16_t*) (response.GetData() + SB_JLPACKET_HEADER_SIZE);
+	size_t count = expect / 2;
+	
+	for( size_t i = 0; i < count; i++, ids++ ) {
+		SaveData(packet, be_btohs(*ids), output);
+	}
+}
+
 }} // namespace Barry::Mode
 
diff --git a/src/m_javaloader.h b/src/m_javaloader.h
index d0a4656..11ce764 100644
--- a/src/m_javaloader.h
+++ b/src/m_javaloader.h
@@ -185,6 +185,7 @@ protected:
 		bool include_subdirs);
 	void ThrowJLError(const std::string &msg, uint8_t cmd);
 	void DoErase(uint8_t cmd, const std::string &cod_name);
+	void SaveData(JLPacket &packet, uint16_t, std::ostream &output);
 
 public:
 	JavaLoader(Controller &con);
@@ -211,6 +212,7 @@ public:
 	void ForceErase(const std::string &cod_name);
 	void GetEventlog(JLEventlog &log);
 	void ClearEventlog();
+	void Save(const std::string &cod_name, std::ostream &output);
 };
 
 }} // namespace Barry::Mode
diff --git a/src/packet.cc b/src/packet.cc
index aa70d8d..ee0fcfd 100644
--- a/src/packet.cc
+++ b/src/packet.cc
@@ -599,5 +599,11 @@ int JLPacket::GetEventlogEntry(uint16_t entry_num)
 	return BigEndianData(entry_num);
 }
 
+int JLPacket::SaveModule(uint16_t id)
+{
+	SimpleCmd(SB_COMMAND_JL_SAVE_MODULE, 0, 2);
+	return BigEndianData(id);
+}
+
 } // namespace Barry
 
diff --git a/src/packet.h b/src/packet.h
index 4725f12..61e8954 100644
--- a/src/packet.h
+++ b/src/packet.h
@@ -227,6 +227,7 @@ public:
 	int GetEventlog()	{ return SimpleCmd(SB_COMMAND_JL_GET_LOG); }
 	int GetEventlogEntry(uint16_t entry_num);
 	int ClearEventlog()	{ return SimpleCmd(SB_COMMAND_JL_CLEAR_LOG); }
+	int SaveModule(uint16_t id);
 
 	//////////////////////////////////
 	// response analysis
diff --git a/src/protocol.h b/src/protocol.h
index 57f4d97..728eaae 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -62,6 +62,7 @@
 #define SB_COMMAND_JL_GET_LOG		0x73
 #define SB_COMMAND_JL_GET_LOG_ENTRY	0x74
 #define SB_COMMAND_JL_CLEAR_LOG		0x88
+#define SB_COMMAND_JL_SAVE_MODULE	0x7e
 
 // JavaLoader response
 #define SB_COMMAND_JL_ACK		0x64
diff --git a/tools/bjavaloader.cc b/tools/bjavaloader.cc
index 2795087..7b3491e 100644
--- a/tools/bjavaloader.cc
+++ b/tools/bjavaloader.cc
@@ -30,6 +30,7 @@
 #include <cstring>
 #include <algorithm>
 #include <getopt.h>
+#include <fstream>
 
 // supported javaloader commands
 #define CMD_LIST	"dir"
@@ -39,6 +40,7 @@
 #define CMD_SETTIME	"settime"
 #define CMD_EVENTLOG    "eventlog"
 #define CMD_CLEAR_LOG   "cleareventlog"
+#define CMD_SAVE        "save"
 
 // time string format specifier and user friendly description
 #define TIME_FMT         "%Y-%m-%d %H:%M:%S"
@@ -74,6 +76,9 @@ void Usage()
    << "   " << CMD_LOAD << " <.cod file> ...\n"
    << "      Loads modules onto the handheld\n"
    << "\n"
+   << "   " << CMD_SAVE << " <module name> ...\n"
+   << "      Retrieves modules from the handheld\n"
+   << "\n"
    << "   " << CMD_ERASE << " [-f] <module name> ...\n"
    << "      Erase module from handheld\n"
    << "\n"
@@ -162,6 +167,34 @@ void GetScreenshot(Barry::Mode::JavaLoader *javaloader, const char *filename)
 	fwrite(bitmap.GetData(), bitmap.GetSize(), 1, fp);
 }
 
+void SaveModule(Barry::Mode::JavaLoader *javaloader, const char *filename)
+{
+	string fname(filename), module;
+	
+	size_t ext_index = fname.rfind(".cod");
+	if( ext_index != string::npos ) {
+		// filename contains .cod extension, strip it for module name
+		module = fname.substr(0, ext_index);
+	}
+	else {
+		// filename does not contain .cod extension, use it as module name
+		module = fname;
+		// append extension to file name
+		fname.append(".cod");
+	}
+	
+	ofstream file(fname.c_str(), ios::binary | ios::trunc);
+	try {
+		javaloader->Save(module.c_str(), file);
+		file.close();
+	}
+	catch( std::exception &e ) {
+		if( file.is_open() )
+			file.close();
+		throw e;
+	}
+}
+
 
 int main(int argc, char *argv[])
 {
@@ -319,6 +352,20 @@ int main(int argc, char *argv[])
 		else if( cmd == CMD_CLEAR_LOG ) {
 			javaloader.ClearEventlog();
 		}
+		else if( cmd == CMD_SAVE ) {
+			if( params.size() == 0 ) {
+				cerr << "specify at least one module to save" << endl;
+				Usage();
+				return 1;
+			}
+			
+			vector<string>::iterator i = params.begin(), end = params.end();
+			for( ; i != end; ++i ) {
+				cout << "saving: " << (*i) << "... ";
+				SaveModule(&javaloader, (*i).c_str());
+				cout << "done." << endl;
+			}
+		}
 		else {
 			cerr << "invalid command \"" << cmd << "\"" << endl;
 			Usage();
-- 
1.6.1.2

From 4952ee36f786a5038b5544316fbfe1d0bd62713b Mon Sep 17 00:00:00 2001
From: Josh Kropf <josh@slashdev.ca>
Date: Tue, 3 Feb 2009 21:55:56 -0500
Subject: [PATCH 4/4] Fixed bug resulting in sibling modules to be ignored in save

---
 src/m_javaloader.cc |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/m_javaloader.cc b/src/m_javaloader.cc
index 1702c93..efd3c83 100644
--- a/src/m_javaloader.cc
+++ b/src/m_javaloader.cc
@@ -895,11 +895,14 @@ void JavaLoader::Save(const std::string &cod_name, std::ostream &output)
 	m_socket->Receive(response);
 	Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + expect);
 	
-	uint16_t *ids = (uint16_t*) (response.GetData() + SB_JLPACKET_HEADER_SIZE);
 	size_t count = expect / 2;
+	uint16_t *ids = new uint16_t[count];
 	
-	for( size_t i = 0; i < count; i++, ids++ ) {
-		SaveData(packet, be_btohs(*ids), output);
+	// copy array of module ID's since we reuse the response packet buffer
+	memcpy(ids, response.GetData() + SB_JLPACKET_HEADER_SIZE, sizeof(uint16_t)*count);
+	
+	for( size_t i = 0; i < count; i++ ) {
+		SaveData(packet, be_btohs(ids[i]), output);
 	}
 }
 
-- 
1.6.1.2

