byte_formatter.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : byte_formatter                                                    *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 1992-$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 "byte_formatter.h"
00016 #include "parser_bits.h"
00017 #include "string_manipulation.h"
00018 
00019 #include <basis/functions.h>
00020 #include <structures/bit_vector.h>
00021 #include <structures/string_array.h>
00022 
00023 //#define DEBUG_BYTE_FORMAT
00024   // uncomment for noisier version.
00025 
00026 #undef LOG
00027 #ifdef DEBUG_BYTE_FORMAT
00028   #define LOG(s) printf("%s\n", astring(s).s())
00029 #else
00030   #define LOG(s) {}
00031 #endif
00032 
00033 #define LINE_SIZE 80
00034 
00035 using namespace basis;
00036 using namespace structures;
00037 
00038 namespace textual {
00039 
00040 void byte_formatter::print_char(abyte to_print, astring &out, char replace)
00041 {
00042   int temp = to_print % 128;
00043   if (!parser_bits::is_printable_ascii(to_print)) out += replace;
00044   else out += char(temp);
00045 }
00046 
00047 void byte_formatter::print_chars(const abyte *to_print, int len, astring &out, char replace)
00048 {
00049   for (int i = 0; i < len; i++)
00050     print_char(to_print[i], out, replace);
00051 }
00052 
00053 void byte_formatter::make_eight(basis::un_int num, astring &out)
00054 {
00055   basis::un_int thresh = 0x10000000;
00056   while (thresh >= 0x10) {
00057     if (num < thresh)
00058       out += '0';
00059     thresh >>= 4;  // zap a nibble.
00060   }
00061 }
00062 
00063 astring byte_formatter::text_dump(const abyte *location, basis::un_int length, basis::un_int label,
00064     const char *eol)
00065 {
00066   astring to_return;
00067   text_dump(to_return, location, length, label, eol);
00068   return to_return;
00069 }
00070 
00071 void byte_formatter::text_dump(astring &output, const byte_array &to_dump, basis::un_int label,
00072     const char *eol)
00073 {
00074   text_dump(output, to_dump.observe(), to_dump.length(), label, eol);
00075 }
00076 
00077 astring byte_formatter::text_dump(const byte_array &to_dump, basis::un_int label, const char *eol)
00078 {
00079   astring output;
00080   text_dump(output, to_dump.observe(), to_dump.length(), label, eol);
00081   return output;
00082 }
00083 
00084 // this is the real version of text_dump.  all the others use it.
00085 void byte_formatter::text_dump(astring &to_return, const abyte *location, basis::un_int length,
00086     basis::un_int label, const char *eol)
00087 {
00088   to_return = "";
00089   int entry_size = 4;
00090   int preamble = 14;
00091 
00092   basis::un_int entries_per_line = (LINE_SIZE - preamble) / entry_size;
00093 
00094   for (basis::un_int i = 0; i < length; i += entries_per_line) {
00095     make_eight(i + label, to_return);
00096     to_return += astring(astring::SPRINTF, "%x", i + label) + astring(" | ");
00097     for (basis::un_int j = 0; j < entries_per_line; j++) {
00098       if (i + j >= length) {
00099         // if at the end of the loop, just print spaces.
00100         to_return += "   ";
00101       } else {
00102         int ord_of_current_char = *(location + i + j) & 0xFF;
00103         if (ord_of_current_char < 0x10) to_return += '0';
00104         to_return += astring(astring::SPRINTF, "%x", int(ord_of_current_char));
00105         to_return += ' ';
00106       }
00107     }
00108 
00109     to_return += "| ";
00110     for (basis::un_int k = i; k < i + entries_per_line; k++) {
00111       if (k >= length) to_return += ' ';
00112         // if past the end of the block, just add spaces.
00113       else print_char(*(location + k), to_return);
00114     }
00115     to_return += astring(" |") + eol;
00116   }
00117 }
00118 
00119 void byte_formatter::parse_dump(const astring &dumped_form, byte_array &bytes_found)
00120 {
00121   bytes_found.reset();
00122   string_array lines_found;
00123   // iterate over the string and break it up into lines.
00124   for (int i = 0; i < dumped_form.length(); i++) {
00125     int indy = dumped_form.find('\n', i);
00126 //hmmm: not platform invariant.  what about '\r' if we see it?
00127 
00128     if (negative(indy)) {
00129       // no more lines found.
00130       if (i < dumped_form.length() - 1) {
00131         // grab the last bit as a line.
00132         lines_found += dumped_form.substring(i, dumped_form.length() - 1);
00133       }
00134       break;
00135     }
00136     // found a normal line ending, so drop everything from the current
00137     // position up to the ending into the list of strings.
00138     lines_found += dumped_form.substring(i, indy - 1);
00139     i = indy + 1;  // jump to next potential line.
00140   }
00141   // now process the lines that we've found.
00142   for (int j = 0; j < lines_found.length(); j++) {
00143     // first step is to find the pipe character that brackets the actual
00144     // data.  we ignore the "address" located before the pipe.
00145     astring &s = lines_found[j];
00146     int bar_one = s.find('|', 0);
00147     if (negative(bar_one)) continue;  // skip this one; it's malformed.
00148     // now we look for the second pipe that comes before the text form of
00149     // the data.  we don't care about the text or anything after.
00150     int bar_two = s.find('|', bar_one + 1);
00151     if (negative(bar_two)) continue;  // skip for same reason.
00152     astring s2 = s.substring(bar_one + 1, bar_two - 1);
00153     byte_array this_part;
00154     string_to_bytes(s2, this_part);
00155     bytes_found += this_part;
00156   }
00157 }
00158 
00160 
00161 void byte_formatter::bytes_to_string(const abyte *to_convert, int length, astring &as_string,
00162     bool space_delimited)
00163 {
00164   if (!to_convert || !length) return;  // nothing to do.
00165   if (negative(length)) return;  // bunk.
00166   as_string = "";  // reset the output parameter.
00167 
00168   // the pattern is used for printing the bytes and considering the delimiter.
00169   astring pattern("%02x");
00170   if (space_delimited) pattern += " ";
00171 
00172   // now zip through the array and dump it into the string.
00173   for (int i = 0; i < length; i++)
00174     as_string += astring(astring::SPRINTF, pattern.s(), to_convert[i]);
00175 }
00176 
00177 // returns true if the character is within the valid ranges of hexadecimal
00178 // nibbles (as text).
00179 bool byte_formatter::in_hex_range(char to_check)
00180 //hmmm: move this to parser bits.
00181 {
00182   return ( (to_check <= '9') && (to_check >= '0') )
00183       || ( (to_check <= 'f') && (to_check >= 'a') )
00184       || ( (to_check <= 'F') && (to_check >= 'A') );
00185 }
00186 
00187 void byte_formatter::string_to_bytes(const char *to_convert, byte_array &as_array)
00188 {
00189   as_array.reset();  // clear the array.
00190   const int len = int(strlen(to_convert));
00191 
00192   // the parser uses a simple state machine for processing the string.
00193   enum states { FINDING_HEX, IGNORING_JUNK };
00194   states state = IGNORING_JUNK;
00195 
00196   int digits = 0;  // the number of digits we've currently found.
00197   int accumulator = 0;  // the current hex duo.
00198 
00199   // loop through the string.
00200   for (int i = 0; i < len; i++) {
00201     switch (state) {
00202       case IGNORING_JUNK: {
00203         if (in_hex_range(to_convert[i])) {
00204           i--;  // skip back to where we were before now.
00205           state = FINDING_HEX;
00206           continue;  // jump to the other state.
00207         }
00208         // otherwise, we could care less what the character is.
00209         break;
00210       }
00211       case FINDING_HEX: {
00212         if (digits >= 2) {
00213           // we have finished a hex byte.
00214           as_array += abyte(accumulator);
00215           accumulator = 0;
00216           digits = 0;
00217           i--;  // skip back for the byte we haven't eaten yet.
00218           state = IGNORING_JUNK;  // jump to other state for a new item.
00219           continue;
00220         }
00221         // we really think this is a digit here and we're not through with
00222         // accumulating them.
00223         accumulator <<= 4;
00224         digits++;
00225         accumulator += string_manipulation::char_to_hex(to_convert[i]);
00226 
00227         // now we sneakily check the next character.
00228         if (!in_hex_range(to_convert[i+1])) {
00229           // we now know we should not be in this state for long.
00230           if (digits) {
00231             // there's still some undigested stuff.
00232             digits = 2;  // fake a finished byte.
00233             continue;  // keep going, but eat the character we were at.
00234           }
00235           // well, there's nothing lost if we just jump to that state.
00236           state = IGNORING_JUNK;
00237           continue;
00238         }
00239         break;
00240       }
00241     }
00242   }
00243   if (digits) {
00244     // snag the last unfinished bit.
00245     as_array += abyte(accumulator);
00246   }
00247 }
00248 
00249 void byte_formatter::bytes_to_string(const byte_array &to_convert, astring &as_string,
00250     bool space_delimited)
00251 {
00252   bytes_to_string(to_convert.observe(), to_convert.length(), as_string,
00253       space_delimited);
00254 }
00255 
00256 void byte_formatter::string_to_bytes(const astring &to_convert, byte_array &as_array)
00257 { string_to_bytes(to_convert.s(), as_array); }
00258 
00259 void byte_formatter::bytes_to_shifted_string(const byte_array &to_convert, astring &as_string)
00260 {
00261 #ifdef DEBUG_BYTE_FORMAT
00262   FUNCDEF("bytes_to_shifted_string");
00263 #endif
00264   bit_vector splitter(8 * to_convert.length(), to_convert.observe());
00265   int i;  // track our current position.
00266   for (i = 0; i < splitter.bits(); i += 7) {
00267     abyte curr = 1;  // start with a bit set already.
00268     for (int j = i; j < i + 7; j++) {
00269       curr <<= 1;  // move to the left.
00270       if (j < splitter.bits())
00271         curr |= abyte(splitter.on(j));  // or in the current position.
00272     }
00273     as_string += char(curr);
00274   }
00275 #ifdef DEBUG_BYTE_FORMAT
00276   LOG(a_sprintf("%d bytes comes out as %d char string.",
00277       to_convert.length(), as_string.length()).s());
00278 #endif
00279 }
00280 
00281 void byte_formatter::shifted_string_to_bytes(const astring &to_convert, byte_array &as_array)
00282 {
00283 #ifdef DEBUG_BYTE_FORMAT
00284   FUNCDEF("shifted_string_to_bytes");
00285 #endif
00286   bit_vector accumulator;
00287 
00288   for (int i = 0; i < to_convert.length(); i++) {
00289     abyte current = abyte(to_convert[i]) & 0x7F;
00290       // get the current bits but remove the faux sign bit.
00291     accumulator.resize(accumulator.bits() + 7);
00292     // now shift off the individual pieces.
00293     for (int j = 0; j < 7; j++) {
00294       // get current bit's value.
00295       current <<= 1;  // shift it up.
00296       abyte set_here = current & 0x80;  // test the highest order bit.
00297       // now flip that bit on or off based on what we saw.
00298       accumulator.set_bit(i * 7 + j, bool(set_here));
00299     }
00300   }
00301 
00302   int remainder = accumulator.bits() % 8;
00303   accumulator.resize(accumulator.bits() - remainder);
00304     // chop off any extraneous bits that are due to our shifting.
00305 
00306 #ifdef DEBUG_BYTE_FORMAT
00307   // there should be no remainder.  and the number of bits should be a multiple
00308   // of eight now.
00309   if (accumulator.bits() % 8)
00310     deadly_error("byte_formatter", func, "number of bits is erroneous.");
00311 #endif
00312 
00313   const byte_array &accumref = accumulator;
00314   for (int q = 0; q < accumulator.bits() / 8; q++)
00315     as_array += accumref[q];
00316 
00317 #ifdef DEBUG_BYTE_FORMAT
00318   LOG(a_sprintf("%d chars comes out as %d bytes.",
00319       to_convert.length(), as_array.length()).s());
00320 #endif
00321 }
00322 
00323 } // namespace
00324 
Generated on Sat Jan 28 04:22:33 2012 for hoople2 project by  doxygen 1.6.3