Archive for the ‘Code’ Category

Perl Snippet … Encoding/Decoding in basE91

Saturday, March 7th, 2009

Whilst conduct some research for the one of our new projects I came across the need to transfer binary information over essentially a textual (i.e. printable character) protocol. I was sure that I would have to resort to base64 encoding but stumbled across basE91. This looked like it would fit the bill and so I grabbed the code and began to dissect its operation.

The code was available in C, ASM and PHP, at base91.sourceforge.net because the new project has Perl at its core there was some tweaking that needed to occur. I’ve attached a stripped version of my basE91 functions below for anyone who wants to get a taste of it.

#!/usr/bin/perl

@enctab = (
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$',
  '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=',
  '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'
);

@dectab = (
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 62, 90, 63, 64, 65, 66, 91, 67, 68, 69, 70, 71, 91, 72, 73,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 74, 75, 76, 77, 78, 79,
  80,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 81, 91, 82, 83, 84,
  85, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 86, 87, 88, 89, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
  91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91
);

sub base91_decode
{
  ($m) = @_;

  $l = length($m);
  $v = -1;
  $o = "";
  $b = 0;
  $n = 0;

  for ($i = 0; $i < $l; $i++)
  {
    $c = $dectab[ord(substr($m, $i, 1))];
 
    next if ($c == 91);

    if ($v < 0)
    {
      $v = $c;
    }
    else
    {
      $v += $c * 91;
      $b |= $v << $n;
      $n += ($v & 8191) > 88 ? 13 : 14;
      do
      {
        $o .= chr($b & 255);
        $b >>= 8;
        $n -= 8;
      } while ($n > 7);
      $v = -1;
    }
  }

  if ($v + 1)
  {
    $o .= chr(($b | $v << $n) & 255);
  }

  return $o;
}

sub base91_encode
{
  ($m) = @_;
  $l = length($m);
  $o = "";
  $b = 0;
  $n = 0;

  for ($i = 0; $i < $l; $i++)
  {
    $b |= ord(substr($m, $i, 1)) << $n;
    $n += 8;
    if ($n > 13)
    {
      $v = $b & 8191;
      if ($v > 88)
      {
        $b >>= 13;
        $n -= 13;
      }
      else
      {
        $v = $b & 16383;
        $b >>= 14;
        $n -= 14;
      }
      $o .= $enctab[$v % 91] . $enctab[$v / 91];
    }
  }
 
  if ($n)
  {
    $o .= $enctab[$b % 91];
    if ($n > 7 || $b > 90)
    {
      $o .= $enctab[$b / 91];
    }
  }
 
  return $o;
}

$test = "This is a test string.";
$test_enc = base91_encode($test);
$test_dec = base91_decode($test_enc);

print "Test (clr): $test\n";
print "Test (enc): $test_enc\n";
print "Test (dec): $test_dec\n";