base32_c.tcl

Go to the documentation of this file.
00001 /*  base32c.tcl --*/
00002 /* */
00003 /*        Implementation of a base32 (std) de/encoder for Tcl.*/
00004 /* */
00005 /*  Public domain*/
00006 /* */
00007 /*  RCS: @(#) $Id: base32_c.tcl,v 1.2 2006/05/28 04:29:09 andreas_kupries Exp $*/
00008 
00009 package require critcl
00010 package require Tcl 8.4
00011 
00012 namespace ::base32 {
00013     /*  Supporting code for the main command.*/
00014     catch {
00015     critcl::cheaders -g
00016     critcl::debug memory symbols
00017     }
00018 
00019     /*  Main commands, encoder & decoder*/
00020 
00021     critcl::ccommand critcl_encode {dummy interp objc objv} {
00022       /* Syntax -*- c -*-
00023        * critcl_encode string
00024        */
00025 
00026       unsigned char* buf;
00027       int           nbuf;
00028 
00029       unsigned char* out;
00030       unsigned char* at;
00031       int           nout;
00032 
00033       /*
00034        * The array used for encoding
00035        */                     /* 123456789 123456789 123456789 12 */
00036       static const char map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
00037 
00038 /* define USAGEE "bitstring"*/
00039 
00040       if (objc != 2) {
00041         Tcl_WrongNumArgs (interp, 1, objv, USAGEE);
00042         return TCL_ERROR;
00043       }
00044 
00045       buf  = Tcl_GetByteArrayFromObj (objv[1], &nbuf);
00046       nout = ((nbuf+4)/5)*8;
00047       out  = (unsigned char*) Tcl_Alloc (nout*sizeof(char));
00048 
00049       for (at = out; nbuf >= 5; nbuf -= 5, buf += 5) {
00050     *(at++) = map [         (buf[0]>>3)                ];
00051     *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ];
00052     *(at++) = map [ 0x1f &  (buf[1]>>1)                ];
00053     *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ];
00054     *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ];
00055     *(at++) = map [ 0x1f &  (buf[3]>>2)                ];
00056     *(at++) = map [ 0x1f & ((buf[3]<<3) | (buf[4]>>5)) ];
00057     *(at++) = map [ 0x1f &  (buf[4])                   ];
00058       }
00059       if (nbuf > 0) {
00060     /* Process partials at end. */
00061     switch (nbuf) {
00062     case 1:
00063       /* |01234567|      2, padding 6
00064        *  xxxxx
00065        *       xxx 00
00066        */
00067 
00068       *(at++) = map [        (buf[0]>>3) ];
00069       *(at++) = map [ 0x1f & (buf[0]<<2) ];
00070       *(at++) = '=';
00071       *(at++) = '=';
00072       *(at++) = '=';
00073       *(at++) = '=';
00074       *(at++) = '=';
00075       *(at++) = '=';
00076       break;
00077     case 2: /* x3/=4 */
00078       /* |01234567|01234567|     4, padding 4
00079        *  xxxxx
00080        *       xxx xx
00081        *             xxxxx
00082        *                  x 0000
00083        */
00084 
00085       *(at++) = map [         (buf[0]>>3)                ];
00086       *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ];
00087       *(at++) = map [ 0x1f &  (buf[1]>>1)                ];
00088       *(at++) = map [ 0x1f &  (buf[1]<<4)                ];
00089       *(at++) = '=';
00090       *(at++) = '=';
00091       *(at++) = '=';
00092       *(at++) = '=';
00093       break;
00094     case 3:
00095       /* |01234567|01234567|01234567|    5, padding 3
00096        *  xxxxx
00097        *       xxx xx
00098        *             xxxxx
00099        *                  x xxxx
00100        *                        xxxx 0
00101        */
00102 
00103       *(at++) = map [         (buf[0]>>3)                ];
00104       *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ];
00105       *(at++) = map [ 0x1f &  (buf[1]>>1)                ];
00106       *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ];
00107       *(at++) = map [ 0x1f &  (buf[2]<<1)                ];
00108       *(at++) = '=';
00109       *(at++) = '=';
00110       *(at++) = '=';
00111       break;
00112     case 4:
00113       /* |01234567|01234567|01234567|012334567|  7, padding 1
00114        *  xxxxx
00115        *       xxx xx
00116        *             xxxxx
00117        *                  x xxxx
00118        *                        xxxx
00119        *                             xxxxx
00120        *                                  xxxx 0
00121        */
00122 
00123       *(at++) = map [         (buf[0]>>3)                ];
00124       *(at++) = map [ 0x1f & ((buf[0]<<2) | (buf[1]>>6)) ];
00125       *(at++) = map [ 0x1f &  (buf[1]>>1)                ];
00126       *(at++) = map [ 0x1f & ((buf[1]<<4) | (buf[2]>>4)) ];
00127       *(at++) = map [ 0x1f & ((buf[2]<<1) | (buf[3]>>7)) ];
00128       *(at++) = map [ 0x1f &  (buf[3]>>2)                ];
00129       *(at++) = map [ 0x1f &  (buf[3]<<3)                ];
00130       *(at++) = '=';
00131       break;
00132     }
00133       }
00134 
00135       Tcl_SetObjResult (interp, Tcl_NewStringObj (out, nout));
00136       Tcl_Free ((char*) out);
00137       return TCL_OK;
00138     }
00139 
00140 
00141     critcl::ccommand critcl_decode {dummy interp objc objv} {
00142       /* Syntax -*- c -*-
00143        * critcl_decode estring
00144        */
00145 
00146       unsigned char* buf;
00147       int           nbuf;
00148 
00149       unsigned char* out;
00150       unsigned char* at;
00151       unsigned char  x [8];
00152       int           nout;
00153 
00154       int i, j, a, pad, nx;
00155 
00156       /*
00157        * An array for translating single base-32 characters into a value.
00158        * Disallowed input characters have a value of 64.  Upper and lower
00159        * case is the same. Only 128 chars, as everything above char(127)
00160        * is 64.
00161        */
00162       static const char map [] = {
00163     /* \00 */ 64, 64, 64, 64, 64, 64, 64, 64,  64, 64, 64, 64, 64, 64, 64, 64, 
00164     /* DLE */ 64, 64, 64, 64, 64, 64, 64, 64,  64, 64, 64, 64, 64, 64, 64, 64, 
00165     /* SPC */ 64, 64, 64, 64, 64, 64, 64, 64,  64, 64, 64, 64, 64, 64, 64, 64, 
00166     /* '0' */ 64, 64, 26, 27, 28, 29, 30, 31,  64, 64, 64, 64, 64, 64, 64, 64, 
00167     /* '@' */ 64,  0,  1,  2,  3,  4,  5,  6,   7,  8,  9, 10, 11, 12, 13, 14,
00168     /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22,  23, 24, 25, 64, 64, 64, 64, 64,
00169     /* '`' */ 64,  0,  1,  2,  3,  4,  5,  6,   7,  8,  9, 10, 11, 12, 13, 14,
00170     /* 'p' */ 15, 16, 17, 18, 19, 20, 21, 22,  23, 24, 25, 64, 64, 64, 64, 64
00171       };
00172 
00173 /* define USAGED "estring"*/
00174 
00175       if (objc != 2) {
00176         Tcl_WrongNumArgs (interp, 1, objv, USAGED);
00177         return TCL_ERROR;
00178       }
00179 
00180       buf = Tcl_GetStringFromObj (objv[1], &nbuf);
00181 
00182       if (nbuf % 8) {
00183     Tcl_SetObjResult (interp, Tcl_NewStringObj ("Length is not a multiple of 8", -1));
00184         return TCL_ERROR;
00185       }
00186 
00187       nout = (nbuf/8)*5 *TCL_UTF_MAX;
00188       out  = (unsigned char*) Tcl_Alloc (nout*sizeof(char));
00189 
00190 /* define HIGH(x) (((x) & 0x80) != 0)*/
00191 /* define BADC(x) ((x) == 64)*/
00192 /* define BADCHAR(a,j) (HIGH ((a)) || BADC (x [(j)] = map [(a)]))*/
00193 
00194       for (pad = 0, i=0, at = out; i < nbuf; i += 8, buf += 8){
00195     for (j=0; j < 8; j++){
00196       a = buf [j];
00197 
00198       if (a == '=') {
00199         x[j] = 0;
00200         pad++;
00201         continue;
00202       } else if (pad) {
00203         char     msg [120];
00204         sprintf (msg,
00205              "Invalid character at index %d: \"=\" (padding found in the middle of the input)",
00206              j-1);
00207         Tcl_Free ((char*) out);
00208         Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1));
00209         return TCL_ERROR;
00210       }
00211 
00212       if (BADCHAR (a,j)) {
00213         char     msg [100];
00214         sprintf (msg,"Invalid character at index %d: \"%c\"",j,a);
00215         Tcl_Free ((char*) out);
00216         Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1));
00217         return TCL_ERROR;
00218       }
00219     }
00220 
00221     *(at++) = (x[0]<<3) | (x[1]>>2)            ;
00222     *(at++) = (x[1]<<6) | (x[2]<<1) | (x[3]>>4);
00223     *(at++) = (x[3]<<4) | (x[4]>>1)            ;
00224     *(at++) = (x[4]<<7) | (x[5]<<2) | (x[6]>>3);
00225     *(at++) = (x[6]<<5) | x[7]                 ;
00226       }
00227 
00228       if (pad) {
00229     if (pad == 1) {
00230       at -= 1;
00231     } else if (pad == 3) {
00232       at -= 2;
00233     } else if (pad == 4) {
00234       at -= 3;
00235     } else if (pad == 6) {
00236       at -= 4;
00237     } else {
00238       char     msg [100];
00239       sprintf (msg,"Invalid padding of length %d",pad);
00240       Tcl_Free ((char*) out);
00241       Tcl_SetObjResult (interp, Tcl_NewStringObj (msg, -1));
00242       return TCL_ERROR;
00243     }
00244       }
00245 
00246       Tcl_SetObjResult (interp, Tcl_NewByteArrayObj (out, at-out));
00247       Tcl_Free ((char*) out);
00248       return TCL_OK;
00249     }
00250 }
00251 
00252 /*  ### ### ### ######### ######### #########*/
00253 /*  Ready*/
00254 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1