ManaPlus
base64.cpp
Go to the documentation of this file.
1 /*
2  +----------------------------------------------------------------------+
3  | PHP HTML Embedded Scripting Language Version 3.0 |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 1997-2000 PHP Development Team (See Credits file) |
6  +----------------------------------------------------------------------+
7  | This program is free software; you can redistribute it and/or modify |
8  | it under the terms of one of the following licenses: |
9  | |
10  | A) the GNU General Public License as published by the Free Software |
11  | Foundation; either version 2 of the License, or (at your option) |
12  | any later version. |
13  | |
14  | B) the PHP License as published by the PHP Development Team and |
15  | included in the distribution in the file: LICENSE |
16  | |
17  | This program is distributed in the hope that it will be useful, |
18  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
19  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20  | GNU General Public License for more details. |
21  | |
22  | You should have received a copy of both licenses referred to here. |
23  | If you did not, or have any questions about PHP licensing, please |
24  | contact [email protected]. |
25  +----------------------------------------------------------------------+
26  | Author: Jim Winstead ([email protected]) |
27  +----------------------------------------------------------------------+
28  */
29 
30 #include "utils/base64.h"
31 
32 #include "utils/cast.h"
33 
34 #include "debug.h"
35 
36 static char base64_table[] =
37 {
38  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
39  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
40  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
41  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
42  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
43 };
44 static const char base64_pad = '=';
45 
46 unsigned char *php3_base64_encode(const unsigned char *restrict const string,
47  int length,
48  int *restrict const ret_length)
49 {
50  if (string == nullptr)
51  return nullptr;
52  const unsigned char *current = string;
53  int i = 0;
54  unsigned char *const result = static_cast<unsigned char *>(
55  calloc(CAST_SIZE((length + 3 - length % 3) * 4 / 3 + 1)
56  * sizeof(unsigned char), 1));
57  if (result == nullptr)
58  return nullptr;
59 
60  while (length > 2)
61  { /* keep going until we have less than 24 bits */
62  result[i++] = base64_table[current[0] >> 2];
63  result[i++] = base64_table[((current[0] & 0x03)
64  << 4) + (current[1] >> 4)];
65  result[i++] = base64_table[((current[1] & 0x0f)
66  << 2) + (current[2] >> 6)];
67  result[i++] = base64_table[current[2] & 0x3f];
68 
69  current += 3;
70  length -= 3; /* we just handle 3 octets of data */
71  }
72 
73  /* now deal with the tail end of things */
74  if (length != 0)
75  {
76  result[i++] = base64_table[current[0] >> 2];
77  if (length > 1)
78  {
79  result[i++] = base64_table[((current[0] & 0x03) << 4)
80  + (current[1] >> 4)];
81  result[i++] = base64_table[(current[1] & 0x0f) << 2];
82  result[i++] = base64_pad;
83  }
84  else
85  {
86  result[i++] = base64_table[(current[0] & 0x03) << 4];
87  result[i++] = base64_pad;
88  result[i++] = base64_pad;
89  }
90  }
91  if (ret_length != nullptr)
92  {
93  *ret_length = i;
94  }
95  result[i] = '\0';
96  return result;
97 }
98 
99 /* as above, but backwards. :) */
100 unsigned char *php3_base64_decode(const unsigned char *restrict const string,
101  const int length,
102  int *restrict const ret_length)
103 {
104  const unsigned char *current = string;
105  int ch;
106  int i = 0;
107  int j = 0;
108  int k;
109 
110  unsigned char *result = static_cast<unsigned char *>(
111  calloc(length + 1, 1));
112 
113  if (result == nullptr)
114  return nullptr;
115 
116  /* run through the whole string, converting as we go */
117  while ((ch = *current++) != '\0')
118  {
119  if (ch == base64_pad)
120  break;
121 
122  /* When Base64 gets POSTed, all pluses are interpreted as spaces.
123  This line changes them back. It's not exactly the Base64 spec,
124  but it is completely compatible with it (the spec says that
125  spaces are invalid). This will also save many people considerable
126  headache. - Turadg Aleahmad <[email protected]>
127  */
128 
129  if (ch == ' ') ch = '+';
130 
131  const char *const chp = strchr(base64_table, ch);
132  if (chp == nullptr)
133  continue;
134  ch = CAST_S32(chp - base64_table);
135 
136  switch (i % 4)
137  {
138  case 0:
139  result[j] = CAST_U8(ch << 2U);
140  break;
141  case 1:
142  result[j++] |= CAST_U8(ch >> 4U);
143  result[j] = CAST_U8((ch & 0x0f) << 4U);
144  break;
145  case 2:
146  result[j++] |= CAST_U8(ch >>2U);
147  result[j] = CAST_U8((ch & 0x03) << 6U);
148  break;
149  case 3:
150  result[j++] |= CAST_U8(ch);
151  break;
152  default:
153  break;
154  }
155  i++;
156  }
157 
158  k = j;
159  /* mop things up if we ended on a boundary */
160  if (ch == base64_pad)
161  {
162  switch (i % 4)
163  {
164  case 0:
165  case 1:
166  free(result);
167  return nullptr;
168  case 2:
169  k++;
170  // copy from 3. is it should be here?
171  result[k++] = 0;
172  break;
173  case 3:
174  result[k++] = 0;
175  break;
176  default:
177  break;
178  }
179  }
180  if (ret_length != nullptr)
181  {
182  *ret_length = j;
183  }
184  result[k] = '\0';
185  return result;
186 }
187 
188 std::string encodeBase64String(std::string value)
189 {
190  int sz = 0;
191  const unsigned char *const str = reinterpret_cast<unsigned char*>(
192  const_cast<char*>(value.c_str()));
193  unsigned char *const buf = php3_base64_encode(
194  str, CAST_S32(value.size()), &sz);
195  if (buf == nullptr)
196  return std::string();
197 
198  value = std::string(reinterpret_cast<char*>(buf), sz);
199  free(buf);
200  return value;
201 }
202 
203 std::string decodeBase64String(std::string value)
204 {
205  int sz = 0;
206  const unsigned char *const str = reinterpret_cast<unsigned char*>(
207  const_cast<char*>(value.c_str()));
208  unsigned char *const buf = php3_base64_decode(
209  str, CAST_S32(value.size()), &sz);
210 
211  if (buf != nullptr)
212  value = std::string(reinterpret_cast<char*>(buf), sz);
213  else
214  value.clear();
215  free(buf);
216  return value;
217 }
static const char base64_pad
Definition: base64.cpp:44
unsigned char * php3_base64_encode(const unsigned char *const string, int length, int *const ret_length)
Definition: base64.cpp:46
static char base64_table[]
Definition: base64.cpp:36
unsigned char * php3_base64_decode(const unsigned char *const string, const int length, int *const ret_length)
Definition: base64.cpp:100
std::string decodeBase64String(std::string value)
Definition: base64.cpp:203
std::string encodeBase64String(std::string value)
Definition: base64.cpp:188
#define CAST_S32
Definition: cast.h:30
#define CAST_SIZE
Definition: cast.h:34
#define CAST_U8
Definition: cast.h:27
#define restrict
Definition: localconsts.h:165