Branch data Line data Source code
1 : : /** @file serialise.cc
2 : : * @brief functions to convert Xapian objects to strings and back
3 : : */
4 : : /* Copyright (C) 2006,2007,2008,2009,2010 Olly Betts
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, write to the Free Software
18 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : : */
20 : :
21 : : #include <config.h>
22 : :
23 : : #include <xapian/document.h>
24 : : #include <xapian/error.h>
25 : : #include <xapian/positioniterator.h>
26 : : #include <xapian/termiterator.h>
27 : : #include <xapian/valueiterator.h>
28 : :
29 : : #include "omassert.h"
30 : : #include "omenquireinternal.h"
31 : : #include "serialise.h"
32 : : #include "serialise-double.h"
33 : : #include "utils.h"
34 : : #include "weightinternal.h"
35 : :
36 : : #include <string>
37 : : #include <cstring>
38 : :
39 : : using namespace std;
40 : :
41 : : size_t
42 : 12357257 : decode_length(const char ** p, const char *end, bool check_remaining)
43 : : {
44 [ - + ]: 12357257 : if (*p == end) {
45 : 0 : throw Xapian::NetworkError("Bad encoded length: no data");
46 : : }
47 : :
48 : 12357257 : size_t len = static_cast<unsigned char>(*(*p)++);
49 [ + + ]: 12357257 : if (len == 0xff) {
50 : 859006 : len = 0;
51 : : unsigned char ch;
52 : 859006 : int shift = 0;
53 [ + + ]: 2059261 : do {
54 [ + - ][ - + ]: 2059261 : if (*p == end || shift > 28)
55 : 0 : throw Xapian::NetworkError("Bad encoded length: insufficient data");
56 : 2059261 : ch = *(*p)++;
57 : 2059261 : len |= size_t(ch & 0x7f) << shift;
58 : 2059261 : shift += 7;
59 : : } while ((ch & 0x80) == 0);
60 : 859006 : len += 255;
61 : : }
62 [ + + ][ + + ]: 12357257 : if (check_remaining && len > size_t(end - *p)) {
63 : 15 : throw Xapian::NetworkError("Bad encoded length: length greater than data");
64 : : }
65 : 12357242 : return len;
66 : : }
67 : :
68 : : string
69 : 54533 : serialise_error(const Xapian::Error &e)
70 : : {
71 : 54533 : string result;
72 : 54533 : result += encode_length(strlen(e.get_type()));
73 : 54533 : result += e.get_type();
74 : 54533 : result += encode_length(e.get_context().length());
75 : 54533 : result += e.get_context();
76 : 54533 : result += encode_length(e.get_msg().length());
77 : 54533 : result += e.get_msg();
78 : : // The "error string" goes last so we don't need to store its length.
79 : 54533 : const char * err = e.get_error_string();
80 [ + + ]: 54533 : if (err) result += err;
81 : 0 : return result;
82 : : }
83 : :
84 : : void
85 : 54527 : unserialise_error(const string &serialised_error, const string &prefix,
86 : : const string &new_context)
87 : : {
88 : : // Use c_str() so last string is nul-terminated.
89 : 54527 : const char * p = serialised_error.c_str();
90 : 54527 : const char * end = p + serialised_error.size();
91 : : size_t len;
92 : 54527 : len = decode_length(&p, end, true);
93 [ - + # # ]: 54527 : if (len == 7 && memcmp(p, "UNKNOWN", 7) == 0) {
94 : 0 : throw Xapian::InternalError("UNKNOWN");
95 : : }
96 : 54527 : string type(p, len);
97 : 54527 : p += len;
98 : :
99 : 54527 : len = decode_length(&p, end, true);
100 : 54527 : string context(p, len);
101 : 54527 : p += len;
102 : :
103 : 54527 : len = decode_length(&p, end, true);
104 : 54527 : string msg(prefix);
105 : 54527 : msg.append(p, len);
106 : 54527 : p += len;
107 : :
108 [ + + ]: 54527 : const char * error_string = (p == end) ? NULL : p;
109 : :
110 [ - + ][ # # ]: 54527 : if (!context.empty() && !new_context.empty()) {
[ - + ]
111 : 0 : msg += "; context was: ";
112 : 0 : msg += context;
113 : 0 : context = new_context;
114 : : }
115 : :
116 : : #include <xapian/errordispatch.h>
117 : :
118 : 0 : string newmsg = "Unknown remote exception type ";
119 : 0 : newmsg += type;
120 : 0 : newmsg += ": ";
121 : 0 : newmsg += msg;
122 : 163581 : throw Xapian::InternalError(newmsg, context);
123 : : }
124 : :
125 : : string
126 : 8808 : serialise_stats(const Xapian::Weight::Internal &stats)
127 : : {
128 : 8808 : string result;
129 : :
130 : 8808 : result += encode_length(stats.total_length);
131 : 8808 : result += encode_length(stats.collection_size);
132 : 8808 : result += encode_length(stats.rset_size);
133 : :
134 : 8808 : result += encode_length(stats.termfreqs.size());
135 : 8808 : map<string, TermFreqs>::const_iterator i;
136 [ + + ]: 19908 : for (i = stats.termfreqs.begin(); i != stats.termfreqs.end(); ++i) {
137 : 11100 : result += encode_length(i->first.size());
138 : 11100 : result += i->first;
139 : 11100 : result += encode_length(i->second.termfreq);
140 [ + + ]: 11100 : if (stats.rset_size != 0)
141 : 234 : result += encode_length(i->second.reltermfreq);
142 : : }
143 : :
144 : 0 : return result;
145 : : }
146 : :
147 : : Xapian::Weight::Internal
148 : 8808 : unserialise_stats(const string &s)
149 : : {
150 : 8808 : const char * p = s.data();
151 : 8808 : const char * p_end = p + s.size();
152 : :
153 : 8808 : Xapian::Weight::Internal stat;
154 : :
155 : 8808 : stat.total_length = decode_length(&p, p_end, false);
156 : 8808 : stat.collection_size = decode_length(&p, p_end, false);
157 : 8808 : stat.rset_size = decode_length(&p, p_end, false);
158 : :
159 : 8808 : size_t n = decode_length(&p, p_end, false);
160 [ + + ]: 19908 : while (n--) {
161 : 11100 : size_t len = decode_length(&p, p_end, true);
162 : 11100 : string term(p, len);
163 : 11100 : p += len;
164 : 11100 : Xapian::doccount termfreq(decode_length(&p, p_end, false));
165 [ + + ]: 11100 : if (stat.rset_size == 0) {
166 : 10866 : stat.termfreqs.insert(make_pair(term, TermFreqs(termfreq, 0)));
167 : : } else {
168 : 234 : Xapian::doccount reltermfreq(decode_length(&p, p_end, false));
169 : : stat.termfreqs.insert(make_pair(term,
170 : 234 : TermFreqs(termfreq, reltermfreq)));
171 : : }
172 : : }
173 : :
174 : 0 : return stat;
175 : : }
176 : :
177 : : string
178 : 4404 : serialise_mset(const Xapian::MSet &mset)
179 : : {
180 : 4404 : string result;
181 : :
182 : 4404 : result += encode_length(mset.get_firstitem());
183 : 4404 : result += encode_length(mset.get_matches_lower_bound());
184 : 4404 : result += encode_length(mset.get_matches_estimated());
185 : 4404 : result += encode_length(mset.get_matches_upper_bound());
186 : 4404 : result += encode_length(mset.get_uncollapsed_matches_lower_bound());
187 : 4404 : result += encode_length(mset.get_uncollapsed_matches_estimated());
188 : 4404 : result += encode_length(mset.get_uncollapsed_matches_upper_bound());
189 : 4404 : result += serialise_double(mset.get_max_possible());
190 : 4404 : result += serialise_double(mset.get_max_attained());
191 : :
192 : 4404 : result += serialise_double(mset.internal->percent_factor);
193 : :
194 : 4404 : result += encode_length(mset.size());
195 [ + + ]: 43068 : for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
196 : 38664 : result += serialise_double(i.get_weight());
197 : 38664 : result += encode_length(*i);
198 : 38664 : result += encode_length(i.get_collapse_key().size());
199 : 38664 : result += i.get_collapse_key();
200 : 38664 : result += encode_length(i.get_collapse_count());
201 : 4404 : }
202 : :
203 : : const map<string, Xapian::MSet::Internal::TermFreqAndWeight> &termfreqandwts
204 : 4404 : = mset.internal->termfreqandwts;
205 : :
206 : 4404 : map<string, Xapian::MSet::Internal::TermFreqAndWeight>::const_iterator j;
207 [ + + ]: 9972 : for (j = termfreqandwts.begin(); j != termfreqandwts.end(); ++j) {
208 : 5568 : result += encode_length(j->first.size());
209 : 5568 : result += j->first;
210 : 5568 : result += encode_length(j->second.termfreq);
211 : 5568 : result += serialise_double(j->second.termweight);
212 : : }
213 : :
214 : 0 : return result;
215 : : }
216 : :
217 : : Xapian::MSet
218 : 4404 : unserialise_mset(const char * p, const char * p_end)
219 : : {
220 : 4404 : Xapian::doccount firstitem = decode_length(&p, p_end, false);
221 : 4404 : Xapian::doccount matches_lower_bound = decode_length(&p, p_end, false);
222 : 4404 : Xapian::doccount matches_estimated = decode_length(&p, p_end, false);
223 : 4404 : Xapian::doccount matches_upper_bound = decode_length(&p, p_end, false);
224 : 4404 : Xapian::doccount uncollapsed_lower_bound = decode_length(&p, p_end, false);
225 : 4404 : Xapian::doccount uncollapsed_estimated = decode_length(&p, p_end, false);
226 : 4404 : Xapian::doccount uncollapsed_upper_bound = decode_length(&p, p_end, false);
227 : 4404 : Xapian::weight max_possible = unserialise_double(&p, p_end);
228 : 4404 : Xapian::weight max_attained = unserialise_double(&p, p_end);
229 : :
230 : 4404 : double percent_factor = unserialise_double(&p, p_end);
231 : :
232 : 4404 : vector<Xapian::Internal::MSetItem> items;
233 : 4404 : size_t msize = decode_length(&p, p_end, false);
234 [ + + ]: 43068 : while (msize-- > 0) {
235 : 38664 : Xapian::weight wt = unserialise_double(&p, p_end);
236 : 38664 : Xapian::docid did = decode_length(&p, p_end, false);
237 : 38664 : size_t len = decode_length(&p, p_end, true);
238 : 38664 : string key(p, len);
239 : 38664 : p += len;
240 : 38664 : Xapian::doccount collapse_cnt = decode_length(&p, p_end, false);
241 : 38664 : items.push_back(Xapian::Internal::MSetItem(wt, did, key, collapse_cnt));
242 : : }
243 : :
244 : 4404 : map<string, Xapian::MSet::Internal::TermFreqAndWeight> terminfo;
245 [ + + ]: 9972 : while (p != p_end) {
246 : 5568 : Xapian::MSet::Internal::TermFreqAndWeight tfaw;
247 : 5568 : size_t len = decode_length(&p, p_end, true);
248 : 5568 : string term(p, len);
249 : 5568 : p += len;
250 : 5568 : tfaw.termfreq = decode_length(&p, p_end, false);
251 : 5568 : tfaw.termweight = unserialise_double(&p, p_end);
252 : 5568 : terminfo.insert(make_pair(term, tfaw));
253 : : }
254 : :
255 : : return Xapian::MSet(new Xapian::MSet::Internal(
256 : : firstitem,
257 : : matches_upper_bound,
258 : : matches_lower_bound,
259 : : matches_estimated,
260 : : uncollapsed_upper_bound,
261 : : uncollapsed_lower_bound,
262 : : uncollapsed_estimated,
263 : : max_possible, max_attained,
264 : 4404 : items, terminfo, percent_factor));
265 : : }
266 : :
267 : : string
268 : 4410 : serialise_rset(const Xapian::RSet &rset)
269 : : {
270 : 4410 : const set<Xapian::docid> & items = rset.internal->get_items();
271 : 4410 : string result;
272 : 4410 : set<Xapian::docid>::const_iterator i;
273 : 4410 : Xapian::docid lastdid = 0;
274 [ + + ]: 4470 : for (i = items.begin(); i != items.end(); ++i) {
275 : 60 : Xapian::docid did = *i;
276 : 60 : result += encode_length(did - lastdid - 1);
277 : 60 : lastdid = did;
278 : : }
279 : 0 : return result;
280 : : }
281 : :
282 : : Xapian::RSet
283 : 4404 : unserialise_rset(const string &s)
284 : : {
285 : 4404 : Xapian::RSet rset;
286 : :
287 : 4404 : const char * p = s.data();
288 : 4404 : const char * p_end = p + s.size();
289 : :
290 : 4404 : Xapian::docid did = 0;
291 [ + + ]: 4464 : while (p != p_end) {
292 : 60 : did += decode_length(&p, p_end, false) + 1;
293 : 60 : rset.add_document(did);
294 : : }
295 : :
296 : 0 : return rset;
297 : : }
298 : :
299 : : string
300 : 98191 : serialise_document(const Xapian::Document &doc)
301 : : {
302 : 98191 : string result;
303 : :
304 : 98191 : size_t n = doc.values_count();
305 : 98191 : result += encode_length(n);
306 : 98191 : Xapian::ValueIterator value;
307 [ + + ]: 485324 : for (value = doc.values_begin(); value != doc.values_end(); ++value) {
308 : 387133 : result += encode_length(value.get_valueno());
309 : 387133 : result += encode_length((*value).size());
310 : 387133 : result += *value;
311 : 387133 : --n;
312 : : }
313 : : Assert(n == 0);
314 : :
315 : 98191 : n = doc.termlist_count();
316 : 98191 : result += encode_length(n);
317 : 98191 : Xapian::TermIterator term;
318 [ + + ]: 1406600 : for (term = doc.termlist_begin(); term != doc.termlist_end(); ++term) {
319 : 1308409 : result += encode_length((*term).size());
320 : 1308409 : result += *term;
321 : 1308409 : result += encode_length(term.get_wdf());
322 : :
323 : 1308409 : size_t x = term.positionlist_count();
324 : 1308409 : result += encode_length(x);
325 : 1308409 : Xapian::PositionIterator pos;
326 : 1308409 : Xapian::termpos oldpos = 0;
327 [ + + ]: 2641200 : for (pos = term.positionlist_begin(); pos != term.positionlist_end(); ++pos) {
328 : 1332791 : Xapian::termpos diff = *pos - oldpos;
329 : 1332791 : string delta = encode_length(diff);
330 : 1332791 : result += delta;
331 : 1332791 : oldpos = *pos;
332 : 1332791 : --x;
333 : : }
334 : : Assert(x == 0);
335 : 1308409 : --n;
336 : : }
337 : : Assert(n == 0);
338 : :
339 : 98191 : result += doc.get_data();
340 : 98191 : return result;
341 : : }
342 : :
343 : : Xapian::Document
344 : 98189 : unserialise_document(const string &s)
345 : : {
346 : 98189 : Xapian::Document doc;
347 : 98189 : const char * p = s.data();
348 : 98189 : const char * p_end = p + s.size();
349 : :
350 : 98189 : size_t n_values = decode_length(&p, p_end, false);
351 [ + + ]: 485321 : while (n_values--) {
352 : 387132 : Xapian::valueno valno = decode_length(&p, p_end, false);
353 : 387132 : size_t len = decode_length(&p, p_end, true);
354 : 387132 : doc.add_value(valno, string(p, len));
355 : 387132 : p += len;
356 : : }
357 : :
358 : 98189 : size_t n_terms = decode_length(&p, p_end, false);
359 [ + + ]: 1406597 : while (n_terms--) {
360 : 1308408 : size_t len = decode_length(&p, p_end, true);
361 : 1308408 : string term(p, len);
362 : 1308408 : p += len;
363 : :
364 : : // Set all the wdf using add_term, then pass wdf_inc 0 to add_posting.
365 : 1308408 : Xapian::termcount wdf = decode_length(&p, p_end, false);
366 : 1308408 : doc.add_term(term, wdf);
367 : :
368 : 1308408 : size_t n_pos = decode_length(&p, p_end, false);
369 : 1308408 : Xapian::termpos pos = 0;
370 [ + + ]: 2641199 : while (n_pos--) {
371 : 1332791 : pos += decode_length(&p, p_end, false);
372 : 1332791 : doc.add_posting(term, pos, 0);
373 : : }
374 : : }
375 : :
376 : 98189 : doc.set_data(string(p, p_end - p));
377 : 0 : return doc;
378 : : }
|