Last active
October 13, 2015 12:07
-
-
Save chrox/4193209 to your computer and use it in GitHub Desktop.
Just another KPV launcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.mobileread.chrox.patch.kpw.kpvlauncher; | |
import java.io.PrintStream; | |
import java.security.AllPermission; | |
import java.security.Permission; | |
import java.util.Date; | |
import java.util.Map; | |
import java.util.Arrays; | |
import java.net.URI; | |
import serp.bytecode.BCClass; | |
import serp.bytecode.Code; | |
import serp.bytecode.Instruction; | |
import org.json.simple.JSONObject; | |
import org.json.simple.JSONArray; | |
import com.amazon.kindle.restricted.runtime.Framework; | |
import com.amazon.kindle.restricted.content.catalog.ContentCatalog; | |
import com.mobileread.ixtab.jbpatch.Log; | |
import com.mobileread.ixtab.jbpatch.Patch; | |
import com.mobileread.ixtab.jbpatch.PatchMetadata; | |
import com.mobileread.ixtab.jbpatch.PatchMetadata.PatchableClass; | |
public class BookletPatch extends Patch { | |
// located at /opt/amazon/ebook/lib/kaf.jar | |
private static final String CLASS_BOOKLETCALLER_530 = "com.amazon.kindle.restricted.booklet.impl.S"; | |
public static final String MD5_BOOKLETCALLER_530_BEFORE = "b584b11d2a9f771398bc4def8e7a5f0e"; | |
public static final String MD5_BOOKLETCALLER__530_AFTER = "e01e0d69b57991f62196bacca98da4b2"; | |
// located at /opt/amazon/ebook/booklet/Reader.jar | |
private static final String CLASS_BOOKLETSTARTER_530 = "com.amazon.ebook.booklet.reader.ReaderBooklet"; | |
public static final String MD5_BOOKLETSTARTER_530_BEFORE = "571f2eee300f932c3f7419108ea969de"; | |
public static final String MD5_BOOKLETSTARTER_530_AFTER = "dcd0431dbded7e07c38aec2688364b92"; | |
// located at /opt/amazon/ebook/lib/kafindexer.jar | |
private static final String CLASS_INDEXERBUNDLE_530 = "com.amazon.kindle.indexer.bundle.IndexerBundle"; | |
public static final String MD5_INDEXERBUNDLE_530_BEFORE = "632a6f3b66aeefb84ad63a479ab2b5e3"; | |
public static final String MD5_INDEXERBUNDLE_530_AFTER = "dcd0431dbded7e07c38aec2688364b92"; | |
private static final PrintStream log = Log.INSTANCE; | |
private static final String[] doc_types = {"pdf","djvu","epub","cbz","chm","doc","fb2","htm","html","pdb","rtf","tcr","xps","zip"}; | |
public int getVersion() { | |
return 20121204; | |
} | |
public Permission[] getRequiredPermissions() { | |
return new Permission[] {new AllPermission()}; | |
} | |
protected void initLocalization(String locale, Map map) { | |
if (RESOURCE_ID_ENGLISH.equals(locale)) { | |
map.put(I18N_JBPATCH_NAME, "Substitude pdf viewer with KPV"); | |
map.put(I18N_JBPATCH_DESCRIPTION, "This patch allows to use KPV to read PDF documents."); | |
} | |
} | |
public PatchMetadata getMetadata() { | |
return new PatchMetadata(this).withClass( | |
new PatchableClass(CLASS_BOOKLETCALLER_530).withChecksums( | |
MD5_BOOKLETCALLER_530_BEFORE, MD5_BOOKLETCALLER__530_AFTER)).withClass( | |
new PatchableClass(CLASS_BOOKLETSTARTER_530).withChecksums( | |
MD5_BOOKLETSTARTER_530_BEFORE, MD5_BOOKLETSTARTER_530_AFTER)).withClass( | |
new PatchableClass(CLASS_INDEXERBUNDLE_530).withChecksums( | |
MD5_INDEXERBUNDLE_530_BEFORE, MD5_INDEXERBUNDLE_530_AFTER)); | |
} | |
public String perform(String md5, BCClass clazz) throws Throwable { | |
if (md5.equals(MD5_BOOKLETCALLER_530_BEFORE)) { | |
return patchMethodBookletCaller(clazz); | |
} | |
if (md5.equals(MD5_BOOKLETSTARTER_530_BEFORE)) { | |
return patchMethodBookletStarter(clazz); | |
} | |
/* // for debug use | |
if (md5.equals(MD5_INDEXERBUNDLE_530_BEFORE)) { | |
return patchMethodCallCC(clazz); | |
}*/ | |
return "unsupported MD5: "+md5; | |
} | |
private void sanitize(Code c) { | |
c.calculateMaxLocals(); | |
c.calculateMaxStack(); | |
} | |
private String patchMethodBookletCaller(BCClass clazz) throws Exception { | |
Code c = clazz.getDeclaredMethod("DxA").getCode(false); | |
//dump(c); | |
c.afterLast(); | |
Instruction ret = c.previous(); | |
//c.beforeFirst(); | |
c.before(102); | |
c.aload().setLocal(1); | |
c.invokestatic().setMethod(BookletPatch.class.getDeclaredMethod("bypassCaller", new Class[] {String.class})); | |
c.ifeq().setTarget(ret); | |
//dump(c); | |
sanitize(c); | |
return null; | |
} | |
private String patchMethodBookletStarter(BCClass clazz) throws Exception { | |
Code c = clazz.getDeclaredMethod("start").getCode(false); | |
//dump(c); | |
c.afterLast(); | |
Instruction ret = c.previous(); | |
c.beforeFirst(); | |
c.aload().setLocal(1); | |
c.invokestatic().setMethod(BookletPatch.class.getDeclaredMethod("startKPV", new Class[] {URI.class})); | |
c.ifeq().setTarget(ret); | |
//dump(c); | |
sanitize(c); | |
return null; | |
} | |
private String patchMethodCallCC(BCClass clazz) throws Exception { | |
Code c = clazz.getDeclaredMethod("eL").getCode(false); | |
//dump(c); | |
c.before(220); | |
c.aload().setLocal(1); | |
c.aload().setLocal(2); | |
c.aload().setLocal(11); | |
c.invokestatic().setMethod(BookletPatch.class.getDeclaredMethod("ccRequestLog", new Class[] {String.class, String.class, JSONObject.class})); | |
//dump(c); | |
sanitize(c); | |
return null; | |
} | |
public static int bypassCaller(String str) { | |
log("Booklet is called with URI: " + str); | |
String path = ""; | |
try { | |
path = new URI(str).getPath(); | |
} catch (Exception e) { | |
log("E: while parsing Path in " + str + ": "); | |
e.printStackTrace(log); | |
return -1; | |
} | |
int dot = path.lastIndexOf('.'); | |
String ext = (dot == -1) ? "" : path.substring(dot+1).toLowerCase(); | |
if (Arrays.asList(doc_types).contains(ext)) { | |
log("Bypassing booklet caller on " + path); | |
return 0; | |
} | |
return -1; | |
} | |
public static int startKPV(URI uri) { | |
String path = uri.getPath(); | |
log("Booklet is started with doc: " + path); | |
int dot = path.lastIndexOf('.'); | |
String ext = (dot == -1) ? "" : path.substring(dot+1).toLowerCase(); | |
if (Arrays.asList(doc_types).contains(ext)) { | |
long lastAccess = new Date().getTime() / 1000L; | |
updateCC(path, ext.toUpperCase(), lastAccess, 0.0f); | |
log("Opening " + path + " with kindlepdfviewer..."); | |
String[] cmd = new String[] {"/mnt/us/kindlepdfviewer/kpdf.sh", path}; | |
try { | |
// Run kpdf command | |
Runtime.getRuntime().exec(cmd); | |
//throw new RuntimeException(); | |
} catch (Exception e) { | |
e.printStackTrace(log); | |
} | |
return 0; | |
} | |
return -1; | |
} | |
public static void updateCC(String path, String tag, long lastAccess, float percentFinished) { | |
path = JSONObject.escape(path); | |
String json_query = "{\"filter\":{\"Equals\":{\"value\":\"" + path + "\",\"path\":\"location\"}},\"type\":\"QueryRequest\",\"maxResults\":1,\"sortOrder\":[{\"order\":\"descending\",\"path\":\"lastAccess\"},{\"order\":\"ascending\",\"path\":\"titles[0].collation\"}],\"startIndex\":0,\"id\":1,\"resultType\":\"fast\"}"; | |
JSONObject json = CCRequest("query", json_query); | |
JSONArray values = (JSONArray) json.get("values"); | |
JSONObject value =(JSONObject) values.get(0); | |
String uuid = (String) value.get("uuid"); | |
String json_change = "{\"commands\":[{\"update\":{\"uuid\":\"" + uuid + "\",\"lastAccess\":" + lastAccess + ",\"percentFinished\":" + percentFinished + ",\"displayTags\":[\"" + tag + "\"]" + "}}],\"type\":\"ChangeRequest\",\"id\":1}"; | |
CCRequest("change", json_change); | |
} | |
public static JSONObject CCRequest(String req_type, String req_json) { | |
ContentCatalog CC = (ContentCatalog)Framework.getService(ContentCatalog.class); | |
JSONObject json = CC.eL(req_type, req_json, 200, 5); | |
//log("CCRequest:type:" + req_type +",json=" + req_json); | |
//log("*************************************"); | |
//log("CCReturn:json=" + json.toJSONString()); | |
return json; | |
} | |
public static void ccRequestLog(String type, String cal_json, JSONObject ret_json) { | |
log("CCRequest:type:" + type +",json=" + cal_json); | |
log("....................................."); | |
log("CCReturn:json=" + ret_json); | |
/*try { | |
throw new RuntimeException(); | |
} catch (Exception e) { | |
e.printStackTrace(log); | |
}*/ | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
export LC_ALL="en_US.UTF-8" | |
echo unlock > /proc/keypad | |
echo unlock > /proc/fiveway | |
# we're always starting from our working directory | |
cd /mnt/us/kindlepdfviewer/ | |
# bind-mount system fonts | |
if ! grep /mnt/us/kindlepdfviewer/fonts/host /proc/mounts; then | |
mount -o bind /usr/java/lib/fonts /mnt/us/kindlepdfviewer/fonts/host | |
fi | |
# check if we are supposed to shut down the Amazon framework | |
if test "$1" == "--framework_stop"; then | |
shift 1 | |
/etc/init.d/framework stop | |
fi | |
# stop cvm | |
killall -stop cvm | |
# finally call reader | |
./reader.lua "$1" 2> crash.log | |
# unmount system fonts | |
if grep /mnt/us/kindlepdfviewer/fonts/host /proc/mounts; then | |
umount /mnt/us/kindlepdfviewer/fonts/host | |
fi | |
# always try to continue cvm | |
killall -cont cvm || restart framework | |
# return to home screen | |
lipc-set-prop com.lab126.appmgrd start app://com.lab126.booklet.home |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
INSERT INTO "properties" VALUES('com.lab126.booklet.kpvbooklet','lipcId','com.lab126.booklet.kpvbooklet'); | |
INSERT INTO "properties" VALUES('com.lab126.booklet.kpvbooklet','jar','/opt/amazon/ebook/booklet/KPVBooklet.jar'); | |
INSERT INTO "mimetypes" VALUES('pdf','MT:application/pdf'); | |
INSERT INTO "extenstions" VALUES('pdf','MT:application/pdf'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/pdf','PDF'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/pdf','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.pdf','true'); | |
INSERT INTO "mimetypes" VALUES('djvu','MT:image/x.djvu'); | |
INSERT INTO "extenstions" VALUES('djvu','MT:image/x.djvu'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','image/x.djvu','DjVu'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:image/x.djvu','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.djvu','true'); | |
INSERT INTO "mimetypes" VALUES('epub','MT:application/epub+zip'); | |
INSERT INTO "extenstions" VALUES('epub','MT:application/epub+zip'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/epub+zip','EPUB'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/epub+zip','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.epub','true'); | |
INSERT INTO "mimetypes" VALUES('cbz','MT:application/cbz'); | |
INSERT INTO "extenstions" VALUES('cbz','MT:application/cbz'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/cbz','CBZ'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/cbz','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.cbz','true'); | |
INSERT INTO "mimetypes" VALUES('chm','MT:application/chm'); | |
INSERT INTO "extenstions" VALUES('chm','MT:application/chm'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/chm','CHM'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/chm','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.chm','true'); | |
INSERT INTO "mimetypes" VALUES('doc','MT:application/doc'); | |
INSERT INTO "extenstions" VALUES('doc','MT:application/doc'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/doc','DOC'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/doc','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.doc','true'); | |
INSERT INTO "mimetypes" VALUES('fb2','MT:application/fb2'); | |
INSERT INTO "extenstions" VALUES('fb2','MT:application/fb2'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/fb2','FB2'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/fb2','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.fb2','true'); | |
INSERT INTO "mimetypes" VALUES('htm','MT:text/htm'); | |
INSERT INTO "extenstions" VALUES('htm','MT:text/htm'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','text/htm','HTML'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:text/htm','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.htm','true'); | |
INSERT INTO "mimetypes" VALUES('html','MT:text/html'); | |
INSERT INTO "extenstions" VALUES('html','MT:text/html'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','text/html','HTML'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:text/html','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.html','true'); | |
INSERT INTO "mimetypes" VALUES('pdb','MT:application/pdb'); | |
INSERT INTO "extenstions" VALUES('pdb','MT:application/pdb'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/pdb','PDB'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/pdb','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.pdb','true'); | |
INSERT INTO "mimetypes" VALUES('rtf','MT:application/rtf'); | |
INSERT INTO "extenstions" VALUES('rtf','MT:application/rtf'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/rtf','RTF'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/rtf','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.rtf','true'); | |
INSERT INTO "mimetypes" VALUES('tcr','MT:application/tcr'); | |
INSERT INTO "extenstions" VALUES('tcr','MT:application/tcr'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/tcr','TCR'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/tcr','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.tcr','true'); | |
INSERT INTO "mimetypes" VALUES('txt','MT:text/plain'); | |
INSERT INTO "extenstions" VALUES('txt','MT:text/plain'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','text/plain','TXT'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:text/plain','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.txt','true'); | |
INSERT INTO "mimetypes" VALUES('xps','MT:application/xps'); | |
INSERT INTO "extenstions" VALUES('xps','MT:application/xps'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/xps','XPS'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/xps','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.xps','true'); | |
INSERT INTO "mimetypes" VALUES('zip','MT:application/zip'); | |
INSERT INTO "extenstions" VALUES('zip','MT:application/zip'); | |
INSERT INTO "properties" VALUES('archive.displaytags.mimetypes','application/zip','ZIP'); | |
INSERT INTO "associations" VALUES('com.lab126.booklet.kpvbooklet','application','MT:application/zip','true'); | |
INSERT INTO "associations" VALUES('com.lab126.generic.extractor','extractor','GL:*.zip','true'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment