Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

CGIpack

by jeroenes (Priest)
on Jan 18, 2001 at 12:03 UTC ( [id://52724]=sourcecode: print w/replies, xml ) Need Help??
Category: CGI programming or Text
Author/Contact Info J. Elassaiss-Schaap
Description: CGIpack is a module I wrote in this response.

I came up with this solution. The encoder takes a list of data, together with a list with the desired number of bits to be saved. The bits are divided into chunks of 6 bits, that are encoded with the alphanumeric characters *and* % and - (64 characters in total). The resulting string is short, contains as little bits as possible and/or desired by the user.

See POD for further info.

Update:Version 0.02 has working 32 bit values now. Still pondering 64 bits.

Update2:Thanx to ChOas, I now know that perl 5.6 has another implementation of pack, *and* that 64 bits can be used only if you have a 64bit machine and 64 bit support is compiled in. I've chosen to comment that line in decode, you can uncomment it if your environment is right, otherwise there is a risk of a fatal error. Please let me know if you succesfully use 64 bits.

Wishlist:

  • Apply tye's quad for 57 bit integers
  • Add wrapper, to accomodate: characters, strings, signed integers.
package CGIpack;
use strict;

=head1 NAME

CGIpack - Transforms parameters into a packed list of URL-compatible c
+haracters
and vice versa.

=head1 SYNOPSIS

 use CGIpack;

 # Transform a list of numbers and back. 
 #Results in:
 @data=(15,13,2**23,0,2**31);
 @bitsizes = (4,14,24,1,55 );
 $encoded=encode({ bitsizes=>[@bitsizes], data=>[@data]});
 $decoded=join ', ', decode( {str=>$encoded, bitsizes=>[@bitsizes]} );
 ## only converted 32 bits instead of 55
 #Data: 15, 13, 8388608, 0, 2147483648
 #Encoded: V30000W000004000
 #Decoded array: 15, 13, 8388608, 0, 2147483648
 
=head1 DESCRIPTION

CGIpack is a module I wrote in response to a question.  Question went 
+like: 
"I want my users to save a URL containing a CGI with parameters.  To a
+void 
problems with email-readers, the list should be as short as possible, 
+and 
to avoid users messing around with the values I would like to see them
+ 
encoded in a certain way."

I came up with this solution.  The encoder takes a list of data, toget
+her 
with a list with the desired number of bits to be saved.  The bits are
+ 
divided into chunks of 6 bits, that are encoded with the alphanumeric 
characters *and* % and - (64 characters in total). The resulting strin
+g
is short, contains as little bits as possible and/or desired by the us
+er. 

=over 4

=item encode( $hashref )

Takes a hashref, which should contain a member 'data', referring to a 
+list, 
and a member 'bitsizes', referring to a list containing the number of 
desired bits for every value in the list. 

=item decode( $hashref )

Takes a hashref, which should contain a member 'str', containing a str
+ing 
of characters produced by encode (preferably, you may wanna roll your 
+own 
;-) and a member 'bitsizes', referring to a list containing the number
+ of 
desired bits for every value encoded in the string.

=back

=head1 CAVEAT

If you want to encode characters, you will have to convert them manual
+ly 
using unpack/pack 'c'.  I just may add a wrapper for that in the futur
+e, 
though.

It does work on 32 bit integers, but not yet on 64 bit. I'm a little p
+uzzled
why not, it may have something to do with the fact I'm working on a 32
+-bit
pentium right now. Will try at home with my PPC.

=head1 AUTHOR

Jeroen Elassaiss-Schaap

=head1 LICENSE

Perl/ artisitic license

=head1 STATUS

Alpha

=cut

use Exporter;
use vars qw( @EXPORT @ISA @VERSION);
@VERSION = 0.021;
@ISA = qw( Exporter );
@EXPORT = qw( &encode &decode);

sub encode{
    my $hash = shift;
    my @data = @{$hash->{'data'}};
    my @bitsizes = @{$hash->{'bitsizes'}};
    my ($str, $bitstr);
    for my $bits (@bitsizes) {
        $bitstr .= unpack("b$bits", pack('VV', shift( @data ) ));
    }
    $bitstr .= '0' x ( length($bitstr) % 6 );
     for my $item (0..( length($bitstr) / 6 - 1 )){
         my $val=pack('b6', substr($bitstr, $item*6, 6) );
         for ($val) {
             tr    [\100\077\000-\010\011-\043\044-\075]
                 [\045\055\060-\071\101-\132\141-\172];
            $str.=$_;
        }
     }
    $str;
}

sub decode{
    my $hash = shift;
    my $str = $hash->{'str'};
    my @bitsizes= @{$hash->{'bitsizes'}};
     my ($bitstr, $val);
     my @data;
    for (split //, $str){
        tr    [\045\055\060-\071\101-\132\141-\172]
            [\100\077\000-\010\011-\043\044-\075];
        $bitstr .= unpack("b6",$_); 
    }
    my $pointer = 0;
    for my $bits (@bitsizes) {
        my $val;
        for ($bits) {
            $val = unpack('c',pack("b$_",substr( $bitstr, $pointer, $_
+ ))), last
                if $bits < 9;
            $val = unpack('v',pack("b$_",substr( $bitstr, $pointer, $_
+ ))), last
                if $bits < 17;
            $val = unpack('V',pack("b32",substr( $bitstr, $pointer, $_
+ ))), last
                if $bits < 33;
            if (! eval('{$val = unpack("Q",pack("b$_",substr( '.
                    '$bitstr, $pointer, $_ )));1;}') ) {
                warn "only converted 32 bits instead of $_\n";
                $val = unpack('V',pack("b$_",
                    substr( $bitstr, $pointer, $_ )));
            }
        }
        push( @data, $val);
        $pointer += $bits;
    }
    @data;
}

1;
Replies are listed 'Best First'.
(yakko: 64bit test) Re: CGIpack
by yakko (Friar) on Jan 19, 2001 at 20:56 UTC
    Since I have access to a 64bit platform, I can at least offer a data point. Here's what I get when running the snippet in the POD on an UltraSPARC-II (a quad-way E450):

    Encoded: V30000W000004000 Decoded array: 15, 13, 8388608, 0, 549755813888

    Looks like I get to sort out {,un}pack sooner than I thought, since this now has my curiosity :o)

    (64bit OS, perl 5.6 compiled manually with 64bit ints, btw)

    --
    Me spell chucker work grate. Need grandma chicken.

Re: CGIpack
by marius (Hermit) on Jan 18, 2001 at 21:33 UTC
    Now that is the coolest use of {un}pack that I've seen yet. (Not that I personally have seen many uses for it, but this one is cool!) This is definitely going into my personal snippets.. ++jeroenes!

    -marius

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://52724]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (8)
As of 2024-04-25 11:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found