bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Feature request - base64 Filename Safe Alphabet


From: Bo Borgerson
Subject: Re: Feature request - base64 Filename Safe Alphabet
Date: Wed, 18 Jun 2008 19:52:11 -0400
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

Simon Josefsson wrote:
> Christopher Kerr <address@hidden> writes:
> 
>> After being burned by using `head -c6 /dev/urandom | base64` as part of a 
>> directory name, I realised that it would be useful if base64 had an option 
>> to 
>> generate URL and Filename safe encodings, as specified in RFC 3548 section 4.
>>
>> This would make
>> cat FILE | base64 --filename-safe
>> equivalent to
>> cat FILE | base64 | tr '+/' '-_'
>> using the current coreutils tools.
> 
> I think --filename-safe is a good idea.  The documentation should
> discuss the potential for generating files starting with '-' or '--'.
> Patching gnulib's base64.c to support an arbitrary alphabet seems messy.
> Patches welcome though.

Hi Simon,

I thought I'd take a stab at this and see where it goes.

What I've done is exposed an additional set of functions, *_a, which
take an arbitrary alphabet as an extra parameter.  Each historical
function now calls one of these with the 'main' alphabet.  I then added
a parallel set of functions, *_filesafe, which call the *_a functions
with the alphabet described above.

It is a little messy, I think, because the large hand-initialized
data-structures are duplicated.  The messiness could be reduced by
having base64 just expose the *_a interface for using an arbitrary
alphabet, and adding a second module (base64_filesafe?) that provided
that specific alternate (with all its attendant bulk).

In any case, as with my previous patches I've tried not to alter the
behavior of any already existing functions.

I've also attached a small patch against coreutils' base64 utility that
provides the desired behavior.  There are no documentation/tests/etc
yet.  It's only for demonstration purposes.

How does this look to you?

Thanks,

Bo
>From fcb70d9fdd1c7979f0e3ee499a4824cccc8fd771 Mon Sep 17 00:00:00 2001
From: Bo Borgerson <address@hidden>
Date: Wed, 18 Jun 2008 19:16:01 -0400
Subject: [PATCH] base64: Provide an interface for alphabet configurationi and a 
filesafe alphabet.

* lib/base64.c (base64_encode_a): Was base64_encode.  Takes an alphabet.
(base64_encode_alloc_a): Was base64_encode_alloc. Takes an alphabet.
(isbase64_a): Was isbase64.  Takes an alphabet.
(isbase64 isbase64_filesafe): Call isbase64_a with appropriate alphabet.
(decode_4): Takes an alphabet.
(base64_decode_ctx_a): Was base64_decode_ctx. Takes an alphabet.
(base64_decode_alloc_ctx_a): Was base64_decode_alloc_ctx. Takes an alphabet.
* lib/base64.h (base64_encode): Now a wrapper around base64_encode_a.
(base64_encode_filesafe): Likewise.
(base64_encode_alloc): Now a wrapper around base64_encode_alloc_a.
(base64_encode_alloc_filesafe): Likewise.
(base64_decode_ctx): Now a wrapper around base64_decode_ctx_a.
(base64_decode_ctx_filesafe): Likewise.
(base64_decode): Likewise.
(base64_decode_alloc_ctx): Now a wrapper around base64_decode_alloc_ctx_a.
(base64_decode_alloc_ctx_filesafe): Likewise.
(base64_decode_alloc): Likewise.

Signed-off-by: Bo Borgerson <address@hidden>
---
 lib/base64.c |  327 ++++++++++++++++++++++++++++++++++++++++++---------------
 lib/base64.h |   54 ++++++++--
 2 files changed, 287 insertions(+), 94 deletions(-)

diff --git a/lib/base64.c b/lib/base64.c
index 8aff430..01baa62 100644
--- a/lib/base64.c
+++ b/lib/base64.c
@@ -61,17 +61,22 @@ to_uchar (char ch)
   return ch;
 }
 
+const char b64str_main[64] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const char b64str_filesafe[64] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+
 /* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
    If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
    possible.  If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
    terminate the output buffer. */
 void
-base64_encode (const char *restrict in, size_t inlen,
-              char *restrict out, size_t outlen)
+base64_encode_a (const char *restrict in, size_t inlen,
+                char *restrict out, size_t outlen,
+                const char *b64str)
 {
-  static const char b64str[64] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
   while (inlen && outlen)
     {
       *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
@@ -113,7 +118,8 @@ base64_encode (const char *restrict in, size_t inlen,
    indicates length of the requested memory block, i.e.,
    BASE64_LENGTH(inlen) + 1. */
 size_t
-base64_encode_alloc (const char *in, size_t inlen, char **out)
+base64_encode_alloc_a (const char *in, size_t inlen, char **out,
+                      const char *b64str)
 {
   size_t outlen = 1 + BASE64_LENGTH (inlen);
 
@@ -153,7 +159,7 @@ base64_encode_alloc (const char *in, size_t inlen, char 
**out)
 
    IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
    as the formal parameter rather than "x".  */
-#define B64(_)                                 \
+#define B64M(_)                                        \
   ((_) == 'A' ? 0                              \
    : (_) == 'B' ? 1                            \
    : (_) == 'C' ? 2                            \
@@ -220,71 +226,206 @@ base64_encode_alloc (const char *in, size_t inlen, char 
**out)
    : (_) == '/' ? 63                           \
    : -1)
 
-static const signed char b64[0x100] = {
-  B64 (0), B64 (1), B64 (2), B64 (3),
-  B64 (4), B64 (5), B64 (6), B64 (7),
-  B64 (8), B64 (9), B64 (10), B64 (11),
-  B64 (12), B64 (13), B64 (14), B64 (15),
-  B64 (16), B64 (17), B64 (18), B64 (19),
-  B64 (20), B64 (21), B64 (22), B64 (23),
-  B64 (24), B64 (25), B64 (26), B64 (27),
-  B64 (28), B64 (29), B64 (30), B64 (31),
-  B64 (32), B64 (33), B64 (34), B64 (35),
-  B64 (36), B64 (37), B64 (38), B64 (39),
-  B64 (40), B64 (41), B64 (42), B64 (43),
-  B64 (44), B64 (45), B64 (46), B64 (47),
-  B64 (48), B64 (49), B64 (50), B64 (51),
-  B64 (52), B64 (53), B64 (54), B64 (55),
-  B64 (56), B64 (57), B64 (58), B64 (59),
-  B64 (60), B64 (61), B64 (62), B64 (63),
-  B64 (64), B64 (65), B64 (66), B64 (67),
-  B64 (68), B64 (69), B64 (70), B64 (71),
-  B64 (72), B64 (73), B64 (74), B64 (75),
-  B64 (76), B64 (77), B64 (78), B64 (79),
-  B64 (80), B64 (81), B64 (82), B64 (83),
-  B64 (84), B64 (85), B64 (86), B64 (87),
-  B64 (88), B64 (89), B64 (90), B64 (91),
-  B64 (92), B64 (93), B64 (94), B64 (95),
-  B64 (96), B64 (97), B64 (98), B64 (99),
-  B64 (100), B64 (101), B64 (102), B64 (103),
-  B64 (104), B64 (105), B64 (106), B64 (107),
-  B64 (108), B64 (109), B64 (110), B64 (111),
-  B64 (112), B64 (113), B64 (114), B64 (115),
-  B64 (116), B64 (117), B64 (118), B64 (119),
-  B64 (120), B64 (121), B64 (122), B64 (123),
-  B64 (124), B64 (125), B64 (126), B64 (127),
-  B64 (128), B64 (129), B64 (130), B64 (131),
-  B64 (132), B64 (133), B64 (134), B64 (135),
-  B64 (136), B64 (137), B64 (138), B64 (139),
-  B64 (140), B64 (141), B64 (142), B64 (143),
-  B64 (144), B64 (145), B64 (146), B64 (147),
-  B64 (148), B64 (149), B64 (150), B64 (151),
-  B64 (152), B64 (153), B64 (154), B64 (155),
-  B64 (156), B64 (157), B64 (158), B64 (159),
-  B64 (160), B64 (161), B64 (162), B64 (163),
-  B64 (164), B64 (165), B64 (166), B64 (167),
-  B64 (168), B64 (169), B64 (170), B64 (171),
-  B64 (172), B64 (173), B64 (174), B64 (175),
-  B64 (176), B64 (177), B64 (178), B64 (179),
-  B64 (180), B64 (181), B64 (182), B64 (183),
-  B64 (184), B64 (185), B64 (186), B64 (187),
-  B64 (188), B64 (189), B64 (190), B64 (191),
-  B64 (192), B64 (193), B64 (194), B64 (195),
-  B64 (196), B64 (197), B64 (198), B64 (199),
-  B64 (200), B64 (201), B64 (202), B64 (203),
-  B64 (204), B64 (205), B64 (206), B64 (207),
-  B64 (208), B64 (209), B64 (210), B64 (211),
-  B64 (212), B64 (213), B64 (214), B64 (215),
-  B64 (216), B64 (217), B64 (218), B64 (219),
-  B64 (220), B64 (221), B64 (222), B64 (223),
-  B64 (224), B64 (225), B64 (226), B64 (227),
-  B64 (228), B64 (229), B64 (230), B64 (231),
-  B64 (232), B64 (233), B64 (234), B64 (235),
-  B64 (236), B64 (237), B64 (238), B64 (239),
-  B64 (240), B64 (241), B64 (242), B64 (243),
-  B64 (244), B64 (245), B64 (246), B64 (247),
-  B64 (248), B64 (249), B64 (250), B64 (251),
-  B64 (252), B64 (253), B64 (254), B64 (255)
+#define B64F(_)                                        \
+  ((_) == 'A' ? 0                              \
+   : (_) == 'B' ? 1                            \
+   : (_) == 'C' ? 2                            \
+   : (_) == 'D' ? 3                            \
+   : (_) == 'E' ? 4                            \
+   : (_) == 'F' ? 5                            \
+   : (_) == 'G' ? 6                            \
+   : (_) == 'H' ? 7                            \
+   : (_) == 'I' ? 8                            \
+   : (_) == 'J' ? 9                            \
+   : (_) == 'K' ? 10                           \
+   : (_) == 'L' ? 11                           \
+   : (_) == 'M' ? 12                           \
+   : (_) == 'N' ? 13                           \
+   : (_) == 'O' ? 14                           \
+   : (_) == 'P' ? 15                           \
+   : (_) == 'Q' ? 16                           \
+   : (_) == 'R' ? 17                           \
+   : (_) == 'S' ? 18                           \
+   : (_) == 'T' ? 19                           \
+   : (_) == 'U' ? 20                           \
+   : (_) == 'V' ? 21                           \
+   : (_) == 'W' ? 22                           \
+   : (_) == 'X' ? 23                           \
+   : (_) == 'Y' ? 24                           \
+   : (_) == 'Z' ? 25                           \
+   : (_) == 'a' ? 26                           \
+   : (_) == 'b' ? 27                           \
+   : (_) == 'c' ? 28                           \
+   : (_) == 'd' ? 29                           \
+   : (_) == 'e' ? 30                           \
+   : (_) == 'f' ? 31                           \
+   : (_) == 'g' ? 32                           \
+   : (_) == 'h' ? 33                           \
+   : (_) == 'i' ? 34                           \
+   : (_) == 'j' ? 35                           \
+   : (_) == 'k' ? 36                           \
+   : (_) == 'l' ? 37                           \
+   : (_) == 'm' ? 38                           \
+   : (_) == 'n' ? 39                           \
+   : (_) == 'o' ? 40                           \
+   : (_) == 'p' ? 41                           \
+   : (_) == 'q' ? 42                           \
+   : (_) == 'r' ? 43                           \
+   : (_) == 's' ? 44                           \
+   : (_) == 't' ? 45                           \
+   : (_) == 'u' ? 46                           \
+   : (_) == 'v' ? 47                           \
+   : (_) == 'w' ? 48                           \
+   : (_) == 'x' ? 49                           \
+   : (_) == 'y' ? 50                           \
+   : (_) == 'z' ? 51                           \
+   : (_) == '0' ? 52                           \
+   : (_) == '1' ? 53                           \
+   : (_) == '2' ? 54                           \
+   : (_) == '3' ? 55                           \
+   : (_) == '4' ? 56                           \
+   : (_) == '5' ? 57                           \
+   : (_) == '6' ? 58                           \
+   : (_) == '7' ? 59                           \
+   : (_) == '8' ? 60                           \
+   : (_) == '9' ? 61                           \
+   : (_) == '-' ? 62                           \
+   : (_) == '_' ? 63                           \
+   : -1)
+
+
+const signed char b64_main[0x100] = {
+  B64M (0), B64M (1), B64M (2), B64M (3),
+  B64M (4), B64M (5), B64M (6), B64M (7),
+  B64M (8), B64M (9), B64M (10), B64M (11),
+  B64M (12), B64M (13), B64M (14), B64M (15),
+  B64M (16), B64M (17), B64M (18), B64M (19),
+  B64M (20), B64M (21), B64M (22), B64M (23),
+  B64M (24), B64M (25), B64M (26), B64M (27),
+  B64M (28), B64M (29), B64M (30), B64M (31),
+  B64M (32), B64M (33), B64M (34), B64M (35),
+  B64M (36), B64M (37), B64M (38), B64M (39),
+  B64M (40), B64M (41), B64M (42), B64M (43),
+  B64M (44), B64M (45), B64M (46), B64M (47),
+  B64M (48), B64M (49), B64M (50), B64M (51),
+  B64M (52), B64M (53), B64M (54), B64M (55),
+  B64M (56), B64M (57), B64M (58), B64M (59),
+  B64M (60), B64M (61), B64M (62), B64M (63),
+  B64M (64), B64M (65), B64M (66), B64M (67),
+  B64M (68), B64M (69), B64M (70), B64M (71),
+  B64M (72), B64M (73), B64M (74), B64M (75),
+  B64M (76), B64M (77), B64M (78), B64M (79),
+  B64M (80), B64M (81), B64M (82), B64M (83),
+  B64M (84), B64M (85), B64M (86), B64M (87),
+  B64M (88), B64M (89), B64M (90), B64M (91),
+  B64M (92), B64M (93), B64M (94), B64M (95),
+  B64M (96), B64M (97), B64M (98), B64M (99),
+  B64M (100), B64M (101), B64M (102), B64M (103),
+  B64M (104), B64M (105), B64M (106), B64M (107),
+  B64M (108), B64M (109), B64M (110), B64M (111),
+  B64M (112), B64M (113), B64M (114), B64M (115),
+  B64M (116), B64M (117), B64M (118), B64M (119),
+  B64M (120), B64M (121), B64M (122), B64M (123),
+  B64M (124), B64M (125), B64M (126), B64M (127),
+  B64M (128), B64M (129), B64M (130), B64M (131),
+  B64M (132), B64M (133), B64M (134), B64M (135),
+  B64M (136), B64M (137), B64M (138), B64M (139),
+  B64M (140), B64M (141), B64M (142), B64M (143),
+  B64M (144), B64M (145), B64M (146), B64M (147),
+  B64M (148), B64M (149), B64M (150), B64M (151),
+  B64M (152), B64M (153), B64M (154), B64M (155),
+  B64M (156), B64M (157), B64M (158), B64M (159),
+  B64M (160), B64M (161), B64M (162), B64M (163),
+  B64M (164), B64M (165), B64M (166), B64M (167),
+  B64M (168), B64M (169), B64M (170), B64M (171),
+  B64M (172), B64M (173), B64M (174), B64M (175),
+  B64M (176), B64M (177), B64M (178), B64M (179),
+  B64M (180), B64M (181), B64M (182), B64M (183),
+  B64M (184), B64M (185), B64M (186), B64M (187),
+  B64M (188), B64M (189), B64M (190), B64M (191),
+  B64M (192), B64M (193), B64M (194), B64M (195),
+  B64M (196), B64M (197), B64M (198), B64M (199),
+  B64M (200), B64M (201), B64M (202), B64M (203),
+  B64M (204), B64M (205), B64M (206), B64M (207),
+  B64M (208), B64M (209), B64M (210), B64M (211),
+  B64M (212), B64M (213), B64M (214), B64M (215),
+  B64M (216), B64M (217), B64M (218), B64M (219),
+  B64M (220), B64M (221), B64M (222), B64M (223),
+  B64M (224), B64M (225), B64M (226), B64M (227),
+  B64M (228), B64M (229), B64M (230), B64M (231),
+  B64M (232), B64M (233), B64M (234), B64M (235),
+  B64M (236), B64M (237), B64M (238), B64M (239),
+  B64M (240), B64M (241), B64M (242), B64M (243),
+  B64M (244), B64M (245), B64M (246), B64M (247),
+  B64M (248), B64M (249), B64M (250), B64M (251),
+  B64M (252), B64M (253), B64M (254), B64M (255)
+};
+
+const signed char b64_filesafe[0x100] = {
+  B64F (0), B64F (1), B64F (2), B64F (3),
+  B64F (4), B64F (5), B64F (6), B64F (7),
+  B64F (8), B64F (9), B64F (10), B64F (11),
+  B64F (12), B64F (13), B64F (14), B64F (15),
+  B64F (16), B64F (17), B64F (18), B64F (19),
+  B64F (20), B64F (21), B64F (22), B64F (23),
+  B64F (24), B64F (25), B64F (26), B64F (27),
+  B64F (28), B64F (29), B64F (30), B64F (31),
+  B64F (32), B64F (33), B64F (34), B64F (35),
+  B64F (36), B64F (37), B64F (38), B64F (39),
+  B64F (40), B64F (41), B64F (42), B64F (43),
+  B64F (44), B64F (45), B64F (46), B64F (47),
+  B64F (48), B64F (49), B64F (50), B64F (51),
+  B64F (52), B64F (53), B64F (54), B64F (55),
+  B64F (56), B64F (57), B64F (58), B64F (59),
+  B64F (60), B64F (61), B64F (62), B64F (63),
+  B64F (64), B64F (65), B64F (66), B64F (67),
+  B64F (68), B64F (69), B64F (70), B64F (71),
+  B64F (72), B64F (73), B64F (74), B64F (75),
+  B64F (76), B64F (77), B64F (78), B64F (79),
+  B64F (80), B64F (81), B64F (82), B64F (83),
+  B64F (84), B64F (85), B64F (86), B64F (87),
+  B64F (88), B64F (89), B64F (90), B64F (91),
+  B64F (92), B64F (93), B64F (94), B64F (95),
+  B64F (96), B64F (97), B64F (98), B64F (99),
+  B64F (100), B64F (101), B64F (102), B64F (103),
+  B64F (104), B64F (105), B64F (106), B64F (107),
+  B64F (108), B64F (109), B64F (110), B64F (111),
+  B64F (112), B64F (113), B64F (114), B64F (115),
+  B64F (116), B64F (117), B64F (118), B64F (119),
+  B64F (120), B64F (121), B64F (122), B64F (123),
+  B64F (124), B64F (125), B64F (126), B64F (127),
+  B64F (128), B64F (129), B64F (130), B64F (131),
+  B64F (132), B64F (133), B64F (134), B64F (135),
+  B64F (136), B64F (137), B64F (138), B64F (139),
+  B64F (140), B64F (141), B64F (142), B64F (143),
+  B64F (144), B64F (145), B64F (146), B64F (147),
+  B64F (148), B64F (149), B64F (150), B64F (151),
+  B64F (152), B64F (153), B64F (154), B64F (155),
+  B64F (156), B64F (157), B64F (158), B64F (159),
+  B64F (160), B64F (161), B64F (162), B64F (163),
+  B64F (164), B64F (165), B64F (166), B64F (167),
+  B64F (168), B64F (169), B64F (170), B64F (171),
+  B64F (172), B64F (173), B64F (174), B64F (175),
+  B64F (176), B64F (177), B64F (178), B64F (179),
+  B64F (180), B64F (181), B64F (182), B64F (183),
+  B64F (184), B64F (185), B64F (186), B64F (187),
+  B64F (188), B64F (189), B64F (190), B64F (191),
+  B64F (192), B64F (193), B64F (194), B64F (195),
+  B64F (196), B64F (197), B64F (198), B64F (199),
+  B64F (200), B64F (201), B64F (202), B64F (203),
+  B64F (204), B64F (205), B64F (206), B64F (207),
+  B64F (208), B64F (209), B64F (210), B64F (211),
+  B64F (212), B64F (213), B64F (214), B64F (215),
+  B64F (216), B64F (217), B64F (218), B64F (219),
+  B64F (220), B64F (221), B64F (222), B64F (223),
+  B64F (224), B64F (225), B64F (226), B64F (227),
+  B64F (228), B64F (229), B64F (230), B64F (231),
+  B64F (232), B64F (233), B64F (234), B64F (235),
+  B64F (236), B64F (237), B64F (238), B64F (239),
+  B64F (240), B64F (241), B64F (242), B64F (243),
+  B64F (244), B64F (245), B64F (246), B64F (247),
+  B64F (248), B64F (249), B64F (250), B64F (251),
+  B64F (252), B64F (253), B64F (254), B64F (255)
 };
 
 #if UCHAR_MAX == 255
@@ -296,12 +437,25 @@ static const signed char b64[0x100] = {
 /* Return true if CH is a character from the Base64 alphabet, and
    false otherwise.  Note that '=' is padding and not considered to be
    part of the alphabet.  */
+
 bool
-isbase64 (char ch)
+isbase64_a (char ch, const signed char *b64)
 {
   return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
 }
 
+bool
+isbase64 (char ch)
+{
+  return isbase64_a (ch, b64_main);
+}
+
+bool
+isbase64_filesafe (char ch)
+{
+  return isbase64_a (ch, b64_filesafe);
+}
+
 /* Initialize decode-context buffer, CTX.  */
 void
 base64_decode_ctx_init (struct base64_decode_context *ctx)
@@ -372,13 +526,13 @@ get_4 (struct base64_decode_context *ctx,
    *OUTLEN to reflect the number of bytes remaining in *OUT.  */
 static inline bool
 decode_4 (char const *restrict in, size_t inlen,
-         char *restrict *outp, size_t *outleft)
+         char *restrict *outp, size_t *outleft, const signed char *b64)
 {
   char *out = *outp;
   if (inlen < 2)
     return false;
 
-  if (!isbase64 (in[0]) || !isbase64 (in[1]))
+  if (!isbase64_a (in[0], b64) || !isbase64_a (in[1], b64))
     return false;
 
   if (*outleft)
@@ -401,7 +555,7 @@ decode_4 (char const *restrict in, size_t inlen,
     }
   else
     {
-      if (!isbase64 (in[2]))
+      if (!isbase64_a (in[2], b64))
        return_false;
 
       if (*outleft)
@@ -421,7 +575,7 @@ decode_4 (char const *restrict in, size_t inlen,
        }
       else
        {
-         if (!isbase64 (in[3]))
+         if (!isbase64_a (in[3], b64))
            return_false;
 
          if (*outleft)
@@ -456,9 +610,10 @@ decode_4 (char const *restrict in, size_t inlen,
    buffer is processed as a unit.  */
 
 bool
-base64_decode_ctx (struct base64_decode_context *ctx,
-                  const char *restrict in, size_t inlen,
-                  char *restrict out, size_t *outlen)
+base64_decode_ctx_a (struct base64_decode_context *ctx,
+                    const char *restrict in, size_t inlen,
+                    char *restrict out, size_t *outlen,
+                    unsigned const char *b64)
 {
   size_t outleft = *outlen;
   bool ignore_newlines = ctx != NULL;
@@ -482,7 +637,7 @@ base64_decode_ctx (struct base64_decode_context *ctx,
              /* Save a copy of outleft, in case we need to re-parse this
                 block of four bytes.  */
              outleft_save = outleft;
-             if (!decode_4 (in, inlen, &out, &outleft))
+             if (!decode_4 (in, inlen, &out, &outleft, b64))
                break;
 
              in += 4;
@@ -523,7 +678,7 @@ base64_decode_ctx (struct base64_decode_context *ctx,
            inlen = 0;
            break;
          }
-       if (!decode_4 (non_nl, inlen, &out, &outleft))
+       if (!decode_4 (non_nl, inlen, &out, &outleft, b64))
          break;
 
        inlen = in_end - in;
@@ -547,9 +702,9 @@ base64_decode_ctx (struct base64_decode_context *ctx,
    input was invalid, in which case *OUT is NULL and *OUTLEN is
    undefined. */
 bool
-base64_decode_alloc_ctx (struct base64_decode_context *ctx,
-                        const char *in, size_t inlen, char **out,
-                        size_t *outlen)
+base64_decode_alloc_ctx_a (struct base64_decode_context *ctx,
+                          const char *in, size_t inlen, char **out,
+                          size_t *outlen, unsigned const char *b64)
 {
   /* This may allocate a few bytes too many, depending on input,
      but it's not worth the extra CPU time to compute the exact size.
@@ -562,7 +717,7 @@ base64_decode_alloc_ctx (struct base64_decode_context *ctx,
   if (!*out)
     return true;
 
-  if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
+  if (!base64_decode_ctx_a (ctx, in, inlen, *out, &needlen, b64))
     {
       free (*out);
       *out = NULL;
diff --git a/lib/base64.h b/lib/base64.h
index 9c31651..e48f73b 100644
--- a/lib/base64.h
+++ b/lib/base64.h
@@ -35,27 +35,65 @@ struct base64_decode_context
   char buf[4];
 };
 
+extern const char b64str_main[];
+extern const char b64str_filesafe[];
+
+extern const signed char b64_main[];
+extern const signed char b64_filesafe[];
+
 extern bool isbase64 (char ch);
 
-extern void base64_encode (const char *restrict in, size_t inlen,
-                          char *restrict out, size_t outlen);
+extern void base64_encode_a (const char *restrict in, size_t inlen,
+                            char *restrict out, size_t outlen,
+                            const char *b64str);
+
+#define base64_encode(in, inlen, out, outlen) \
+       base64_encode_a (in, inlen, out, outlen, b64str_main)
 
-extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
+#define base64_encode_filesafe(in, inlen, out, outlen) \
+       base64_encode_a (in, inlen, out, outlen, b64str_filesafe)
+
+extern size_t base64_encode_alloc_a (const char *in, size_t inlen, char **out,
+                                    const char *b64str);
+#define base64_encode_alloc(in, inlen, out) \
+       base64_encode_alloc_a (in, inlen, out, b64str_main)
+
+#define base64_encode_alloc_filesafe(in, inlen, out) \
+       base64_encode_alloc_a (in, inlen, out, b64str_filesafe)
 
 extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
 
-extern bool base64_decode_ctx (struct base64_decode_context *ctx,
-                              const char *restrict in, size_t inlen,
-                              char *restrict out, size_t *outlen);
+extern bool base64_decode_ctx_a (struct base64_decode_context *ctx,
+                                const char *restrict in, size_t inlen,
+                                char *restrict out, size_t *outlen,
+                                unsigned const char *b64);
 
 extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
                                     const char *in, size_t inlen,
                                     char **out, size_t *outlen);
 
+#define base64_decode_ctx(ctx, in, inlen, out, outlen) \
+       base64_decode_ctx_a (ctx, in, inlen, out, outlen, b64_main)
+
+#define base64_decode_ctx_filesafe(ctx, in, inlen, out, outlen) \
+       base64_decode_ctx_a (ctx, in, inlen, out, outlen, b64_filesafe)
+
+extern bool base64_decode_alloc_ctx_a (struct base64_decode_context *ctx,
+                                      const char *in, size_t inlen, char **out,
+                                      size_t *outlen, unsigned const char 
*b64);
+
+#define base64_decode_alloc_ctx(ctx, in, inlen, out, outlen) \
+       base64_decode_alloc_ctx_a (ctx, in, inlen, out, outlen, b64_main)
+
+#define base64_decode_alloc_ctx_filesafe(ctx, in, inlen, out, outlen) \
+       base64_decode_alloc_ctx_a (ctx, in, inlen, out, outlen, b64_filesafe)
+
+/* These are provided for historical usage.  They treat newlines as garbage. */
+
 #define base64_decode(in, inlen, out, outlen) \
-       base64_decode_ctx (NULL, in, inlen, out, outlen)
+       base64_decode_ctx_a (NULL, in, inlen, out, outlen, b64_main)
 
 #define base64_decode_alloc(in, inlen, out, outlen) \
-       base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
+       base64_decode_alloc_ctx_a (NULL, in, inlen, out, b64_main)
 
 #endif /* BASE64_H */
-- 
1.5.4.3

>From e2402bcb80ec1d18555c7e4bca591ca3a14253ed Mon Sep 17 00:00:00 2001
From: Bo Borgerson <address@hidden>
Date: Wed, 18 Jun 2008 19:27:03 -0400
Subject: [PATCH] base64: Add new option --filename-safe.

* src/base64.c (static bool filesafe_alphabet) Flag set by new option.
(usage): Describe new option.
(do_encode): Choose appropriate function based on desired alphabet.
(do_decode): Likewise.
(main): Set new option.

Signed-off-by: Bo Borgerson <address@hidden>
---
 src/base64.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/base64.c b/src/base64.c
index 5067b28..979e3b3 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -37,11 +37,24 @@
 
 #define AUTHORS proper_name ("Simon Josefsson")
 
+/* This can be set to true on the command line with the
+   --filename-safe option. */
+static bool filesafe_alphabet = false;
+
+/* For long options that have no equivalent short option, use a
+   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
+enum
+{
+  FILESAFE_OPTION = CHAR_MAX + 1
+};
+
+
 static struct option const long_options[] =
 {
   {"decode", no_argument, 0, 'd'},
   {"wrap", required_argument, 0, 'w'},
   {"ignore-garbage", no_argument, 0, 'i'},
+  {"filename-safe", no_argument, 0, FILESAFE_OPTION},
 
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
@@ -69,6 +82,11 @@ Base64 encode or decode FILE, or standard input, to standard 
output.\n\
 \n\
 "), stdout);
       fputs (_("\
+      --filename-safe   Use a base64 alphabet that contains `-' and `_'\n\
+                        instead of `+' and `/'.\n\
+\n\
+"), stdout);
+      fputs (_("\
       --help            Display this help and exit.\n\
       --version         Output version information and exit.\n"), stdout);
       fputs (_("\
@@ -156,7 +174,10 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
        {
          /* Process input one block at a time.  Note that BLOCKSIZE %
             3 == 0, so that no base64 pads will appear in output. */
-         base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
+         if (filesafe_alphabet)
+           base64_encode_filesafe (inbuf, sum, outbuf, BASE64_LENGTH (sum));
+         else
+           base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
 
          wrap_write (outbuf, BASE64_LENGTH (sum), wrap_column,
                      &current_column, out);
@@ -219,7 +240,10 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage)
          if (k == 1 && ctx.i == 0)
            break;
          n = BLOCKSIZE;
-         ok = base64_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
+         ok = filesafe_alphabet
+               ?base64_decode_ctx_filesafe (&ctx, inbuf, (k == 0 ? sum : 0),
+                                            outbuf, &n)
+               :base64_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, 
&n);
 
          if (fwrite (outbuf, 1, n, out) < n)
            error (EXIT_FAILURE, errno, _("write error"));
@@ -270,6 +294,10 @@ main (int argc, char **argv)
        ignore_garbage = true;
        break;
 
+      case FILESAFE_OPTION:
+       filesafe_alphabet = true;
+       break;
+
        case_GETOPT_HELP_CHAR;
 
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
-- 
1.5.4.3


reply via email to

[Prev in Thread] Current Thread [Next in Thread]