infoton.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : infoton                                                           *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 2002-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 #include "infoton.h"
00016 
00017 #include <basis/functions.h>
00018 #include <loggers/critical_events.h>
00019 #include <loggers/program_wide_logger.h>
00020 #include <structures/string_array.h>
00021 #include <textual/byte_formatter.h>
00022 
00023 using namespace basis;
00024 using namespace loggers;
00025 using namespace structures;
00026 using namespace textual;
00027 
00028 namespace octopi {
00029 
00030 #undef LOG
00031 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
00032 
00033 //#define DEBUG_INFOTON
00034   // if uncommented, then extra checks are made.
00035 
00036 const abyte FAST_PACK_VERSION = 0x14;
00037   // this single byte version number should be increased when the network
00038   // protocol changes.  it only ensures that the fast_pack method will reject
00039   // a lower version.
00040 
00041 infoton::infoton(const string_array &classifier)
00042 : _classifier(new string_array(classifier))
00043 {
00044 //  FUNCDEF("constructor [string_array]");
00045 }
00046 
00047 infoton::infoton(const astring &class_1)
00048 : _classifier(new string_array)
00049 {
00050 //  FUNCDEF("constructor [one string]");
00051   *_classifier += class_1;
00052 }
00053 
00054 infoton::infoton(const astring &class_1, const astring &class_2)
00055 : _classifier(new string_array)
00056 {
00057 //  FUNCDEF("constructor [two strings]");
00058   *_classifier += class_1;
00059   *_classifier += class_2;
00060 }
00061 
00062 infoton::infoton(const astring &class_1, const astring &class_2,
00063     const astring &class_3)
00064 : _classifier(new string_array)
00065 {
00066 //  FUNCDEF("constructor [three strings]");
00067   *_classifier += class_1;
00068   *_classifier += class_2;
00069   *_classifier += class_3;
00070 }
00071 
00072 infoton::infoton(const infoton &to_copy)
00073 : root_object(),
00074   packable(),
00075   clonable(),
00076   _classifier(new string_array(*to_copy._classifier))
00077 {}
00078 
00079 infoton::~infoton()
00080 { WHACK(_classifier); }
00081 
00082 infoton &infoton::operator = (const infoton &to_copy)
00083 { *_classifier = *to_copy._classifier; return *this; }
00084 
00085 const string_array &infoton::classifier() const
00086 { return *_classifier; }
00087 
00088 bool infoton::check_classifier(const astring &classname, const astring &caller)
00089 {
00090   bool to_return = true;
00091   if (!_classifier->length())
00092     to_return = false;
00093   for (int i = 0; i < _classifier->length(); i++) {
00094     if (!(*_classifier)[i].length())
00095       to_return = false;
00096   }
00097   if (!to_return) {
00098     program_wide_logger::get().log(classname + "::" + caller
00099         + ": invalid classifier provided.", ALWAYS_PRINT);
00100   }
00101   return to_return;
00102 }
00103 
00104 void infoton::set_classifier(const string_array &new_classifier)
00105 {
00106 #ifdef DEBUG_INFOTON
00107   FUNCDEF("set_classifier [string_array]");
00108 #endif
00109   *_classifier = new_classifier;
00110 #ifdef DEBUG_INFOTON
00111   check_classifier(class_name(), func);
00112 #endif
00113 }
00114 
00115 void infoton::set_classifier(const astring &class_1)
00116 {
00117 #ifdef DEBUG_INFOTON
00118   FUNCDEF("set_classifier [1 string]");
00119 #endif
00120   _classifier->reset();
00121   *_classifier += class_1;
00122 #ifdef DEBUG_INFOTON
00123   check_classifier(class_name(), func);
00124 #endif
00125 }
00126 
00127 void infoton::set_classifier(const astring &class_1, const astring &class_2)
00128 {
00129 #ifdef DEBUG_INFOTON
00130   FUNCDEF("set_classifier [2 strings]");
00131 #endif
00132   _classifier->reset();
00133   *_classifier += class_1;
00134   *_classifier += class_2;
00135 #ifdef DEBUG_INFOTON
00136   check_classifier(class_name(), func);
00137 #endif
00138 }
00139 
00140 void infoton::set_classifier(const astring &class_1, const astring &class_2,
00141     const astring &class_3)
00142 {
00143 #ifdef DEBUG_INFOTON
00144   FUNCDEF("set_classifier [3 strings]");
00145 #endif
00146   _classifier->reset();
00147   *_classifier += class_1;
00148   *_classifier += class_2;
00149   *_classifier += class_3;
00150 #ifdef DEBUG_INFOTON
00151   check_classifier(class_name(), func);
00152 #endif
00153 }
00154 
00155 int infoton::fast_pack_overhead(const string_array &classifier)
00156 {
00157   return classifier.packed_size()  // for classifier.
00158       + sizeof(int)  // for the package size.
00159       + 1;  // for the version byte.
00160 }
00161 
00162 void infoton::fast_pack(byte_array &packed_form, const infoton &to_pack)
00163 {
00164 //  FUNCDEF("fast_pack");
00165   structures::attach(packed_form, FAST_PACK_VERSION);
00166     // add the tasty version byte as the very first item.
00167   structures::pack_array(packed_form, to_pack.classifier());
00168   // must first put the packed infoton into a byte array, then use the
00169   // byte array's packing support.
00170   int len_prior = packed_form.length();
00171   structures::attach(packed_form, int(0));
00172     // save space for length.
00173 //hmmm: this could use obscure_pack for more reliability.
00174   to_pack.pack(packed_form);
00175   int added_len = packed_form.length() - sizeof(int) - len_prior;
00176 
00177   // shift in the length in the place where we made space.
00178   basis::un_int temp = basis::un_int(added_len);
00179   for (basis::un_int i = 0; i < sizeof(int); i++) {
00180     packed_form[len_prior + i] = abyte(temp % 0x100);
00181     temp >>= 8;
00182   }
00183 }
00184 
00185 bool infoton::test_fast_unpack(const byte_array &packed_form,
00186     int &packed_length)
00187 {
00188 //  FUNCDEF("test_fast_unpack");
00189   packed_length = 0;
00190   if (!packed_form.length()) return false;
00191 
00192   // make sure we have the right version number, first.
00193   if (packed_form[0] != FAST_PACK_VERSION)
00194     return false;
00195 
00196   un_int strings_held = 0;
00197   byte_array len_bytes = packed_form.subarray(1, 2 * sizeof(int));
00198   if (!structures::obscure_detach(len_bytes, strings_held) || !strings_held) {
00199     return false;
00200   }
00201 
00202   // check through all of the strings.
00203   const void *zero_posn = packed_form.observe() + sizeof(int) * 2 + 1;
00204   for (int i = 0; i < (int)strings_held; i++) {
00205     // locate the zero termination if possible.
00206     int index = int((abyte *)zero_posn - packed_form.observe());
00207     zero_posn = memchr(packed_form.observe() + index, '\0',
00208         packed_form.length() - index);
00209     // make sure we could find the zero termination.
00210     if (!zero_posn) {
00211       // nope, never saw a zero.  good thing we checked.
00212       return false;
00213     }
00214   }
00215 
00216   // base our expected position for the data length on the position of the
00217   // last string we found.
00218   int datalen_start = int((abyte *)zero_posn - packed_form.observe()) + 1;
00219   byte_array just_len = packed_form.subarray(datalen_start,
00220       datalen_start + sizeof(int) - 1);
00221   if (!structures::detach(just_len, packed_length)) return false;
00222   packed_length += datalen_start + sizeof(int);
00223     // include the classifier length and integer package length.
00224   return true;
00225 }
00226 
00227 bool infoton::fast_unpack(byte_array &packed_form, string_array &classifier,
00228     byte_array &info)
00229 {
00230   FUNCDEF("fast_unpack");
00231   classifier.reset();
00232   info.reset();
00233   abyte version_checking = 0;
00234   if (!structures::detach(packed_form, version_checking)) return false;
00235   if (version_checking != FAST_PACK_VERSION) return false;
00236   if (!structures::unpack_array(packed_form, classifier)) return false;
00237   int len = 0;
00238   if (!structures::detach(packed_form, len)) return false;
00239   if (len > packed_form.length()) {
00240     // not enough data.
00241     continuable_error(static_class_name(), func, "failed to have enough data!");
00242     return false;
00243   }
00244   info = packed_form.subarray(0, len - 1);
00245   packed_form.zap(0, len - 1);
00246   return true;
00247 }
00248 
00249 } //namespace.
00250 
Generated on Sat Jan 28 04:22:43 2012 for hoople2 project by  doxygen 1.6.3