ADDED: chars_base64/3 for efficient bidirectional Base64 conversion.

This commit is contained in:
Markus Triska
2020-07-22 20:17:46 +02:00
parent 82dfa690d2
commit 4c510001ce
5 changed files with 112 additions and 4 deletions

View File

@@ -314,6 +314,7 @@ pub enum SystemClauseType {
GetEnv,
SetEnv,
UnsetEnv,
CharsBase64,
}
impl SystemClauseType {
@@ -526,6 +527,7 @@ impl SystemClauseType {
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
}
}
@@ -718,6 +720,7 @@ impl SystemClauseType {
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
_ => None,
}
}

View File

@@ -3,7 +3,8 @@
get_single_char/1,
read_line_to_chars/3,
read_term_from_chars/2,
write_term_to_chars/3]).
write_term_to_chars/3,
chars_base64/3]).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).
@@ -194,3 +195,42 @@ read_line_to_chars(Stream, Cs0, Cs) :-
; read_line_to_chars(Stream, Rest, Cs)
)
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Relation between a list of characters Cs and its Base64 encoding Bs,
also a list of characters.
Options are:
- padding(Boolean)
Whether to use padding: true (the default) or false.
- charset(C)
Either 'standard' (RFC 4648 §4, the default) or 'url' (RFC 4648 §5).
Example:
?- chars_base64("hello", Bs, []).
Bs = "aGVsbG8="
; false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
chars_base64(Cs, Bs, Options) :-
must_be(list, Options),
( member(O, Options), var(O) ->
instantiation_error(chars_base64/3)
; ( member(padding(Padding), Options) -> true
; Padding = true
),
( member(charset(Charset), Options) -> true
; Charset = standard
)
),
must_be(boolean, Padding),
( var(Cs) ->
must_be(list, Bs),
maplist(must_be(character), Bs),
'$chars_base64'(Cs, Bs, Padding, Charset)
; must_be(list, Cs),
maplist(must_be(character), Cs),
'$chars_base64'(Cs, Bs, Padding, Charset)
).

View File

@@ -55,6 +55,7 @@ use crate::native_tls::TlsConnector;
extern crate select;
use roxmltree;
use base64;
pub fn get_key() -> KeyEvent {
let key;
@@ -5745,6 +5746,68 @@ impl MachineState {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
env::remove_var(key);
}
&SystemClauseType::CharsBase64 => {
let mut options = vec![];
for i in 3..5 {
match self.store(self.deref(self[temp_v!(i)])) {
Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
options.push(atom.as_str());
} else {
unreachable!()
}
}
_ => {
unreachable!()
}
};
}
let config =
if options[0] == "true" {
if options[1] == "standard" {
base64::STANDARD
} else {
base64::URL_SAFE
}
} else {
if options[1] == "standard" {
base64::STANDARD_NO_PAD
} else {
base64::URL_SAFE_NO_PAD
}
};
if self.store(self.deref(self[temp_v!(1)])).is_ref() {
let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
let bytes = base64::decode_config(b64, config);
match bytes {
Ok(bs) => {
let mut string = String::new();
for c in bs {
string.push(c as char);
}
let cstr = self.heap.put_complete_string(&string);
self.unify(self[temp_v!(1)], cstr);
}
_ => {
self.fail = true;
return Ok(());
}
}
} else {
let mut bytes = vec![];
for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() {
bytes.push(c as u8);
}
let b64 = base64::encode_config(bytes, config);
let cstr = self.heap.put_complete_string(&b64);
self.unify(self[temp_v!(2)], cstr);
}
}
};
return_from_clause!(self.last_call, self)