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