a10c2874af2b7a97c5d9d46c17ef5cc8914cdb1a
[mstardict] / src / libwrapper.cpp
1 /*
2  *  MStarDict - International dictionary for Maemo.
3  *  Copyright (C) 2010 Roman Moravcik
4  *
5  *  base on code of stardict:
6  *  Copyright (C) 2003-2007 Hu Zheng <huzheng_001@163.com>
7  *
8  *  based on code of sdcv:
9  *  Copyright (C) 2005-2006 Evgeniy <dushistov@mail.ru>
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <glib/gi18n.h>
31 #include <map>
32
33 #include "libwrapper.hpp"
34 #include "mstardict.hpp"
35
36 static
37 std::string xdxf2text(const char *p)
38 {
39     std::string res;
40     for (; *p; ++p) {
41         if (*p != '<') {
42             if (g_str_has_prefix(p, "&gt;")) {
43                 res += ">";
44                 p += 3;
45             } else if (g_str_has_prefix(p, "&lt;")) {
46                 res += "<";
47                 p += 3;
48             } else if (g_str_has_prefix(p, "&amp;")) {
49                 res += "&";
50                 p += 4;
51             } else if (g_str_has_prefix(p, "&quot;")) {
52                 res += "\"";
53                 p += 5;
54             } else
55                 res += *p;
56             continue;
57         }
58
59         const char *next = strchr(p, '>');
60         if (!next)
61             continue;
62
63         std::string name(p + 1, next - p - 1);
64
65         if (name == "abr")
66             res += "";
67         else if (name == "/abr")
68             res += "";
69         else if (name == "k") {
70             const char *begin = next;
71             if ((next = strstr(begin, "</k>")) != NULL)
72                 next += sizeof("</k>") - 1 - 1;
73             else
74                 next = begin;
75         } else if (name == "b")
76             res += "";
77         else if (name == "/b")
78             res += "";
79         else if (name == "i")
80             res += "";
81         else if (name == "/i")
82             res += "";
83         else if (name == "tr")
84             res += "[";
85         else if (name == "/tr")
86             res += "]";
87         else if (name == "ex")
88             res += "";
89         else if (name == "/ex")
90             res += "";
91         else if (!name.empty() && name[0] == 'c' && name != "co") {
92             std::string::size_type pos = name.find("code");
93             if (pos != std::string::size_type(-1)) {
94                 pos += sizeof("code=\"") - 1;
95                 std::string::size_type end_pos = name.find("\"");
96                 std::string color(name, pos, end_pos - pos);
97                 res += "";
98             } else {
99                 res += "";
100             }
101         } else if (name == "/c")
102             res += "";
103
104         p = next;
105     }
106     return res;
107 }
108
109 static
110 string parse_data(const gchar *data)
111 {
112     if (!data)
113         return "";
114
115     string res;
116     guint32 data_size, sec_size = 0;
117     gchar *m_str;
118     const gchar *p = data;
119     data_size = *((guint32 *) p);
120     p += sizeof(guint32);
121     while (guint32(p - data) < data_size) {
122         switch (*p++) {
123         case 'g':
124         case 'm':
125         case 'l':               //need more work...
126             sec_size = strlen(p);
127             if (sec_size) {
128                 res += "\n";
129                 m_str = g_strndup(p, sec_size);
130                 res += m_str;
131                 g_free(m_str);
132             }
133             sec_size++;
134             break;
135         case 'x':
136             sec_size = strlen(p);
137             if (sec_size) {
138                 res += "\n";
139                 m_str = g_strndup(p, sec_size);
140                 res += xdxf2text(m_str);
141                 g_free(m_str);
142             }
143             sec_size++;
144             break;
145         case 't':
146             sec_size = strlen(p);
147             if (sec_size) {
148                 res += "\n";
149                 m_str = g_strndup(p, sec_size);
150                 res += "[" + string(m_str) + "]";
151                 g_free(m_str);
152             }
153             sec_size++;
154             break;
155         case 'y':
156             sec_size = strlen(p);
157             sec_size++;
158             break;
159         case 'W':
160         case 'P':
161             sec_size = *((guint32 *) p);
162             sec_size += sizeof(guint32);
163             break;
164         }
165         p += sec_size;
166     }
167
168     return res;
169 }
170
171 void
172 Library::ListWords(CurrentIndex *iIndex)
173 {
174     CurrentIndex *iCurrent = (CurrentIndex *) g_memdup(iIndex,
175                                                        sizeof(CurrentIndex) *
176                                                        query_dictmask.size());
177
178     oStarDict->ResultsListClear();
179
180     int iWordCount = 0;
181     const gchar *poCurrentWord = poGetCurrentWord(iIndex, query_dictmask, 0);
182     if (poCurrentWord) {
183         oStarDict->ResultsListInsertLast(poCurrentWord);
184         iWordCount++;
185
186         while (iWordCount < 30 && (poCurrentWord = poGetNextWord(NULL, iIndex, query_dictmask, 0))) {
187             oStarDict->ResultsListInsertLast(poCurrentWord);
188             iWordCount++;
189         }
190     }
191     oStarDict->ResultsReScroll();
192
193     if (iCurrent)
194         g_free(iCurrent);
195 }
196
197 bool
198 Library::BuildResultData(std::vector < InstantDictIndex > &dictmask,
199                          const char *sWord,
200                          CurrentIndex *iIndex,
201                          int iLib,
202                          TSearchResultList &res_list)
203 {
204     int iRealLib;
205     bool bFound = false, bLookupWord = false, bLookupSynonymWord = false;
206     gint nWord = 0, count = 0, i = 0, j = 0;
207
208     iRealLib = dictmask[iLib].index;
209
210     bLookupWord = LookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
211     if (!bLookupWord)
212         bLookupWord =
213             LookupSimilarWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
214     if (!bLookupWord)
215         bLookupWord =
216             SimpleLookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
217
218     bLookupSynonymWord =
219         LookupSynonymWord(sWord, iIndex[iLib].synidx, iIndex[iLib].synidx_suggest, iRealLib, 0);
220     if (!bLookupSynonymWord)
221         bLookupSynonymWord =
222             LookupSynonymSimilarWord(sWord, iIndex[iLib].synidx,
223                                      iIndex[iLib].synidx_suggest, iRealLib, 0);
224     if (!bLookupSynonymWord)
225         bLookupSynonymWord =
226             SimpleLookupSynonymWord(sWord, iIndex[iLib].synidx,
227                                     iIndex[iLib].synidx_suggest, iRealLib, 0);
228
229     if (bLookupWord || bLookupSynonymWord) {
230         if (bLookupWord)
231             nWord++;
232
233         if (bLookupSynonymWord)
234             nWord += GetOrigWordCount(iIndex[iLib].synidx, iRealLib, false);
235
236         if (bLookupWord) {
237             count = GetOrigWordCount(iIndex[iLib].idx, iRealLib, true);
238             for (i = 0; i < count; i++) {
239                 res_list.push_back(TSearchResult(dict_name(iLib),
240                                                  poGetWord(iIndex[iLib].idx, iRealLib,
241                                                            0),
242                                                  parse_data
243                                                  (poGetOrigWordData
244                                                   (iIndex[iLib].idx + i, iRealLib))));
245             }
246             i = 1;
247         } else {
248             i = 0;
249         }
250         for (j = 0; i < nWord; i++, j++) {
251             res_list.push_back(TSearchResult(dict_name(iLib),
252                                              poGetWord(iIndex[iLib].synidx + j,
253                                                        iRealLib, 0),
254                                              parse_data(poGetOrigWordData
255                                                         (iIndex[iLib].synidx + j, iRealLib))));
256         }
257
258         bFound = true;
259     }
260
261     return bFound;
262 }
263
264 bool
265 Library::SimpleLookup(const gchar *sWord,
266                       CurrentIndex *piIndex)
267 {
268     CurrentIndex *iIndex;
269     TSearchResultList results;
270     bool bFound = false;
271
272     if (!piIndex)
273         iIndex = (CurrentIndex *) g_malloc(sizeof(CurrentIndex) * query_dictmask.size());
274     else
275         iIndex = piIndex;
276
277     for (size_t iLib = 0; iLib < query_dictmask.size(); iLib++) {
278         if (BuildResultData(query_dictmask, sWord, iIndex, iLib, results))
279             bFound = true;
280     }
281
282     if (!piIndex)
283         g_free(iIndex);
284
285     return bFound;
286 }
287
288 bool
289 Library::LookupWithFuzzy(const gchar *sWord)
290 {
291     static const int MAX_FUZZY_MATCH_ITEM = 100;
292     gchar *fuzzy_reslist[MAX_FUZZY_MATCH_ITEM];
293     bool bFound = false;
294
295     oStarDict->ResultsListClear();
296
297     bFound = Libs::LookupWithFuzzy(sWord, fuzzy_reslist, MAX_FUZZY_MATCH_ITEM, query_dictmask);
298     if (bFound) {
299         SimpleLookup(fuzzy_reslist[0], iCurrentIndex);
300
301         for (int i = 0; i < MAX_FUZZY_MATCH_ITEM && fuzzy_reslist[i]; i++) {
302             oStarDict->ResultsListInsertLast(fuzzy_reslist[i]);
303             g_free(fuzzy_reslist[i]);
304         }
305         oStarDict->ResultsReScroll();
306     }
307
308     return bFound;
309 }
310
311 bool
312 Library::LookupWithRule(const gchar *sWord)
313 {
314     gint iMatchCount = 0;
315     bool bFound = false;
316     gchar **ppMatchWord =
317         (gchar **) g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB) * query_dictmask.size());
318
319     oStarDict->ResultsListClear();
320
321     iMatchCount = Libs::LookupWithRule(sWord, ppMatchWord, query_dictmask);
322     if (iMatchCount) {
323         for (gint i = 0; i < iMatchCount; i++)
324             oStarDict->ResultsListInsertLast(ppMatchWord[i]);
325
326         SimpleLookup(ppMatchWord[0], iCurrentIndex);
327         oStarDict->ResultsReScroll();
328
329         for (gint i = 0; i < iMatchCount; i++)
330             g_free(ppMatchWord[i]);
331
332         bFound = true;
333     }
334     g_free(ppMatchWord);
335     return bFound;
336 }
337
338 bool
339 Library::LookupWithRegex(const gchar *sWord)
340 {
341     gint iMatchCount = 0;
342     bool bFound = false;
343     gchar **ppMatchWord =
344         (gchar **) g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB) * query_dictmask.size());
345
346     oStarDict->ResultsListClear();
347
348     iMatchCount = Libs::LookupWithRegex(sWord, ppMatchWord, query_dictmask);
349     if (iMatchCount) {
350         for (gint i = 0; i < iMatchCount; i++)
351             oStarDict->ResultsListInsertLast(ppMatchWord[i]);
352
353         SimpleLookup(ppMatchWord[0], iCurrentIndex);
354         oStarDict->ResultsReScroll();
355
356         for (gint i = 0; i < iMatchCount; i++)
357             g_free(ppMatchWord[i]);
358
359         bFound = true;
360     }
361     g_free(ppMatchWord);
362     return bFound;
363 }
364
365 static void
366 LookupProgressDialogUpdate(gpointer data,
367                            double fraction)
368 {
369     GtkWidget *dialog = GTK_WIDGET(data);
370     GtkWidget *progress;
371
372     progress = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), "progress"));
373     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
374
375     while (gtk_events_pending())
376         gtk_main_iteration();
377 }
378
379 bool
380 Library::LookupData(const gchar *sWord)
381 {
382     GtkWidget *dialog;
383     bool cancel = false;
384     bool bFound = false;
385
386     std::vector < std::vector < gchar * > > reslist(query_dictmask.size());
387
388
389     oStarDict->ResultsListClear();
390     oStarDict->ShowProgressIndicator(true);
391     dialog = oStarDict->CreateLookupProgressDialog(&cancel);
392
393     bFound = Libs::LookupData(sWord, &reslist[0], LookupProgressDialogUpdate, (gpointer) dialog, &cancel, query_dictmask);
394     if (bFound) {
395         for (size_t iLib = 0; iLib < query_dictmask.size(); iLib++) {
396             if (!reslist[iLib].empty()) {
397                 SimpleLookup(reslist[iLib][0], iCurrentIndex);
398
399                 for (std::vector < gchar *>::iterator i = reslist[iLib].begin();
400                      i != reslist[iLib].end(); ++i) {
401                     oStarDict->ResultsListInsertLast(*i);
402                 }
403                 break;
404             }
405         }
406         oStarDict->ResultsReScroll();
407     }
408     oStarDict->ShowProgressIndicator(false);
409     oStarDict->DestroyLookupProgressDialog(dialog);
410     return bFound;
411 }
412
413 Library::Library(MStarDict *mStarDict):Libs(NULL, FALSE, 0, 0)
414 {
415     oStarDict = mStarDict;
416     iCurrentIndex = NULL;
417 }
418
419 Library::~Library()
420 {
421     if (iCurrentIndex)
422         g_free(iCurrentIndex);
423 }