/CVox/src/com/cvox/browser/ScriptDatabase.java

http://eyes-free.googlecode.com/ · Java · 258 lines · 154 code · 55 blank · 49 comment · 19 complexity · 4e059e6bce1b386a63a60763b967e373 MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.cvox.browser;
  17. import java.io.InputStream;
  18. import java.util.HashMap;
  19. import java.util.LinkedList;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.regex.Matcher;
  23. import java.util.regex.Pattern;
  24. import org.json.JSONArray;
  25. import org.json.JSONObject;
  26. import android.content.ContentValues;
  27. import android.content.Context;
  28. import android.content.res.Resources;
  29. import android.database.Cursor;
  30. import android.database.sqlite.SQLiteDatabase;
  31. import android.database.sqlite.SQLiteOpenHelper;
  32. import android.util.Log;
  33. public class ScriptDatabase extends SQLiteOpenHelper {
  34. public final static String TAG = ScriptDatabase.class.toString();
  35. public final static String DB_NAME = "scripts";
  36. public final static int DB_VERSION = 3;
  37. public final static String TABLE_SCRIPTS = "scripts";
  38. public final static String FIELD_SCRIPT_NAME = "title";
  39. public final static String FIELD_SCRIPT_AUTHOR = "author";
  40. public final static String FIELD_SCRIPT_DESCRIP = "descrip";
  41. public final static String FIELD_SCRIPT_DOMAINREGEX = "domain";
  42. public final static String FIELD_SCRIPT_CONTENT = "content";
  43. public final static String FIELD_SCRIPT_ENABLED = "enabled";
  44. private final Resources res;
  45. public ScriptDatabase(Context context) {
  46. super(context, DB_NAME, null, DB_VERSION);
  47. this.res = context.getResources();
  48. }
  49. public void onCreate(SQLiteDatabase db) {
  50. db.execSQL("CREATE TABLE " + TABLE_SCRIPTS
  51. + " (_id INTEGER PRIMARY KEY, "
  52. + FIELD_SCRIPT_NAME + " TEXT, "
  53. + FIELD_SCRIPT_AUTHOR + " TEXT, "
  54. + FIELD_SCRIPT_DESCRIP + " TEXT, "
  55. + FIELD_SCRIPT_DOMAINREGEX + " TEXT, "
  56. + FIELD_SCRIPT_CONTENT + " TEXT, "
  57. + FIELD_SCRIPT_ENABLED + " INTEGER)");
  58. // populate database with a few example scripts
  59. try {
  60. this.insertScript(db, Util.getRawString(res, R.raw.gws));
  61. this.insertScript(db, Util.getRawString(res, R.raw.basic));
  62. //this.insertScript(db, Util.getRawString(res, R.raw.email));
  63. //this.insertScript(db, Util.getRawString(res, R.raw.halfscan));
  64. //this.insertScript(db, Util.getRawString(res, R.raw.sharedigg));
  65. //this.insertScript(db, Util.getRawString(res, R.raw.wikipedia));
  66. //this.insertScript(db, Util.getRawString(res, R.raw.slashdot));
  67. //this.insertScript(db, Util.getRawString(res, R.raw.userscripts));
  68. } catch(Exception e) {
  69. Log.e(TAG, "Problem while inserting default scripts", e);
  70. }
  71. }
  72. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  73. int currentVersion = oldVersion;
  74. if(currentVersion != newVersion) {
  75. db.execSQL("DROP TABLE IF EXISTS " + TABLE_SCRIPTS);
  76. onCreate(db);
  77. }
  78. }
  79. public static Pattern headerRegex = Pattern.compile("^// @([^\\s]+)\\s+(.+?)$", Pattern.MULTILINE);
  80. public final static String UNKNOWN = "Unknown";
  81. /**
  82. * Format a domain "include" statement so it behaves nicely as a Java regex.
  83. */
  84. public static String formatDomain(String domain) {
  85. // escape any "." and replace "*" with generic matcher
  86. domain = domain.replace(".", "\\.");
  87. domain = domain.replace("*", ".*");
  88. return domain;
  89. }
  90. /**
  91. * Import the given script into our database.
  92. * @throws Exception if problem parsing script
  93. */
  94. public long insertScript(SQLiteDatabase db, String raw) throws Exception {
  95. if(db == null) db = this.getWritableDatabase();
  96. // extract metadata from script comments
  97. String name = UNKNOWN, author = UNKNOWN, descrip = UNKNOWN;
  98. StringBuilder include = new StringBuilder();
  99. include.append('(');
  100. try {
  101. Matcher matcher = headerRegex.matcher(raw);
  102. while(matcher.find()) {
  103. String key = matcher.group(1),
  104. value = matcher.group(2);
  105. Log.d(TAG, String.format("found header %s=%s", key, value));
  106. if("name".equals(key)) {
  107. name = value;
  108. } else if("author".equals(key)) {
  109. author = value;
  110. } else if("description".equals(key)) {
  111. descrip = value;
  112. } else if("include".equals(key)) {
  113. include.append(formatDomain(value));
  114. include.append('|');
  115. }
  116. }
  117. } catch(Exception e) {
  118. Log.e(TAG, "Problem while parsing script header", e);
  119. }
  120. String domainregex = "";
  121. if(include.length() > 0) {
  122. // replace last '|' with a closing bracket
  123. include.setCharAt(include.length() - 1, ')');
  124. domainregex = include.toString();
  125. }
  126. // script is valid if has name and parsable domain regex
  127. if(UNKNOWN.equals(name))
  128. throw new Exception("No name found in script");
  129. try {
  130. Pattern.compile(domainregex);
  131. } catch(Exception e) {
  132. throw new Exception("Problem parsing domain regex", e);
  133. }
  134. //Log.d(TAG, String.format("domainregex=%s", domainregex));
  135. ContentValues values = new ContentValues();
  136. values.put(FIELD_SCRIPT_NAME, name);
  137. values.put(FIELD_SCRIPT_AUTHOR, author);
  138. values.put(FIELD_SCRIPT_DESCRIP, descrip);
  139. values.put(FIELD_SCRIPT_DOMAINREGEX, domainregex);
  140. values.put(FIELD_SCRIPT_CONTENT, raw);
  141. values.put(FIELD_SCRIPT_ENABLED, 1);
  142. return db.insert(TABLE_SCRIPTS, null, values);
  143. }
  144. /**
  145. * Return cursor across all scripts.
  146. */
  147. public Cursor getScripts() {
  148. SQLiteDatabase db = this.getReadableDatabase();
  149. return db.query(TABLE_SCRIPTS, new String[] { "_id", FIELD_SCRIPT_NAME,
  150. FIELD_SCRIPT_AUTHOR, FIELD_SCRIPT_DESCRIP, FIELD_SCRIPT_DOMAINREGEX,
  151. FIELD_SCRIPT_ENABLED }, null, null, null, null, null);
  152. }
  153. /**
  154. * Delete a specific script.
  155. */
  156. public void deleteScript(long id) {
  157. SQLiteDatabase db = this.getWritableDatabase();
  158. db.delete(TABLE_SCRIPTS, "_id = ?", new String[] { Long.toString(id) });
  159. }
  160. /**
  161. * Toggle the enabled state of the given script.
  162. */
  163. public void toggleEnabled(long id) {
  164. SQLiteDatabase db = this.getWritableDatabase();
  165. // first read the existing status
  166. Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_ENABLED }, "_id = ?", new String[] { Long.toString(id) }, null, null, null);
  167. if(cur == null || !cur.moveToFirst()) return;
  168. int value = cur.getInt(cur.getColumnIndex(FIELD_SCRIPT_ENABLED));
  169. cur.close();
  170. // update to have the opposite value
  171. ContentValues values = new ContentValues();
  172. values.put(FIELD_SCRIPT_ENABLED, (value == 0) ? 1 : 0);
  173. db.update(TABLE_SCRIPTS, values, "_id = ?", new String[] { Long.toString(id) });
  174. }
  175. private Map<Pattern,String> cache = new HashMap<Pattern,String>();
  176. private void validateCache() {
  177. SQLiteDatabase db = this.getReadableDatabase();
  178. Cursor cur = db.query(TABLE_SCRIPTS, new String[] { FIELD_SCRIPT_DOMAINREGEX,
  179. FIELD_SCRIPT_CONTENT }, FIELD_SCRIPT_ENABLED + " = 1", null, null, null, null);
  180. int COL_DOMAINREGEX = cur.getColumnIndex(FIELD_SCRIPT_DOMAINREGEX),
  181. COL_CONTENT = cur.getColumnIndex(FIELD_SCRIPT_CONTENT);
  182. cache.clear();
  183. while(cur.moveToNext()) {
  184. String domainregex = cur.getString(COL_DOMAINREGEX),
  185. content = cur.getString(COL_CONTENT);
  186. cache.put(Pattern.compile(domainregex), content);
  187. }
  188. cur.close();
  189. }
  190. /**
  191. * Return Javascript (CONTENT) for all scripts that should be active given
  192. * this specific url.
  193. */
  194. public List<String> getActive(String url) {
  195. List<String> active = new LinkedList<String>();
  196. this.validateCache();
  197. for(Pattern trial : cache.keySet()) {
  198. if(trial.matcher(url).matches())
  199. active.add(cache.get(trial));
  200. }
  201. return active;
  202. }
  203. }