Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / src / ime-core / userdict.cpp
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 <stdlib.h>
40 #include "userdict.h"
41
42
43 bool
44 CUserDict::load(const char  *fname)
45 {
46     int rc = sqlite3_open(":memory:", &m_db);
47
48     if (rc != SQLITE_OK) {
49         sqlite3_close(m_db);
50         return false;
51     }
52
53     m_fname = strdup(fname);
54     rc = _copyDb(Load);
55
56     return _createTable() && _createIndexes();
57 }
58
59
60 void
61 CUserDict::free()
62 {
63     if (m_fname) {
64         _copyDb(Save);
65         ::free(m_fname);
66         m_fname = NULL;
67     }
68
69     if (m_db) {
70         sqlite3_close(m_db);
71         m_db = NULL;
72     }
73 }
74
75
76 unsigned
77 CUserDict::addWord(CSyllables &syllables, const wstring& word)
78 {
79     assert(m_db != NULL);
80     assert(syllables.size() >= 2 && syllables.size() <= MAX_USRDEF_WORD_LEN);
81
82     sqlite3_stmt *stmt;
83     const char *sql_str =
84         "INSERT INTO dict (len, i0, f0, t0, i1, f1, t1, i2, f2, t2, i3, f3, t3, i4, f4, t4, i5, f5, t5, utf8str) \
85          VALUES           (?,   ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?);";
86     const char *tail;
87
88     sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
89
90     int i = 1;
91     sqlite3_bind_int(stmt, i++, syllables.size());
92
93     CSyllables::iterator it = syllables.begin();
94     CSyllables::iterator ite = syllables.end();
95     for (; it != ite; ++it) {
96         sqlite3_bind_int(stmt, i++, it->initial);
97         sqlite3_bind_int(stmt, i++, it->final);
98         sqlite3_bind_int(stmt, i++, it->tone);
99     }
100
101     while (i <= MAX_USRDEF_WORD_LEN * 3 + 1)
102         sqlite3_bind_int(stmt, i++, 0);
103
104     char buf[MAX_USRDEF_WORD_LEN * 6 + 1];
105     WCSTOMBS(buf, word.c_str(), sizeof(buf) - 1);
106     sqlite3_bind_text(stmt, i, (const char*)buf, strlen(buf), NULL);
107
108     unsigned ret = (SQLITE_DONE == sqlite3_step(stmt)) ?
109                    INI_USRDEF_WID + sqlite3_last_insert_rowid(m_db) :
110                    0;
111
112     sqlite3_finalize(stmt);
113     _copyDb(Save);
114     return ret;
115 }
116
117
118 void
119 CUserDict::removeWord(unsigned wid)
120 {
121     assert(m_db != NULL);
122     char    *zErr = NULL;
123     char sql[256] = "DELETE FROM dict WHERE id=";
124
125     if (wid > INI_USRDEF_WID) {
126         sprintf(sql, "%s%d;", sql, (wid - INI_USRDEF_WID));
127         sqlite3_exec(m_db, sql, NULL, NULL, &zErr);
128
129         m_dict.erase(m_dict.find(wid - INI_USRDEF_WID));
130     }
131 }
132
133
134 void
135 CUserDict::getWords(CSyllables &syllables,
136                     std::vector<CPinyinTrie::TWordIdInfo> &result)
137 {
138     assert(m_db != NULL);
139
140     char *sql_str;
141     const char *tail;
142     std::string i_conditions, f_conditions, t_conditions;
143     int length = syllables.size();
144     sqlite3_stmt *stmt;
145     int rc;
146     char buf[256];
147
148     if (length > MAX_USRDEF_WORD_LEN)
149         return;
150
151     for (int i = 0; i < length; i++) {
152         sprintf(buf, " and i%d=%d", i, syllables[i].initial);
153         i_conditions += buf;
154
155         if (!syllables[i].final)
156             continue;
157
158         sprintf(buf, " and f%i=%i", i, syllables[i].final);
159         f_conditions += buf;
160
161         if (!syllables[i].tone)
162             continue;
163
164         sprintf(buf, " and t%i=%i", i, syllables[i].tone);
165         t_conditions += buf;
166     }
167
168     sql_str = sqlite3_mprintf(
169         "SELECT id, utf8str FROM dict WHERE len=%i%q%q%q;",
170         length,
171         i_conditions.c_str(),
172         f_conditions.c_str(),
173         t_conditions.c_str());
174
175     rc = sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
176     if (rc != SQLITE_OK) {
177         sqlite3_free(sql_str);
178         fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
179         return;
180     }
181
182     unsigned id = 0;
183     TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
184     const unsigned char     *utf8str = NULL;
185     CPinyinTrie::TWordIdInfo word;
186
187     while (SQLITE_ROW == sqlite3_step(stmt)) {
188         id = sqlite3_column_int(stmt, 0);
189         utf8str = sqlite3_column_text(stmt, 1);
190
191         if (id >= MAX_USRDEF_WID - INI_USRDEF_WID)
192             continue;
193
194         memset(&cwstr[0], 0, sizeof(cwstr));
195         MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
196
197         word.m_id = id + INI_USRDEF_WID;
198         word.m_bSeen = 1;
199         result.push_back(word);
200
201         m_dict.insert(std::make_pair(id, wstring(cwstr)));
202     }
203
204     sqlite3_free(sql_str);
205     sqlite3_finalize(stmt);
206 }
207
208
209 const TWCHAR*
210 CUserDict::operator [](unsigned wid)
211 {
212     assert(m_db != NULL);
213
214     sqlite3_stmt *stmt = NULL;
215     int rc = SQLITE_OK;
216     const char *tail;
217     char sql_str[256];
218
219     if (wid <= INI_USRDEF_WID || wid > MAX_USRDEF_WID)
220         return NULL;
221
222     wid -= INI_USRDEF_WID;
223
224     std::map<unsigned, wstring>::const_iterator it = m_dict.find(wid);
225     if (it != m_dict.end())
226         return it->second.c_str();
227
228     sprintf(sql_str, "SELECT utf8str FROM dict WHERE id=%d;", wid);
229
230     rc = sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
231     if (rc != SQLITE_OK) {
232         fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
233         return NULL;
234     }
235
236     const TWCHAR *ret = NULL;
237     const unsigned char *utf8str = NULL;
238     TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
239     if (SQLITE_ROW == sqlite3_step(stmt)) {
240         utf8str = sqlite3_column_text(stmt, 0);
241         MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
242         wstring wstr(cwstr);
243         m_dict.insert(std::make_pair(wid, wstr));
244         ret = wstr.c_str();
245     }
246
247     sqlite3_finalize(stmt);
248     return ret;
249 }
250
251 int
252 CUserDict::_copyDb(DBCopyDirection direction)
253 {
254     sqlite3 *disk_db;
255     int rc = sqlite3_open(m_fname, &disk_db);
256
257     if (rc == SQLITE_OK) {
258         sqlite3 *dst = direction == Load ? m_db : disk_db;
259         sqlite3 *src = direction == Save ? m_db : disk_db;
260         sqlite3_backup *backup = sqlite3_backup_init(dst, "main", src, "main");
261         if (backup) {
262             sqlite3_backup_step(backup, -1);
263             sqlite3_backup_finish(backup);
264         }
265         rc = sqlite3_errcode(dst);
266     }
267
268     sqlite3_close(disk_db);
269     return rc;
270 }
271
272 bool
273 CUserDict::_createTable()
274 {
275     assert(m_db != NULL);
276
277     char *zErr = NULL;
278     int rc = SQLITE_OK;
279     const char *sql_str =
280         "CREATE TABLE IF NOT EXISTS dict( \
281          id INTEGER PRIMARY KEY, len INTEGER, \
282          i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, \
283          f0 INTEGER, f1 INTEGER, f2 INTEGER, f3 INTEGER, f4 INTEGER, f5 INTEGER, \
284          t0 INTEGER, t1 INTEGER, t2 INTEGER, t3 INTEGER, t4 INTEGER, t5 INTEGER, \
285          utf8str TEXT, UNIQUE (i0, i1, i2, i3, i4, i5, utf8str));";
286
287     rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
288     if (rc != SQLITE_OK) {
289         if (zErr != NULL) {
290             fprintf(stderr, "SQL error: %s\n", zErr);
291             sqlite3_free(zErr);
292         }
293         return false;
294     }
295
296     return true;
297 }
298
299 bool
300 CUserDict::_createIndexes()
301 {
302     assert(m_db != NULL);
303
304     char *zErr = NULL;
305     int rc = SQLITE_OK;
306     const char * sql_str =
307         "CREATE INDEX IF NOT EXISTS index_0 ON dict (len, i0, i1, i2, i3, i4, i5);";
308
309     rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
310     if (rc != SQLITE_OK) {
311         if (zErr != NULL) {
312             fprintf(stderr, "SQL error: %s\n", zErr);
313             sqlite3_free(zErr);
314         }
315         return false;
316     }
317
318     return true;
319 }