|
| 1 | +... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. |
| 2 | +... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| 3 | + |
| 4 | +(.using |
| 5 | + [library |
| 6 | + [lux (.except text) |
| 7 | + [data |
| 8 | + ["[0]" text (.only) |
| 9 | + [character (.only Character)]] |
| 10 | + ["[0]" binary |
| 11 | + ["[1]!" \\unsafe]] |
| 12 | + [collection |
| 13 | + ["[0]" list]]] |
| 14 | + [math |
| 15 | + [number |
| 16 | + ["[0]" /64 (.only) |
| 17 | + ["[0]" natural]]]] |
| 18 | + [macro |
| 19 | + ["[0]" template] |
| 20 | + ["[0]" expansion]] |
| 21 | + [abstract |
| 22 | + ["[0]" monad]] |
| 23 | + [control |
| 24 | + ["[0]" maybe]] |
| 25 | + [aspect |
| 26 | + ["[0]" case (.only Case)]]]]) |
| 27 | + |
| 28 | +... https://en.wikipedia.org/wiki/Base64 |
| 29 | +(the paddding_for_2 "=") |
| 30 | +(the paddding_for_1 (.text ..paddding_for_2 ..paddding_for_2)) |
| 31 | + |
| 32 | +(expansion.let [,*mapping (these [00 "A"] |
| 33 | + [01 "B"] |
| 34 | + [02 "C"] |
| 35 | + [03 "D"] |
| 36 | + [04 "E"] |
| 37 | + [05 "F"] |
| 38 | + [06 "G"] |
| 39 | + [07 "H"] |
| 40 | + [08 "I"] |
| 41 | + [09 "J"] |
| 42 | + [10 "K"] |
| 43 | + [11 "L"] |
| 44 | + [12 "M"] |
| 45 | + [13 "N"] |
| 46 | + [14 "O"] |
| 47 | + [15 "P"] |
| 48 | + |
| 49 | + [16 "Q"] |
| 50 | + [17 "R"] |
| 51 | + [18 "S"] |
| 52 | + [19 "T"] |
| 53 | + [20 "U"] |
| 54 | + [21 "V"] |
| 55 | + [22 "W"] |
| 56 | + [23 "X"] |
| 57 | + [24 "Y"] |
| 58 | + [25 "Z"] |
| 59 | + [26 "a"] |
| 60 | + [27 "b"] |
| 61 | + [28 "c"] |
| 62 | + [29 "d"] |
| 63 | + [30 "e"] |
| 64 | + [31 "f"] |
| 65 | + |
| 66 | + [32 "g"] |
| 67 | + [33 "h"] |
| 68 | + [34 "i"] |
| 69 | + [35 "j"] |
| 70 | + [36 "k"] |
| 71 | + [37 "l"] |
| 72 | + [38 "m"] |
| 73 | + [39 "n"] |
| 74 | + [40 "o"] |
| 75 | + [41 "p"] |
| 76 | + [42 "q"] |
| 77 | + [43 "r"] |
| 78 | + [44 "s"] |
| 79 | + [45 "t"] |
| 80 | + [46 "u"] |
| 81 | + [47 "v"] |
| 82 | + |
| 83 | + [48 "w"] |
| 84 | + [49 "x"] |
| 85 | + [50 "y"] |
| 86 | + [51 "z"] |
| 87 | + [52 "0"] |
| 88 | + [53 "1"] |
| 89 | + [54 "2"] |
| 90 | + [55 "3"] |
| 91 | + [56 "4"] |
| 92 | + [57 "5"] |
| 93 | + [58 "6"] |
| 94 | + [59 "7"] |
| 95 | + [60 "8"] |
| 96 | + [61 "9"] |
| 97 | + [62 "+"] |
| 98 | + [63 "/"])] |
| 99 | + (these (the (digit it) |
| 100 | + (text.Injection Natural) |
| 101 | + (`` (when it |
| 102 | + (,, (template.with [,value ,character] |
| 103 | + [,value ,character] |
| 104 | + |
| 105 | + [,*mapping])) |
| 106 | + |
| 107 | + else |
| 108 | + (undefined)))) |
| 109 | + |
| 110 | + (the (value it) |
| 111 | + (-> Character |
| 112 | + (Maybe Natural)) |
| 113 | + (`` (when it |
| 114 | + (,, (template.with [,value ,character] |
| 115 | + [(character ,character) |
| 116 | + {.#Some ,value}] |
| 117 | + |
| 118 | + [,*mapping])) |
| 119 | + |
| 120 | + (character (,, (static ..paddding_for_2))) |
| 121 | + {.#Some 00} |
| 122 | + |
| 123 | + else |
| 124 | + {.#None}))))) |
| 125 | + |
| 126 | +(the mask_6 |
| 127 | + (/64.mask 6)) |
| 128 | + |
| 129 | +(the size_of_sequence_of_bytes |
| 130 | + 3) |
| 131 | + |
| 132 | +(the (sequence_of_digits it offset) |
| 133 | + (-> binary!.Binary |
| 134 | + (text.Injection Natural)) |
| 135 | + (let [every_byte (binary!.size it) |
| 136 | + [every_sequence_of_bytes excess] (natural./% ..size_of_sequence_of_bytes every_byte) |
| 137 | + byte_0 (binary!.bits_08 (natural.+ 0 offset) it) |
| 138 | + byte_1 (binary!.bits_08 (natural.+ 1 offset) it) |
| 139 | + byte_2 (binary!.bits_08 (natural.+ 2 offset) it)] |
| 140 | + (.text (digit (/64.>> 2 byte_0)) |
| 141 | + (digit (/64.and ..mask_6 |
| 142 | + (/64.or (/64.<< 4 byte_0) |
| 143 | + (/64.>> 4 byte_1)))) |
| 144 | + (digit (/64.and ..mask_6 |
| 145 | + (/64.or (/64.<< 2 byte_1) |
| 146 | + (/64.>> 6 byte_2)))) |
| 147 | + (digit (/64.and ..mask_6 |
| 148 | + byte_2))))) |
| 149 | + |
| 150 | +(every Byte |
| 151 | + Natural) |
| 152 | + |
| 153 | +(the (with_padding_1 byte_0) |
| 154 | + (text.Injection Byte) |
| 155 | + (.text (digit (/64.>> 2 byte_0)) |
| 156 | + (digit (/64.and ..mask_6 |
| 157 | + (/64.<< 4 byte_0))) |
| 158 | + ..paddding_for_1)) |
| 159 | + |
| 160 | +(the (with_padding_2 [byte_0 byte_1]) |
| 161 | + (text.Injection [Byte Byte]) |
| 162 | + (.text (digit (/64.>> 2 byte_0)) |
| 163 | + (digit (/64.and ..mask_6 |
| 164 | + (/64.or (/64.<< 4 byte_0) |
| 165 | + (/64.>> 4 byte_1)))) |
| 166 | + (digit (/64.and ..mask_6 |
| 167 | + (/64.<< 2 byte_1))) |
| 168 | + ..paddding_for_2)) |
| 169 | + |
| 170 | +(the (some_text it) |
| 171 | + (text.Injection binary!.Binary) |
| 172 | + (let [every_byte (binary!.size it) |
| 173 | + [every_sequence_of_bytes excess] (natural./% ..size_of_sequence_of_bytes every_byte)] |
| 174 | + (.text (|> (list.indices every_sequence_of_bytes) |
| 175 | + (list.mix (function (_ index total) |
| 176 | + (.text total (sequence_of_digits it (natural.x ..size_of_sequence_of_bytes index)))) |
| 177 | + "")) |
| 178 | + (when excess |
| 179 | + 1 (let [offset (natural.x ..size_of_sequence_of_bytes every_sequence_of_bytes)] |
| 180 | + (with_padding_1 (binary!.bits_08 (natural.+ 0 offset) it))) |
| 181 | + 2 (let [offset (natural.x ..size_of_sequence_of_bytes every_sequence_of_bytes)] |
| 182 | + (with_padding_2 [(binary!.bits_08 (natural.+ 0 offset) it) |
| 183 | + (binary!.bits_08 (natural.+ 1 offset) it)])) |
| 184 | + else ... 0 |
| 185 | + "")))) |
| 186 | + |
| 187 | +(the size_of_sequence_of_digits |
| 188 | + 4) |
| 189 | + |
| 190 | +(the mask_8 |
| 191 | + (/64.mask 8)) |
| 192 | + |
| 193 | +(the (sequence_of_bytes every_digit offset) |
| 194 | + (-> Text Natural |
| 195 | + (Maybe [Byte Byte Byte])) |
| 196 | + (monad.let maybe.monad |
| 197 | + [character_0 (value (.text_char# (natural.+ 0 offset) every_digit)) |
| 198 | + character_1 (value (.text_char# (natural.+ 1 offset) every_digit)) |
| 199 | + character_2 (value (.text_char# (natural.+ 2 offset) every_digit)) |
| 200 | + character_3 (value (.text_char# (natural.+ 3 offset) every_digit))] |
| 201 | + (pure [(/64.or (/64.<< 2 character_0) |
| 202 | + (/64.>> 4 character_1)) |
| 203 | + (/64.and ..mask_8 |
| 204 | + (/64.or (/64.<< 4 character_1) |
| 205 | + (/64.>> 2 character_2))) |
| 206 | + (/64.and ..mask_8 |
| 207 | + (/64.or (/64.<< 6 character_2) |
| 208 | + character_3))]))) |
| 209 | + |
| 210 | +(the (if_text it) |
| 211 | + (-> Text |
| 212 | + (Either Text binary!.Binary)) |
| 213 | + (let [every_digit (text.size it) |
| 214 | + [every_sequence_of_digits excess] (natural./% ..size_of_sequence_of_digits every_digit)] |
| 215 | + (when excess |
| 216 | + 0 (let [last_sequence (-- every_sequence_of_digits) |
| 217 | + padded? (text.ends_with? ..paddding_for_2 it) |
| 218 | + fully_padded? (text.ends_with? ..paddding_for_1 it) |
| 219 | + simple_size (natural.x ..size_of_sequence_of_bytes every_sequence_of_digits) |
| 220 | + size (if fully_padded? |
| 221 | + (natural.- 2 simple_size) |
| 222 | + |
| 223 | + padded? |
| 224 | + (natural.- 1 simple_size) |
| 225 | + |
| 226 | + ... else |
| 227 | + (natural.+ 0 simple_size))] |
| 228 | + (when (|> (list.indices every_sequence_of_digits) |
| 229 | + (list.mix' maybe.monad |
| 230 | + (function (_ index total) |
| 231 | + (let [offset_0 (natural.x ..size_of_sequence_of_bytes index)] |
| 232 | + (monad.let maybe.monad |
| 233 | + [[byte_0 byte_1 byte_2] (sequence_of_bytes it (natural.x ..size_of_sequence_of_digits index))] |
| 234 | + (pure (if (and (natural.= last_sequence index) |
| 235 | + padded?) |
| 236 | + (if fully_padded? |
| 237 | + (|> total |
| 238 | + (binary!.has_08! (natural.+ 0 offset_0) byte_0)) |
| 239 | + (|> total |
| 240 | + (binary!.has_08! (natural.+ 0 offset_0) byte_0) |
| 241 | + (binary!.has_08! (natural.+ 1 offset_0) byte_1))) |
| 242 | + (|> total |
| 243 | + (binary!.has_08! (natural.+ 0 offset_0) byte_0) |
| 244 | + (binary!.has_08! (natural.+ 1 offset_0) byte_1) |
| 245 | + (binary!.has_08! (natural.+ 2 offset_0) byte_2))))))) |
| 246 | + (binary!.empty size))) |
| 247 | + {.#Some it} |
| 248 | + {.#Right it} |
| 249 | + |
| 250 | + else |
| 251 | + {.#Left it})) |
| 252 | + 2 (if_text (.text it ..paddding_for_1)) |
| 253 | + 3 (if_text (.text it ..paddding_for_2)) |
| 254 | + _ {.#Left it}))) |
| 255 | + |
| 256 | +(the .public text |
| 257 | + (Case Text binary!.Binary) |
| 258 | + (case.new ..if_text ..some_text)) |
0 commit comments