0cc7001612d25a30ca7e8f3720e5d94df5813952
[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                   const gchar *oword)
112 {
113     if (!data)
114         return "";
115
116     string mark;
117     guint32 data_size, sec_size = 0;
118     gchar *m_str;
119     const gchar *p = data;
120     data_size = *((guint32 *) p);
121     p += sizeof(guint32);
122     size_t iPlugin;
123     size_t nPlugins = pMStarDict->oStarDictPlugins->ParseDataPlugins.nplugins();
124     unsigned int parsed_size;
125     ParseResult parse_result;
126
127     while (guint32(p - data) < data_size) {
128         for (iPlugin = 0; iPlugin < nPlugins; iPlugin++) {
129             parse_result.clear();
130             if (pMStarDict->oStarDictPlugins->ParseDataPlugins.parse(iPlugin, p, &parsed_size, parse_result, oword)) {
131                 p += parsed_size;
132                 break;
133             }
134         }
135         if (iPlugin != nPlugins) {
136             for (std::list<ParseResultItem>::iterator it = parse_result.item_list.begin(); it != parse_result.item_list.end(); ++it) {
137                 switch (it->type) {
138                     case ParseResultItemType_mark:
139                         g_debug("ParseResultItemType_mark");
140                         mark += it->mark->pango;
141                         break;
142                     case ParseResultItemType_link:
143 //                      g_debug("ParseResultItemType_link: %s", it->mark->pango.c_str());
144                         mark += it->mark->pango;
145                         break;
146                     case ParseResultItemType_res:
147                     {
148                         g_debug("ParseResultItemType_res");
149                         bool loaded = false;
150                         if (it->res->type == "image") {
151                         } else if (it->res->type == "sound") {
152                         } else if (it->res->type == "video") {
153                         } else {
154                         }
155                         if (!loaded) {
156                             mark += "<span foreground=\"red\">";
157                             gchar *m_str = g_markup_escape_text(it->res->key.c_str(), -1);
158                             mark += m_str;
159                             g_free(m_str);
160                             mark += "</span>";
161                         }
162                         break;
163                     }
164                     case ParseResultItemType_widget:
165                         g_debug("ParseResultItemType_widget");
166                         break;
167                     default:
168                         g_debug("ParseResultItemType_default");
169                         break;
170                 }
171             }
172             parse_result.clear();
173             continue;
174         }
175
176         switch (*p++) {
177         case 'g':
178         case 'h':
179         case 'm':
180         case 'l':               //need more work...
181             sec_size = strlen(p);
182             if (sec_size) {
183                 mark += "\n";
184                 m_str = g_strndup(p, sec_size);
185                 mark += m_str;
186                 g_free(m_str);
187             }
188             sec_size++;
189             break;
190         case 'x':
191             sec_size = strlen(p);
192             if (sec_size) {
193                 mark += "\n";
194                 m_str = g_strndup(p, sec_size);
195                 mark += xdxf2text(m_str);
196                 g_free(m_str);
197             }
198             sec_size++;
199             break;
200         case 't':
201             sec_size = strlen(p);
202             if (sec_size) {
203                 mark += "\n";
204                 m_str = g_strndup(p, sec_size);
205                 mark += "[" + string(m_str) + "]";
206                 g_free(m_str);
207             }
208             sec_size++;
209             break;
210         case 'y':
211             sec_size = strlen(p);
212             sec_size++;
213             break;
214         case 'W':
215         case 'P':
216             sec_size = *((guint32 *) p);
217             sec_size += sizeof(guint32);
218             break;
219         }
220         p += sec_size;
221     }
222
223     return mark;
224 }
225
226 void
227 Library::ListWords(CurrentIndex *iIndex)
228 {
229     CurrentIndex *iCurrent = (CurrentIndex *) g_memdup(iIndex,
230                                                        sizeof(CurrentIndex) *
231                                                        query_dictmask.size());
232
233     oStarDict->ResultsListClear();
234
235     int iWordCount = 0;
236     const gchar *poCurrentWord = poGetCurrentWord(iIndex, query_dictmask, 0);
237     if (poCurrentWord) {
238         oStarDict->ResultsListInsertLast(poCurrentWord);
239         iWordCount++;
240
241         while (iWordCount < 30 && (poCurrentWord = poGetNextWord(NULL, iIndex, query_dictmask, 0))) {
242             oStarDict->ResultsListInsertLast(poCurrentWord);
243             iWordCount++;
244         }
245     }
246     oStarDict->ResultsReScroll();
247
248     if (iCurrent)
249         g_free(iCurrent);
250 }
251
252 bool
253 Library::BuildResultData(std::vector < InstantDictIndex > &dictmask,
254                          const char *sWord,
255                          CurrentIndex *iIndex,
256                          int iLib,
257                          TSearchResultList &res_list)
258 {
259     int iRealLib;
260     bool bFound = false, bLookupWord = false, bLookupSynonymWord = false;
261     gint nWord = 0, count = 0, i = 0, j = 0;
262     glong iWordIdx;
263
264     iRealLib = dictmask[iLib].index;
265
266     bLookupWord = LookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
267     if (!bLookupWord)
268         bLookupWord =
269             LookupSimilarWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
270     if (!bLookupWord)
271         bLookupWord =
272             SimpleLookupWord(sWord, iIndex[iLib].idx, iIndex[iLib].idx_suggest, iRealLib, 0);
273
274     bLookupSynonymWord =
275         LookupSynonymWord(sWord, iIndex[iLib].synidx, iIndex[iLib].synidx_suggest, iRealLib, 0);
276     if (!bLookupSynonymWord)
277         bLookupSynonymWord =
278             LookupSynonymSimilarWord(sWord, iIndex[iLib].synidx,
279                                      iIndex[iLib].synidx_suggest, iRealLib, 0);
280     if (!bLookupSynonymWord)
281         bLookupSynonymWord =
282             SimpleLookupSynonymWord(sWord, iIndex[iLib].synidx,
283                                     iIndex[iLib].synidx_suggest, iRealLib, 0);
284
285     if (bLookupWord || bLookupSynonymWord) {
286         if (bLookupWord)
287             nWord++;
288
289         if (bLookupSynonymWord)
290             nWord += GetOrigWordCount(iIndex[iLib].synidx, iRealLib, false);
291
292         if (bLookupWord) {
293             count = GetOrigWordCount(iIndex[iLib].idx, iRealLib, true);
294             for (i = 0; i < count; i++) {
295                 res_list.push_back(TSearchResult(dict_name(iLib),
296                                                  poGetOrigWord(iIndex[iLib].idx, iRealLib),
297                                                  parse_data(poGetOrigWordData(iIndex[iLib].idx + i, iRealLib),
298                                                             poGetOrigWord(iIndex[iLib].idx, iRealLib))));
299             }
300             i = 1;
301         } else {
302             i = 0;
303         }
304         for (j = 0; i < nWord; i++, j++) {
305             iWordIdx = poGetOrigSynonymWordIdx(iIndex[iLib].synidx + j, iRealLib);
306             res_list.push_back(TSearchResult(dict_name(iLib),
307                                              poGetOrigWord(iWordIdx, iRealLib),
308                                              parse_data(poGetOrigWordData(iWordIdx, iRealLib),
309                                                         poGetOrigWord(iWordIdx, iRealLib))));
310         }
311
312         bFound = true;
313     }
314
315     return bFound;
316 }
317
318 bool
319 Library::SimpleLookup(const gchar *sWord,
320                       CurrentIndex *piIndex)
321 {
322     CurrentIndex *iIndex;
323     TSearchResultList results;
324     bool bFound = false;
325
326     if (!piIndex)
327         iIndex = (CurrentIndex *) g_malloc(sizeof(CurrentIndex) * query_dictmask.size());
328     else
329         iIndex = piIndex;
330
331     for (size_t iLib = 0; iLib < query_dictmask.size(); iLib++) {
332         if (BuildResultData(query_dictmask, sWord, iIndex, iLib, results))
333             bFound = true;
334     }
335
336     if (!piIndex)
337         g_free(iIndex);
338
339     return bFound;
340 }
341
342 bool
343 Library::LookupWithFuzzy(const gchar *sWord)
344 {
345     static const int MAX_FUZZY_MATCH_ITEM = 100;
346     gchar *fuzzy_reslist[MAX_FUZZY_MATCH_ITEM];
347     bool bFound = false;
348
349     oStarDict->ResultsListClear();
350
351     bFound = Libs::LookupWithFuzzy(sWord, fuzzy_reslist, MAX_FUZZY_MATCH_ITEM, query_dictmask);
352     if (bFound) {
353         SimpleLookup(fuzzy_reslist[0], iCurrentIndex);
354
355         for (int i = 0; i < MAX_FUZZY_MATCH_ITEM && fuzzy_reslist[i]; i++) {
356             oStarDict->ResultsListInsertLast(fuzzy_reslist[i]);
357             g_free(fuzzy_reslist[i]);
358         }
359         oStarDict->ResultsReScroll();
360     }
361
362     return bFound;
363 }
364
365 bool
366 Library::LookupWithRule(const gchar *sWord)
367 {
368     gint iMatchCount = 0;
369     bool bFound = false;
370     gchar **ppMatchWord =
371         (gchar **) g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB) * query_dictmask.size());
372
373     oStarDict->ResultsListClear();
374
375     iMatchCount = Libs::LookupWithRule(sWord, ppMatchWord, query_dictmask);
376     if (iMatchCount) {
377         for (gint i = 0; i < iMatchCount; i++)
378             oStarDict->ResultsListInsertLast(ppMatchWord[i]);
379
380         SimpleLookup(ppMatchWord[0], iCurrentIndex);
381         oStarDict->ResultsReScroll();
382
383         for (gint i = 0; i < iMatchCount; i++)
384             g_free(ppMatchWord[i]);
385
386         bFound = true;
387     }
388     g_free(ppMatchWord);
389     return bFound;
390 }
391
392 bool
393 Library::LookupWithRegex(const gchar *sWord)
394 {
395     gint iMatchCount = 0;
396     bool bFound = false;
397     gchar **ppMatchWord =
398         (gchar **) g_malloc(sizeof(gchar *) * (MAX_MATCH_ITEM_PER_LIB) * query_dictmask.size());
399
400     oStarDict->ResultsListClear();
401
402     iMatchCount = Libs::LookupWithRegex(sWord, ppMatchWord, query_dictmask);
403     if (iMatchCount) {
404         for (gint i = 0; i < iMatchCount; i++)
405             oStarDict->ResultsListInsertLast(ppMatchWord[i]);
406
407         SimpleLookup(ppMatchWord[0], iCurrentIndex);
408         oStarDict->ResultsReScroll();
409
410         for (gint i = 0; i < iMatchCount; i++)
411             g_free(ppMatchWord[i]);
412
413         bFound = true;
414     }
415     g_free(ppMatchWord);
416     return bFound;
417 }
418
419 static void
420 LookupProgressDialogUpdate(gpointer data,
421                            double fraction)
422 {
423     GtkWidget *dialog = GTK_WIDGET(data);
424     GtkWidget *progress;
425
426     progress = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), "progress_bar"));
427     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
428
429     while (gtk_events_pending())
430         gtk_main_iteration();
431 }
432
433 bool
434 Library::LookupData(const gchar *sWord)
435 {
436     GtkWidget *dialog;
437     bool cancel = false;
438     bool bFound = false;
439
440     std::vector < std::vector < gchar * > > reslist(query_dictmask.size());
441
442
443     oStarDict->ResultsListClear();
444     oStarDict->ShowProgressIndicator(true);
445     dialog = oStarDict->CreateLookupProgressDialog(&cancel);
446
447     bFound = Libs::LookupData(sWord, &reslist[0], LookupProgressDialogUpdate, (gpointer) dialog, &cancel, query_dictmask);
448     if (bFound) {
449         for (size_t iLib = 0; iLib < query_dictmask.size(); iLib++) {
450             if (!reslist[iLib].empty()) {
451                 SimpleLookup(reslist[iLib][0], iCurrentIndex);
452
453                 for (std::vector < gchar *>::iterator i = reslist[iLib].begin();
454                      i != reslist[iLib].end(); ++i) {
455                     oStarDict->ResultsListInsertLast(*i);
456                 }
457                 break;
458             }
459         }
460         oStarDict->ResultsReScroll();
461     }
462     oStarDict->ShowProgressIndicator(false);
463     oStarDict->DestroyLookupProgressDialog(dialog);
464     return bFound;
465 }
466
467 Library::Library(MStarDict *mStarDict):Libs(NULL, FALSE, 0, 0)
468 {
469     oStarDict = mStarDict;
470     iCurrentIndex = NULL;
471 }
472
473 Library::~Library()
474 {
475     if (iCurrentIndex)
476         g_free(iCurrentIndex);
477 }