Skip to content

Instantly share code, notes, and snippets.

@gitbuh
Created September 13, 2012 08:02
Show Gist options
  • Save gitbuh/3712767 to your computer and use it in GitHub Desktop.
Save gitbuh/3712767 to your computer and use it in GitHub Desktop.
qpdiff
all : dist/x86/qpdiff dist/arm/qpdiff
dist/x86/qpdiff :
g++ -Wall -Wextra -pedantic src/qpdiff.cpp -o dist/x86/qpdiff
dist/arm/qpdiff :
arm-linux-gnueabi-g++ -Wall -Wextra -pedantic src/qpdiff.cpp -o dist/arm/qpdiff
clean :
rm dist/x86/qpdiff dist/arm/qpdiff
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
using namespace std;
string env(string var, string defaultval) {
const char* value = getenv(var.c_str());
return value == NULL ? defaultval : value;
}
string env(string var) {
return env(var, "");
}
int main( int argc, char** argv ) {
if (argc < 4) {
cout << "Title, old file and new file are required." << endl;
return 1;
}
const char* title = argv[1];
ifstream oldfile (argv[2], ios::in|ios::binary);
ifstream newfile (argv[3], ios::in|ios::binary);
char oldchar;
char newchar;
if (!(oldfile.is_open() && newfile.is_open())) {
cout << "Unable to open files." << endl;
return 2;
}
// find changed bytes
ostringstream oldbytes;
ostringstream newbytes;
int pos = 0;
int lastpos = -2;
while (!oldfile.eof()) {
if (newfile.eof()) {
cout << "File sizes don't match." << endl;
return 3;
}
oldfile.get(oldchar);
newfile.get(newchar);
if (oldchar != newchar) {
if (pos == lastpos + 1) {
oldbytes << ", \"" << hex << (int)oldchar << "\"";
newbytes << ", \"" << hex << (int)newchar << "\"";
} else {
if (lastpos != -2) {
oldbytes << "]," << endl;
newbytes << "]," << endl;
}
oldbytes << setw(8) << setfill(' ') << "\"" << pos << "\": [\"" << hex << (int)oldchar << "\"";
newbytes << setw(8) << setfill(' ') << "\"" << pos << "\": [\"" << hex << (int)newchar << "\"";
}
lastpos = pos;
}
++pos;
}
if (lastpos != -2) {
oldbytes << "]" << endl;
newbytes << "]" << endl;
}
oldfile.close();
newfile.close();
// write patch
cout << "{" << endl <<
"\"title\": \"" << title << "\"," << endl <<
"\"author\": \"" << env("PATCH_AUTHOR", "Anonymous") << "\"," << endl <<
"\"target\": \"" << env("PATCH_TARGET") << "\"," << endl <<
"\"version\": \"" << env("PATCH_VERSION", "1.0") << "\"," << endl <<
"\"initial\": { " << endl << oldbytes.str() << endl << " } " << endl <<
"\"options\": { \"" << env("PATCH_OPTION_NAME", "Patched") << "\" { " << endl <<
newbytes.str() << " } } " << endl << "}" << endl;
return 0;
}
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi">
<style>
label { display: block; font-weight: bold; color: #999; line-height: 200%; }
label input, textarea { width:100%; border:1px solid silver; border-radius: 3px; line-height: 150%; color: #666; }
input[type="submit"], input[type="button"] { border:1px solid #ccc; border-radius: 3px; padding: 1em; color:white; font-weight: bold; }
input[type="submit"] { float: right; background: #393 }
input[type="button"] { background: #933 }
form, fieldset, textarea { border:none; margin: none; padding: none; }
</style>
</head>
<body>
<h1>qpdiff</h1>
<textarea id="response" style="display:none"></textarea>
<form method="GET" action="."><fieldset>
<label>Patch title: <input name="title" type="text" value=""></label>
<label>Original file: <input name="oldfile" type="text" value=""></label>
<label>Modified file: <input name="newfile" type="text" value=""></label>
<label>Patch target: <input name="PATCH_TARGET" type="text" value=""></label>
<label>Patch version: <input name="PATCH_VERSION" type="text" value=""></label>
<label>Patch author: <input name="PATCH_AUTHOR" type="text" value=""></label>
<label>Patch option name: <input name="PATCH_OPTION_NAME" type="text" value=""></label>
<br>
<div><input type="button" name="quit" value="Quit"><input type="submit" value="Create patch"></div>
</fieldset></form>
<script>
var form = document.forms[0],
responseArea = document.getElementById('response');
function requestURL(string) {
return "http://localhost:8987/" + encodeURIComponent(string) + "/";
}
function makeRequest(data, onComplete) {
var xhr = new XMLHttpRequest();
if (onComplete)
xhr.onreadystatechange = onComplete;
xhr.open("GET", requestURL(data), true);
xhr.send();
}
// load saved form data
makeRequest('load', function() {
var data;
if (this.readyState == 4) {
data = JSON.parse(this.responseText);
for (key in form) {
if (form[key] && form[key].type == "text" && form[key].name) {
form[key].value = data[form[key].name];
}
}
}
});
// quit button
form.quit.onclick = function() {
makeRequest('exit');
}
// submit button
form.onsubmit = function() {
var data = {}, key;
for (key in form) {
if (form[key] && form[key].type == "text" && form[key].name) {
data[form[key].name] = form[key].value;
}
}
makeRequest(JSON.stringify(data), function() {
if (this.readyState == 4) {
responseArea.style.display = 'block';
responseArea.style.height = this.responseText.split('\n').length + 'em';
responseArea.textContent = this.responseText;
}
});
return false;
}
</script>
</body>
</html>
// https://developer.mozilla.org/en-US/docs/Rhino/Shell
// http://jebbeich.blogspot.com/2011/10/simple-webserver-for-rhino-in.html
importPackage(java.io);
importPackage(java.net);
function saveUrl(url, file) {
var uc = new URL(url).openConnection();
uc.connect();
var input = uc.getInputStream();
var output = new FileOutputStream(file);
var buffer = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1 << 8);
var bytes = -1;
while ((bytes = input.read(buffer)) > -1) {
output.write(buffer, 0, bytes);
}
input.close();
output.close();
}
function startServer(html) {
var s = new ServerSocket(8987);
var remote, is, out, request, str, writer;
function respond(text) {
out.println(text);
out.flush();
remote.close();
}
print('Waiting for connection');
while (1) {
try {
remote = s.accept();
is = new BufferedReader(new InputStreamReader(remote.getInputStream()));
out = new PrintWriter(remote.getOutputStream());
request = '';
do {
str = is.readLine();
request += str;
// stop reading once a blank line is hit.
} while (!str.equals(''));
// Send the headers
out.println('HTTP/1.0 200 OK');
out.println('Content-Type: text/html');
out.println('Server: qpdiff');
// this blank line signals the end of the headers
out.println('');
// strip request to first path segment, must have terminating slash
request = decodeURIComponent(request.replace(/.*?\//, '').replace(/\/.*/, ''));
print('Got request: ' + request);
// exit
if (request == 'exit') {
print('Stopping server.');
return;
}
// load
if (request == 'load') {
print('Loading settings.');
respond(readFile('/mnt/sdcard/qpdiff.json'));
continue;
}
// form post, convert request to an object
request = JSON.parse(request);
// store request
writer = new FileWriter('/mnt/sdcard/qpdiff.json');
writer.write(JSON.stringify(request));
writer.close();
var commandOpts = { output: "", err: "", env: request };
runCommand('/bin/qpdiff',
request.title, request.oldfile, request.newfile, commandOpts);
print('Command output: ' + commandOpts.output);
if (commandOpts.err)
print('Command errors: ' + commandOpts.err);
respond(commandOpts.output);
} catch (e) {
print('Error: ' + e);
}
}
}
function main() {
try {
print("Updating files.");
// update html file
var html = readUrl('https://raw.github.com/gist/3712767/server/qpdiff.html');
var writer = new FileWriter('/mnt/sdcard/qpdiff.html');
writer.write(html);
writer.close();
// update qpdiff binary
saveUrl('https://raw.github.com/gist/3712767/dist/arm/qpdiff', '/mnt/sdcard/qpdiff.bin')
runCommand('su', '-c',
'cp /mnt/sdcard/qpdiff.bin /bin/qpdiff; rm /mnt/sdcard/qpdiff.bin');
// load the droid stuff and show a webview
print("Loading web view.");
load('/sdcard/com.googlecode.rhinoforandroid/extras/rhino/android.js');
var droid = new Android();
droid.webViewShow("file:///mnt/sdcard/qpdiff.html");
// main loop
print("Starting server.");
startServer(html);
// exiting
} catch (e) {
print('Error: ' + e);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment