5773069 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n base64.c
  1 /* base64 contains the needed support for base64 alphabet system, */
  2 /* as described in RFC1521 */
  3 /*
  4 Copyright 2003,04 Aris Adamantiadis
  5 
  6 This file is part of the SSH Library
  7 
  8 The SSH Library is free software; you can redistribute it and/or modify
  9 it under the terms of the GNU Lesser General Public License as published by
 10 the Free Software Foundation; either version 2.1 of the License, or (at your
 11 option) any later version.
 12 
 13 The SSH Library is distributed in the hope that it will be useful, but
 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 16 License for more details.
 17 
 18 You should have received a copy of the GNU Lesser General Public License
 19 along with the SSH Library; see the file COPYING.  If not, write to
 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 21 MA 02111-1307, USA. */
 22 
 23 /* just the dirtiest part of code i ever made */
 24 #include <string.h>
 25 #include <stdio.h>
 26 #include <stdlib.h>
 27 #include "libssh/priv.h"
 28 static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 29                         "abcdefghijklmnopqrstuvwxyz"
 30                         "0123456789+/" ;
 31 
 32 /* transformations */
 33 #define SET_A(n,i) do { n |= (i&63) <<18; } while (0)
 34 #define SET_B(n,i) do { n |= (i&63) <<12; } while (0)
 35 #define SET_C(n,i) do { n |= (i&63) << 6; } while (0)
 36 #define SET_D(n,i) do { n |= (i&63); } while (0)
 37 
 38 #define GET_A(n) ((n & 0xff0000) >> 16)
 39 #define GET_B(n) ((n & 0xff00) >> 8)
 40 #define GET_C(n) (n & 0xff)
 41 
 42 static int _base64_to_bin(unsigned char dest[3], char *source,int num);
 43 static int get_equals(char *string);
 44 
 45 /* first part : base 64 to binary */
 46 
 47 /* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/
 48 /* it returns NULL */
 49 BUFFER *base64_to_bin(char *source){
 50     int len;
 51     int equals;
 52     BUFFER *buffer=buffer_new();
 53     unsigned char block[3];
 54 
 55     /* get the number of equals signs, which mirrors the padding */
 56     equals=get_equals(source);
 57     if(equals>2){
 58         buffer_free(buffer);
 59         return NULL;
 60     }
 61 
 62     len=strlen(source);
 63     while(len>4){
 64         if(_base64_to_bin(block,source,3)){
 65             buffer_free(buffer);
 66             return NULL;
 67         }
 68         buffer_add_data(buffer,block,3);
 69         len-=4;
 70         source+=4;
 71     }
 72     /* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */
 73     switch(len){
 74 /* (1) the final quantum of encoding input is an integral
 75    multiple of 24 bits; here, the final unit of encoded output will be
 76    an integral multiple of 4 characters with no "=" padding */
 77         case 4:
 78             if(equals!=0){
 79                 buffer_free(buffer);
 80                 return NULL;
 81             }
 82             if(_base64_to_bin(block,source,3)){
 83                 buffer_free(buffer);
 84                 return NULL;
 85             }
 86             buffer_add_data(buffer,block,3);
 87             return buffer;
 88 /*(2) the final quantum of encoding input is exactly 8 bits; here, the final
 89    unit of encoded output will be two characters followed by two "="
 90    padding characters */
 91         case 2:
 92             if(equals!=2){
 93                 buffer_free(buffer);
 94                 return NULL;
 95             }
 96             if(_base64_to_bin(block,source,1)){
 97                 buffer_free(buffer);
 98                 return NULL;
 99             }
100             buffer_add_data(buffer,block,1);
101             return buffer;
102 /* the final quantum of encoding input is
103    exactly 16 bits; here, the final unit of encoded output will be three
104    characters followed by one "=" padding character */
105         case 3:
106             if(equals!=1){
107                 buffer_free(buffer);
108                 return NULL;
109             }
110             if(_base64_to_bin(block,source,2)){
111                 buffer_free(buffer);
112                 return NULL;
113             }
114             buffer_add_data(buffer,block,2);
115             return buffer;
116         default:
117             /* 4,3,2 are the only padding size allowed */
118             buffer_free(buffer);
119             return NULL;
120    }
121    return NULL;
122 }
123     
124 #define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\
125                                         if(!ptr) return -1;\
126                                         i=ptr-alphabet;\
127                                         SET_##letter(*block,i);\
128                                         } while(0)
129 /* returns 0 if ok, -1 if not (ie invalid char into the stuff) */
130 static int to_block4(unsigned long *block, char *source,int num){
131     char *ptr;
132     unsigned int i;
133     *block=0;
134     if(num<1)
135         return 0;
136     BLOCK(A,0); /* 6 bits */
137     BLOCK(B,1); /* 12 */
138     if(num<2)
139         return 0;
140     BLOCK(C,2); /* 18 */
141     if(num < 3)
142         return 0;
143     BLOCK(D,3); /* 24 */
144     return 0;
145 }
146 
147 /* num = numbers of final bytes to be decoded */ 
148 static int _base64_to_bin(unsigned char dest[3], char *source,int num){
149    unsigned long block;
150    if(to_block4(&block,source,num))
151        return -1;
152    dest[0]=GET_A(block);
153    dest[1]=GET_B(block);
154    dest[2]=GET_C(block);
155    return 0;
156 }
157 
158 /* counts the number of "=" signs, and replace them by zeroes */
159 static int get_equals(char *string){
160     char *ptr=string;
161     int num=0;
162     while((ptr=strchr(ptr,'='))){
163         num++;
164         *ptr=0;
165         ptr++;
166     }
167     
168     return num;
169 }
170 
171 /* thanks sysk for debugging my mess :) */
172 #define BITS(n) ((1<<n)-1)
173 static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){
174     switch (len){
175         case 1:
176             dest[0]=alphabet[(source[0]>>2)];
177             dest[1]=alphabet[((source[0] & BITS(2)) << 4)];
178             dest[2]='=';
179             dest[3]='=';
180             break;
181         case 2:
182             dest[0]=alphabet[source[0]>>2];
183             dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
184             dest[2]=alphabet[(source[1]&BITS(4)) << 2]; 
185             dest[3]='=';
186             break;
187         case 3:
188             dest[0]=alphabet[(source[0]>>2)]; 
189             dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
190             dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2]; 
191             dest[3]=alphabet[source[2]&BITS(6)];
192         break;
193     }
194 }
195 
196 char *bin_to_base64(unsigned char *source, int len){
197     int flen=len + (3 - (len %3)); /* round to upper 3 multiple */
198     char *buffer;
199     char *ptr;
200     flen=(4 * flen)/3 + 1 ;
201     ptr=buffer=malloc(flen);
202     while(len>0){
203         _bin_to_base64(ptr,source,len>3?3:len);
204         ptr+=4;
205         source +=3;
206         len -=3;
207     }
208     ptr[0]=0;
209     return buffer;
210 }
5773070 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59