OpenGrok

Cross Reference: userdict.cpp
xref: /nv-g11n/inputmethod/sunpinyin2/src/ime-core/userdict.cpp
Home | History | Annotate | Line # | Download | only in ime-core
      1 /*
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
      3  *
      4  * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
      5  *
      6  * The contents of this file are subject to the terms of either the GNU Lesser
      7  * General Public License Version 2.1 only ("LGPL") or the Common Development and
      8  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
      9  * file except in compliance with the License. You can obtain a copy of the CDDL at
     10  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
     11  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
     12  * specific language governing permissions and limitations under the License. When
     13  * distributing the software, include this License Header Notice in each file and
     14  * include the full text of the License in the License file as well as the
     15  * following notice:
     16  *
     17  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
     18  * (CDDL)
     19  * For Covered Software in this distribution, this License shall be governed by the
     20  * laws of the State of California (excluding conflict-of-law provisions).
     21  * Any litigation relating to this License shall be subject to the jurisdiction of
     22  * the Federal Courts of the Northern District of California and the state courts
     23  * of the State of California, with venue lying in Santa Clara County, California.
     24  *
     25  * Contributor(s):
     26  *
     27  * If you wish your version of this file to be governed by only the CDDL or only
     28  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
     29  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
     30  * license." If you don't indicate a single choice of license, a recipient has the
     31  * option to distribute your version of this file under either the CDDL or the LGPL
     32  * Version 2.1, or to extend the choice of license to its licensees as provided
     33  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
     34  * Version 2 license, then the option applies only if the new code is made subject
     35  * to such option by the copyright holder.
     36  */
     37 
     38 #include <assert.h>
     39 #include "userdict.h"
     40 
     41 
     42 bool CUserDict::load(const char  *fname)
     43 {
     44     int rc = sqlite3_open(fname, &m_db);
     45 
     46     if (rc != SQLITE_OK) {
     47         sqlite3_close(m_db);
     48         return false;
     49     }
     50 
     51     return _createTable() && _createIndexes();
     52 }
     53 
     54 
     55 void CUserDict::free()
     56 {
     57     if (m_db) {
     58         sqlite3_close(m_db);
     59         m_db = NULL;
     60     }
     61 }
     62 
     63 
     64 unsigned CUserDict::addWord (CSyllables &syllables, const wstring& word)
     65 {
     66     assert(m_db != NULL);
     67     assert (syllables.size() >= 2 && syllables.size() <= MAX_USRDEF_WORD_LEN);
     68 
     69     sqlite3_stmt *stmt;
     70     const char *sql_str =
     71         "INSERT INTO dict (len, i0, f0, t0, i1, f1, t1, i2, f2, t2, i3, f3, t3, i4, f4, t4, i5, f5, t5, utf8str) \
     72          VALUES           (?,   ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?);";
     73     const char *tail;
     74 
     75     sqlite3_prepare (m_db, sql_str, strlen(sql_str), &stmt, &tail);
     76 
     77     int i = 1;
     78     sqlite3_bind_int (stmt, i++, syllables.size());
     79 
     80     CSyllables::iterator it  = syllables.begin();
     81     CSyllables::iterator ite = syllables.end();
     82     for (; it != ite; ++it) {
     83         sqlite3_bind_int (stmt, i++, it->initial);
     84         sqlite3_bind_int (stmt, i++, it->final);
     85         sqlite3_bind_int (stmt, i++, it->tone);
     86     }
     87 
     88     while (i <= MAX_USRDEF_WORD_LEN*3 + 1)
     89         sqlite3_bind_int (stmt, i++, 0);
     90 
     91     char buf[MAX_USRDEF_WORD_LEN*6+1];
     92     WCSTOMBS(buf, word.c_str(), sizeof(buf) - 1);
     93     sqlite3_bind_text (stmt, i, (const char *)buf, strlen(buf), NULL);
     94 
     95     unsigned ret = (SQLITE_DONE == sqlite3_step (stmt))?
     96                    INI_USRDEF_WID + sqlite3_last_insert_rowid (m_db):
     97                    0;
     98 
     99     sqlite3_finalize (stmt);
    100     return ret;
    101 }
    102 
    103 
    104 void CUserDict::removeWord (unsigned wid)
    105 {
    106     assert (m_db != NULL);
    107     char    *zErr = NULL;
    108     char sql[256] = "DELETE FROM dict WHERE id=";
    109 
    110     if (wid > INI_USRDEF_WID) {
    111         sprintf(sql, "%s%d;", sql, (wid - INI_USRDEF_WID));
    112         sqlite3_exec(m_db, sql, NULL, NULL, &zErr);
    113     }
    114 }
    115 
    116 
    117 void CUserDict::getWords (CSyllables &syllables,
    118                           std::vector<CPinyinTrie::TWordIdInfo> &result)
    119 {
    120     assert (m_db != NULL);
    121 
    122     char *sql_str;
    123     const char *tail;
    124     std::string i_conditions, f_conditions, t_conditions;
    125     int length = syllables.size();
    126     sqlite3_stmt *stmt;
    127     int rc;
    128     char buf[256];
    129 
    130     if (length > MAX_USRDEF_WORD_LEN)
    131         return;
    132 
    133     for (int i=0; i<length; i++) {
    134         sprintf (buf, " and i%d=%d", i, syllables[i].initial);
    135         i_conditions += buf;
    136 
    137         if (!syllables[i].final)
    138             continue;
    139 
    140         sprintf (buf, " and f%i=%i", i, syllables[i].final);
    141         f_conditions += buf;
    142 
    143         if (!syllables[i].tone)
    144             continue;
    145 
    146         sprintf (buf, " and t%i=%i", i, syllables[i].tone);
    147         t_conditions += buf;
    148     }
    149 
    150     sql_str = sqlite3_mprintf("SELECT id, utf8str FROM dict WHERE len=%i%q%q%q;",
    151                                length, i_conditions.c_str(), f_conditions.c_str(), t_conditions.c_str());
    152 
    153     rc = sqlite3_prepare(m_db, sql_str, strlen (sql_str), &stmt, &tail);
    154     if(rc != SQLITE_OK) {
    155         sqlite3_free(sql_str);
    156         fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
    157         return;
    158     }
    159 
    160     unsigned id = 0;
    161     TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
    162     const unsigned char     *utf8str = NULL;
    163     CPinyinTrie::TWordIdInfo word;
    164 
    165     while(SQLITE_ROW == sqlite3_step(stmt)) {
    166         id      = sqlite3_column_int  (stmt, 0);
    167         utf8str = sqlite3_column_text (stmt, 1);
    168 
    169         if (id >= MAX_USRDEF_WID - INI_USRDEF_WID)
    170             continue;
    171 
    172         memset(&cwstr[0], 0, sizeof(cwstr));
    173         MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
    174 
    175         word.m_id = id + INI_USRDEF_WID;
    176         word.m_len = length;
    177         word.m_bSeen = 1;
    178         result.push_back (word);
    179 
    180         m_dict.insert (std::make_pair (id, wstring(cwstr)));
    181     }
    182 
    183     sqlite3_free(sql_str);
    184     sqlite3_finalize(stmt);
    185 }
    186 
    187 
    188 const TWCHAR* CUserDict::operator [] (unsigned wid)
    189 {
    190     assert (m_db != NULL);
    191 
    192     sqlite3_stmt *stmt=NULL;
    193     int rc = SQLITE_OK;
    194     const char *tail;
    195     char sql_str[256];
    196 
    197     if (wid <= INI_USRDEF_WID || wid > MAX_USRDEF_WID)
    198         return NULL;
    199 
    200     wid -= INI_USRDEF_WID;
    201 
    202     std::map<unsigned, wstring>::const_iterator it = m_dict.find(wid);
    203     if (it != m_dict.end ())
    204         return it->second.c_str ();
    205 
    206     sprintf (sql_str, "SELECT utf8str FROM dict WHERE id=%d;", wid);
    207 
    208     rc = sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
    209     if(rc != SQLITE_OK) {
    210         fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
    211         return NULL;
    212     }
    213 
    214     const TWCHAR *ret = NULL;
    215     const unsigned char *utf8str = NULL;
    216     TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
    217     if (SQLITE_ROW == sqlite3_step(stmt)) {
    218         utf8str = sqlite3_column_text(stmt, 0);
    219         MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
    220         wstring wstr(cwstr);
    221         m_dict.insert (std::make_pair (wid, wstr));
    222         ret = wstr.c_str();
    223     }
    224 
    225     sqlite3_finalize (stmt);
    226     return ret;
    227 }
    228 
    229 
    230 bool CUserDict::_createTable()
    231 {
    232     assert(m_db != NULL);
    233 
    234     char *zErr = NULL;
    235     int  rc = SQLITE_OK;
    236     const char *sql_str =
    237         "CREATE TABLE IF NOT EXISTS dict( \
    238          id INTEGER PRIMARY KEY, len INTEGER, \
    239          i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, \
    240          f0 INTEGER, f1 INTEGER, f2 INTEGER, f3 INTEGER, f4 INTEGER, f5 INTEGER, \
    241          t0 INTEGER, t1 INTEGER, t2 INTEGER, t3 INTEGER, t4 INTEGER, t5 INTEGER, \
    242          utf8str TEXT, UNIQUE (i0, i1, i2, i3, i4, i5, utf8str));";
    243 
    244     rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
    245     if(rc != SQLITE_OK) {
    246         if (zErr != NULL) {
    247             fprintf(stderr, "SQL error: %s\n", zErr);
    248             sqlite3_free(zErr);
    249         }
    250         return false;
    251     }
    252 
    253     return true;
    254 }
    255 
    256 bool CUserDict::_createIndexes()
    257 {
    258     assert(m_db!=NULL);
    259 
    260     char *zErr = NULL;
    261     int  rc = SQLITE_OK;
    262     const char * sql_str =
    263         "CREATE INDEX IF NOT EXISTS index_0 ON dict (len, i0, i1, i2, i3, i4, i5);";
    264 
    265     rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
    266     if(rc != SQLITE_OK) {
    267         if (zErr != NULL) {
    268             fprintf(stderr, "SQL error: %s\n", zErr);
    269             sqlite3_free(zErr);
    270         }
    271         return false;
    272     }
    273 
    274     return true;
    275 }
    276