libgeda
|
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 }