hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit efd1f6e16dacf1582945fcc0783902882fff06a2
parent 99a2ba4ad4720e7253642c78e4eaf156deb2a2d2
Author: Bor Grošelj Simić <bgs@turminal.net>
Date:   Tue, 17 May 2022 21:54:28 +0200

encoding::pem: implement writer

Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>

Diffstat:
Mencoding/pem/+test.ha | 49+++++++++++++++++++++++++++----------------------
Mencoding/pem/pem.ha | 43+++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 22 deletions(-)

diff --git a/encoding/pem/+test.ha b/encoding/pem/+test.ha @@ -3,9 +3,14 @@ use bufio; use bytes; use io; +use fmt; use strings; +use strio; @test fn read() void = { + const testcert_str = fmt::asprintf( + "garbage\ngarbage\ngarbage\n{}garbage\n", cert_str); + defer free(testcert_str); const in = bufio::fixed(strings::toutf8(testcert_str), io::mode::READ); const dec = newdecoder(&in); defer finish(&dec); @@ -22,6 +27,8 @@ use strings; }; @test fn read_many() void = { + const testmany = fmt::asprintf("{}{}", cert_str, privkey_str); + defer free(testmany); const in = bufio::fixed(strings::toutf8(testmany), io::mode::READ); const dec = newdecoder(&in); defer finish(&dec); @@ -40,11 +47,24 @@ use strings; assert(next(&dec) is io::EOF); }; -const testcert_str: str = ` -garbage -garbage -garbage ------BEGIN CERTIFICATE----- +@test fn write() void = { + let out = strio::dynamic(); + const stream = newencoder("CERTIFICATE", &out)!; + io::writeall(&stream, testcert_bin)!; + io::close(&stream)!; + assert(strio::string(&out) == cert_str); + io::close(&out)!; + + let out = strio::dynamic(); + const stream = newencoder("PRIVATE KEY", &out)!; + io::writeall(&stream, testprivkey_bin)!; + io::close(&stream)!; + assert(strio::string(&out) == privkey_str); + io::close(&out)!; +}; + +const cert_str: str = +`-----BEGIN CERTIFICATE----- MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0 @@ -58,7 +78,6 @@ DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo= -----END CERTIFICATE----- -garbage `; const testcert_bin: [_]u8 = [ @@ -111,22 +130,8 @@ const testcert_bin: [_]u8 = [ 0x22, 0xdd, 0x35, 0x81, 0x46, 0x93, 0x22, 0x9a, ]; -const testmany: str = ` ------BEGIN CERTIFICATE----- -MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G -A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y -aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0 -ZSBhdXRob3JpdHkwHhcNMTEwNTIzMjAzODIxWhcNMTIxMjIyMDc0MTUxWjB9MQsw -CQYDVQQGEwJCRTEPMA0GA1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2Vy -dGlmaWNhdGUgYXV0aG9yaXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdu -dVRMUyBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMB -BwNCAARS2I0jiuNn14Y2sSALCX3IybqiIJUvxUpj+oNfzngvj/Niyv2394BWnW4X -uQ4RTEiywK87WRcWMGgJB5kX/t2no0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud -DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG -SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA -l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo= ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- +const privkey_str: str = +`-----BEGIN PRIVATE KEY----- MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgVcB/UNPxalR9zDYAjQIf jojUDiQuGnSJrFEEzZPT/92hRANCAASc7UJtgnF/abqWM60T3XNJEzBv5ez9TdwK H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ diff --git a/encoding/pem/pem.ha b/encoding/pem/pem.ha @@ -4,6 +4,7 @@ use ascii; use bufio; use encoding::base64; use errors; +use fmt; use io; use os; use strings; @@ -195,3 +196,45 @@ fn b64_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = { return len(sub); }; + +export type pemencoder = struct { + stream: io::stream, + out: *io::stream, + b64: base64::encoder, + label: str, +}; + +const pemencoder_vt: io::vtable = io::vtable { + writer = &pem_write, + closer = &pem_wclose, + ... +}; + +// Creates a new PEM encoder stream. The stream has to be closed to write the +// trailer. +export fn newencoder(label: str, s: *io::stream) (pemencoder | io::error) = { + fmt::fprintf(s, "{}{}{}\n", begin, label, suffix)?; + return pemencoder { + stream = &pemencoder_vt, + out = s, + b64 = base64::newencoder(&base64::std_encoding, s), + label = label, + }; +}; + +fn pem_write(s: *io::stream, buf: const []u8) (size | io::error) = { + let s = s: *pemencoder; + let buf = buf: []u8; + let z = 0z; + for (len(buf) >= 48; buf = buf[48..]) { + z += io::writeall(&s.b64, buf[..48])?; + z += io::write(s.out, ['\n'])?; + }; + return z + io::writeall(&s.b64, buf)?; +}; + +fn pem_wclose(s: *io::stream) (void | io::error) = { + let s = s: *pemencoder; + io::close(&s.b64)?; + fmt::fprintf(s.out, "\n{}{}{}\n", end, s.label, suffix)?; +};