35
36:- module(base64,
37 [ base64/2, 38 base64url/2, 39
40 base64//1, 41 base64url//1 42 ]).
43
67
73
74base64(Plain, Encoded) :-
75 nonvar(Plain),
76 !,
77 atom_codes(Plain, PlainCodes),
78 phrase(base64(PlainCodes), EncCodes),
79 atom_codes(Encoded, EncCodes).
80base64(Plain, Encoded) :-
81 nonvar(Encoded),
82 !,
83 atom_codes(Encoded, EncCodes),
84 phrase(base64(PlainCodes), EncCodes),
85 atom_codes(Plain, PlainCodes).
86base64(_, _) :-
87 throw(error(instantiation_error, _)).
88
97
98base64url(Plain, Encoded) :-
99 nonvar(Plain),
100 !,
101 atom_codes(Plain, PlainCodes),
102 phrase(encode_url(PlainCodes), EncCodes),
103 atom_codes(Encoded, EncCodes).
104base64url(Plain, Encoded) :-
105 nonvar(Encoded),
106 !,
107 atom_codes(Encoded, EncCodes),
108 phrase(decode_url(PlainCodes), EncCodes),
109 atom_codes(Plain, PlainCodes).
110base64url(_, _) :-
111 throw(error(instantiation_error, _)).
112
118
119base64(Input) -->
120 { nonvar(Input) },
121 !,
122 encode(Input).
123base64(Output) -->
124 decode(Output).
125
131
132base64url(Input) -->
133 { nonvar(Input) },
134 !,
135 encode_url(Input).
136base64url(Output) -->
137 decode_url(Output).
138
139 142
143encode([I0, I1, I2|Rest]) -->
144 !,
145 [O0, O1, O2, O3],
146 { A is (I0<<16)+(I1<<8)+I2,
147 O00 is (A>>18) /\ 0x3f,
148 O01 is (A>>12) /\ 0x3f,
149 O02 is (A>>6) /\ 0x3f,
150 O03 is A /\ 0x3f,
151 base64_char(O00, O0),
152 base64_char(O01, O1),
153 base64_char(O02, O2),
154 base64_char(O03, O3)
155 },
156 encode(Rest).
157encode([I0, I1]) -->
158 !,
159 [O0, O1, O2, 0'=],
160 { A is (I0<<16)+(I1<<8),
161 O00 is (A>>18) /\ 0x3f,
162 O01 is (A>>12) /\ 0x3f,
163 O02 is (A>>6) /\ 0x3f,
164 base64_char(O00, O0),
165 base64_char(O01, O1),
166 base64_char(O02, O2)
167 }.
168encode([I0]) -->
169 !,
170 [O0, O1, 0'=, 0'=],
171 { A is (I0<<16),
172 O00 is (A>>18) /\ 0x3f,
173 O01 is (A>>12) /\ 0x3f,
174 base64_char(O00, O0),
175 base64_char(O01, O1)
176 }.
177encode([]) -->
178 [].
179
180
181encode_url([I0, I1, I2|Rest]) -->
182 !,
183 [O0, O1, O2, O3],
184 { A is (I0<<16)+(I1<<8)+I2,
185 O00 is (A>>18) /\ 0x3f,
186 O01 is (A>>12) /\ 0x3f,
187 O02 is (A>>6) /\ 0x3f,
188 O03 is A /\ 0x3f,
189 base64url_char(O00, O0),
190 base64url_char(O01, O1),
191 base64url_char(O02, O2),
192 base64url_char(O03, O3)
193 },
194 encode_url(Rest).
195encode_url([I0, I1]) -->
196 !,
197 [O0, O1, O2],
198 { A is (I0<<16)+(I1<<8),
199 O00 is (A>>18) /\ 0x3f,
200 O01 is (A>>12) /\ 0x3f,
201 O02 is (A>>6) /\ 0x3f,
202 base64url_char(O00, O0),
203 base64url_char(O01, O1),
204 base64url_char(O02, O2)
205 }.
206encode_url([I0]) -->
207 !,
208 [O0, O1],
209 { A is (I0<<16),
210 O00 is (A>>18) /\ 0x3f,
211 O01 is (A>>12) /\ 0x3f,
212 base64url_char(O00, O0),
213 base64url_char(O01, O1)
214 }.
215encode_url([]) -->
216 [].
217
218
219 222
223decode(Text) -->
224 [C0, C1, C2, C3],
225 !,
226 { base64_char(B0, C0),
227 base64_char(B1, C1)
228 },
229 !,
230 { C3 == 0'=
231 -> ( C2 == 0'=
232 -> A is (B0<<18) + (B1<<12),
233 I0 is (A>>16) /\ 0xff,
234 Text = [I0|Rest]
235 ; base64_char(B2, C2)
236 -> A is (B0<<18) + (B1<<12) + (B2<<6),
237 I0 is (A>>16) /\ 0xff,
238 I1 is (A>>8) /\ 0xff,
239 Text = [I0,I1|Rest]
240 )
241 ; base64_char(B2, C2),
242 base64_char(B3, C3)
243 -> A is (B0<<18) + (B1<<12) + (B2<<6) + B3,
244 I0 is (A>>16) /\ 0xff,
245 I1 is (A>>8) /\ 0xff,
246 I2 is A /\ 0xff,
247 Text = [I0,I1,I2|Rest]
248 },
249 decode(Rest).
250decode([]) -->
251 [].
252
257
258decode_url(Text) -->
259 [C0, C1, C2, C3],
260 !,
261 { base64url_char(B0, C0),
262 base64url_char(B1, C1),
263 base64url_char(B2, C2),
264 base64url_char(B3, C3),
265 A is (B0<<18) + (B1<<12) + (B2<<6) + B3,
266 I0 is (A>>16) /\ 0xff,
267 I1 is (A>>8) /\ 0xff,
268 I2 is A /\ 0xff,
269 Text = [I0,I1,I2|Rest]
270 },
271 decode_url(Rest).
272decode_url(Text) -->
273 [C0, C1, C2],
274 !,
275 { base64url_char(B0, C0),
276 base64url_char(B1, C1),
277 base64url_char(B2, C2),
278 A is (B0<<18) + (B1<<12) + (B2<<6),
279 I0 is (A>>16) /\ 0xff,
280 I1 is (A>>8) /\ 0xff,
281 Text = [I0,I1]
282 }.
283decode_url(Text) -->
284 [C0, C1],
285 !,
286 { base64url_char(B0, C0),
287 base64url_char(B1, C1),
288 A is (B0<<18) + (B1<<12),
289 I0 is (A>>16) /\ 0xff,
290 Text = [I0]
291 }.
292decode_url([]) -->
293 [].
294
295
296 299
300base64_char(00, 0'A).
301base64_char(01, 0'B).
302base64_char(02, 0'C).
303base64_char(03, 0'D).
304base64_char(04, 0'E).
305base64_char(05, 0'F).
306base64_char(06, 0'G).
307base64_char(07, 0'H).
308base64_char(08, 0'I).
309base64_char(09, 0'J).
310base64_char(10, 0'K).
311base64_char(11, 0'L).
312base64_char(12, 0'M).
313base64_char(13, 0'N).
314base64_char(14, 0'O).
315base64_char(15, 0'P).
316base64_char(16, 0'Q).
317base64_char(17, 0'R).
318base64_char(18, 0'S).
319base64_char(19, 0'T).
320base64_char(20, 0'U).
321base64_char(21, 0'V).
322base64_char(22, 0'W).
323base64_char(23, 0'X).
324base64_char(24, 0'Y).
325base64_char(25, 0'Z).
326base64_char(26, 0'a).
327base64_char(27, 0'b).
328base64_char(28, 0'c).
329base64_char(29, 0'd).
330base64_char(30, 0'e).
331base64_char(31, 0'f).
332base64_char(32, 0'g).
333base64_char(33, 0'h).
334base64_char(34, 0'i).
335base64_char(35, 0'j).
336base64_char(36, 0'k).
337base64_char(37, 0'l).
338base64_char(38, 0'm).
339base64_char(39, 0'n).
340base64_char(40, 0'o).
341base64_char(41, 0'p).
342base64_char(42, 0'q).
343base64_char(43, 0'r).
344base64_char(44, 0's).
345base64_char(45, 0't).
346base64_char(46, 0'u).
347base64_char(47, 0'v).
348base64_char(48, 0'w).
349base64_char(49, 0'x).
350base64_char(50, 0'y).
351base64_char(51, 0'z).
352base64_char(52, 0'0).
353base64_char(53, 0'1).
354base64_char(54, 0'2).
355base64_char(55, 0'3).
356base64_char(56, 0'4).
357base64_char(57, 0'5).
358base64_char(58, 0'6).
359base64_char(59, 0'7).
360base64_char(60, 0'8).
361base64_char(61, 0'9).
362base64_char(62, 0'+).
363base64_char(63, 0'/).
364
365base64url_char_x(62, 0'-).
366base64url_char_x(63, 0'_).
367
368base64url_char(D, E) :-
369 base64url_char_x(D, E),
370 !.
371base64url_char(D, E) :-
372 base64_char(D, E),
373 !.
374base64url_char(D, E) :-
375 throw(error(syntax_error(base64url_char(D, E)), _)).
376
377
378 381
382:- multifile prolog:error_message//1.
383
384prolog:error_message(syntax_error(base64url_char(_D,E))) -->
385 { nonvar(E) },
386 !,
387 [ 'Illegal Base64URL character: "~c"'-[E] ].