Article 6750 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:6750
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!pipex!uunet!psgrain!ee.und.ac.za!tplinfm
From: barrett@lucy.ee.und.ac.za (Alan Barrett)
Newsgroups: comp.lang.perl
Subject: MIME encoding/decoding in perl
Date: 13 Oct 1993 15:46:46 +0200
Organization: Elec. Eng., Univ. Natal, Durban, S. Africa
Lines: 63
Message-ID: <29h0s6$sgu@lucy.ee.und.ac.za>
NNTP-Posting-Host: lucy.ee.und.ac.za

Here's a base64 decoder.  It uses pack/unpack with the 'B*' format to
do much of the work.  (Larry, any chance of direct support for the MIME
base64 and quoted-printable encodings in pack/unpack?  We have uuencode
already...)

--apb
Alan Barrett, Dept. of Electronic Eng., Univ. of Natal, Durban, South Africa
RFC822: barrett@ee.und.ac.za

#!/usr/bin/perl
# b64decode -- decode a raw BASE64 message
# A P Barrett, October 1993

# usage: b64decode [files]

# Input is read from stdin or from the named files.  Each named file
# is processed separately.  The input should be raw base64-encoded data,
# without any heades, trailers or other junk (so remove that first,
# before using b64decode).  See RFC-1341 for the definition of
# base64 encoding.
# Output is the decoded message, and is sent to stdout with 8 data bits
# per output character.

# The present implementation is horribly inefficient.

$base64alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
                  'abcdefghijklmnopqrstuvwxyz'.
                  '0123456789+/'; # and '='
$base64pad = '=';

$leftover = '';
while (<>) {
    # ignore illegal characters
    s/[^$base64alphabet]//go;
    # insert the leftover stuff from last time
    $_ = $leftover . $_;
    # if there are not a multiple of 4 bytes, keep the leftovers for later
    m/^((....)*)/; $_=$&; $leftover=$';
    # turn each group of 4 values into 3 bytes
    s/(....)/&b64decodesub($1)/eg;
    # special processing at EOF for last few bytes
    if (eof) {
	$_ .= &b64decodesub($leftover); $leftover = '';
    }
    # output it
    print $_;
}

# b64decodesub -- takes some characters in the base64 alphabet and
# returns the raw bytes that they represent.
sub b64decodesub
{
    local ($_) = @_[0];

    # translate each char to a value in the range 0 to 63
    eval qq{ tr!$base64alphabet!\0-\77!; };
    # keep 6 bits out of every 8, and pack them together
    $_ = unpack('B*', $_); # look at the bits
    s/(..)(......)/$2/g;   # keep 6 bits of every 8
    s/((........)*)(.*)/$1/; # throw away spare bits (not multiple of 8)
    $_ = pack('B*', $_);   # turn the bits back into bytes
    $_; # return
}


