Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "sqlite3_android"
     18 
     19 #include <ctype.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include <unicode/ucol.h>
     25 #include <unicode/uiter.h>
     26 #include <unicode/ustring.h>
     27 #include <unicode/utypes.h>
     28 #include <cutils/log.h>
     29 
     30 #include "sqlite3_android.h"
     31 #include "PhoneNumberUtils.h"
     32 #include "PhonebookIndex.h"
     33 
     34 #define ENABLE_ANDROID_LOG 0
     35 #define SMALL_BUFFER_SIZE 10
     36 #define PHONE_NUMBER_BUFFER_SIZE 40
     37 
     38 static int collate16(void *p, int n1, const void *v1, int n2, const void *v2)
     39 {
     40     UCollator *coll = (UCollator *) p;
     41     UCollationResult result = ucol_strcoll(coll, (const UChar *) v1, n1,
     42                                                  (const UChar *) v2, n2);
     43 
     44     if (result == UCOL_LESS) {
     45         return -1;
     46     } else if (result == UCOL_GREATER) {
     47         return 1;
     48     } else {
     49         return 0;
     50     }
     51 }
     52 
     53 static int collate8(void *p, int n1, const void *v1, int n2, const void *v2)
     54 {
     55     UCollator *coll = (UCollator *) p;
     56     UCharIterator i1, i2;
     57     UErrorCode status = U_ZERO_ERROR;
     58 
     59     uiter_setUTF8(&i1, (const char *) v1, n1);
     60     uiter_setUTF8(&i2, (const char *) v2, n2);
     61 
     62     UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status);
     63 
     64     if (U_FAILURE(status)) {
     65 //        ALOGE("Collation iterator error: %d\n", status);
     66     }
     67 
     68     if (result == UCOL_LESS) {
     69         return -1;
     70     } else if (result == UCOL_GREATER) {
     71         return 1;
     72     } else {
     73         return 0;
     74     }
     75 }
     76 
     77 /**
     78  * Obtains the first UNICODE letter from the supplied string, normalizes and returns it.
     79  */
     80 static void get_phonebook_index(
     81     sqlite3_context * context, int argc, sqlite3_value ** argv)
     82 {
     83     if (argc != 2) {
     84       sqlite3_result_null(context);
     85       return;
     86     }
     87 
     88     char const * src = (char const *)sqlite3_value_text(argv[0]);
     89     char const * locale = (char const *)sqlite3_value_text(argv[1]);
     90     if (src == NULL || src[0] == 0 || locale == NULL) {
     91       sqlite3_result_null(context);
     92       return;
     93     }
     94 
     95     UCharIterator iter;
     96     uiter_setUTF8(&iter, src, -1);
     97 
     98     UBool isError = FALSE;
     99     UChar index[SMALL_BUFFER_SIZE];
    100     uint32_t len = android::GetPhonebookIndex(&iter, locale, index, sizeof(index), &isError);
    101     if (isError) {
    102       sqlite3_result_null(context);
    103       return;
    104     }
    105 
    106     uint32_t outlen = 0;
    107     uint8_t out[SMALL_BUFFER_SIZE];
    108     for (uint32_t i = 0; i < len; i++) {
    109       U8_APPEND(out, outlen, sizeof(out), index[i], isError);
    110       if (isError) {
    111         sqlite3_result_null(context);
    112         return;
    113       }
    114     }
    115 
    116     if (outlen == 0) {
    117       sqlite3_result_null(context);
    118       return;
    119     }
    120 
    121     sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT);
    122 }
    123 
    124 static void phone_numbers_equal(sqlite3_context * context, int argc, sqlite3_value ** argv)
    125 {
    126     if (argc != 2 && argc != 3) {
    127         sqlite3_result_int(context, 0);
    128         return;
    129     }
    130 
    131     char const * num1 = (char const *)sqlite3_value_text(argv[0]);
    132     char const * num2 = (char const *)sqlite3_value_text(argv[1]);
    133 
    134     bool use_strict = false;
    135     if (argc == 3) {
    136         use_strict = (sqlite3_value_int(argv[2]) != 0);
    137     }
    138 
    139     if (num1 == NULL || num2 == NULL) {
    140         sqlite3_result_null(context);
    141         return;
    142     }
    143 
    144     bool equal =
    145         (use_strict ?
    146          android::phone_number_compare_strict(num1, num2) :
    147          android::phone_number_compare_loose(num1, num2));
    148 
    149     if (equal) {
    150         sqlite3_result_int(context, 1);
    151     } else {
    152         sqlite3_result_int(context, 0);
    153     }
    154 }
    155 
    156 static void phone_number_stripped_reversed(sqlite3_context * context, int argc,
    157       sqlite3_value ** argv)
    158 {
    159     if (argc != 1) {
    160         sqlite3_result_int(context, 0);
    161         return;
    162     }
    163 
    164     char const * number = (char const *)sqlite3_value_text(argv[0]);
    165     if (number == NULL) {
    166         sqlite3_result_null(context);
    167         return;
    168     }
    169 
    170     char out[PHONE_NUMBER_BUFFER_SIZE];
    171     int outlen = 0;
    172     android::phone_number_stripped_reversed_inter(number, out, PHONE_NUMBER_BUFFER_SIZE, &outlen);
    173     sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT);
    174 }
    175 
    176 
    177 #if ENABLE_ANDROID_LOG
    178 static void android_log(sqlite3_context * context, int argc, sqlite3_value ** argv)
    179 {
    180     char const * tag = "sqlite_trigger";
    181     char const * msg = "";
    182     int msgIndex = 0;
    183 
    184     switch (argc) {
    185         case 2:
    186             tag = (char const *)sqlite3_value_text(argv[0]);
    187             if (tag == NULL) {
    188                 tag = "sqlite_trigger";
    189             }
    190             msgIndex = 1;
    191         case 1:
    192             msg = (char const *)sqlite3_value_text(argv[msgIndex]);
    193             if (msg == NULL) {
    194                 msg = "";
    195             }
    196             LOG(LOG_INFO, tag, msg);
    197             sqlite3_result_int(context, 1);
    198             return;
    199 
    200         default:
    201             sqlite3_result_int(context, 0);
    202             return;
    203     }
    204 }
    205 #endif
    206 
    207 static void delete_file(sqlite3_context * context, int argc, sqlite3_value ** argv)
    208 {
    209     if (argc != 1) {
    210         sqlite3_result_int(context, 0);
    211         return;
    212     }
    213 
    214     char const * path = (char const *)sqlite3_value_text(argv[0]);
    215     // Don't allow ".." in paths
    216     if (path == NULL || strstr(path, "/../") != NULL) {
    217         sqlite3_result_null(context);
    218         return;
    219     }
    220 
    221     // We only allow deleting files in the EXTERNAL_STORAGE path, or one of the
    222     // SECONDARY_STORAGE paths
    223     bool good_path = false;
    224     char const * external_storage = getenv("EXTERNAL_STORAGE");
    225     if (external_storage && strncmp(external_storage, path, strlen(external_storage)) == 0) {
    226         good_path = true;
    227     } else {
    228         // check SECONDARY_STORAGE, which should be a colon separated list of paths
    229         char const * secondary_paths = getenv("SECONDARY_STORAGE");
    230         while (secondary_paths && secondary_paths[0]) {
    231             const char* colon = strchr(secondary_paths, ':');
    232             int length = (colon ? colon - secondary_paths : strlen(secondary_paths));
    233             if (strncmp(secondary_paths, path, length) == 0) {
    234                 good_path = true;
    235             }
    236             secondary_paths += length;
    237             while (*secondary_paths == ':') secondary_paths++;
    238         }
    239     }
    240 
    241     if (!good_path) {
    242         sqlite3_result_null(context);
    243         return;
    244     }
    245 
    246     int err = unlink(path);
    247     if (err != -1) {
    248         // No error occured, return true
    249         sqlite3_result_int(context, 1);
    250     } else {
    251         // An error occured, return false
    252         sqlite3_result_int(context, 0);
    253     }
    254 }
    255 
    256 static void tokenize_auxdata_delete(void * data)
    257 {
    258     sqlite3_stmt * statement = (sqlite3_stmt *)data;
    259     sqlite3_finalize(statement);
    260 }
    261 
    262 static void base16Encode(char* dest, const char* src, uint32_t size)
    263 {
    264     static const char * BASE16_TABLE = "0123456789abcdef";
    265     for (uint32_t i = 0; i < size; i++) {
    266         char ch = *src++;
    267         *dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ];
    268         *dest++ = BASE16_TABLE[ (ch & 0x0f)      ];
    269     }
    270 }
    271 
    272 struct SqliteUserData {
    273     sqlite3 * handle;
    274     UCollator* collator;
    275 };
    276 
    277 /**
    278  * This function is invoked as:
    279  *
    280  *  _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>,
    281  *             <use_token_index>, <data_tag>)
    282  *
    283  * If <use_token_index> is omitted, it is treated as 0.
    284  * If <data_tag> is omitted, it is treated as NULL.
    285  *
    286  * It will split <data> on each instance of <delimiter> and insert each token
    287  * into <token_table>. The following columns in <token_table> are used:
    288  * token TEXT, source INTEGER, token_index INTEGER, tag (any type)
    289  * The token_index column is not required if <use_token_index> is 0.
    290  * The tag column is not required if <data_tag> is NULL.
    291  *
    292  * One row is inserted for each token in <data>.
    293  * In each inserted row, 'source' is <data_row_id>.
    294  * In the first inserted row, 'token' is the hex collation key of
    295  * the entire <data> string, and 'token_index' is 0.
    296  * In each row I (where 1 <= I < N, and N is the number of tokens in <data>)
    297  * 'token' will be set to the hex collation key of the I:th token (0-based).
    298  * If <use_token_index> != 0, 'token_index' is set to I.
    299  * If <data_tag> is not NULL, 'tag' is set to <data_tag>.
    300  *
    301  * In other words, there will be one row for the entire string,
    302  * and one row for each token except the first one.
    303  *
    304  * The function returns the number of tokens generated.
    305  */
    306 static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv)
    307 {
    308     //ALOGD("enter tokenize");
    309     int err;
    310     int useTokenIndex = 0;
    311     int useDataTag = 0;
    312 
    313     if (!(argc >= 4 || argc <= 6)) {
    314         ALOGE("Tokenize requires 4 to 6 arguments");
    315         sqlite3_result_null(context);
    316         return;
    317     }
    318 
    319     if (argc > 4) {
    320         useTokenIndex = sqlite3_value_int(argv[4]);
    321     }
    322 
    323     if (argc > 5) {
    324         useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL);
    325     }
    326 
    327     sqlite3 * handle = sqlite3_context_db_handle(context);
    328     UCollator* collator = (UCollator*)sqlite3_user_data(context);
    329     char const * tokenTable = (char const *)sqlite3_value_text(argv[0]);
    330     if (tokenTable == NULL) {
    331         ALOGE("tokenTable null");
    332         sqlite3_result_null(context);
    333         return;
    334     }
    335 
    336     // Get or create the prepared statement for the insertions
    337     sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0);
    338     if (!statement) {
    339         char const * tokenIndexCol = useTokenIndex ? ", token_index" : "";
    340         char const * tokenIndexParam = useTokenIndex ? ", ?" : "";
    341         char const * dataTagCol = useDataTag ? ", tag" : "";
    342         char const * dataTagParam = useDataTag ? ", ?" : "";
    343         char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);",
    344                 tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam);
    345         err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL);
    346         sqlite3_free(sql);
    347         if (err) {
    348             ALOGE("prepare failed");
    349             sqlite3_result_null(context);
    350             return;
    351         }
    352         // This binds the statement to the table it was compiled against, which is argv[0].
    353         // If this function is ever called with a different table the finalizer will be called
    354         // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table.
    355         sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete);
    356     } else {
    357         // Reset the cached statement so that binding the row ID will work properly
    358         sqlite3_reset(statement);
    359     }
    360 
    361     // Bind the row ID of the source row
    362     int64_t rowID = sqlite3_value_int64(argv[1]);
    363     err = sqlite3_bind_int64(statement, 2, rowID);
    364     if (err != SQLITE_OK) {
    365         ALOGE("bind failed");
    366         sqlite3_result_null(context);
    367         return;
    368     }
    369 
    370     // Bind <data_tag> to the tag column
    371     if (useDataTag) {
    372         int dataTagParamIndex = useTokenIndex ? 4 : 3;
    373         err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]);
    374         if (err != SQLITE_OK) {
    375             ALOGE("bind failed");
    376             sqlite3_result_null(context);
    377             return;
    378         }
    379     }
    380 
    381     // Get the raw bytes for the string to tokenize
    382     // the string will be modified by following code
    383     // however, sqlite did not reuse the string, so it is safe to not dup it
    384     UChar * origData = (UChar *)sqlite3_value_text16(argv[2]);
    385     if (origData == NULL) {
    386         sqlite3_result_null(context);
    387         return;
    388     }
    389 
    390     // Get the raw bytes for the delimiter
    391     const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]);
    392     if (delim == NULL) {
    393         ALOGE("can't get delimiter");
    394         sqlite3_result_null(context);
    395         return;
    396     }
    397 
    398     UChar * token = NULL;
    399     UChar *state;
    400     int numTokens = 0;
    401 
    402     do {
    403         if (numTokens == 0) {
    404             token = origData;
    405         }
    406 
    407         // Reset the program so we can use it to perform the insert
    408         sqlite3_reset(statement);
    409         UErrorCode status = U_ZERO_ERROR;
    410         char keybuf[1024];
    411         uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1);
    412         if (result > sizeof(keybuf)) {
    413             // TODO allocate memory for this super big string
    414             ALOGE("ucol_getSortKey needs bigger buffer %d", result);
    415             break;
    416         }
    417         uint32_t keysize = result-1;
    418         uint32_t base16Size = keysize*2;
    419         char *base16buf = (char*)malloc(base16Size);
    420         base16Encode(base16buf, keybuf, keysize);
    421         err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC);
    422 
    423         if (err != SQLITE_OK) {
    424             ALOGE(" sqlite3_bind_text16 error %d", err);
    425             free(base16buf);
    426             break;
    427         }
    428 
    429         if (useTokenIndex) {
    430             err = sqlite3_bind_int(statement, 3, numTokens);
    431             if (err != SQLITE_OK) {
    432                 ALOGE(" sqlite3_bind_int error %d", err);
    433                 free(base16buf);
    434                 break;
    435             }
    436         }
    437 
    438         err = sqlite3_step(statement);
    439         free(base16buf);
    440 
    441         if (err != SQLITE_DONE) {
    442             ALOGE(" sqlite3_step error %d", err);
    443             break;
    444         }
    445         numTokens++;
    446         if (numTokens == 1) {
    447             // first call
    448             u_strtok_r(origData, delim, &state);
    449         }
    450     } while ((token = u_strtok_r(NULL, delim, &state)) != NULL);
    451     sqlite3_result_int(context, numTokens);
    452 }
    453 
    454 static void localized_collator_dtor(UCollator* collator)
    455 {
    456     ucol_close(collator);
    457 }
    458 
    459 #define LOCALIZED_COLLATOR_NAME "LOCALIZED"
    460 
    461 // This collator may be removed in the near future, so you MUST not use now.
    462 #define PHONEBOOK_COLLATOR_NAME "PHONEBOOK"
    463 
    464 extern "C" int register_localized_collators(sqlite3* handle, const char* systemLocale, int utf16Storage)
    465 {
    466     int err;
    467     UErrorCode status = U_ZERO_ERROR;
    468     void* icudata;
    469 
    470     UCollator* collator = ucol_open(systemLocale, &status);
    471     if (U_FAILURE(status)) {
    472         return -1;
    473     }
    474 
    475     ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
    476     if (U_FAILURE(status)) {
    477         return -1;
    478     }
    479 
    480     status = U_ZERO_ERROR;
    481     char buf[1024];
    482     ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
    483 
    484     if (utf16Storage) {
    485         err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF16, collator,
    486                 collate16, (void(*)(void*))localized_collator_dtor);
    487     } else {
    488         err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF8, collator,
    489                 collate8, (void(*)(void*))localized_collator_dtor);
    490     }
    491 
    492     if (err != SQLITE_OK) {
    493         return err;
    494     }
    495 
    496     // Register the _TOKENIZE function
    497     err = sqlite3_create_function(handle, "_TOKENIZE", 4, SQLITE_UTF16, collator, tokenize, NULL, NULL);
    498     if (err != SQLITE_OK) {
    499         return err;
    500     }
    501     err = sqlite3_create_function(handle, "_TOKENIZE", 5, SQLITE_UTF16, collator, tokenize, NULL, NULL);
    502     if (err != SQLITE_OK) {
    503         return err;
    504     }
    505     err = sqlite3_create_function(handle, "_TOKENIZE", 6, SQLITE_UTF16, collator, tokenize, NULL, NULL);
    506     if (err != SQLITE_OK) {
    507         return err;
    508     }
    509 
    510 
    511     //// PHONEBOOK_COLLATOR
    512     // The collator may be removed in the near future. Do not depend on it.
    513     // TODO: it might be better to have another function for registering phonebook collator.
    514     status = U_ZERO_ERROR;
    515     if (strcmp(systemLocale, "ja") == 0 || strcmp(systemLocale, "ja_JP") == 0) {
    516         collator = ucol_open("ja@collation=phonebook", &status);
    517     } else {
    518         collator = ucol_open(systemLocale, &status);
    519     }
    520     if (U_FAILURE(status)) {
    521         return -1;
    522     }
    523 
    524     status = U_ZERO_ERROR;
    525     ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
    526     if (U_FAILURE(status)) {
    527         return -1;
    528     }
    529 
    530     status = U_ZERO_ERROR;
    531     // ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
    532     if (utf16Storage) {
    533         err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF16, collator,
    534                 collate16, (void(*)(void*))localized_collator_dtor);
    535     } else {
    536         err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF8, collator,
    537                 collate8, (void(*)(void*))localized_collator_dtor);
    538     }
    539 
    540     if (err != SQLITE_OK) {
    541         return err;
    542     }
    543     //// PHONEBOOK_COLLATOR
    544 
    545     return SQLITE_OK;
    546 }
    547 
    548 
    549 extern "C" int register_android_functions(sqlite3 * handle, int utf16Storage)
    550 {
    551     int err;
    552     UErrorCode status = U_ZERO_ERROR;
    553 
    554     UCollator * collator = ucol_open(NULL, &status);
    555     if (U_FAILURE(status)) {
    556         return -1;
    557     }
    558 
    559     if (utf16Storage) {
    560         // Note that text should be stored as UTF-16
    561         err = sqlite3_exec(handle, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
    562         if (err != SQLITE_OK) {
    563             return err;
    564         }
    565 
    566         // Register the UNICODE collation
    567         err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF16, collator, collate16,
    568                 (void(*)(void*))localized_collator_dtor);
    569     } else {
    570         err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF8, collator, collate8,
    571                 (void(*)(void*))localized_collator_dtor);
    572     }
    573 
    574     if (err != SQLITE_OK) {
    575         return err;
    576     }
    577 
    578     // Register the PHONE_NUM_EQUALS function
    579     err = sqlite3_create_function(
    580         handle, "PHONE_NUMBERS_EQUAL", 2,
    581         SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL);
    582     if (err != SQLITE_OK) {
    583         return err;
    584     }
    585 
    586     // Register the PHONE_NUM_EQUALS function with an additional argument "use_strict"
    587     err = sqlite3_create_function(
    588         handle, "PHONE_NUMBERS_EQUAL", 3,
    589         SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL);
    590     if (err != SQLITE_OK) {
    591         return err;
    592     }
    593 
    594     // Register the _DELETE_FILE function
    595     err = sqlite3_create_function(handle, "_DELETE_FILE", 1, SQLITE_UTF8, NULL, delete_file, NULL, NULL);
    596     if (err != SQLITE_OK) {
    597         return err;
    598     }
    599 
    600 #if ENABLE_ANDROID_LOG
    601     // Register the _LOG function
    602     err = sqlite3_create_function(handle, "_LOG", 1, SQLITE_UTF8, NULL, android_log, NULL, NULL);
    603     if (err != SQLITE_OK) {
    604         return err;
    605     }
    606 #endif
    607 
    608     // Register the GET_PHONEBOOK_INDEX function
    609     err = sqlite3_create_function(handle,
    610         "GET_PHONEBOOK_INDEX",
    611         2, SQLITE_UTF8, NULL,
    612         get_phonebook_index,
    613         NULL, NULL);
    614     if (err != SQLITE_OK) {
    615         return err;
    616     }
    617 
    618     // Register the _PHONE_NUMBER_STRIPPED_REVERSED function, which imitates
    619     // PhoneNumberUtils.getStrippedReversed.  This function is not public API,
    620     // it is only used for compatibility with Android 1.6 and earlier.
    621     err = sqlite3_create_function(handle,
    622         "_PHONE_NUMBER_STRIPPED_REVERSED",
    623         1, SQLITE_UTF8, NULL,
    624         phone_number_stripped_reversed,
    625         NULL, NULL);
    626     if (err != SQLITE_OK) {
    627         return err;
    628     }
    629 
    630     return SQLITE_OK;
    631 }
    632