1 /***************************************************************************
2 *   Copyright (C) 2007 by BOP                                             *
3 *                                                                         *
4 *   This program is free software; you can redistribute it and/or modify  *
5 *   it under the terms of the GNU General Public License as published by  *
6 *   the Free Software Foundation; either version 2 of the License, or     *
7 *   (at your option) any later version.                                   *
8 *                                                                         *
9 *   This program is distributed in the hope that it will be useful,       *
10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 *   GNU General Public License for more details.                          *
13 *                                                                         *
14 *   You should have received a copy of the GNU General Public License     *
15 *   along with this program; if not, write to the                         *
16 *   Free Software Foundation, Inc.,                                       *
17 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18 ***************************************************************************/
19 
20 #include "ebook.h"
21 
22 #include <eb/eb.h>
23 #include <eb/binary.h>
24 #include <eb/text.h>
25 #include <eb/font.h>
26 #include <eb/appendix.h>
27 #include <eb/error.h>
28 
29 const int HitsBufferSize = 10000;
30 
topMenu()31 QList <CandItem> EbMenu::topMenu()
32 {
33 
34     EB_Position pos = menu();
35     if (!isValidPosition(pos)) {
36         QList<CandItem> i;
37         return i;
38     }
39 
40     QString t;
41     return candidate(pos, &t);
42 
43 }
44 
EBook(HookMode hmode)45 EBook::EBook(HookMode hmode)
46     : EbCore(hmode)
47 {
48 }
49 
~EBook()50 EBook::~EBook()
51 {
52 }
53 
searchQuery(int maxcnt,const QString & query,SearchType type)54 int EBook::searchQuery(int maxcnt, const QString& query, SearchType type)
55 {
56     switch (type) {
57     case SearchKeyWord:
58     case SearchCrossWord:
59     {
60         words = query.split(QRegExp("\\s+"), QString::SkipEmptyParts);
61         return hitMultiWord(maxcnt, words, type);
62     }
63     default:
64         words = QStringList(query);
65         return hitWord(maxcnt, query, type);
66     }
67 }
68 
hitMultiWord(int maxcnt,const QStringList & words,SearchType stype)69 int EBook::hitMultiWord(int maxcnt, const QStringList &words, SearchType stype)
70 {
71     hits.clear();
72     if ((stype == SearchKeyWord && !isHaveWordSearch()) ||
73         (stype == SearchCrossWord && !isHaveCrossSearch()) )
74         return 0;
75 
76     if ( maxcnt <= 0 )
77         maxcnt = HitsBufferSize;
78     int count = 0;
79     for (;;) {
80         EB_Error_Code ecode;
81         if (stype == SearchKeyWord) {
82             ecode = searchKeyword(words);
83         } else {
84             ecode = searchCross(words);
85         }
86         if (ecode != EB_SUCCESS) {
87             break;
88         }
89 
90         QList <EB_Hit> wrk = hitList(HitsBufferSize);
91         if (wrk.count() == 0) {
92             return 0;
93         }
94 
95         foreach(EB_Hit w, wrk) {
96             bool same_text = false;
97             foreach(EB_Hit h, hits) {
98                 if (w.text.page == h.text.page &&
99                     w.text.offset == h.text.offset) {
100                     same_text = true;
101                     break;
102                 }
103             }
104             if (same_text) continue;
105 
106             hits << w;
107             count++;
108             if (count >= maxcnt) break;
109         }
110 
111         break;
112     }
113 
114     return count;
115 }
116 
hitWord(int maxcnt,const QString & word,SearchType type)117 int EBook::hitWord(int maxcnt, const QString &word, SearchType type)
118 {
119     hits.clear();
120     if ( maxcnt <= 0 ) maxcnt = HitsBufferSize;
121     EB_Error_Code ecode;
122     if (type == SearchWord) {
123 	if (!isHaveWordSearch())
124 	    return 0;
125         ecode = searchWord(word);
126         if (ecode != EB_SUCCESS) {
127             return -1;
128         }
129     } else if (type == SearchEndWord) {
130 	if (!isHaveEndwordSearch())
131 	    return 0;
132         ecode = searchEndword(word);
133         if (ecode != EB_SUCCESS) {
134             return -1;
135         }
136     } else {
137 	if (!isHaveExactwordSearch())
138 	    return 0;
139         ecode = searchExactword(word);
140         if (ecode != EB_SUCCESS) {
141             return -1;
142         }
143     }
144 
145     QList <EB_Hit> wrk = hitList(HitsBufferSize);
146     if (wrk.count() == 0) {
147         return 0;
148     }
149 
150     int count = 0;
151     foreach(EB_Hit w, wrk) {
152         bool same_text = false;
153         foreach (EB_Hit h, hits) {
154             if (w.text.page == h.text.page &&
155                 w.text.offset == h.text.offset) {
156                 same_text = true;
157                 break;
158             }
159         }
160         if (same_text)  continue;
161         hits << w;
162 
163         count++;
164         if (count >= maxcnt) break;
165     }
166     return count;
167 }
168 
emphasize(const QString & str,const QString & word)169 static QString emphasize(const QString &str, const QString &word)
170 {
171     enum { NO_SKIP=0, SKIP_TAG=0x01, SKIP_ENT=0x02 };
172     QString ret;
173     int slen = str.length();
174     int wlen = word.length();
175     unsigned int skip = NO_SKIP;
176 
177     for (int i = 0; i < slen; i++) {
178         QChar a = str[i];
179         if ((slen - i) < wlen) {
180             ret += a;
181             continue;
182         }
183         if (a == '<') {
184             skip |= SKIP_TAG;
185             ret += a;
186             continue;
187         }
188         if (a == '&') {
189             skip |= SKIP_ENT;
190             ret += a;
191             continue;
192         }
193         if (skip) {
194             if (a == '>')
195                 skip &= ~SKIP_TAG;
196 	    else if (a == ';')
197 		skip &= ~SKIP_ENT;
198             ret += a;
199             continue;
200         }
201         if (a.isSpace()) {
202             ret += a;
203             continue;
204         }
205         QString cmp = str.mid(i, wlen);
206         if (!QString::compare(cmp, word, Qt::CaseInsensitive)) {
207             ret += "<span class=sel>" + cmp + "</span>";
208             i += wlen - 1;
209         } else {
210             ret += a;
211         }
212     }
213 
214     return ret;
215 }
216 
getMatch(int index,QString * head_l,QString * head_v,QString * text,bool highlightMatches)217 void EBook::getMatch(int index, QString *head_l, QString *head_v, QString *text, bool highlightMatches)
218 {
219     getText(index, head_l, head_v, text);
220     if (highlightMatches) {
221         foreach(QString s, words) {
222             *head_v = emphasize(*head_v, s);
223             *text = emphasize(*text, s);
224         }
225     }
226 }
227 
getText(int index,QString * head_l,QString * head_v,QString * text)228 void EBook::getText(int index, QString *head_l, QString *head_v, QString *text)
229 {
230     QString t_v = hitText(index);
231     QString h_v = hitHeading(index);
232 
233     int p = t_v.indexOf('\n');
234     if (h_v.isEmpty()) {
235         h_v = t_v.left(p);
236         t_v = t_v.mid(p+1);
237     } else if (h_v == t_v.left(p)) {
238         t_v = t_v.mid(p+1);
239     }
240     QString h_l = h_v;
241 
242     if (h_l.contains('<')) {
243         h_l.replace(QRegExp("<img[^>]+>"), "?");
244         //h_l.replace(regRep1, "?");
245         if (h_l.contains('<')) {
246             h_l.replace(QRegExp("<[^>]+>"), "");
247             //h_l.replace(regRep2, "");
248 	}
249     }
250 
251     int sp = 0;
252     while((sp = h_l.indexOf('&', sp)) >= 0) {
253 	if (h_l.mid(sp+1, 3) == "lt;")
254             h_l.replace(sp, 4, '<');
255         else if (h_l.mid(sp+1, 3) == "gt;")
256             h_l.replace(sp, 4, '>');
257         else if(h_l.mid(sp+1, 4) == "amp;")
258             h_l.replace(sp, 5, '&');
259         else {
260             int ep = h_l.indexOf(';', sp+1);
261             if (ep < 0) break;
262             h_l.replace(sp, ep-sp+1, '?');
263         }
264         sp++;
265     }
266 
267     *head_l = h_l;
268     *head_v = h_v;
269     *text = t_v;
270 }
271 
hitFull(int maxcnt)272 int EbAll::hitFull(int maxcnt)
273 {
274     hits.clear();
275     EB_Error_Code ecode;
276     EB_Position position;
277     int count = 0;
278 
279     if (firstSeek) {
280         position = startText();
281         if (!isValidPosition(position)) {
282             return -1;
283         }
284         firstSeek = false;
285     } else {
286         position = seekPosition;
287     }
288     EB_Hit hit;
289     hit.heading = position;
290     hit.text = position;
291     hits << hit;
292     count++;
293     while (count <= maxcnt) {
294         ecode = seekText(position);
295         if (ecode != EB_SUCCESS) {
296             break;
297         }
298         ecode = forwardText();
299         if (ecode != EB_SUCCESS) {
300             if (ecode == EB_ERR_END_OF_CONTENT &&
301                 position.page < book.subbook_current->text.end_page) {
302                 //qDebug() << "hitFull : page=" << position.page
303                 //         << "offset=" << position.offset
304                 //         << "end page=" << book.subbook_current->text.end_page;
305                 position = tellText( );
306                 //qDebug() << "tell_text : page=" << position.page
307                 //         << "offset=" << position.offset;
308                 if (!isValidPosition(position)){
309                     break;
310                 }
311                 if (position.page >= book.subbook_current->text.end_page) {
312                     //    qDebug() << "hitFull : page=" << position.page
313                     //             << "offset=" << position.offset ;
314                     break;
315                 }
316                 position.offset += 2;
317             } else {
318                 break;
319             }
320         } else {
321             position = tellText();
322             if (!isValidPosition(position)){
323                 break;
324             }
325         }
326         if (count < maxcnt) {
327             EB_Hit hit;
328             hit.heading = position;
329             hit.text = position;
330             hits << hit;
331         }
332         count++;
333     }
334     seekPosition = position;
335     return count - 1;
336 }
337 
setStartHit(const EB_Position & text_pos)338 int EbAll::setStartHit(const EB_Position &text_pos)
339 {
340     seekPosition = text_pos;
341     firstSeek = false;
342     return 0;
343 }
344 
345