Merge branch 'master' into sru_2_0
[yaz-moved-to-github.git] / src / base64.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file base64.c
7  * \brief Base64 encode/decode utilities
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <string.h>
14 #include <yaz/base64.h>
15
16 void yaz_base64encode(const char *in, char *out)
17 {
18     static char encoding[] =
19         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
20     unsigned char buf[3];
21     long n;
22
23     while (*in != 0)
24     {
25         const char *pad = 0;
26         buf[0] = in[0];
27         buf[1] = in[1];
28         if (in[1] == 0)
29         {
30             buf[2] = 0;
31             pad = "==";
32         }
33         else
34         {
35             buf[2] = in[2];
36             if (in[2] == 0)
37                 pad = "=";
38         }
39
40         /* Treat three eight-bit numbers as on 24-bit number */
41         n = (buf[0] << 16) + (buf[1] << 8) + buf[2];
42
43         /* Write the six-bit chunks out as four encoded characters */
44         *out++ = encoding[(n >> 18) & 63];
45         *out++ = encoding[(n >> 12) & 63];
46         if (in[1] != 0)
47             *out++ = encoding[(n >> 6) & 63];
48         if (in[1] != 0 && in[2] != 0)
49             *out++ = encoding[n & 63];
50
51         if (pad != 0) {
52             while (*pad != 0)
53                 *out++ = *pad++;
54             break;
55         }
56         in += 3;
57     }
58     *out++ = 0;
59 }
60
61 static int next_char(const char **in, size_t *len)
62 {
63     const char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
64         "abcdefghijklmnopqrstuvwxyz0123456789+/";
65     const char *p;
66     while (*len > 0 && strchr("\r\n\t\f ", **in))
67     {
68         (*len)--;
69         (*in)++;
70     }
71     if (*len > 0 && **in == '=')
72         return -2;
73     if (*len > 0 && (p = strchr(map, **in)))
74     {
75         (*len)--;
76         (*in)++;
77         return p - map;
78     }
79     return -1;
80 }
81
82 int yaz_base64decode(const char *in, char *out)
83 {
84     size_t len = strlen(in);
85
86     while (len >= 4)
87     {
88         int i0, i1, i2, i3;
89
90         i0 = next_char(&in, &len);
91         if (i0 < 0)
92             return -1;
93         i1 = next_char(&in, &len);
94         if (i1 < 0)
95             return -1;
96         *(out++) = i0 << 2 | i1 >> 4;
97         i2 = next_char(&in, &len);
98         if (i2 == -2)
99             break;
100         if (i2 == -1)
101             return -1;
102         *(out++) = i1 << 4 | i2 >> 2;
103         i3 = next_char(&in, &len);
104         if (i3 == -2)
105             break;
106         if (i3 == -1)
107             return -1;
108         *(out++) = i2 << 6 | i3;
109     }
110     *out = '\0';
111     return 0;
112 }
113
114 /*
115  * Local variables:
116  * c-basic-offset: 4
117  * c-file-style: "Stroustrup"
118  * indent-tabs-mode: nil
119  * End:
120  * vim: shiftwidth=4 tabstop=8 expandtab
121  */
122