1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "b64.h"
22#include "Exception.h"
23
24#include <limits>
25#include <stdio.h>
26
27namespace love
28{
29
30// Translation table as described in RFC1113
31static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
32
33// Translation table to decode (created by Bob Trower)
34static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
35
36/**
37 * encode 3 8-bit binary bytes as 4 '6-bit' characters
38 **/
39static void b64_encode_block(char in[3], char out[4], int len)
40{
41 out[0] = (char) cb64[(int)((in[0] & 0xfc) >> 2)];
42 out[1] = (char) cb64[(int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4))];
43 out[2] = (char) (len > 1 ? cb64[(int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6))] : '=');
44 out[3] = (char) (len > 2 ? cb64[(int)(in[2] & 0x3f)] : '=');
45}
46
47char *b64_encode(const char *src, size_t srclen, size_t linelen, size_t &dstlen)
48{
49 if (linelen == 0)
50 linelen = std::numeric_limits<size_t>::max();
51
52 size_t blocksout = 0;
53 size_t srcpos = 0;
54
55 size_t adjustment = (srclen % 3) ? (3 - (srclen % 3)) : 0;
56 size_t paddedlen = ((srclen + adjustment) / 3) * 4;
57
58 dstlen = paddedlen + paddedlen / linelen;
59
60 if (dstlen == 0)
61 return nullptr;
62
63 char *dst = nullptr;
64 try
65 {
66 dst = new char[dstlen + 1];
67 }
68 catch (std::exception &)
69 {
70 throw love::Exception("Out of memory.");
71 }
72
73 size_t dstpos = 0;
74
75 while (srcpos < srclen)
76 {
77 char in[3] = {0};
78 char out[4] = {0};
79
80 int len = 0;
81
82 for (int i = 0; i < 3; i++)
83 {
84 if (srcpos >= srclen)
85 break;
86
87 in[i] = src[srcpos++];
88 len++;
89 }
90
91 if (len > 0)
92 {
93 b64_encode_block(in, out, len);
94
95 for (int i = 0; i < 4 && dstpos < dstlen; i++, dstpos++)
96 dst[dstpos] = out[i];
97
98 blocksout++;
99 }
100
101 if (blocksout >= linelen / 4 || srcpos >= srclen)
102 {
103 if (blocksout > 0 && dstpos < dstlen)
104 dst[dstpos++] = '\n';
105
106 blocksout = 0;
107 }
108 }
109
110 dst[dstpos] = '\0';
111 return dst;
112}
113
114static void b64_decode_block(char in[4], char out[3])
115{
116 out[0] = (char)(in[0] << 2 | in[1] >> 4);
117 out[1] = (char)(in[1] << 4 | in[2] >> 2);
118 out[2] = (char)(((in[2] << 6) & 0xc0) | in[3]);
119}
120
121char *b64_decode(const char *src, size_t srclen, size_t &size)
122{
123 size_t paddedsize = (srclen / 4) * 3;
124
125 char *dst = nullptr;
126 try
127 {
128 dst = new char[paddedsize];
129 }
130 catch (std::exception &)
131 {
132 throw love::Exception("Out of memory.");
133 }
134
135 char *d = dst;
136
137 char in[4] = {0};
138 char out[3] = {0};
139 size_t i, len, srcpos = 0;
140
141 while (srcpos <= srclen)
142 {
143 for (len = 0, i = 0; i < 4 && srcpos <= srclen; i++)
144 {
145 char v = 0;
146
147 while (srcpos <= srclen && v == 0)
148 {
149 v = src[srcpos++];
150 v = (char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);
151 if (v != 0)
152 v = (char)((v == '$') ? 0 : v - 61);
153 }
154
155 if (srcpos <= srclen)
156 {
157 len++;
158 if (v != 0)
159 in[i] = (char)(v - 1);
160 }
161 else
162 in[i] = 0;
163 }
164
165 if (len)
166 {
167 b64_decode_block(in, out);
168 for (i = 0; i < len - 1; i++)
169 *(d++) = out[i];
170 }
171 }
172
173 size = (size_t)(ptrdiff_t) (d - dst);
174 return dst;
175}
176
177} // love
178