MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

base64.c

00001 /*********************************************************************************
00002 
00003  Copyright 2006-2008 MakingThings
00004 
00005  Licensed under the Apache License, 
00006  Version 2.0 (the "License"); you may not use this file except in compliance 
00007  with the License. You may obtain a copy of the License at
00008 
00009  http://www.apache.org/licenses/LICENSE-2.0 
00010  
00011  Unless required by applicable law or agreed to in writing, software distributed
00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
00014  the specific language governing permissions and limitations under the License.
00015 
00016 *********************************************************************************/
00017 
00018 /* 
00019   Written by Simon Josefsson.  Partially adapted from GNU MailUtils
00020   (mailbox/filter_trans.c, as of 2004-11-28).  Improved by review
00021   from Paul Eggert, Bruno Haible, and Stepan Kasal
00022 */
00023 
00024 #include "base64.h"
00025 
00026 bool isbase64 (char ch);
00027 
00028 /* C89 compliant way to cast 'char' to 'unsigned char'. */
00029 static inline unsigned char to_uchar (char ch)
00030 {
00031   return ch;
00032 }
00033 
00034 /** \defgroup base64 Base 64
00035   The Make Controller Base 64 library provides a way to decode and encode base 64 data.
00036 
00037   This is often handy when you need to send raw/binary data (as opposed to text) through a 
00038   text based format, like XML or JSON.
00039 
00040   Most code lifted from gnulib - http://savannah.gnu.org/projects/gnulib - and written by Simon Josefsson.
00041   \par
00042 
00043   \ingroup Libraries
00044   @{
00045 */
00046 
00047 /**
00048   Base 64 encode a block of data.
00049   Provide a buffer to write into and to read from.  As Base64 encoding results in 
00050   4 bytes for every 3 source bytes, ensure your destination buffer is large enough.
00051 
00052   @param dest The buffer that the encoded string will be written into.
00053   @param dest_size The maximum number of bytes to write into the destination buffer.
00054   @param src A block of data to encode.
00055   @param src_size The number of bytes from src to encode.
00056   @return The length of the generated string (not including null termination).
00057 
00058   \par Example
00059   \code
00060   #define BUFF_SIZE 256
00061   char encode_buf[BUFF_SIZE];
00062   int len = Base64_Encode(encode_buf, BUFF_SIZE, "test", 4);
00063   // we now have "dGVzdA==" in encode_buf, and len is 8
00064   \endcode
00065 */
00066 int Base64_Encode(char* dest, int dest_size, const char* src, int src_size)
00067 {
00068   // our library of valid b64 chars
00069   static const unsigned char b64str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00070   int orig_size = dest_size;
00071 
00072   while(dest_size && src_size)
00073   {
00074     *dest++ = b64str[(to_uchar (src[0]) >> 2) & 0x3f];
00075     if(!--dest_size)
00076       break;
00077 
00078     *dest++ = b64str[((to_uchar (src[0]) << 4)
00079                 + (--src_size ? to_uchar (src[1]) >> 4 : 0))
00080                 & 0x3f];
00081     if(!--dest_size)
00082       break;
00083 
00084     *dest++ = (src_size ? b64str[((to_uchar (src[1]) << 2)
00085                 + (--src_size ? to_uchar (src[2]) >> 6 : 0)) & 0x3f] : '=');
00086     if(!--dest_size)
00087       break;
00088 
00089     *dest++ = src_size ? b64str[to_uchar (src[2]) & 0x3f] : '=';
00090     if(!--dest_size)
00091       break;
00092 
00093     if(src_size)
00094       src_size--;
00095     if(src_size)
00096       src += 3;
00097   }
00098   if(dest_size)
00099     *dest = '\0';
00100   return orig_size - dest_size;
00101 }
00102 
00103 /* With this approach this file works independent of the charset used
00104    (think EBCDIC).  However, it does assume that the characters in the
00105    Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255.  POSIX
00106    1003.1-2001 require that char and unsigned char are 8-bit
00107    quantities, though, taking care of that problem.  But this may be a
00108    potential problem on non-POSIX C99 platforms.
00109 
00110    IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
00111    as the formal parameter rather than "x".  */
00112 #define B64(_)          \
00113   ((_) == 'A' ? 0       \
00114    : (_) == 'B' ? 1       \
00115    : (_) == 'C' ? 2       \
00116    : (_) == 'D' ? 3       \
00117    : (_) == 'E' ? 4       \
00118    : (_) == 'F' ? 5       \
00119    : (_) == 'G' ? 6       \
00120    : (_) == 'H' ? 7       \
00121    : (_) == 'I' ? 8       \
00122    : (_) == 'J' ? 9       \
00123    : (_) == 'K' ? 10        \
00124    : (_) == 'L' ? 11        \
00125    : (_) == 'M' ? 12        \
00126    : (_) == 'N' ? 13        \
00127    : (_) == 'O' ? 14        \
00128    : (_) == 'P' ? 15        \
00129    : (_) == 'Q' ? 16        \
00130    : (_) == 'R' ? 17        \
00131    : (_) == 'S' ? 18        \
00132    : (_) == 'T' ? 19        \
00133    : (_) == 'U' ? 20        \
00134    : (_) == 'V' ? 21        \
00135    : (_) == 'W' ? 22        \
00136    : (_) == 'X' ? 23        \
00137    : (_) == 'Y' ? 24        \
00138    : (_) == 'Z' ? 25        \
00139    : (_) == 'a' ? 26        \
00140    : (_) == 'b' ? 27        \
00141    : (_) == 'c' ? 28        \
00142    : (_) == 'd' ? 29        \
00143    : (_) == 'e' ? 30        \
00144    : (_) == 'f' ? 31        \
00145    : (_) == 'g' ? 32        \
00146    : (_) == 'h' ? 33        \
00147    : (_) == 'i' ? 34        \
00148    : (_) == 'j' ? 35        \
00149    : (_) == 'k' ? 36        \
00150    : (_) == 'l' ? 37        \
00151    : (_) == 'm' ? 38        \
00152    : (_) == 'n' ? 39        \
00153    : (_) == 'o' ? 40        \
00154    : (_) == 'p' ? 41        \
00155    : (_) == 'q' ? 42        \
00156    : (_) == 'r' ? 43        \
00157    : (_) == 's' ? 44        \
00158    : (_) == 't' ? 45        \
00159    : (_) == 'u' ? 46        \
00160    : (_) == 'v' ? 47        \
00161    : (_) == 'w' ? 48        \
00162    : (_) == 'x' ? 49        \
00163    : (_) == 'y' ? 50        \
00164    : (_) == 'z' ? 51        \
00165    : (_) == '0' ? 52        \
00166    : (_) == '1' ? 53        \
00167    : (_) == '2' ? 54        \
00168    : (_) == '3' ? 55        \
00169    : (_) == '4' ? 56        \
00170    : (_) == '5' ? 57        \
00171    : (_) == '6' ? 58        \
00172    : (_) == '7' ? 59        \
00173    : (_) == '8' ? 60        \
00174    : (_) == '9' ? 61        \
00175    : (_) == '+' ? 62        \
00176    : (_) == '/' ? 63        \
00177    : -1)
00178 
00179 static const signed char b64[0x100] = {
00180   B64 (0), B64 (1), B64 (2), B64 (3),
00181   B64 (4), B64 (5), B64 (6), B64 (7),
00182   B64 (8), B64 (9), B64 (10), B64 (11),
00183   B64 (12), B64 (13), B64 (14), B64 (15),
00184   B64 (16), B64 (17), B64 (18), B64 (19),
00185   B64 (20), B64 (21), B64 (22), B64 (23),
00186   B64 (24), B64 (25), B64 (26), B64 (27),
00187   B64 (28), B64 (29), B64 (30), B64 (31),
00188   B64 (32), B64 (33), B64 (34), B64 (35),
00189   B64 (36), B64 (37), B64 (38), B64 (39),
00190   B64 (40), B64 (41), B64 (42), B64 (43),
00191   B64 (44), B64 (45), B64 (46), B64 (47),
00192   B64 (48), B64 (49), B64 (50), B64 (51),
00193   B64 (52), B64 (53), B64 (54), B64 (55),
00194   B64 (56), B64 (57), B64 (58), B64 (59),
00195   B64 (60), B64 (61), B64 (62), B64 (63),
00196   B64 (64), B64 (65), B64 (66), B64 (67),
00197   B64 (68), B64 (69), B64 (70), B64 (71),
00198   B64 (72), B64 (73), B64 (74), B64 (75),
00199   B64 (76), B64 (77), B64 (78), B64 (79),
00200   B64 (80), B64 (81), B64 (82), B64 (83),
00201   B64 (84), B64 (85), B64 (86), B64 (87),
00202   B64 (88), B64 (89), B64 (90), B64 (91),
00203   B64 (92), B64 (93), B64 (94), B64 (95),
00204   B64 (96), B64 (97), B64 (98), B64 (99),
00205   B64 (100), B64 (101), B64 (102), B64 (103),
00206   B64 (104), B64 (105), B64 (106), B64 (107),
00207   B64 (108), B64 (109), B64 (110), B64 (111),
00208   B64 (112), B64 (113), B64 (114), B64 (115),
00209   B64 (116), B64 (117), B64 (118), B64 (119),
00210   B64 (120), B64 (121), B64 (122), B64 (123),
00211   B64 (124), B64 (125), B64 (126), B64 (127),
00212   B64 (128), B64 (129), B64 (130), B64 (131),
00213   B64 (132), B64 (133), B64 (134), B64 (135),
00214   B64 (136), B64 (137), B64 (138), B64 (139),
00215   B64 (140), B64 (141), B64 (142), B64 (143),
00216   B64 (144), B64 (145), B64 (146), B64 (147),
00217   B64 (148), B64 (149), B64 (150), B64 (151),
00218   B64 (152), B64 (153), B64 (154), B64 (155),
00219   B64 (156), B64 (157), B64 (158), B64 (159),
00220   B64 (160), B64 (161), B64 (162), B64 (163),
00221   B64 (164), B64 (165), B64 (166), B64 (167),
00222   B64 (168), B64 (169), B64 (170), B64 (171),
00223   B64 (172), B64 (173), B64 (174), B64 (175),
00224   B64 (176), B64 (177), B64 (178), B64 (179),
00225   B64 (180), B64 (181), B64 (182), B64 (183),
00226   B64 (184), B64 (185), B64 (186), B64 (187),
00227   B64 (188), B64 (189), B64 (190), B64 (191),
00228   B64 (192), B64 (193), B64 (194), B64 (195),
00229   B64 (196), B64 (197), B64 (198), B64 (199),
00230   B64 (200), B64 (201), B64 (202), B64 (203),
00231   B64 (204), B64 (205), B64 (206), B64 (207),
00232   B64 (208), B64 (209), B64 (210), B64 (211),
00233   B64 (212), B64 (213), B64 (214), B64 (215),
00234   B64 (216), B64 (217), B64 (218), B64 (219),
00235   B64 (220), B64 (221), B64 (222), B64 (223),
00236   B64 (224), B64 (225), B64 (226), B64 (227),
00237   B64 (228), B64 (229), B64 (230), B64 (231),
00238   B64 (232), B64 (233), B64 (234), B64 (235),
00239   B64 (236), B64 (237), B64 (238), B64 (239),
00240   B64 (240), B64 (241), B64 (242), B64 (243),
00241   B64 (244), B64 (245), B64 (246), B64 (247),
00242   B64 (248), B64 (249), B64 (250), B64 (251),
00243   B64 (252), B64 (253), B64 (254), B64 (255)
00244 };
00245 
00246 /* Return true if CH is a character from the Base64 alphabet, and
00247    false otherwise.  Note that '=' is padding and not considered to be
00248    part of the alphabet.  */
00249 bool isbase64 (char ch)
00250 {
00251   //return uchar_in_range(to_uchar (ch)); && (0 <= b64[to_uchar(ch)]); -- uchar_in_range is always true for a uchar
00252   return (0 <= b64[to_uchar(ch)]);
00253 }
00254 
00255 /**
00256   Decode a Base64 string into a block of data.
00257 
00258   @param dest A pointer to the block of data to write in.
00259   @param dest_size A pointer to the maximum number of bytes to write into dest.  The number of bytes successfully written
00260   will be stored in this value upon return.
00261   @param src The base 64 string to decode.
00262   @param src_size The size of the base 64 string.
00263   @return True on successful decode, false on failure.
00264 
00265   \par Example
00266   \code
00267   #define BUFF_SIZE 256
00268   char decode_buf[BUFF_SIZE];
00269   int decode_size = BUFF_SIZE;
00270   bool result = Base64_Decode(decode_buf, &decode_size, "dGVzdA==", 8);
00271   // we now have "test" in decode_buf, and decode_size is set to 6
00272   \endcode
00273 */
00274 bool Base64_Decode(char* dest, int* dest_size, const char* src, int src_size)
00275 {
00276   int out_remaining = *dest_size;
00277 
00278   while(src_size >= 2)
00279   {
00280     if(!isbase64 (src[0]) || !isbase64 (src[1]))
00281       break;
00282     if(out_remaining)
00283     {
00284       *dest++ = ((b64[to_uchar (src[0])] << 2) | (b64[to_uchar (src[1])] >> 4)); 
00285       out_remaining--;
00286     }
00287     if(src_size == 2)
00288       break;
00289     if(src[2] == '=')
00290     {
00291       if(src_size != 4)
00292         break;
00293       if(src[3] != '=')
00294         break;
00295     }
00296     else
00297     {
00298       if(!isbase64 (src[2]))
00299         break;
00300       if(out_remaining)
00301       {
00302         *dest++ = (((b64[to_uchar (src[1])] << 4) & 0xf0) | (b64[to_uchar (src[2])] >> 2));
00303         out_remaining--;
00304       }
00305       if(src_size == 3)
00306         break;
00307       if(src[3] == '=')
00308       {
00309         if(src_size != 4)
00310           break;
00311       }
00312       else
00313       {
00314         if(!isbase64 (src[3]))
00315           break;
00316         if(out_remaining)
00317         {
00318           *dest++ = (((b64[to_uchar (src[2])] << 6) & 0xc0) | b64[to_uchar (src[3])]);
00319           out_remaining--;
00320         }
00321       }
00322     }
00323     src += 4;
00324     src_size -= 4;
00325   }
00326   *dest_size -= out_remaining;
00327   if(src_size != 0)
00328     return false;
00329 
00330   return true;
00331 }
00332 
00333 /** @}
00334 */
00335 
00336 
00337 
00338 

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.