feisty meow concerns codebase  2.140
infoton.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : infoton *
4 * Author : Chris Koeritz *
5 * *
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 \*****************************************************************************/
14 
15 #include "infoton.h"
16 
17 #include <basis/functions.h>
21 #include <textual/byte_formatter.h>
22 
23 using namespace basis;
24 using namespace loggers;
25 using namespace structures;
26 using namespace textual;
27 
28 namespace octopi {
29 
30 #undef LOG
31 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
32 
33 //#define DEBUG_INFOTON
34  // if uncommented, then extra checks are made.
35 
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
39  // a lower version.
40 
41 infoton::infoton(const string_array &classifier)
42 : _classifier(new string_array(classifier))
43 {
44  FUNCDEF("constructor [string_array]");
45 }
46 
47 infoton::infoton(const astring &class_1)
48 : _classifier(new string_array)
49 {
50  FUNCDEF("constructor [one string]");
51  *_classifier += class_1;
52 }
53 
54 infoton::infoton(const astring &class_1, const astring &class_2)
55 : _classifier(new string_array)
56 {
57  FUNCDEF("constructor [two strings]");
58  *_classifier += class_1;
59  *_classifier += class_2;
60 }
61 
62 infoton::infoton(const astring &class_1, const astring &class_2,
63  const astring &class_3)
64 : _classifier(new string_array)
65 {
66  FUNCDEF("constructor [three strings]");
67  *_classifier += class_1;
68  *_classifier += class_2;
69  *_classifier += class_3;
70 }
71 
72 infoton::infoton(const infoton &to_copy)
73 : root_object(),
74  packable(),
75  clonable(),
76  _classifier(new string_array(*to_copy._classifier))
77 {}
78 
80 { WHACK(_classifier); }
81 
83 { *_classifier = *to_copy._classifier; return *this; }
84 
86 { return *_classifier; }
87 
88 bool infoton::check_classifier(const astring &classname, const astring &caller)
89 {
90  bool to_return = true;
91  if (!_classifier->length())
92  to_return = false;
93  for (int i = 0; i < _classifier->length(); i++) {
94  if (!(*_classifier)[i].length())
95  to_return = false;
96  }
97  if (!to_return) {
98  program_wide_logger::get().log(classname + "::" + caller
99  + ": invalid classifier provided.", ALWAYS_PRINT);
100  }
101  return to_return;
102 }
103 
104 void infoton::set_classifier(const string_array &new_classifier)
105 {
106 #ifdef DEBUG_INFOTON
107  FUNCDEF("set_classifier [string_array]");
108 #endif
109  *_classifier = new_classifier;
110 #ifdef DEBUG_INFOTON
111  check_classifier(class_name(), func);
112 #endif
113 }
114 
115 void infoton::set_classifier(const astring &class_1)
116 {
117 #ifdef DEBUG_INFOTON
118  FUNCDEF("set_classifier [1 string]");
119 #endif
120  _classifier->reset();
121  *_classifier += class_1;
122 #ifdef DEBUG_INFOTON
123  check_classifier(class_name(), func);
124 #endif
125 }
126 
127 void infoton::set_classifier(const astring &class_1, const astring &class_2)
128 {
129 #ifdef DEBUG_INFOTON
130  FUNCDEF("set_classifier [2 strings]");
131 #endif
132  _classifier->reset();
133  *_classifier += class_1;
134  *_classifier += class_2;
135 #ifdef DEBUG_INFOTON
136  check_classifier(class_name(), func);
137 #endif
138 }
139 
140 void infoton::set_classifier(const astring &class_1, const astring &class_2,
141  const astring &class_3)
142 {
143 #ifdef DEBUG_INFOTON
144  FUNCDEF("set_classifier [3 strings]");
145 #endif
146  _classifier->reset();
147  *_classifier += class_1;
148  *_classifier += class_2;
149  *_classifier += class_3;
150 #ifdef DEBUG_INFOTON
151  check_classifier(class_name(), func);
152 #endif
153 }
154 
156 {
157  return classifier.packed_size() // for classifier.
158  + sizeof(int) // for the package size.
159  + 1; // for the version byte.
160 }
161 
162 void infoton::fast_pack(byte_array &packed_form, const infoton &to_pack)
163 {
164  FUNCDEF("fast_pack");
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;
176 
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);
181  temp >>= 8;
182  }
183 }
184 
185 bool infoton::test_fast_unpack(const byte_array &packed_form,
186  int &packed_length)
187 {
188  FUNCDEF("test_fast_unpack");
189  packed_length = 0;
190  if (!packed_form.length()) return false;
191 
192  // make sure we have the right version number, first.
193  if (packed_form[0] != FAST_PACK_VERSION)
194  return false;
195 
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) {
199  return false;
200  }
201 
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.
210  if (!zero_posn) {
211  // nope, never saw a zero. good thing we checked.
212  return false;
213  }
214  }
215 
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.
224  return true;
225 }
226 
227 bool infoton::fast_unpack(byte_array &packed_form, string_array &classifier,
228  byte_array &info)
229 {
230  FUNCDEF("fast_unpack");
231  classifier.reset();
232  info.reset();
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;
237  int len = 0;
238  if (!structures::detach(packed_form, len)) return false;
239  if (len > packed_form.length()) {
240  // not enough data.
241  continuable_error(static_class_name(), func, "failed to have enough data!");
242  return false;
243  }
244  info = packed_form.subarray(0, len - 1);
245  packed_form.zap(0, len - 1);
246  return true;
247 }
248 
249 } //namespace.
250 
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition: array.h:349
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition: array.h:172
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition: array.h:443
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition: array.h:769
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
A clonable object knows how to make copy of itself.
Definition: contracts.h:109
A base class for objects that can pack into an array of bytes.
Definition: byte_array.h:87
virtual const char * class_name() const =0
Returns the bare name of this class as a constant character pointer.
An infoton is an individual request parcel with accompanying information.
Definition: infoton.h:32
infoton & operator=(const infoton &to_copy)
assigns only the base class portion.
Definition: infoton.cpp:82
virtual ~infoton()
Definition: infoton.cpp:79
static void fast_pack(basis::byte_array &packed_form, const infoton &to_pack)
flattens an infoton "to_pack" into the byte array "packed_form".
Definition: infoton.cpp:162
static int fast_pack_overhead(const structures::string_array &classifier)
reports how much space is needed to pack the "classifier".
Definition: infoton.cpp:155
bool check_classifier(const basis::astring &class_name, const basis::astring &caller)
checks that the classifier seems valid.
Definition: infoton.cpp:88
static bool test_fast_unpack(const basis::byte_array &packed_form, int &packed_length)
checks that the "packed_form" could hold a valid packed infoton.
Definition: infoton.cpp:185
static bool fast_unpack(basis::byte_array &packed_form, structures::string_array &classifier, basis::byte_array &info)
undoes a previous fast_pack to restore the previous information.
Definition: infoton.cpp:227
const structures::string_array & classifier() const
this array of strings is the "name" for this infoton.
Definition: infoton.cpp:85
infoton(const structures::string_array &classifier)
creates an infoton with the "classifier".
Definition: infoton.cpp:41
void set_classifier(const structures::string_array &new_classifier)
sets the infoton's classifier to the "new_classifier".
Definition: infoton.cpp:104
virtual void pack(basis::byte_array &packed_form) const =0
stuffs the data in the infoton into the "packed_form".
An array of strings with some additional helpful methods.
Definition: string_array.h:32
virtual int packed_size() const
Returns the number of bytes this string array would consume if packed.
Definition: string_array.h:115
#define continuable_error(c, f, i)
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
unsigned char abyte
A fairly important unit which is seldom defined...
Definition: definitions.h:51
unsigned int un_int
Abbreviated name for unsigned integers.
Definition: definitions.h:62
A logger that sends to the console screen using the standard output device.
const abyte FAST_PACK_VERSION
Definition: infoton.cpp:36
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
bool obscure_detach(byte_array &packed_form, un_int &to_detach)
shifts the number back and checks validity, false returned if corrupted.
void attach(byte_array &packed_form, const byte_array &to_attach)
Packs a byte_array "to_attach" into "packed_form".
bool unpack_array(basis::byte_array &packed_form, basis::array< contents > &to_unpack)
provides a way to unpack any array that stores packable objects.
void pack_array(basis::byte_array &packed_form, const basis::array< contents > &to_pack)
provides a way to pack any array that stores packable objects.
bool detach(byte_array &packed_form, byte_array &to_detach)
Unpacks a byte_array "to_detach" from "packed_form".
#define static_class_name()