libgeda

s_encoding.c

Go to the documentation of this file.
00001 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif
00041 
00042 #include <ctype.h>
00043 #include <glib.h>
00044 #ifdef HAVE_STRING_H
00045 #include <string.h>
00046 #endif
00047 
00048 static gchar s_encoding_Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00049 #define s_encoding_Pad64    '='
00050 static guchar s_encoding_Base64_rank[256] = {
00051     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0x00-0x0f   */
00052     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0x10-0x1f   */
00053     255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /* 0x20-0x2f   */
00054      52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /* 0x30-0x3f   */
00055     255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, /* 0x40-0x4f   */
00056      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /* 0x50-0x5f   */
00057     255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6f   */
00058      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, /* 0x70-0x7f   */
00059     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0x80-0x8f   */
00060     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0x90-0x9f   */
00061     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xa0-0xaf   */
00062     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xb0-0xbf   */
00063     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xc0-0xcf   */
00064     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xd0-0xdf   */
00065     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xe0-0xef   */
00066     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0xf0-0xff   */
00067 };
00068 
00082 gchar* s_encoding_base64_encode (gchar* src, guint srclen, 
00083                  guint* dstlenp, gboolean strict) 
00084 {
00085   gchar* dst;
00086   guint dstpos;
00087   guchar input[3];
00088   guchar output[4];
00089   guint ocnt;
00090   guint i;
00091 
00092   if (srclen == 0) 
00093     return NULL;    /* FIX: Or return ""? */
00094 
00095   /* Calculate required length of dst.  4 bytes of dst are needed for
00096      every 3 bytes of src. */
00097   *dstlenp = (((srclen + 2) / 3) * 4)+5;
00098   if (strict)
00099     *dstlenp += (*dstlenp / 72);    /* Handle trailing \n */
00100 
00101   dst = g_new(gchar, *dstlenp );
00102 
00103   /* bulk encoding */
00104   dstpos = 0;
00105   ocnt = 0;
00106   while (srclen >= 3) 
00107     {
00108       /*
00109     Convert 3 bytes of src to 4 bytes of output
00110 
00111     output[0] = input[0] 7:2
00112     output[1] = input[0] 1:0 input[1] 7:4
00113     output[2] = input[1] 3:0 input[2] 7:6
00114     output[3] = input[1] 5:0
00115 
00116        */
00117       input[0] = *src++;
00118       input[1] = *src++;
00119       input[2] = *src++;
00120       srclen -= 3;
00121 
00122       output[0] = (input[0] >> 2);
00123       output[1] = ((input[0] & 0x03) << 4) + 
00124     (input[1] >> 4);
00125       output[2] = ((input[1] & 0x0f) << 2) + 
00126     (input[2] >> 6);
00127       output[3] = (input[2] & 0x3f);
00128 
00129       g_assert ((dstpos + 4) < *dstlenp);
00130 
00131       /* Map output to the Base64 alphabet */
00132       dst[dstpos++] = s_encoding_Base64[(guint) output[0]];
00133       dst[dstpos++] = s_encoding_Base64[(guint) output[1]];
00134       dst[dstpos++] = s_encoding_Base64[(guint) output[2]];
00135       dst[dstpos++] = s_encoding_Base64[(guint) output[3]];
00136 
00137       /* Add a newline if strict and  */
00138       if (strict)
00139     if ((++ocnt % (72/4)) == 0) 
00140       dst[dstpos++] = '\n';
00141     }
00142 
00143   /* Now worry about padding with remaining 1 or 2 bytes */
00144   if (srclen != 0) 
00145     {
00146       input[0] = input[1] = input[2] = '\0';
00147       for (i = 0; i < srclen; i++) 
00148     input[i] = *src++;
00149 
00150       output[0] = (input[0] >> 2);
00151       output[1] = ((input[0] & 0x03) << 4) + 
00152     (input[1] >> 4);
00153       output[2] = ((input[1] & 0x0f) << 2) + 
00154     (input[2] >> 6);
00155 
00156       g_assert ((dstpos + 4) < *dstlenp);
00157 
00158       dst[dstpos++] = s_encoding_Base64[(guint) output[0]];
00159       dst[dstpos++] = s_encoding_Base64[(guint) output[1]];
00160 
00161       if (srclen == 1)
00162     dst[dstpos++] = s_encoding_Pad64;
00163       else
00164     dst[dstpos++] = s_encoding_Base64[(guint) output[2]];
00165 
00166       dst[dstpos++] = s_encoding_Pad64;
00167     }
00168 
00169   g_assert (dstpos <= *dstlenp);
00170 
00171   dst[dstpos] = '\0';
00172 
00173   *dstlenp = dstpos + 1;
00174 
00175   return dst;
00176 }
00177 
00191 gchar *s_encoding_base64_decode (gchar* src, guint srclen, guint* dstlenp)
00192 {
00193 
00194   gchar* dst;
00195   guint   dstidx, state, ch = 0;
00196   gchar  res;
00197   guchar pos;
00198 
00199   if (srclen == 0) 
00200     srclen = strlen(src);
00201   state = 0;
00202   dstidx = 0;
00203   res = 0;
00204 
00205   dst = g_new(gchar, srclen+1);
00206   *dstlenp = srclen+1;
00207 
00208   while (srclen > 0)
00209     {
00210       srclen--;
00211       ch = *src++;
00212       if (ch == s_encoding_Pad64) 
00213     break;
00214       if (s_encoding_Base64_rank[ch]==255) /* Skip any non-base64 anywhere */
00215     continue;
00216 
00217       pos = s_encoding_Base64_rank[ch];
00218 
00219       switch (state) 
00220     {
00221     case 0:
00222       dst[dstidx] = (pos << 2);
00223       state = 1;
00224       break;
00225     case 1:
00226       dst[dstidx] |= (pos >> 4);
00227       res = ((pos & 0x0f) << 4);
00228       dstidx++;
00229       state = 2;
00230       break;
00231     case 2:
00232       dst[dstidx] = res | (pos >> 2);
00233       res = (pos & 0x03) << 6;
00234       dstidx++;
00235       state = 3;
00236       break;
00237     case 3:
00238       dst[dstidx] = res | pos;
00239       dstidx++;
00240       state = 0;
00241       break;
00242     default:
00243       break;
00244     }
00245     }
00246   /*
00247    * We are done decoding Base-64 chars.  Let's see if we ended
00248    * on a byte boundary, and/or with erroneous trailing characters.
00249    */
00250   if (ch == s_encoding_Pad64)           /* We got a pad char. */
00251     {
00252       switch (state) 
00253     {
00254     case 0:             /* Invalid = in first position */
00255     case 1:             /* Invalid = in second position */
00256       return NULL;
00257     case 2:             /* Valid, means one byte of info */
00258                                 /* Skip any number of spaces. */
00259       while (srclen > 0)
00260         {
00261           srclen--;
00262           ch = *src++;
00263           if (ch == s_encoding_Pad64) break;
00264           if (s_encoding_Base64_rank[ch] != 255) break;
00265         }
00266                                 /* Make sure there is another trailing = sign. */
00267       if (ch != s_encoding_Pad64) 
00268         {
00269           g_free(dst);
00270           *dstlenp = 0;
00271           return NULL;
00272         }
00273                                 /* FALLTHROUGH */
00274     case 3:             /* Valid, means two bytes of info */
00275                                 /*
00276                                  * We know this char is an =.  Is there anything but
00277                                  * whitespace after it?
00278                                  */
00279       while (srclen > 0)
00280         {
00281           srclen--;
00282           ch = *src++;
00283           if (s_encoding_Base64_rank[ch] != 255) 
00284         {
00285           g_free(dst);
00286           *dstlenp = 0;
00287           return NULL;
00288         }
00289         }
00290                                 /*
00291                                  * Now make sure for cases 2 and 3 that the "extra"
00292                                  * bits that slopped past the last full byte were
00293                                  * zeros.  If we don't check them, they become a
00294                                  * subliminal channel.
00295                                  */
00296       if (res != 0)
00297         {
00298           g_free(dst);
00299           *dstlenp = 0;
00300           return NULL;
00301         }
00302     default:
00303       break;
00304     }
00305     } else 
00306       {
00307     /*
00308      * We ended by seeing the end of the string.  Make sure we
00309      * have no partial bytes lying around.
00310      */
00311     if (state != 0) 
00312       {
00313         g_free(dst);
00314         *dstlenp = 0;
00315         return NULL;
00316       }
00317       }
00318   dst[dstidx]=0;
00319   *dstlenp = dstidx;
00320   return dst;
00321 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines