1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.text.Codec;
13 
14 
15 /**
16  * Fast B64 Encoder/Decoder as described in RFC 1421.
17  * <p>Does not insert or interpret whitespace as described in RFC
18  * 1521. If you require this you must pre/post process your data.
19  * <p> Note that in a web context the usual case is to not want
20  * linebreaks or other white space in the encoded output.
21  */
22 class B64Code {
23     private enum char __pad = '=';
24     private enum char[] __rfc1421alphabet =
25             [
26                 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
27                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
28                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
29                 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
30             ];
31 
32     private __gshared byte[] __rfc1421nibbles;
33 
34     private enum char[] __rfc4648urlAlphabet =
35             [
36                 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
37                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
38                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
39                 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
40             ];
41 
42     private __gshared byte[] __rfc4648urlNibbles;
43 
44     shared static this() {
45         
46         __rfc1421nibbles = new byte[256];
47         for (int i = 0; i < 256; i++)
48             __rfc1421nibbles[i] = -1;
49         for (byte b = 0; b < 64; b++)
50             __rfc1421nibbles[cast(byte) __rfc1421alphabet[b]] = b;
51         __rfc1421nibbles[cast(byte) __pad] = 0;
52 
53         __rfc4648urlNibbles = new byte[256];
54         for (int i = 0; i < 256; i++)
55             __rfc4648urlNibbles[i] = -1;
56         for (byte b = 0; b < 64; b++)
57             __rfc4648urlNibbles[cast(byte) __rfc4648urlAlphabet[b]] = b;
58         __rfc4648urlNibbles[cast(byte) __pad] = 0;
59     }
60 
61     private this() {
62     }
63 
64 
65     
66     /**
67      * Fast Base 64 encode as described in RFC 1421.
68      * <p>Does not insert whitespace as described in RFC 1521.
69      * <p> Avoids creating extra copies of the input/output.
70      *
71      * @param b byte array to encode.
72      * @return char array containing the encoded form of the input.
73      */
74     static const(char)[] encode(byte[] b) {
75         if (b is null)
76             return null;
77 
78         int bLen = cast(int)b.length;
79         int cLen = ((bLen + 2) / 3) * 4;
80         char[] c = new char[cLen];
81         int ci = 0;
82         int bi = 0;
83         byte b0, b1, b2;
84         int stop = (bLen / 3) * 3;
85         while (bi < stop) {
86             b0 = b[bi++];
87             b1 = b[bi++];
88             b2 = b[bi++];
89             c[ci++] = __rfc1421alphabet[(b0 >>> 2) & 0x3f];
90             c[ci++] = __rfc1421alphabet[(b0 << 4) & 0x3f | (b1 >>> 4) & 0x0f];
91             c[ci++] = __rfc1421alphabet[(b1 << 2) & 0x3f | (b2 >>> 6) & 0x03];
92             c[ci++] = __rfc1421alphabet[b2 & 0x3f];
93         }
94 
95         if (bLen != bi) {
96             switch (bLen % 3) {
97                 case 2:
98                     b0 = b[bi++];
99                     b1 = b[bi++];
100                     c[ci++] = __rfc1421alphabet[(b0 >>> 2) & 0x3f];
101                     c[ci++] = __rfc1421alphabet[(b0 << 4) & 0x3f | (b1 >>> 4) & 0x0f];
102                     c[ci++] = __rfc1421alphabet[(b1 << 2) & 0x3f];
103                     c[ci++] = __pad;
104                     break;
105 
106                 case 1:
107                     b0 = b[bi++];
108                     c[ci++] = __rfc1421alphabet[(b0 >>> 2) & 0x3f];
109                     c[ci++] = __rfc1421alphabet[(b0 << 4) & 0x3f];
110                     c[ci++] = __pad;
111                     c[ci++] = __pad;
112                     break;
113 
114                 default:
115                     break;
116             }
117         }
118 
119         return c;
120     }
121 
122 }