packable.cpp

Go to the documentation of this file.
00001 #ifndef PACKABLE_IMPLEMENTATION_FILE
00002 #define PACKABLE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : packable                                                          *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1995-$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 "function.h"
00019 #include "packable.h"
00020 
00021 #include <math.h>
00022 
00023 packable::~packable() {}
00024 
00025 int packable::packed_size() const { return 0; }
00026 
00027 namespace basis {
00028 
00029 // these helper functions do most of the real "work", if any.
00030 
00031 void rotate_in(byte_array &attach_into, int to_attach, int size_in_bytes)
00032 {
00033   u_int temp = u_int(to_attach);
00034   for (int i = 0; i < size_in_bytes; i++) {
00035     attach_into += byte(temp % 0x100);
00036     temp >>= 8;
00037   }
00038 }
00039 
00040 void snag_out(byte_array &eat_from, u_int &accumulator, int size_in_bytes)
00041 {
00042   accumulator = 0;
00043   for (int i = 0; i < size_in_bytes; i++) {
00044     accumulator <<= 8;
00045     accumulator += eat_from[size_in_bytes - i - 1];
00046   }
00047   eat_from.zap(0, size_in_bytes - 1);
00048 }
00049 
00051 
00052 int packed_size(byte_array &packed_form)
00053 { return 2 * sizeof(int) + packed_form.length(); }
00054 
00055 void attach(byte_array &packed_form, const byte_array &to_attach)
00056 {
00057   obscure_attach(packed_form, to_attach.length());
00058   packed_form += to_attach;
00059 }
00060 
00061 bool detach(byte_array &packed_form, byte_array &to_detach)
00062 {
00063   int len = 0;
00064   if (!obscure_detach(packed_form, len)) return false;
00065   if (packed_form.length() < len) return false;
00066   to_detach = packed_form.subarray(0, len - 1);
00067   packed_form.zap(0, len - 1);
00068   return true;
00069 }
00070 
00072 
00073 // these are the only "real" attach/detach functions on number types.  the
00074 // others are all faking it by calling these.
00075 
00076 void attach(byte_array &packed_form, u_int to_attach)
00077 { rotate_in(packed_form, to_attach, 4); }
00078 
00079 bool detach(byte_array &packed_form, u_int &to_detach)
00080 {
00081   if (packed_form.length() < 4) return false;
00082   u_int temp;
00083   snag_out(packed_form, temp, 4);
00084   to_detach = u_int(temp);
00085   return true;
00086 }
00087 
00088 void attach(byte_array &packed_form, u_short to_attach)
00089 { rotate_in(packed_form, to_attach, 2); }
00090 
00091 bool detach(byte_array &packed_form, u_short &to_detach)
00092 {
00093   if (packed_form.length() < 2) return false;
00094   u_int temp;
00095   snag_out(packed_form, temp, 2);
00096   to_detach = u_short(temp);
00097   return true;
00098 }
00099 
00100 void attach(byte_array &packed_form, byte to_attach)
00101 { packed_form += to_attach; }
00102 
00103 bool detach(byte_array &packed_form, byte &to_detach)
00104 {
00105   if (packed_form.length() < 1) return false;
00106   to_detach = packed_form[0];
00107   packed_form.zap(0, 0);
00108   return true;
00109 }
00110 
00112 
00113 void attach(byte_array &packed_form, int to_attach)
00114 { attach(packed_form, u_int(to_attach)); }
00115 
00116 bool detach(byte_array &packed_form, int &to_detach)
00117 { return detach(packed_form, (u_int &)to_detach); }
00118 
00119 void attach(byte_array &packed_form, u_long to_attach)
00120 { attach(packed_form, u_int(to_attach)); }
00121 
00122 bool detach(byte_array &packed_form, u_long &to_detach)
00123 { return detach(packed_form, (u_int &)to_detach); }
00124 
00125 void attach(byte_array &packed_form, long to_attach)
00126 { attach(packed_form, u_int(to_attach)); }
00127 
00128 bool detach(byte_array &packed_form, long &to_detach)
00129 { return detach(packed_form, (u_int &)to_detach); }
00130 
00131 void attach(byte_array &packed_form, short to_attach)
00132 { attach(packed_form, u_short(to_attach)); }
00133 
00134 bool detach(byte_array &packed_form, short &to_detach)
00135 { return detach(packed_form, (u_short &)to_detach); }
00136 
00137 void attach(byte_array &packed_form, char to_attach)
00138 { attach(packed_form, byte(to_attach)); }
00139 
00140 bool detach(byte_array &packed_form, char &to_detach)
00141 { return detach(packed_form, (byte &)to_detach); }
00142 
00143 void attach(byte_array &packed_form, bool to_attach)
00144 { attach(packed_form, byte(to_attach)); }
00145 
00146 void attach(byte_array &packed_form, const char *to_attach)
00147 {
00148   const int len = int(strlen(to_attach));
00149   const int old_pos = packed_form.last();
00150   packed_form.insert(old_pos + 1, len + 1);
00151   memory_assign((char *)packed_form.observe() + old_pos + 1, to_attach,
00152       len + 1);
00153 }
00154 
00155 bool detach(byte_array &packed_form, istring &to_detach)
00156 {
00157   if (!packed_form.length()) return false;
00158   // locate the zero termination if possible.
00159   const void *zero_posn = memchr(packed_form.observe(), '\0',
00160       packed_form.length()); 
00161   // make sure we could find the zero termination.
00162   if (!zero_posn) {
00163     // nope, never saw a zero.  good thing we checked.
00164     to_detach.reset();
00165     return false;
00166   }
00167   // set the string up using a standard constructor since we found the zero
00168   // position; we know the string constructor will be happy.
00169   to_detach = (char *)packed_form.observe();
00170   // compute the length of the string we found based on the position of the
00171   // zero character.
00172   int find_len = int((byte *)zero_posn - packed_form.observe());
00173   // whack the portion of the array that we consumed.
00174   packed_form.zap(0, find_len);
00175   return true;
00176 }
00177 
00179 
00180 // can't assume that bool is same size as byte, although it should fit
00181 // into a byte just fine.
00182 bool detach(byte_array &packed_form, bool &to_detach)
00183 {
00184   byte chomp;
00185   if (!detach(packed_form, chomp)) return false;
00186   to_detach = !!chomp;
00187   return true;
00188 }
00189 
00190 // operates on a number less than 1.0 that we need to snag the next digit
00191 // to the right of the decimal point from.
00192 inline double break_off_digit(double &input) {
00193 //printf(istring(istring::SPRINTF, "break input=%f\n", input).s());
00194   input *= 10.0;
00195 //printf(istring(istring::SPRINTF, "after mult=%f\n", input).s());
00196   double mod_part = fmod(input, 1.0);
00197 //printf(istring(istring::SPRINTF, "modded=%f\n", mod_part).s());
00198   double to_return = input - mod_part;
00199 //printf(istring(istring::SPRINTF, "to ret=%f\n", to_return).s());
00200   input -= to_return;
00201   return to_return;
00202 }
00203 
00204 void attach(byte_array &packed_form, double to_pack)
00205 {
00206   int exponent = 0;
00207   double mantissa = frexp(to_pack, &exponent);
00208   byte pos = mantissa < 0.0? false : true;
00209   mantissa = fabs(mantissa);
00210 //printf("mant=%10.10f pos=%d expon=%d\n", mantissa, int(pos), exponent);
00211   packed_form += pos;
00212   attach(packed_form, exponent);
00213   byte_array mantis;
00214   // even if the double has 52 bits for mantissa (where ms docs say 44),
00215   // a 16 digit bcd encoded number should handle the size (based on size of
00216   // 2^52 in digits).
00217   for (int i = 0; i < 9; i++) {
00218     double dig1 = break_off_digit(mantissa);
00219 //printf(istring(istring::SPRINTF, "break digit=%d\n", int(dig1)).s());
00220     double dig2 = break_off_digit(mantissa);
00221 //printf(istring(istring::SPRINTF, "break digit=%d\n", int(dig2)).s());
00222     mantis += byte(dig1 * 16 + dig2);
00223   }
00224   attach(packed_form, mantis);
00225 //printf("attach exit\n");
00226 }
00227 
00228 bool detach(byte_array &packed_form, double &to_unpack)
00229 {
00230 //printf("detach entry\n");
00231   if (packed_form.length() < 1) return false;  // no sign byte.
00232   byte pos = packed_form[0];
00233 //printf(istring(istring::SPRINTF, "pos=%d\n", int(pos)).s());
00234   packed_form.zap(0, 0);
00235   int exponent;
00236   if (!detach(packed_form, exponent)) return false;
00237 //printf(istring(istring::SPRINTF, "expon=%d\n", exponent).s());
00238   byte_array mantis;
00239   if (!detach(packed_form, mantis)) return false;
00240   double mantissa = 0;
00241   for (int i = mantis.last(); i >= 0; i--) {
00242     byte chop = mantis[i];
00243     double dig1 = chop / 16;
00244 //printf(istring(istring::SPRINTF, "break digit=%d\n", int(dig1)).s());
00245     double dig2 = chop % 16;
00246 //printf(istring(istring::SPRINTF, "break digit=%d\n", int(dig2)).s());
00247     mantissa += dig2;
00248     mantissa /= 10;
00249     mantissa += dig1;
00250     mantissa /= 10;
00251   }
00252 //printf(istring(istring::SPRINTF, "mant=%10.10f\n", mantissa).s());
00253   to_unpack = ldexp(mantissa, exponent);
00254   if (!pos) to_unpack = -1.0 * to_unpack;
00255 //printf("pos=%d\n", int(pos));
00256 //printf(istring(istring::SPRINTF, "to_unpack=%f\n", to_unpack).s());
00257 //printf("detach exit\n");
00258   return true;
00259 }
00260 
00261 void attach(byte_array &packed_form, float to_pack)
00262 { attach(packed_form, double(to_pack)); }
00263 
00264 bool detach(byte_array &packed_form, float &to_unpack)
00265 {
00266   double real_unpack;
00267   bool to_return = detach(packed_form, real_unpack);
00268   to_unpack = (float)real_unpack;
00269   return to_return;
00270 }
00271 
00273 
00274 void obscure_attach(byte_array &packed_form, int to_attach)
00275 {
00276 //printf("initial value=%x\n", to_attach);
00277   u_int first_part = 0xfade0000;
00278 //printf("first part curr=%x\n", first_part);
00279   u_int second_part = 0x0000ce0f;
00280 //printf("second part curr=%x\n", second_part);
00281   first_part = first_part | (to_attach & 0x0000ffff);
00282 //printf("first part now=%x\n", first_part);
00283   second_part = second_part | (to_attach & 0xffff0000);
00284 //printf("second part now=%x\n", second_part);
00285   attach(packed_form, first_part);
00286   attach(packed_form, second_part);
00287 }
00288 
00289 bool obscure_detach(byte_array &packed_form, int &to_detach)
00290 {
00291   u_int first_part;
00292   u_int second_part;
00293   if (!detach(packed_form, first_part)) return false;
00294   if (!detach(packed_form, second_part)) return false;
00295 //printf("first part after unpack=%x\n", first_part);
00296 //printf("second part after unpack=%x\n", second_part);
00297   if (u_int(first_part & 0xffff0000) != u_int(0xfade0000)) return false;
00298 //printf("first part with and=%x\n", first_part & 0xffff0000);
00299   if (u_int(second_part & 0x0000ffff) != u_int(0x0000ce0f)) return false;
00300 //printf("second part with and=%x\n", second_part & 0x0000ffff);
00301   to_detach = int( (second_part & 0xffff0000) + (first_part & 0x0000ffff) );
00302 //printf("final result=%x\n", to_detach);
00303   return true;
00304 }
00305 
00307 
00308 } // namespace
00309 
00310 
00311 #endif //PACKABLE_IMPLEMENTATION_FILE
00312 

Generated on Sat Aug 30 04:31:42 2008 for HOOPLE Libraries by  doxygen 1.5.1