infoton.cpp

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

Generated on Fri Aug 29 04:28:59 2008 for HOOPLE Libraries by  doxygen 1.5.1