13 | --------------------------------------------------------------------------------
14 | -- Length calculations
15 | --------------------------------------------------------------------------------
17 | ||| Given a length of input data, calculate the length of its Base64 encoding.
18 | |||
19 | ||| Base64 encodes every three input bytes as four output bytes.
20 | |||
21 | ||| A final partial group of one or two bytes is padded to a complete
22 | ||| four-byte group.
23 | |||
24 | ||| The returned length does not include a trailing NUL byte.
25 | |||
26 | export
31 | ||| Calculate the number of Base64 bytes required to encode a given number
32 | ||| of input bytes.
33 | |||
34 | ||| This is the natural-number counterpart of `base64EncodeLength` and is
35 | ||| used internally when allocating statically sized mutable buffers.
36 | |||
41 | --------------------------------------------------------------------------------
42 | -- Internal constants
43 | --------------------------------------------------------------------------------
45 | ||| The ASCII representation of the Base64 padding character.
46 | |||
50 | --------------------------------------------------------------------------------
51 | -- Internal Base64 table access
52 | --------------------------------------------------------------------------------
54 | ||| Look up the first Base64 character generated from an input byte.
55 | |||
56 | ||| The `e0a` table maps each possible input byte directly to the Base64
57 | ||| character represented by its upper six bits.
58 | |||
63 | assert_total $
64 | idris_crash
65 | "Data.String.Base64.Encode.indexBase64First: invalid input byte"
69 | ||| Look up a Base64 character using the second optimized encoding table.
70 | |||
71 | ||| The input is a six-bit Base64 alphabet index represented as `Bits8`.
72 | |||
77 | assert_total $
78 | idris_crash
79 | "Data.String.Base64.Encode.indexBase64Second: invalid Base64 index"
83 | ||| Look up a Base64 character using the third optimized encoding table.
84 | |||
85 | ||| The input is a six-bit Base64 alphabet index represented as `Bits8`.
86 | |||
91 | assert_total $
92 | idris_crash
93 | "Data.String.Base64.Encode.indexBase64Third: invalid Base64 index"
97 | --------------------------------------------------------------------------------
98 | -- Mutable buffer access
99 | --------------------------------------------------------------------------------
101 | ||| Write a byte to a mutable buffer at a natural-number offset.
102 | |||
103 | ||| The mutable buffer is scoped to the current `F1` region. The offset is
104 | ||| dynamically converted to a valid `Fin n`; failure indicates an internal
105 | ||| encoder invariant violation.
106 | |||
107 | ||| All offsets passed by the encoder are derived from the precomputed Base64
108 | ||| output length and are therefore expected to be in bounds.
109 | |||
114 | assert_total $
115 | idris_crash
116 | "Data.String.Base64.Encode.writeByte: output offset out of bounds"
120 | --------------------------------------------------------------------------------
121 | -- Three-byte hot path
122 | --------------------------------------------------------------------------------
124 | ||| Encode three input bytes into four Base64 bytes.
125 | |||
126 | ||| This is the hot path of the native encoder.
127 | |||
128 | ||| Three input bytes contain 24 bits, which are divided into four six-bit
129 | ||| Base64 indices:
130 | |||
131 | ||| 76543210 76543210 76543210
132 | ||| aaaaaabb bbbbcccc ccdddddd
133 | |||
134 | ||| The optimized encoding tables from `Data.String.Base64.Internal` are used
135 | ||| to translate the resulting indices into their ASCII Base64 bytes.
136 | |||
137 | ||| The destination buffer must contain at least four writable bytes beginning
138 | ||| at `destOffset`.
139 | |||
170 | --------------------------------------------------------------------------------
171 | -- Final partial groups
172 | --------------------------------------------------------------------------------
174 | ||| Encode a final one-byte Base64 group.
175 | |||
176 | ||| One input byte produces two Base64 characters followed by two padding
177 | ||| characters:
178 | |||
179 | ||| xx==
180 | |||
181 | ||| The destination buffer must contain at least four writable bytes beginning
182 | ||| at `destOffset`.
183 | |||
200 | ||| Encode a final two-byte Base64 group.
201 | |||
202 | ||| Two input bytes produce three Base64 characters followed by one padding
203 | ||| character:
204 | |||
205 | ||| xxx=
206 | |||
207 | ||| The destination buffer must contain at least four writable bytes beginning
208 | ||| at `destOffset`.
209 | |||
233 | --------------------------------------------------------------------------------
234 | -- Native encoder
235 | --------------------------------------------------------------------------------
237 | ||| Encode a list of bytes into a preallocated mutable Base64 buffer.
238 | |||
239 | ||| The destination buffer must be large enough to hold
240 | ||| `base64EncodeLengthNat (length input)` bytes.
241 | |||
242 | ||| Complete three-byte groups are processed using the optimized Base64
243 | ||| encoding lookup tables. Only the final one- or two-byte group uses the
244 | ||| padding-specific paths.
245 | |||
246 | ||| Mutation remains entirely inside the `F1` region associated with the
247 | ||| supplied `MBuffer`.
248 | |||
249 | ||| The returned natural number is the number of bytes written.
250 | |||
254 | where
268 | --------------------------------------------------------------------------------
269 | -- List encoding
270 | --------------------------------------------------------------------------------
272 | ||| Encode a list of bytes into Base64.
273 | |||
274 | ||| The implementation is entirely native Idris2 and has no dependency on an
275 | ||| external C Base64 implementation.
276 | |||
277 | ||| A mutable byte buffer of exactly the required output size is allocated
278 | ||| inside an `F1` region. The encoder writes directly into this buffer using
279 | ||| the optimized lookup tables from `Data.String.Base64.Internal`.
280 | |||
281 | ||| Once encoding is complete, the mutable buffer is frozen without copying
282 | ||| and converted to the requested `List Bits8` result.
283 | |||
284 | ||| The returned list contains ASCII Base64 bytes.
285 | |||
286 | export
293 | in
294 | run1 $ T1.do
300 | --------------------------------------------------------------------------------
301 | -- String encoding
302 | --------------------------------------------------------------------------------
304 | ||| Encode a list of bytes into a Base64 String.
305 | |||
306 | ||| Base64 output consists entirely of ASCII characters.
307 | |||
308 | ||| The encoder writes directly into a mutable byte buffer inside an `F1`
309 | ||| region and converts the completed buffer directly to a `String`.
310 | |||
311 | ||| This avoids first materializing the Base64 output as a `List Bits8` and
312 | ||| then allocating another buffer solely for UTF-8 decoding.
313 | |||
314 | export
321 | in
322 | run1 $ T1.do