Skip to content

Commit

Permalink
Add std.base64 for encoding and decoding base64
Browse files Browse the repository at this point in the history
Changelog: added
  • Loading branch information
yorickpeterse committed Jul 23, 2024
1 parent 8e70fd6 commit 5e600c1
Show file tree
Hide file tree
Showing 2 changed files with 343 additions and 0 deletions.
259 changes: 259 additions & 0 deletions std/src/std/base64.inko
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
# Base64 encoding and decoding.
#
# This module provides types and methods for encoding and decoding base64 data.
# Data is encoded using the `Encoder` type, while decoding is done using the
# `Decoder` type.

let ENCODE_STD0 = [
0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x44,
0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47,
0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a,
0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x51,
0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54,
0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57,
0x57, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a,
0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x64,
0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67,
0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a,
0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, 0x71,
0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74,
0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77,
0x77, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a,
0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33,
0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36,
0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39,
0x39, 0x2b, 0x2b, 0x2b, 0x2b, 0x2f, 0x2f, 0x2f, 0x2f,
]
let ENCODE_STD1 = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f,
]
let ENCODE_STD2 = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f,
]
let ENCODE_URL0 = [
0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x44,
0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47,
0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a,
0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x51,
0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54,
0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57,
0x57, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a,
0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x64,
0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67,
0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a,
0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d,
0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, 0x71,
0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74,
0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77,
0x77, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a,
0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33,
0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36,
0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39,
0x39, 0x2d, 0x2d, 0x2d, 0x2d, 0x5f, 0x5f, 0x5f, 0x5f,
]
let ENCODE_URL1 = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f,
]
let ENCODE_URL2 = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31,
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x5f,
]
let PAD = 0x3d

# A type for encoding raw input as a base64 sequence of bytes.
#
# # Examples
#
# Encoding input using the standard alphabet from RFC 4648:
#
# ```inko
# import std.base64 (Encoder)
#
# let in = 'abcdefghijklmnopqrstuvwxyz0123456789|@{}/&#[]\\!?()<>=+*;\'"`:^%$~'.to_byte_array
# let out = ByteArray.new
#
# Encoder.new.encode(in, out)
# out.into_string #=> 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5fEB7fS8mI1tdXCE/KCk8Pj0rKjsnImA6XiUkfg=='
# ```
#
# Encoding input using the URL safe alphabet from RFC 4648:
#
# ```inko
# import std.base64 (Encoder)
#
# let in = 'abcdefghijklmnopqrstuvwxyz0123456789|@{}/&#[]\\!?()<>=+*;\'"`:^%$~'.to_byte_array
# let out = ByteArray.new
#
# Encoder.url_safe.encode(in, out)
# out.into_string #=> 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5fEB7fS8mI1tdXCE_KCk8Pj0rKjsnImA6XiUkfg=='
# ```
class pub Encoder {
let @table0: ref Array[Int]
let @table1: ref Array[Int]
let @table2: ref Array[Int]

# Returns an `Encoder` that uses the standard base64 alphabet.
fn static new -> Encoder {
Encoder(table0: ENCODE_STD0, table1: ENCODE_STD1, table2: ENCODE_STD2)
}

# Returns an `Encoder` that uses the URL safe base64 alphabet.
fn static url_safe -> Encoder {
Encoder(table0: ENCODE_URL0, table1: ENCODE_URL1, table2: ENCODE_URL2)
}

# Encodes the `input` `ByteArray` into a sequence of base64 encoded bytes,
# appending the sequence to `output.`
#
# # Encoding large inputs
#
# This method encodes `input` as a whole. For large inputs, you can perform
# incremental encoding by passing the data as a `ByteArray` chunk of which the
# size is a multiple of three. This ensures that padding is only applied to
# the last chunk, resulting in output identical to encoding the entire input
# as a whole.
#
# # Examples
#
# ```inko
# import std.base64 (Encoder)
#
# let out = ByteArray.new
#
# Encoder.new.encode('hello world'.to_byte_array, out)
# out.into_string #=> 'aGVsbG8gd29ybGQ='
# ```
fn pub encode(input: ref ByteArray, output: mut ByteArray) {
# The implementation here is based on the base64 encoder found in Google
# Chrome (https://github.com/chromium/chromium/blob/fd8a8914ca0183f0add65ae55f04e287543c7d4a/third_party/modp_b64/modp_b64.cc).
let mut e0 = @table0
let mut e1 = @table1
let mut e2 = @table2
let size = input.size
let mut i = 0

if size > 2 {
let max = size - 2

while i < max {
let t1 = input.get(i)
let t2 = input.get(i + 1)
let t3 = input.get(i + 2)

output.push(e0.get(t1))
output.push(e1.get((t1 & 0x03 << 4) | (t2 >> 4 & 0x0f)))
output.push(e1.get((t2 & 0x0f << 2) | (t3 >> 6 & 0x03)))
output.push(e2.get(t3))

i += 3
}
}

match size - i {
case 0 -> {}
case 1 -> {
let t1 = input.get(i)

output.push(e0.get(t1))
output.push(e1.get(t1 & 0x03 << 4))
output.push(PAD)
output.push(PAD)
}
case _ -> {
let t1 = input.get(i)
let t2 = input.get(i + 1)

output.push(e0.get(t1))
output.push(e1.get((t1 & 0x03 << 4) | (t2 >> 4 & 0x0f)))
output.push(e2.get(t2 & 0x0f << 2))
output.push(PAD)
}
}
}
}

# A type for decoding a base64 encoded sequence of bytes into a raw sequence of
# bytes.
class pub Decoder {
fn pub decode(input: ref ByteArray, output: mut ByteArray) {
panic('TODO')
}
}
84 changes: 84 additions & 0 deletions std/test/std/test_base64.inko
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import std.base64 (Encoder)
import std.test (Tests)

fn std(input: ref String) -> String {
let output = ByteArray.new

Encoder.new.encode(input.to_byte_array, output)
output.into_string
}

fn url(input: ref String) -> String {
let output = ByteArray.new

Encoder.url_safe.encode(input.to_byte_array, output)
output.into_string
}

fn pub tests(t: mut Tests) {
t.test('Encoder.encode using the standard encoding', fn (t) {
t.equal(std(''), '')
t.equal(std(' '), 'IA==')
t.equal(std('f'), 'Zg==')
t.equal(std('fo'), 'Zm8=')
t.equal(std('foo'), 'Zm9v')
t.equal(std('foob'), 'Zm9vYg==')
t.equal(std('fooba'), 'Zm9vYmE=')
t.equal(std('foobar'), 'Zm9vYmFy')
t.equal(std('0'), 'MA==')
t.equal(std('aa'), 'YWE=')
t.equal(std('hello'), 'aGVsbG8=')
t.equal(std('😃'), '8J+Ygw==')
t.equal(
std("We've Been Trying To Reach You About Your Car's Extended Warranty"),
'V2UndmUgQmVlbiBUcnlpbmcgVG8gUmVhY2ggWW91IEFib3V0IFlvdXIgQ2FyJ3MgRXh0ZW5kZWQgV2FycmFudHk=',
)
t.equal(
std('abcdefghijklmnopqrstuvwxyz0123456789|@{}/&#[]\\!?()<>=+*;\'"`:^%$~'),
'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5fEB7fS8mI1tdXCE/KCk8Pj0rKjsnImA6XiUkfg==',
)

let out = ByteArray.new

Encoder.new.encode(ByteArray.from_array([250]), out)
t.equal(out.into_string, '+g==')
})

t.test('Encoder.encode using the URL safe encoding', fn (t) {
t.equal(url(''), '')
t.equal(url(' '), 'IA==')
t.equal(url('f'), 'Zg==')
t.equal(url('fo'), 'Zm8=')
t.equal(url('foo'), 'Zm9v')
t.equal(url('foob'), 'Zm9vYg==')
t.equal(url('fooba'), 'Zm9vYmE=')
t.equal(url('foobar'), 'Zm9vYmFy')
t.equal(url('0'), 'MA==')
t.equal(url('aa'), 'YWE=')
t.equal(url('hello'), 'aGVsbG8=')
t.equal(url('😃'), '8J-Ygw==')
t.equal(
url("We've Been Trying To Reach You About Your Car's Extended Warranty"),
'V2UndmUgQmVlbiBUcnlpbmcgVG8gUmVhY2ggWW91IEFib3V0IFlvdXIgQ2FyJ3MgRXh0ZW5kZWQgV2FycmFudHk=',
)
t.equal(
url('abcdefghijklmnopqrstuvwxyz0123456789|@{}/&#[]\\!?()<>=+*;\'"`:^%$~'),
'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5fEB7fS8mI1tdXCE_KCk8Pj0rKjsnImA6XiUkfg==',
)

let out = ByteArray.new

Encoder.new.encode(ByteArray.from_array([250]), out)
t.equal(out.into_string, '+g==')
})

t.test('Encoding input in chunks', fn (t) {
let enc = Encoder.new
let out = ByteArray.new

# If the input size is a multiple of 3, there shouldn't be any padding.
enc.encode('abc'.to_byte_array, out)
enc.encode('def'.to_byte_array, out)
t.equal(out.into_string, std('abcdef'))
})
}

0 comments on commit 5e600c1

Please sign in to comment.