1 /*****************************************************************************\
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2002-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
17 #include <basis/functions.h>
18 #include <loggers/critical_events.h>
19 #include <loggers/program_wide_logger.h>
20 #include <structures/string_array.h>
21 #include <textual/byte_formatter.h>
23 using namespace basis;
24 using namespace loggers;
25 using namespace structures;
26 using namespace textual;
31 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
33 //#define DEBUG_INFOTON
34 // if uncommented, then extra checks are made.
36 const abyte FAST_PACK_VERSION = 0x14;
37 // this single byte version number should be increased when the network
38 // protocol changes. it only ensures that the fast_pack method will reject
41 infoton::infoton(const string_array &classifier)
42 : _classifier(new string_array(classifier))
44 FUNCDEF("constructor [string_array]");
47 infoton::infoton(const astring &class_1)
48 : _classifier(new string_array)
50 FUNCDEF("constructor [one string]");
51 *_classifier += class_1;
54 infoton::infoton(const astring &class_1, const astring &class_2)
55 : _classifier(new string_array)
57 FUNCDEF("constructor [two strings]");
58 *_classifier += class_1;
59 *_classifier += class_2;
62 infoton::infoton(const astring &class_1, const astring &class_2,
63 const astring &class_3)
64 : _classifier(new string_array)
66 FUNCDEF("constructor [three strings]");
67 *_classifier += class_1;
68 *_classifier += class_2;
69 *_classifier += class_3;
72 infoton::infoton(const infoton &to_copy)
76 _classifier(new string_array(*to_copy._classifier))
80 { WHACK(_classifier); }
82 infoton &infoton::operator = (const infoton &to_copy)
83 { *_classifier = *to_copy._classifier; return *this; }
85 const string_array &infoton::classifier() const
86 { return *_classifier; }
88 bool infoton::check_classifier(const astring &classname, const astring &caller)
90 bool to_return = true;
91 if (!_classifier->length())
93 for (int i = 0; i < _classifier->length(); i++) {
94 if (!(*_classifier)[i].length())
98 program_wide_logger::get().log(classname + "::" + caller
99 + ": invalid classifier provided.", ALWAYS_PRINT);
104 void infoton::set_classifier(const string_array &new_classifier)
107 FUNCDEF("set_classifier [string_array]");
109 *_classifier = new_classifier;
111 check_classifier(class_name(), func);
115 void infoton::set_classifier(const astring &class_1)
118 FUNCDEF("set_classifier [1 string]");
120 _classifier->reset();
121 *_classifier += class_1;
123 check_classifier(class_name(), func);
127 void infoton::set_classifier(const astring &class_1, const astring &class_2)
130 FUNCDEF("set_classifier [2 strings]");
132 _classifier->reset();
133 *_classifier += class_1;
134 *_classifier += class_2;
136 check_classifier(class_name(), func);
140 void infoton::set_classifier(const astring &class_1, const astring &class_2,
141 const astring &class_3)
144 FUNCDEF("set_classifier [3 strings]");
146 _classifier->reset();
147 *_classifier += class_1;
148 *_classifier += class_2;
149 *_classifier += class_3;
151 check_classifier(class_name(), func);
155 int infoton::fast_pack_overhead(const string_array &classifier)
157 return classifier.packed_size() // for classifier.
158 + sizeof(int) // for the package size.
159 + 1; // for the version byte.
162 void infoton::fast_pack(byte_array &packed_form, const infoton &to_pack)
164 FUNCDEF("fast_pack");
165 structures::attach(packed_form, FAST_PACK_VERSION);
166 // add the tasty version byte as the very first item.
167 structures::pack_array(packed_form, to_pack.classifier());
168 // must first put the packed infoton into a byte array, then use the
169 // byte array's packing support.
170 int len_prior = packed_form.length();
171 structures::attach(packed_form, int(0));
172 // save space for length.
173 //hmmm: this could use obscure_pack for more reliability.
174 to_pack.pack(packed_form);
175 int added_len = packed_form.length() - sizeof(int) - len_prior;
177 // shift in the length in the place where we made space.
178 basis::un_int temp = basis::un_int(added_len);
179 for (basis::un_int i = 0; i < sizeof(int); i++) {
180 packed_form[len_prior + i] = abyte(temp % 0x100);
185 bool infoton::test_fast_unpack(const byte_array &packed_form,
188 FUNCDEF("test_fast_unpack");
190 if (!packed_form.length()) return false;
192 // make sure we have the right version number, first.
193 if (packed_form[0] != FAST_PACK_VERSION)
196 un_int strings_held = 0;
197 byte_array len_bytes = packed_form.subarray(1, 2 * sizeof(int));
198 if (!structures::obscure_detach(len_bytes, strings_held) || !strings_held) {
202 // check through all of the strings.
203 const void *zero_posn = packed_form.observe() + sizeof(int) * 2 + 1;
204 for (int i = 0; i < (int)strings_held; i++) {
205 // locate the zero termination if possible.
206 int index = int((abyte *)zero_posn - packed_form.observe());
207 zero_posn = memchr(packed_form.observe() + index, '\0',
208 packed_form.length() - index);
209 // make sure we could find the zero termination.
211 // nope, never saw a zero. good thing we checked.
216 // base our expected position for the data length on the position of the
217 // last string we found.
218 int datalen_start = int((abyte *)zero_posn - packed_form.observe()) + 1;
219 byte_array just_len = packed_form.subarray(datalen_start,
220 datalen_start + sizeof(int) - 1);
221 if (!structures::detach(just_len, packed_length)) return false;
222 packed_length += datalen_start + sizeof(int);
223 // include the classifier length and integer package length.
227 bool infoton::fast_unpack(byte_array &packed_form, string_array &classifier,
230 FUNCDEF("fast_unpack");
233 abyte version_checking = 0;
234 if (!structures::detach(packed_form, version_checking)) return false;
235 if (version_checking != FAST_PACK_VERSION) return false;
236 if (!structures::unpack_array(packed_form, classifier)) return false;
238 if (!structures::detach(packed_form, len)) return false;
239 if (len > packed_form.length()) {
241 continuable_error(static_class_name(), func, "failed to have enough data!");
244 info = packed_form.subarray(0, len - 1);
245 packed_form.zap(0, len - 1);