Search in sources :

Example 11 with JSONArray

use of com.ichi2.utils.JSONArray in project AnkiChinaAndroid by ankichinateam.

the class Finder method _findTemplate.

private String _findTemplate(String val) {
    // were we given an ordinal number?
    Integer num = null;
    try {
        num = Integer.parseInt(val) - 1;
    } catch (NumberFormatException e) {
        num = null;
    }
    if (num != null) {
        return "c.ord = " + num;
    }
    // search for template names
    List<String> lims = new ArrayList<>();
    for (JSONObject m : mCol.getModels().all()) {
        JSONArray tmpls = m.getJSONArray("tmpls");
        for (int ti = 0; ti < tmpls.length(); ++ti) {
            JSONObject t = tmpls.getJSONObject(ti);
            String templateName = t.getString("name");
            Normalizer.normalize(templateName, Normalizer.Form.NFC);
            if (templateName.equalsIgnoreCase(val)) {
                if (m.getInt("type") == Consts.MODEL_CLOZE) {
                    // if the user has asked for a cloze card, we want
                    // to give all ordinals, so we just limit to the
                    // model instead
                    lims.add("(n.mid = " + m.getLong("id") + ")");
                } else {
                    lims.add("(n.mid = " + m.getLong("id") + " and c.ord = " + t.getInt("ord") + ")");
                }
            }
        }
    }
    return TextUtils.join(" or ", lims.toArray(new String[lims.size()]));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray)

Example 12 with JSONArray

use of com.ichi2.utils.JSONArray in project AnkiChinaAndroid by ankichinateam.

the class Finder method _findField.

private String _findField(String field, String val) {
    /*
         * We need two expressions to query the cards: One that will use JAVA REGEX syntax and another
         * that should use SQLITE LIKE clause syntax.
         */
    String sqlVal = val.replace("%", // For SQLITE, we escape all % signs
    "\\%").replace("*", // And then convert the * into non-escaped % signs
    "%");
    /*
         * The following three lines make sure that only _ and * are valid wildcards.
         * Any other characters are enclosed inside the \Q \E markers, which force
         * all meta-characters in between them to lose their special meaning
         */
    String javaVal = val.replace("_", "\\E.\\Q").replace("*", "\\E.*\\Q");
    /*
         * For the pattern, we use the javaVal expression that uses JAVA REGEX syntax
         */
    Pattern pattern = Pattern.compile("\\Q" + javaVal + "\\E", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
    // find models that have that field
    Map<Long, Object[]> mods = new HashMap<>();
    for (JSONObject m : mCol.getModels().all()) {
        JSONArray flds = m.getJSONArray("flds");
        for (int fi = 0; fi < flds.length(); ++fi) {
            JSONObject f = flds.getJSONObject(fi);
            String fieldName = f.getString("name");
            fieldName = Normalizer.normalize(fieldName, Normalizer.Form.NFC);
            if (fieldName.equalsIgnoreCase(field)) {
                mods.put(m.getLong("id"), new Object[] { m, f.getInt("ord") });
            }
        }
    }
    if (mods.isEmpty()) {
        // nothing has that field
        return null;
    }
    LinkedList<Long> nids = new LinkedList<>();
    try (Cursor cur = mCol.getDb().getDatabase().query("select id, mid, flds from notes where mid in " + Utils.ids2str(new LinkedList<>(mods.keySet())) + " and flds like ? escape '\\'", new String[] { "%" + sqlVal + "%" })) {
        while (cur.moveToNext()) {
            String[] flds = Utils.splitFields(cur.getString(2));
            int ord = (Integer) mods.get(cur.getLong(1))[1];
            String strg = flds[ord];
            if (pattern.matcher(strg).matches()) {
                nids.add(cur.getLong(0));
            }
        }
    }
    if (nids.isEmpty()) {
        return "0";
    }
    return "n.id in " + Utils.ids2str(nids);
}
Also used : Pattern(java.util.regex.Pattern) HashMap(java.util.HashMap) JSONArray(com.ichi2.utils.JSONArray) Cursor(android.database.Cursor) LinkedList(java.util.LinkedList) JSONObject(com.ichi2.utils.JSONObject)

Example 13 with JSONArray

use of com.ichi2.utils.JSONArray in project AnkiChinaAndroid by ankichinateam.

the class Finder method fieldNames.

public List<String> fieldNames(Collection col, boolean downcase) {
    Set<String> fields = new HashSet<>();
    List<String> names = new ArrayList<>();
    for (JSONObject m : col.getModels().all()) {
        JSONArray flds = m.getJSONArray("flds");
        for (int fi = 0; fi < flds.length(); ++fi) {
            JSONObject f = flds.getJSONObject(fi);
            if (!fields.contains(f.getString("name").toLowerCase(Locale.US))) {
                names.add(f.getString("name"));
                fields.add(f.getString("name").toLowerCase(Locale.US));
            }
        }
    }
    if (downcase) {
        return new ArrayList<>(fields);
    }
    return names;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) HashSet(java.util.HashSet)

Example 14 with JSONArray

use of com.ichi2.utils.JSONArray in project AnkiChinaAndroid by ankichinateam.

the class Finder method ordForMid.

/**
 * Find duplicates
 * ***********************************************************
 */
public static Integer ordForMid(Collection col, Map<Long, Integer> fields, long mid, String fieldName) {
    if (!fields.containsKey(mid)) {
        JSONObject model = col.getModels().get(mid);
        JSONArray flds = model.getJSONArray("flds");
        for (int c = 0; c < flds.length(); c++) {
            JSONObject f = flds.getJSONObject(c);
            if (f.getString("name").equalsIgnoreCase(fieldName)) {
                fields.put(mid, c);
                break;
            }
        }
    }
    return fields.get(mid);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Example 15 with JSONArray

use of com.ichi2.utils.JSONArray in project AnkiChinaAndroid by ankichinateam.

the class Media method mediaChangesZip.

/**
 * Media syncing: zips
 * ***********************************************************
 */
/**
 * Unlike python, our temp zip file will be on disk instead of in memory. This avoids storing
 * potentially large files in memory which is not feasible with Android's limited heap space.
 * <p>
 * Notes:
 * <p>
 * - The maximum size of the changes zip is decided by the constant SYNC_ZIP_SIZE. If a media file exceeds this
 * limit, only that file (in full) will be zipped to be sent to the server.
 * <p>
 * - This method will be repeatedly called from MediaSyncer until there are no more files (marked "dirty" in the DB)
 * to send.
 * <p>
 * - Since AnkiDroid avoids scanning the media folder on every sync, it is possible for a file to be marked as a
 * new addition but actually have been deleted (e.g., with a file manager). In this case we skip over the file
 * and mark it as removed in the database. (This behaviour differs from the desktop client).
 * <p>
 */
public Pair<File, List<String>> mediaChangesZip() {
    File f = new File(mCol.getPath().replaceFirst("collection\\.anki2$", "tmpSyncToServer.zip"));
    Cursor cur = null;
    try (ZipOutputStream z = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)))) {
        z.setMethod(ZipOutputStream.DEFLATED);
        List<String> fnames = new ArrayList<>();
        // meta is a list of (fname, zipname), where zipname of null is a deleted file
        // NOTE: In python, meta is a list of tuples that then gets serialized into json and added
        // to the zip as a string. In our version, we use JSON objects from the start to avoid the
        // serialization step. Instead of a list of tuples, we use JSONArrays of JSONArrays.
        JSONArray meta = new JSONArray();
        int sz = 0;
        byte[] buffer = new byte[2048];
        cur = mDb.getDatabase().query("select fname, csum from media where dirty=1 limit " + Consts.SYNC_ZIP_COUNT, null);
        for (int c = 0; cur.moveToNext(); c++) {
            String fname = cur.getString(0);
            String csum = cur.getString(1);
            fnames.add(fname);
            String normname = Utils.nfcNormalized(fname);
            if (!TextUtils.isEmpty(csum)) {
                try {
                    mCol.log("+media zip " + fname);
                    File file = new File(dir(), fname);
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 2048);
                    z.putNextEntry(new ZipEntry(Integer.toString(c)));
                    int count = 0;
                    while ((count = bis.read(buffer, 0, 2048)) != -1) {
                        z.write(buffer, 0, count);
                    }
                    z.closeEntry();
                    bis.close();
                    meta.put(new JSONArray().put(normname).put(Integer.toString(c)));
                    sz += file.length();
                } catch (FileNotFoundException e) {
                    // A file has been marked as added but no longer exists in the media directory.
                    // Skip over it and mark it as removed in the db.
                    removeFile(fname);
                }
            } else {
                mCol.log("-media zip " + fname);
                meta.put(new JSONArray().put(normname).put(""));
            }
            if (sz >= Consts.SYNC_ZIP_SIZE) {
                break;
            }
        }
        z.putNextEntry(new ZipEntry("_meta"));
        z.write(Utils.jsonToString(meta).getBytes());
        z.closeEntry();
        // Don't leave lingering temp files if the VM terminates.
        f.deleteOnExit();
        return new Pair<>(f, fnames);
    } catch (IOException e) {
        Timber.e(e, "Failed to create media changes zip: ");
        throw new RuntimeException(e);
    } finally {
        if (cur != null) {
            cur.close();
        }
    }
}
Also used : ZipEntry(java.util.zip.ZipEntry) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) Cursor(android.database.Cursor) FileInputStream(java.io.FileInputStream) BufferedInputStream(java.io.BufferedInputStream) ZipOutputStream(java.util.zip.ZipOutputStream) FileOutputStream(java.io.FileOutputStream) ZipFile(java.util.zip.ZipFile) File(java.io.File) BufferedOutputStream(java.io.BufferedOutputStream) Pair(android.util.Pair)

Aggregations

JSONArray (com.ichi2.utils.JSONArray)188 JSONObject (com.ichi2.utils.JSONObject)97 Collection (com.ichi2.libanki.Collection)54 Test (org.junit.Test)44 ArrayList (java.util.ArrayList)42 Note (com.ichi2.libanki.Note)40 Card (com.ichi2.libanki.Card)39 DeckConfig (com.ichi2.libanki.DeckConfig)37 RobolectricTest (com.ichi2.anki.RobolectricTest)36 Deck (com.ichi2.libanki.Deck)19 Model (com.ichi2.libanki.Model)19 JSONException (com.ichi2.utils.JSONException)19 Cursor (android.database.Cursor)17 HashMap (java.util.HashMap)16 SuppressLint (android.annotation.SuppressLint)15 IOException (java.io.IOException)14 NonNull (androidx.annotation.NonNull)13 File (java.io.File)10 Response (okhttp3.Response)10 JSONArray (org.json.JSONArray)8