Data formats

Encoding

Base64, base64url, hex and percent-encoding read back, files as base64 and back, and query strings as maps.

Version 1.0.0 · 10 functions · 3 crates

#base64#hex#url#forms#files

Functions

What use encoding.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use base64_encode, base64_decode from encoding (Quillo 0.6).

base64_encode(text: str) → str

text as base64, with padding.

base64_decode(b64: str) → stror an error

Base64 back to text; padding is optional, and spaces and line breaks are ignored.

base64url_encode(text: str) → str

text as base64url without padding, as JWTs and URLs carry it.

base64url_decode(b64: str) → stror an error

Base64url back to text, with or without padding.

file_to_base64(path: str) → stror an error

A file's bytes as base64: an image for a data: URL, an attachment for an API.

base64_to_file(b64: str, path: str) → intor an error

Base64 written to a file as the bytes it holds; how many bytes were written.

hex_encode(text: str) → str

text as lower-case hex.

hex_decode(h: str) → stror an error

Hex back to text.

url_decode(text: str) → stror an error

Percent-encoding undone: caf%C3%A9 is café. A + stays a +.

form_decode(text: str) → mapor an error

A query string or form body as a map: a=1&b=x+y is { a: "1", b: "x y" }. A key given twice keeps the last.

Get it

$ quillo install encoding               # encoding.qwer into this folder$ quillo install encoding --example     # and its example, encoding.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/encoding.qwer$ curl -O https://quillolang.org/plugins/files/encoding.qwe

Then, in your program, all of it or only what you call:

main.qwe
use encoding.qweruse base64_encode, base64_decode from encoding      // Quillo 0.6: only these

It uses these crates, which cargo fetches the first time the plugin is built:

[dependencies]
base64 = "0.22"hex = "0.4"percent-encoding = "2"

Example

encoding.qwe
// Base64, hex and query strings, read back.////   quillo run encoding.qwe      then open http://localhost:8080/decode?b64=Y2Fmw6kuse "encoding.qwer"route GET /decode ? { b64: str } = { text: base64_decode(b64)?, again: base64_encode(base64_decode(b64)?) }route GET /hex ? { text: str } = { hex: hex_encode(text), back: hex_decode(hex_encode(text))? }route GET /form = form_decode("name=Ada+Lovelace&city=London%2C%20UK")?
$ quillo run encoding.qwe$ curl 'localhost:8080/decode?b64=Y2Fmw6k'$ curl 'localhost:8080/hex?text=hi'$ curl 'localhost:8080/form'

Source

encoding.qwer
//! Base64, base64url, hex and percent-encoding, both ways: Quillo makes them, this reads them back.//! version: 1.0.0//!//! [dependencies]//! base64 = "0.22"//! hex = "0.4"//! percent-encoding = "2"use base64::engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE_NO_PAD};use base64::Engine;use std::collections::HashMap;fn utf8(bytes: Vec<u8>) -> Result<String, String> {    String::from_utf8(bytes).map_err(|_| "the bytes are not UTF-8 text: use base64_to_file for binary data".to_string())}/// `text` as base64, with padding.pub fn base64_encode(text: &str) -> String {    STANDARD.encode(text)}/// Base64 back to text; padding is optional, and spaces and line breaks are ignored.pub fn base64_decode(b64: &str) -> Result<String, String> {    let clean: String = b64.chars().filter(|c| !c.is_whitespace()).collect();    utf8(STANDARD_NO_PAD.decode(clean.trim_end_matches('=')).map_err(|e| e.to_string())?)}/// `text` as base64url without padding, as JWTs and URLs carry it.pub fn base64url_encode(text: &str) -> String {    URL_SAFE_NO_PAD.encode(text)}/// Base64url back to text, with or without padding.pub fn base64url_decode(b64: &str) -> Result<String, String> {    utf8(URL_SAFE_NO_PAD.decode(b64.trim().trim_end_matches('=')).map_err(|e| e.to_string())?)}/// A file's bytes as base64: an image for a `data:` URL, an attachment for an API.pub fn file_to_base64(path: &str) -> Result<String, String> {    Ok(STANDARD.encode(std::fs::read(path).map_err(|e| format!("{}: {}", path, e))?))}/// Base64 written to a file as the bytes it holds; how many bytes were written.pub fn base64_to_file(b64: &str, path: &str) -> Result<i64, String> {    let clean: String = b64.chars().filter(|c| !c.is_whitespace()).collect();    let bytes = STANDARD_NO_PAD.decode(clean.trim_end_matches('=')).map_err(|e| e.to_string())?;    std::fs::write(path, &bytes).map_err(|e| format!("{}: {}", path, e))?;    Ok(bytes.len() as i64)}/// `text` as lower-case hex.pub fn hex_encode(text: &str) -> String {    hex::encode(text)}/// Hex back to text.pub fn hex_decode(h: &str) -> Result<String, String> {    utf8(hex::decode(h.trim()).map_err(|e| e.to_string())?)}/// Percent-encoding undone: `caf%C3%A9` is `café`. A `+` stays a `+`.pub fn url_decode(text: &str) -> Result<String, String> {    percent_encoding::percent_decode_str(text).decode_utf8().map(|s| s.into_owned()).map_err(|e| e.to_string())}/// A query string or form body as a map: `a=1&b=x+y` is `{ a: "1", b: "x y" }`. A key given twice keeps the last.pub fn form_decode(text: &str) -> Result<HashMap<String, String>, String> {    let mut out = HashMap::new();    for pair in text.trim_start_matches('?').split('&').filter(|p| !p.is_empty()) {        let (k, v) = pair.split_once('=').unwrap_or((pair, ""));        out.insert(url_decode(&k.replace('+', " "))?, url_decode(&v.replace('+', " "))?);    }    Ok(out)}
Thread
77Useful? Like it, or add to its thread below.

Thread 0 posts

On Encoding: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.