use of com.ichi2.utils.JSONException in project Anki-Android by Ramblurr.
the class Connection method doInBackgroundUpgradeDecks.
private Payload doInBackgroundUpgradeDecks(Payload data) {
// Enable http request canceller
mCancelCallback = new CancelCallback();
String path = (String) data.data[0];
File ankiDir = new File(path);
if (!ankiDir.isDirectory()) {
data.success = false;
data.data = new Object[] { "wrong anki directory" };
return data;
}
// step 1: gather all .anki files into a zip, without media.
// we must store them as 1.anki, 2.anki and provide a map so we don't run into
// encoding issues with the zip file.
File[] fileList = ankiDir.listFiles(new OldAnkiDeckFilter());
List<String> corruptFiles = new ArrayList<String>();
JSONObject map = new JSONObject();
byte[] buf = new byte[1024];
String zipFilename = path + "/upload.zip";
String colFilename = path + AnkiDroidApp.COLLECTION_PATH;
try {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilename));
int n = 1;
for (File f : fileList) {
String deckPath = f.getAbsolutePath();
// set journal mode to delete
try {
AnkiDb d = AnkiDatabaseManager.getDatabase(deckPath);
} catch (SQLiteDatabaseCorruptException e) {
// ignore invalid .anki files
corruptFiles.add(f.getName());
continue;
} finally {
AnkiDatabaseManager.closeDatabase(deckPath);
}
// zip file
String tmpName = n + ".anki";
FileInputStream in = new FileInputStream(deckPath);
ZipEntry ze = new ZipEntry(tmpName);
zos.putNextEntry(ze);
int len;
while ((len = in.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
map.put(tmpName, f.getName());
n++;
}
// if all .anki files were found corrupted, abort
if (fileList.length == corruptFiles.size()) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
ZipEntry ze = new ZipEntry("map.json");
zos.putNextEntry(ze);
InputStream in = new ByteArrayInputStream(Utils.jsonToString(map).getBytes("UTF-8"));
int len;
while ((len = in.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
zos.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
File zipFile = new File(zipFilename);
// step 1.1: if it's over 50MB compressed, it must be upgraded by the user
if (zipFile.length() > 50 * 1024 * 1024) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_exceeds) };
return data;
}
// step 2: upload zip file to upgrade service and get token
BasicHttpSyncer h = new BasicHttpSyncer(null, null);
// note: server doesn't expect it to be gzip compressed, because the zip file is compressed
// enable cancelling
publishProgress(R.string.upgrade_decks_upload, null, true);
try {
HttpResponse resp = h.req("upgrade/upload", new FileInputStream(zipFile), 0, false, null, mCancelCallback);
if (resp == null && !isCancelled()) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
String result;
String key = null;
if (!isCancelled()) {
result = h.stream2String(resp.getEntity().getContent());
if (result != null && result.startsWith("ok:")) {
key = result.split(":")[1];
} else {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
}
while (!isCancelled()) {
result = h.stream2String(h.req("upgrade/status?key=" + key).getEntity().getContent());
if (result.equals("error")) {
data.success = false;
data.data = new Object[] { "error" };
return data;
} else if (result.startsWith("waiting:")) {
publishProgress(R.string.upgrade_decks_upload, result.split(":")[1]);
} else if (result.equals("upgrading")) {
publishProgress(new Object[] { R.string.upgrade_decks_upgrade_started });
} else if (result.equals("ready")) {
break;
} else {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
Thread.sleep(1000);
}
// gzip compression if the client says it can handle it
if (!isCancelled()) {
publishProgress(new Object[] { R.string.upgrade_decks_downloading });
resp = h.req("upgrade/download?key=" + key, null, 6, true, null, mCancelCallback);
// uploads/downloads have finished so disable cancelling
}
publishProgress(R.string.upgrade_decks_downloading, null, false);
if (isCancelled()) {
return null;
}
if (resp == null) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
// step 5: check the received file is valid
InputStream cont = resp.getEntity().getContent();
if (!h.writeToFile(cont, colFilename)) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_sdcard, new File(colFilename).length() / 1048576 + 1) };
(new File(colFilename)).delete();
return data;
}
// check the received file is ok
publishProgress(new Object[] { R.string.sync_check_download_file });
publishProgress(R.string.sync_check_download_file);
try {
AnkiDb d = AnkiDatabaseManager.getDatabase(colFilename);
if (!d.queryString("PRAGMA integrity_check").equalsIgnoreCase("ok")) {
data.success = false;
data.data = new Object[] { sContext.getResources() };
return data;
}
} finally {
AnkiDatabaseManager.closeDatabase(colFilename);
}
Collection col = AnkiDroidApp.openCollection(colFilename);
ArrayList<String> decks = col.getDecks().allNames(false);
ArrayList<String> failed = new ArrayList<String>();
ArrayList<File> mediaDirs = new ArrayList<File>();
for (File f : fileList) {
String name = f.getName().replaceFirst("\\.anki$", "");
if (!decks.contains(name)) {
failed.add(name);
} else {
mediaDirs.add(new File(f.getAbsolutePath().replaceFirst("\\.anki$", ".media")));
}
}
File newMediaDir = new File(col.getMedia().getDir());
// step 6. move media files to new media directory
publishProgress(new Object[] { R.string.upgrade_decks_media });
ArrayList<String> failedMedia = new ArrayList<String>();
File curMediaDir = null;
for (File mediaDir : mediaDirs) {
curMediaDir = mediaDir;
// Check if media directory exists and is local
if (!curMediaDir.exists() || !curMediaDir.isDirectory()) {
// If not try finding it in dropbox 1.2.x
curMediaDir = new File(AnkiDroidApp.getDropboxDir(), mediaDir.getName());
if (!curMediaDir.exists() || !curMediaDir.isDirectory()) {
// No media for this deck
continue;
}
}
// Found media dir, copy files
for (File m : curMediaDir.listFiles()) {
try {
Utils.copyFile(m, new File(newMediaDir, m.getName()));
} catch (IOException e) {
failedMedia.add(curMediaDir.getName().replaceFirst("\\.media$", ".anki"));
break;
}
}
}
data.data = new Object[] { failed, failedMedia, newMediaDir.getAbsolutePath() };
data.success = true;
return data;
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (IllegalStateException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
(new File(zipFilename)).delete();
}
}
use of com.ichi2.utils.JSONException in project Anki-Android by Ramblurr.
the class Connection method doInBackgroundLogin.
private Payload doInBackgroundLogin(Payload data) {
String username = (String) data.data[0];
String password = (String) data.data[1];
BasicHttpSyncer server = new RemoteServer(this, null);
HttpResponse ret = server.hostKey(username, password);
String hostkey = null;
boolean valid = false;
if (ret != null) {
data.returnType = ret.getStatusLine().getStatusCode();
// Log.i(AnkiDroidApp.TAG, "doInBackgroundLogin - response from server: " + data.returnType + " (" + ret.getStatusLine().getReasonPhrase() + ")");
if (data.returnType == 200) {
try {
JSONObject jo = (new JSONObject(server.stream2String(ret.getEntity().getContent())));
hostkey = jo.getString("key");
valid = (hostkey != null) && (hostkey.length() > 0);
} catch (JSONException e) {
valid = false;
} catch (IllegalStateException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} else {
Log.e(AnkiDroidApp.TAG, "doInBackgroundLogin - empty response from server");
}
if (valid) {
data.success = true;
data.data = new String[] { username, hostkey };
} else {
data.success = false;
}
return data;
}
use of com.ichi2.utils.JSONException in project Anki-Android by Ramblurr.
the class Collection method _renderQA.
public HashMap<String, String> _renderQA(Object[] data, List<String> args) {
// data is [cid, nid, mid, did, ord, tags, flds]
// unpack fields and create dict
String[] flist = Utils.splitFields((String) data[6]);
Map<String, String> fields = new HashMap<String, String>();
long modelId = (Long) data[2];
JSONObject model = mModels.get(modelId);
Map<String, Pair<Integer, JSONObject>> fmap = mModels.fieldMap(model);
for (String fname : fmap.keySet()) {
fields.put(fname, flist[fmap.get(fname).first]);
}
fields.put("Tags", ((String) data[5]).trim());
try {
fields.put("Type", (String) model.get("name"));
fields.put("Deck", mDecks.name((Long) data[3]));
JSONObject template;
if (model.getInt("type") == Sched.MODEL_STD) {
template = model.getJSONArray("tmpls").getJSONObject((Integer) data[4]);
} else {
template = model.getJSONArray("tmpls").getJSONObject(0);
}
fields.put("Card", template.getString("name"));
fields.put("c" + (((Integer) data[4]) + 1), "1");
// render q & a
HashMap<String, String> d = new HashMap<String, String>();
try {
d.put("id", Long.toString((Long) data[0]));
String qfmt = template.getString("qfmt");
String afmt = template.getString("afmt");
String html;
String format;
// runFilter mungeFields for type "q"
Models.fieldParser fparser = new Models.fieldParser(fields);
Matcher m = fClozePattern.matcher(qfmt);
format = m.replaceFirst(String.format(Locale.US, "{{cq:%d:", ((Integer) data[4]) + 1));
m = fAltClozePattern.matcher(format);
format = m.replaceFirst(String.format(Locale.US, "<%%cq:%d:", ((Integer) data[4]) + 1));
html = mModels.getCmpldTemplate(format).execute(fparser);
html = (String) AnkiDroidApp.getHooks().runFilter("mungeQA", html, "q", fields, model, data, this);
d.put("q", html);
// empty cloze?
if (model.getInt("type") == Sched.MODEL_CLOZE) {
if (getModels()._availClozeOrds(model, (String) data[6], false).size() == 0) {
d.put("q", "Please edit this note and add some cloze deletions.");
}
}
fields.put("FrontSide", mMedia.stripAudio(d.get("q")));
// runFilter mungeFields for type "a"
fparser = new Models.fieldParser(fields);
m = fClozePattern.matcher(afmt);
format = m.replaceFirst(String.format(Locale.US, "{{ca:%d:", ((Integer) data[4]) + 1));
m = fAltClozePattern.matcher(format);
format = m.replaceFirst(String.format(Locale.US, "<%%ca:%d:", ((Integer) data[4]) + 1));
html = mModels.getCmpldTemplate(format).execute(fparser);
html = (String) AnkiDroidApp.getHooks().runFilter("mungeQA", html, "a", fields, model, data, this);
d.put("a", html);
// empty cloze?
if (model.getInt("type") == Sched.MODEL_CLOZE) {
if (getModels()._availClozeOrds(model, (String) data[6], false).size() == 0) {
d.put("q", AnkiDroidApp.getAppResources().getString(com.ichi2.anki.R.string.empty_cloze_warning, "<a href=" + HELP_SITE + "#cloze>" + AnkiDroidApp.getAppResources().getString(com.ichi2.anki.R.string.help_cloze) + "</a>"));
}
}
} catch (MustacheException e) {
Resources res = AnkiDroidApp.getAppResources();
String templateError = String.format(TEMPLATE_ERROR, res.getString(R.string.template_error), res.getString(R.string.template_error_detail), e.getMessage(), res.getString(R.string.note_type), model.getString("name"), res.getString(R.string.card_type), template.getString("name"), res.getString(R.string.template_error_fix));
d.put("q", templateError);
d.put("a", templateError);
}
return d;
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
use of com.ichi2.utils.JSONException in project Anki-Android by Ramblurr.
the class Media method zipAdded.
// Media syncing - bundling zip files to send to server
// Because there's no standard filename encoding for zips, and because not
// all zip clients support retrieving mtime, we store the files as ascii
// and place a json file in the zip with the necessary information.
// /////////////////////////////////////////////////////
/**
* Add files to a zip until over SYNC_ZIP_SIZE. Return zip data.
*
* @return Returns a tuple with two objects. The first one is the zip file contents, the second a list with the
* filenames of the files inside the zip.
*/
public Pair<File, List<String>> zipAdded() {
File f = new File(mCol.getPath().replaceFirst("collection\\.anki2$", "tmpSyncToServer.zip"));
String sql = "select fname from log where type = " + Integer.toString(MEDIA_ADD);
List<String> filenames = mMediaDb.queryColumn(String.class, sql, 0);
List<String> fnames = new ArrayList<String>();
try {
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
zos.setLevel(8);
JSONObject files = new JSONObject();
int cnt = 0;
long sz = 0;
byte[] buffer = new byte[2048];
boolean finished = true;
for (String fname : filenames) {
fnames.add(fname);
File file = new File(getDir(), fname);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 2048);
ZipEntry entry = new ZipEntry(Integer.toString(cnt));
zos.putNextEntry(entry);
int count = 0;
while ((count = bis.read(buffer, 0, 2048)) != -1) {
zos.write(buffer, 0, count);
}
zos.closeEntry();
bis.close();
files.put(Integer.toString(cnt), fname);
sz += file.length();
if (sz > SYNC_ZIP_SIZE) {
finished = false;
break;
}
cnt += 1;
}
if (finished) {
zos.putNextEntry(new ZipEntry("_finished"));
zos.closeEntry();
}
zos.putNextEntry(new ZipEntry("_meta"));
zos.write(Utils.jsonToString(files).getBytes());
zos.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
return new Pair<File, List<String>>(f, fnames);
}
use of com.ichi2.utils.JSONException in project Anki-Android by Ramblurr.
the class Models method fieldMap.
/**
* "Mapping of field name -> (ord, field).
*/
public Map<String, Pair<Integer, JSONObject>> fieldMap(JSONObject m) {
JSONArray ja;
try {
ja = m.getJSONArray("flds");
// TreeMap<Integer, String> map = new TreeMap<Integer, String>();
Map<String, Pair<Integer, JSONObject>> result = new HashMap<String, Pair<Integer, JSONObject>>();
for (int i = 0; i < ja.length(); i++) {
JSONObject f = ja.getJSONObject(i);
result.put(f.getString("name"), new Pair<Integer, JSONObject>(f.getInt("ord"), f));
}
return result;
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
Aggregations