Skip to content

Commit e5e2a8e

Browse files
committed
FEAT: Base64URL encoding/decoding in DEBASE and ENBASE functions
improves: metaeducation/rebol-issues#2318 Possible test: ``` key1: "qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA==" probe bin: debase/url key1 probe key1 = enbase/url bin ;== should be true ;debase is working also when input is missing the padding key2: "qL8R4QIcQ_ZsRqOAbeRfcZhilN_MksRtDaErMA" probe bin = debase/url key2 ;== should be true ``` For more info see: https://tools.ietf.org/html/rfc4648#section-5
1 parent 8ca6819 commit e5e2a8e

File tree

3 files changed

+166
-15
lines changed

3 files changed

+166
-15
lines changed

src/boot/natives.r

+2
Original file line numberDiff line numberDiff line change
@@ -413,13 +413,15 @@ debase: native [
413413
value [binary! string!] {The string to decode}
414414
/base {Binary base to use}
415415
base-value [integer!] {The base to convert from: 64, 16, or 2}
416+
/url {Base 64 Decoding with URL and Filename Safe Alphabet}
416417
]
417418

418419
enbase: native [
419420
{Encodes a string into a binary-coded string (BASE-64 default).}
420421
value [binary! string!] {If string, will be UTF8 encoded}
421422
/base {Binary base to use}
422423
base-value [integer!] {The base to convert to: 64, 16, or 2}
424+
/url {Base 64 Encoding with URL and Filename Safe Alphabet}
423425
]
424426

425427
decloak: native [

src/core/f-enbase.c

+162-13
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,128 @@
157157
/* 7F DEL */ BIN_ERROR,
158158
};
159159

160+
/***********************************************************************
161+
**
162+
*/ static const REBYTE Debase64URL[128] =
163+
/*
164+
** Base-64-URL binary decoder table.
165+
** See: https://tools.ietf.org/html/rfc4648#section-5
166+
**
167+
***********************************************************************/
168+
{
169+
/* Control Chars */
170+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR, /* 80 */
171+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR,
172+
BIN_SPACE,BIN_SPACE,BIN_SPACE,BIN_ERROR,
173+
BIN_SPACE,BIN_SPACE,BIN_ERROR,BIN_ERROR,
174+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR,
175+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR,
176+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR,
177+
BIN_ERROR,BIN_ERROR,BIN_ERROR,BIN_ERROR,
178+
179+
/* 20 */ BIN_SPACE,
180+
/* 21 ! */ BIN_ERROR,
181+
/* 22 " */ BIN_ERROR,
182+
/* 23 # */ BIN_ERROR,
183+
/* 24 $ */ BIN_ERROR,
184+
/* 25 % */ BIN_ERROR,
185+
/* 26 & */ BIN_ERROR,
186+
/* 27 ' */ BIN_SPACE,
187+
/* 28 ( */ BIN_ERROR,
188+
/* 29 ) */ BIN_ERROR,
189+
/* 2A * */ BIN_ERROR,
190+
/* 2B + */ BIN_ERROR,
191+
/* 2C , */ BIN_ERROR,
192+
/* 2D - */ 62,
193+
/* 2E . */ BIN_ERROR,
194+
/* 2F / */ BIN_ERROR,
195+
196+
/* 30 0 */ 52,
197+
/* 31 1 */ 53,
198+
/* 32 2 */ 54,
199+
/* 33 3 */ 55,
200+
/* 34 4 */ 56,
201+
/* 35 5 */ 57,
202+
/* 36 6 */ 58,
203+
/* 37 7 */ 59,
204+
/* 38 8 */ 60,
205+
/* 39 9 */ 61,
206+
/* 3A : */ BIN_ERROR,
207+
/* 3B ; */ BIN_ERROR,
208+
/* 3C < */ BIN_ERROR,
209+
/* 3D = */ 0, // pad char
210+
/* 3E > */ BIN_ERROR,
211+
/* 3F ? */ BIN_ERROR,
212+
213+
/* 40 @ */ BIN_ERROR,
214+
/* 41 A */ 0,
215+
/* 42 B */ 1,
216+
/* 43 C */ 2,
217+
/* 44 D */ 3,
218+
/* 45 E */ 4,
219+
/* 46 F */ 5,
220+
/* 47 G */ 6,
221+
/* 48 H */ 7,
222+
/* 49 I */ 8,
223+
/* 4A J */ 9,
224+
/* 4B K */ 10,
225+
/* 4C L */ 11,
226+
/* 4D M */ 12,
227+
/* 4E N */ 13,
228+
/* 4F O */ 14,
229+
230+
/* 50 P */ 15,
231+
/* 51 Q */ 16,
232+
/* 52 R */ 17,
233+
/* 53 S */ 18,
234+
/* 54 T */ 19,
235+
/* 55 U */ 20,
236+
/* 56 V */ 21,
237+
/* 57 W */ 22,
238+
/* 58 X */ 23,
239+
/* 59 Y */ 24,
240+
/* 5A Z */ 25,
241+
/* 5B [ */ BIN_ERROR,
242+
/* 5C \ */ BIN_ERROR,
243+
/* 5D ] */ BIN_ERROR,
244+
/* 5E ^ */ BIN_ERROR,
245+
/* 5F _ */ 63,
246+
247+
/* 60 ` */ BIN_ERROR,
248+
/* 61 a */ 26,
249+
/* 62 b */ 27,
250+
/* 63 c */ 28,
251+
/* 64 d */ 29,
252+
/* 65 e */ 30,
253+
/* 66 f */ 31,
254+
/* 67 g */ 32,
255+
/* 68 h */ 33,
256+
/* 69 i */ 34,
257+
/* 6A j */ 35,
258+
/* 6B k */ 36,
259+
/* 6C l */ 37,
260+
/* 6D m */ 38,
261+
/* 6E n */ 39,
262+
/* 6F o */ 40,
263+
264+
/* 70 p */ 41,
265+
/* 71 q */ 42,
266+
/* 72 r */ 43,
267+
/* 73 s */ 44,
268+
/* 74 t */ 45,
269+
/* 75 u */ 46,
270+
/* 76 v */ 47,
271+
/* 77 w */ 48,
272+
/* 78 x */ 49,
273+
/* 79 y */ 50,
274+
/* 7A z */ 51,
275+
/* 7B { */ BIN_ERROR,
276+
/* 7C | */ BIN_ERROR,
277+
/* 7D } */ BIN_ERROR,
278+
/* 7E ~ */ BIN_ERROR,
279+
/* 7F DEL */ BIN_ERROR,
280+
};
281+
160282

161283
/***********************************************************************
162284
**
@@ -171,6 +293,19 @@
171293
"0123456789+/"
172294
};
173295

296+
/***********************************************************************
297+
**
298+
*/ static const REBYTE Enbase64URL[64] =
299+
/*
300+
** Base-64-URL binary encoder table.
301+
**
302+
***********************************************************************/
303+
{
304+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
305+
"abcdefghijklmnopqrstuvwxyz"
306+
"0123456789-_"
307+
};
308+
174309

175310
/***********************************************************************
176311
**
@@ -269,7 +404,7 @@
269404

270405
/***********************************************************************
271406
**
272-
*/ static REBSER *Decode_Base64(REBYTE **src, REBCNT len, REBYTE delim)
407+
*/ static REBSER *Decode_Base64(REBYTE **src, REBCNT len, REBYTE delim, REBOOL urlSafe)
273408
/*
274409
***********************************************************************/
275410
{
@@ -286,6 +421,13 @@
286421
bp = STR_HEAD(ser);
287422
cp = *src;
288423

424+
const REBYTE *table;
425+
if (urlSafe) {
426+
table = Debase64URL;
427+
} else {
428+
table = Debase64;
429+
}
430+
289431
for (; len > 0; cp++, len--) {
290432

291433
// Check for terminating delimiter (optional):
@@ -297,7 +439,7 @@
297439
goto err;
298440
}
299441

300-
lex = Debase64[*cp];
442+
lex = table[*cp];
301443

302444
if (lex < BIN_SPACE) {
303445

@@ -350,7 +492,7 @@
350492

351493
/***********************************************************************
352494
**
353-
*/ REBYTE *Decode_Binary(REBVAL *value, REBYTE *src, REBCNT len, REBINT base, REBYTE delim)
495+
*/ REBYTE *Decode_Binary(REBVAL *value, REBYTE *src, REBCNT len, REBINT base, REBYTE delim, REBOOL urlSafe)
354496
/*
355497
** Scan and convert a binary string.
356498
**
@@ -360,7 +502,7 @@
360502

361503
switch (base) {
362504
case 64:
363-
ser = Decode_Base64(&src, len, delim);
505+
ser = Decode_Base64(&src, len, delim, urlSafe);
364506
break;
365507
case 16:
366508
ser = Decode_Base16(&src, len, delim);
@@ -457,7 +599,7 @@
457599

458600
/***********************************************************************
459601
**
460-
*/ REBSER *Encode_Base64(REBVAL *value, REBSER *series, REBFLG brk)
602+
*/ REBSER *Encode_Base64(REBVAL *value, REBSER *series, REBFLG brk, REBOOL urlSafe)
461603
/*
462604
** Base64 encode a given series. Must be BYTES, not UNICODE.
463605
**
@@ -470,29 +612,36 @@
470612

471613
len = VAL_LEN(value);
472614
src = VAL_BIN(value);
473-
615+
616+
const REBYTE *table;
617+
if(urlSafe) {
618+
table = Enbase64URL;
619+
} else {
620+
table = Enbase64;
621+
}
622+
474623
// slop-factor
475624
series = Prep_String (series, &p, 4 * len / 3 + 2 * (len / 32) + 5);
476625
loop = (int) (len / 3) - 1;
477626
if (4 * loop > 64 && brk) *p++ = LF;
478627

479628
for (x = 0; x <= 3 * loop; x += 3) {
480-
*p++ = Enbase64[src[x] >> 2];
481-
*p++ = Enbase64[((src[x] & 0x3) << 4) + (src[x + 1] >> 4)];
482-
*p++ = Enbase64[((src[x + 1] & 0xF) << 2) + (src[x + 2] >> 6)];
483-
*p++ = Enbase64[(src[x + 2] % 0x40)];
629+
*p++ = table[src[x] >> 2];
630+
*p++ = table[((src[x] & 0x3) << 4) + (src[x + 1] >> 4)];
631+
*p++ = table[((src[x + 1] & 0xF) << 2) + (src[x + 2] >> 6)];
632+
*p++ = table[(src[x + 2] % 0x40)];
484633
if ((x+3) % 48 == 0 && brk)
485634
*p++ = LF;
486635
}
487636

488637
if ((len % 3) != 0) {
489638
p[2] = p[3] = '=';
490-
*p++ = Enbase64[src[x] >> 2];
639+
*p++ = table[src[x] >> 2];
491640
if ((len - x) >= 1)
492-
*p++ = Enbase64[((src[x] & 0x3) << 4) + ((len - x) == 1 ? 0 : src[x + 1] >> 4)];
641+
*p++ = table[((src[x] & 0x3) << 4) + ((len - x) == 1 ? 0 : src[x + 1] >> 4)];
493642
else p++;
494643
if ((len - x) == 2)
495-
*p++ = Enbase64[(src[x + 1] & 0xF) << 2];
644+
*p++ = table[(src[x + 1] & 0xF) << 2];
496645
else p++;
497646
p++;
498647
}

src/core/n-strings.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ static struct digest {
369369

370370
if (D_REF(2)) base = VAL_INT32(D_ARG(3)); // /base
371371

372-
if (!Decode_Binary(D_RET, BIN_SKIP(ser, index), len, base, 0))
372+
if (!Decode_Binary(D_RET, BIN_SKIP(ser, index), len, base, 0, D_REF(4)))
373373
Trap1(RE_INVALID_DATA, D_ARG(1));
374374

375375
return R_RET;
@@ -397,7 +397,7 @@ static struct digest {
397397

398398
switch (base) {
399399
case 64:
400-
ser = Encode_Base64(arg, 0, FALSE);
400+
ser = Encode_Base64(arg, 0, FALSE, D_REF(4));
401401
break;
402402
case 16:
403403
ser = Encode_Base16(arg, 0, FALSE);

0 commit comments

Comments
 (0)