Goto: [ Program Documentation ]

//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Jan 13 08:31:19 PST 1999
// Last Modified: Wed Jan 13 08:31:19 PST 1999
// Filename:      ...improv/doc/examples/improv/vlv/vlv.cpp
// Syntax:        C++; improv
// $Smake:        g++ -O3 -o ../bin/%b -I../include %f -L../lib %
//		     -limprov && strip %b
//
// Description:   Takes Variable Length Values and returns them as
//                the correct value or vice-versa
//

#include "Options.h"
#include <stdlib.h>

#ifndef OLDCPP
   #include <iostream>
   #include <iomanip>
   using namespace std;
#else
   #include <iostream.h>
   #include <iomanip.h>
#endif

#define DECODE 0
#define ENCODE 1

// Global variables for command-line options.
Options  options;            // for command-line processing
int      direction = DECODE; // decoding=0, encoding=1
int      inputStyle = 16;    // number base of the input (2, 10, or 16)
int      outputStyle = 16;   // number base of the output (2, 10, or 16) 
int      inCount = 0;        // number of command line input numbers
int*     input = NULL;       // storage of input numbers;


// function declarations:
void checkOptions(Options& opts);
void displayVLV(int number, ostream& out);
void example(void);
void printbinary(int number, ostream& out);
void usage(const char* command);


///////////////////////////////////////////////////////////////////////////


int main(int argc, char** argv) {
   options.setOptions(argc, argv);
   checkOptions(options);

   if (direction == DECODE) {    // decoding
      unsigned long output = 0;
      for (int i=0; i<inCount; i++) {
         output = output << 7;
         output |= input[i] & 0x7f;
      }
      
      switch (outputStyle) {
         case 2:
            printbinary(output, cout);
            cout << endl;
            break;
         case 16:
            cout << hex << output << endl;
            break;
         default: cout << dec << output << endl;
      }

   } else {                 // encoding
      displayVLV(input[0], cout);
      cout << endl;
   }

   if (input != NULL)   delete [] input;
   return 0;
}

///////////////////////////////////////////////////////////////////////////
   

//////////////////////////////
//
// checkOptions --
//

void checkOptions(Options& opts) {    
   opts.define("2|bin=b");            //    boolean for binary input
   opts.define("d|dec=b");            //    boolean for decimal input
   opts.define("b=b");                //    boolean for binary output
   opts.define("c=b");                //    boolean for decimal output
   opts.define("x|hex=b");            //    boolean for hex output
   opts.define("author=b");
   opts.define("version=b");
   opts.define("example=b");
   opts.define("h|help=b");
   opts.process();

   if (opts.getBoolean("author")) {
      cout << "Written by Craig Stuart Sapp, "
              "craig@ccrma.stanford.edu, January 1999" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << "vlv, version 1.0 (14 Jan 1999)\n"
              "compiled: " << __DATE__ << endl;
      exit(0);
   } else if (opts.getBoolean("help")) {
      usage(opts.getCommand());
      exit(0);
   } else if (opts.getBoolean("example")) {
      example();
      exit(0);
   }

   // determine input style (the default is 16)
   if (opts.getBoolean("2")) {
      inputStyle = 2;
   } else if (opts.getBoolean("d")) {
      inputStyle = 10;
   } else {
      inputStyle = 16;
   }
 
   // determine output style (the default is the input style)
   if (opts.getBoolean("b")) {
      outputStyle = 2;
   } else if (opts.getBoolean("x")) {
      outputStyle = 16;
   } else if (opts.getBoolean("c")) {
      outputStyle = 10;
   } else {
      outputStyle = inputStyle;
   }

   if (opts.getArgCount() == 0) {
      usage(opts.getCommand());
      exit(1);
   } else if (opts.getArgCount() == 1) {     // encoding into VLV values
      direction = ENCODE; 
   } else {                                  // decoding from VLV values
      direction = DECODE;
   }

   // process the input numbers:

   inCount = opts.getArgCount();

   if (inCount > 4) {
      cout << "Error: VLV values cannot have more than four bytes" << endl;
      exit(1);
   }

   if (input != NULL)   delete [] input;
   input = new int[inCount];

   for (int i=1; i<=opts.getArgCount(); i++) {
      input[i-1] = strtol(opts.getArg(i), NULL, inputStyle);
 
      if (direction == DECODE && i != inCount) {
         if (input[i-1] < 0x80 || input[i-1] > 255) {
            cout << "Invalid VLV byte: " << opts.getArg(i) << endl;
            exit(1);
         }
      } else if (direction == DECODE && i == inCount) {
         if (input[i-1] < 0 || input[i-1] >0x7f) {
            cout << "Invalid VLV byte: " << opts.getArg(i) << endl;
            exit(1);
         }
      }

   }
}


//////////////////////////////
//
// displayVLV -- prints the number in VLV form
//

void displayVLV(int number, ostream& out) {
   unsigned long value = (unsigned long)number;

   if (value >= (1 << 28)) {
      cout << "Error: number too large to handle" << endl; 
      exit(1);
   }
  
   unsigned long byte[4];
   byte[0] = (value >> 21) & 0x7f;
   byte[1] = (value >> 14) & 0x7f;
   byte[2] = (value >>  7) & 0x7f;
   byte[3] = (value >>  0) & 0x7f;

   int i;
   int flag = 0;
   for (i=0; i<3; i++) {
      if (byte[i] != 0) {
         flag = 1;
      }
      if (flag) {
         byte[i] |= 0x80;
      }
   }

   for (i=0; i<4; i++) {
      if (byte[i] >= 0x80 || i == 3) {
         switch (outputStyle) {
            case 2:   printbinary(byte[i], out);   break;
            case 16:  out << hex << byte[i];       break;
            default:  out << dec << byte[i];    
         }
         if (i != 3) {
            cout << ' ';
         }
      }
   }
}
            


//////////////////////////////
//
// example -- shows various command-line option calls to program.
//

void example(void) {
   cout << 
   "\n"
   "# convert a hex number to VLV bytes:\n" 
   "vlv 3fff\n"
   "\n"
   "# convert a hex number to VLV bytes in decimal notation:\n" 
   "vlv -c 3fff\n"
   "\n"
   "# convert a decimal number to VLV bytes in decimal notation:\n" 
   "vlv -d -c 54632\n"
   "\n"
   "# convert hex VLV bytes into hex number:\n" 
   "vlv 81 80 F4 00\n"
   "\n"
   "# convert hex VLV bytes into dec number:\n" 
   "vlv -c 81 80 F4 00\n"
   "\n"
   << endl;
}



//////////////////////////////
//
// printbinary -- prints the number in binary form with no
//    leading zeros.
//

void printbinary(int number, ostream& out) {
   unsigned long value = (unsigned long) number;
   int flag = 0;

   for (int i=0; i<32; i++) {
      if (value & (1 << (31-i))) {
         flag = 1;
      }
      
      if (flag) {
         if (value & (1 << (31-i))) {
            out << '1';
         } else {
            out << '0';
         }
      }
   }

   if (flag == 0) {
      out << '0';
   }
}




//////////////////////////////
//
// usage -- how to run this program from the command-line.
//

void usage(const char* command) {
   cout << 
   "\n"
   "Convert/Create Variable Length Values.\n"
   "\n"
   "Usage: " << command << " [-d|-2] [-x|-c|-b] number(s)\n"
   "\n"
   "Options:\n"
   "   -d = input numbers are given in decimal notation (hex is default)\n"
   "   -2 = input numbers are given in binary notation (hex is default)\n"
   "   -b = output numbers are given in binary notation\n" 
   "   -c = output numbers are given in decimal notation\n" 
   "   -x = output numbers are given in hexadecimal notation\n" 
   "   --options = list all options, default values, and aliases\n"
   "\n"
   << endl;
}



// md5sum: 9ab1bf95badc70d153294b2125c4ee7f vlv.cpp [20050403]