loudmouth/src/base64.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /*
       
     2  * base64.c - Base 64 encoding/decoding implementation
       
     3  * Copyright (C) 2006 Collabora Ltd.
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2.1 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this library; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    18  */
       
    19 
       
    20 #include <ctype.h>
       
    21 #include <string.h>
       
    22 
       
    23 #include <glib.h>
       
    24 
       
    25 #include "base64.h"
       
    26 
       
    27 /*
       
    28 |AAAA AABB|BBBB CCCC|CCDD DDDD|
       
    29 
       
    30 0xFC = 1111 1100
       
    31 0x03 = 0000 0011
       
    32 0xF0 = 1111 0000
       
    33 0x0F = 0000 1111
       
    34 0xC0 = 1100 0000
       
    35 0x3F = 0011 1111
       
    36 
       
    37 3 input bytes = 4 output bytes;
       
    38 2 input bytes = 2 output bytes;
       
    39 1 input byte  = 1 output byte.
       
    40 */
       
    41 
       
    42 
       
    43 #ifdef EMULATOR
       
    44 #include "libloudmouth_wsd_solution.h"
       
    45 
       
    46 GET_STATIC_ARRAY_FROM_TLS(encoding, lm_base64, gchar)
       
    47   #define encoding (GET_WSD_VAR_NAME(encoding, lm_base64, s)())
       
    48 
       
    49 #else
       
    50 
       
    51 static const gchar *encoding =
       
    52   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
       
    53 
       
    54 #endif
       
    55 
       
    56 
       
    57 
       
    58 static const guint decoding[256] =
       
    59 {
       
    60   /* ... */
       
    61    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       
    62    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       
    63    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       
    64    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       
    65    0, 0, 0,
       
    66   /* + */
       
    67   62,
       
    68   /* ... */
       
    69    0, 0, 0,
       
    70   /* / , 0-9 */
       
    71   63,
       
    72   52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
       
    73   /* ... */
       
    74    0, 0, 0, 0, 0, 0, 0,
       
    75   /* A */
       
    76    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,
       
    77   13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
       
    78   /* ... */
       
    79    0, 0, 0, 0, 0, 0,
       
    80   /* a */
       
    81   26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
       
    82   39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
       
    83 };
       
    84 
       
    85 #define GET_6_BITS_0(s) (((s)[0] & 0xFC) >> 2)
       
    86 #define GET_6_BITS_1(s) (((s)[0] & 0x03) << 4) | \
       
    87                         (((s)[1] & 0xF0) >> 4)
       
    88 #define GET_6_BITS_2(s) (((s)[1] & 0x0F) << 2) | \
       
    89                         (((s)[2] & 0xC0) >> 6)
       
    90 #define GET_6_BITS_3(s) (((s)[2] & 0x3F) << 0)
       
    91 
       
    92 #define GET_BYTE_0(s) (((decoding[(guchar)(s)[0]] & 0x3F) << 2) | \
       
    93                        ((decoding[(guchar)(s)[1]] & 0x30) >> 4))
       
    94 #define GET_BYTE_1(s) (((decoding[(guchar)(s)[1]] & 0x0F) << 4) | \
       
    95                        ((decoding[(guchar)(s)[2]] & 0x3C) >> 2))
       
    96 #define GET_BYTE_2(s) (((decoding[(guchar)(s)[2]] & 0x03) << 6) | \
       
    97                        ((decoding[(guchar)(s)[3]] & 0xFF) << 0))
       
    98 
       
    99 gchar *_lm_base64_encode (const gchar *txt, gsize n)
       
   100 {
       
   101   guint i;
       
   102   guint len;
       
   103   GString *tmp;
       
   104   GString *str = g_string_new_len (txt, n);
       
   105 
       
   106   len = str->len;
       
   107   /* TODO: calculate requisite output string length and allocate that big a
       
   108    * GString */
       
   109   tmp = g_string_new ("");
       
   110 
       
   111   for (i = 0; i < len; i += 3)
       
   112     {
       
   113       guint c1, c2, c3, c4;
       
   114 
       
   115       switch (i + 3 - len)
       
   116         {
       
   117         case 1:
       
   118           c1 = encoding[GET_6_BITS_0 (str->str + i)];
       
   119           c2 = encoding[GET_6_BITS_1 (str->str + i)];
       
   120           c3 = encoding[GET_6_BITS_2 (str->str + i)];
       
   121           c4 = '=';
       
   122           break;
       
   123         case 2:
       
   124           c1 = encoding[GET_6_BITS_0 (str->str + i)];
       
   125           c2 = encoding[GET_6_BITS_1 (str->str + i)];
       
   126           c3 = '=';
       
   127           c4 = '=';
       
   128           break;
       
   129         default:
       
   130           c1 = encoding[GET_6_BITS_0 (str->str + i)];
       
   131           c2 = encoding[GET_6_BITS_1 (str->str + i)];
       
   132           c3 = encoding[GET_6_BITS_2 (str->str + i)];
       
   133           c4 = encoding[GET_6_BITS_3 (str->str + i)];
       
   134         }
       
   135 
       
   136       g_string_append_printf (tmp, "%c%c%c%c", c1, c2, c3, c4);
       
   137     }
       
   138 
       
   139   return g_string_free (tmp, FALSE);
       
   140 }
       
   141 
       
   142 gchar *_lm_base64_decode (const gchar *str, gsize *len)
       
   143 {
       
   144   guint i;
       
   145   GString *tmp;
       
   146   char group[4];
       
   147   guint filled = 0;
       
   148 
       
   149   *len = 0;
       
   150 
       
   151   for (i = 0; str[i]; i++)
       
   152     {
       
   153       if (str[i] != 'A' &&
       
   154           str[i] != '=' &&
       
   155           !isspace(str[i]) &&
       
   156           decoding[(guchar) str[i]] == 0)
       
   157         {
       
   158           g_debug ("bad character %x at byte %u", (guchar)str[i], i);
       
   159           return NULL;
       
   160         }
       
   161     }
       
   162 
       
   163   tmp = g_string_new ("");
       
   164 
       
   165   for (i = 0; str[i]; i++)
       
   166     {
       
   167       if (isspace(str[i]))
       
   168         continue;
       
   169 
       
   170       group[filled++] = str[i];
       
   171 
       
   172       if (filled == 4)
       
   173         {
       
   174           if (group[3] == '=')
       
   175             {
       
   176               if (group[2] == '=')
       
   177                 {
       
   178                   g_string_append_c (tmp, GET_BYTE_0(group));
       
   179                 }
       
   180               else
       
   181                 {
       
   182                   g_string_append_c (tmp, GET_BYTE_0(group));
       
   183                   g_string_append_c (tmp, GET_BYTE_1(group));
       
   184                 }
       
   185              }
       
   186            else
       
   187             {
       
   188               g_string_append_c (tmp, GET_BYTE_0(group));
       
   189               g_string_append_c (tmp, GET_BYTE_1(group));
       
   190               g_string_append_c (tmp, GET_BYTE_2(group));
       
   191             }
       
   192           filled = 0;
       
   193         }
       
   194     }
       
   195 
       
   196   if (filled)
       
   197     {
       
   198       g_debug ("insufficient padding at end of base64 string:\n%s", str);
       
   199       g_string_free (tmp, TRUE);
       
   200       return NULL;
       
   201     }
       
   202 
       
   203   *len = tmp->len;
       
   204   return g_string_free (tmp, FALSE);
       
   205 }
       
   206 
       
   207