2025-03-23 10:20:31 +09:00
|
|
|
//! Base64 encoding/decoding as specified by
|
|
|
|
|
//! [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648).
|
2024-03-10 18:10:51 -07:00
|
|
|
|
2019-03-02 16:46:04 -05:00
|
|
|
const std = @import("std.zig");
|
2017-12-23 22:08:53 -05:00
|
|
|
const assert = std.debug.assert;
|
2023-10-22 15:46:33 -04:00
|
|
|
const builtin = @import("builtin");
|
2019-02-08 18:18:47 -05:00
|
|
|
const testing = std.testing;
|
2017-12-23 22:08:53 -05:00
|
|
|
const mem = std.mem;
|
2024-09-04 10:10:12 +02:00
|
|
|
const window = mem.window;
|
2017-04-17 19:08:41 -04:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub const Error = error{
|
|
|
|
|
InvalidCharacter,
|
|
|
|
|
InvalidPadding,
|
|
|
|
|
NoSpaceLeft,
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-06 20:35:50 -07:00
|
|
|
const decoderWithIgnoreProto = *const fn (ignore: []const u8) Base64DecoderWithIgnore;
|
2022-03-30 20:38:01 -07:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// Base64 codecs
|
|
|
|
|
pub const Codecs = struct {
|
|
|
|
|
alphabet_chars: [64]u8,
|
|
|
|
|
pad_char: ?u8,
|
2022-03-30 20:38:01 -07:00
|
|
|
decoderWithIgnore: decoderWithIgnoreProto,
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
Encoder: Base64Encoder,
|
|
|
|
|
Decoder: Base64Decoder,
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// The Base64 alphabet defined in
|
|
|
|
|
/// [RFC 4648 section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4).
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".*;
|
|
|
|
|
fn standardBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore {
|
|
|
|
|
return Base64DecoderWithIgnore.init(standard_alphabet_chars, '=', ignore);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// Standard Base64 codecs, with padding, as defined in
|
|
|
|
|
/// [RFC 4648 section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4).
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub const standard = Codecs{
|
|
|
|
|
.alphabet_chars = standard_alphabet_chars,
|
|
|
|
|
.pad_char = '=',
|
|
|
|
|
.decoderWithIgnore = standardBase64DecoderWithIgnore,
|
|
|
|
|
.Encoder = Base64Encoder.init(standard_alphabet_chars, '='),
|
|
|
|
|
.Decoder = Base64Decoder.init(standard_alphabet_chars, '='),
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// Standard Base64 codecs, without padding, as defined in
|
|
|
|
|
/// [RFC 4648 section 3.2](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2).
|
2021-03-26 16:01:44 +01:00
|
|
|
pub const standard_no_pad = Codecs{
|
|
|
|
|
.alphabet_chars = standard_alphabet_chars,
|
|
|
|
|
.pad_char = null,
|
|
|
|
|
.decoderWithIgnore = standardBase64DecoderWithIgnore,
|
|
|
|
|
.Encoder = Base64Encoder.init(standard_alphabet_chars, null),
|
|
|
|
|
.Decoder = Base64Decoder.init(standard_alphabet_chars, null),
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// The URL-safe Base64 alphabet defined in
|
|
|
|
|
/// [RFC 4648 section 5](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub const url_safe_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
|
|
|
|
|
fn urlSafeBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore {
|
|
|
|
|
return Base64DecoderWithIgnore.init(url_safe_alphabet_chars, null, ignore);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// URL-safe Base64 codecs, with padding, as defined in
|
|
|
|
|
/// [RFC 4648 section 5](https://datatracker.ietf.org/doc/html/rfc4648#section-5).
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub const url_safe = Codecs{
|
2021-03-26 16:01:44 +01:00
|
|
|
.alphabet_chars = url_safe_alphabet_chars,
|
|
|
|
|
.pad_char = '=',
|
|
|
|
|
.decoderWithIgnore = urlSafeBase64DecoderWithIgnore,
|
|
|
|
|
.Encoder = Base64Encoder.init(url_safe_alphabet_chars, '='),
|
|
|
|
|
.Decoder = Base64Decoder.init(url_safe_alphabet_chars, '='),
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-23 10:20:31 +09:00
|
|
|
/// URL-safe Base64 codecs, without padding, as defined in
|
|
|
|
|
/// [RFC 4648 section 3.2](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2).
|
2021-03-26 16:01:44 +01:00
|
|
|
pub const url_safe_no_pad = Codecs{
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
.alphabet_chars = url_safe_alphabet_chars,
|
|
|
|
|
.pad_char = null,
|
|
|
|
|
.decoderWithIgnore = urlSafeBase64DecoderWithIgnore,
|
|
|
|
|
.Encoder = Base64Encoder.init(url_safe_alphabet_chars, null),
|
|
|
|
|
.Decoder = Base64Decoder.init(url_safe_alphabet_chars, null),
|
|
|
|
|
};
|
|
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
pub const Base64Encoder = struct {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
alphabet_chars: [64]u8,
|
|
|
|
|
pad_char: ?u8,
|
2017-04-17 19:08:41 -04:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// A bunch of assertions, then simply pass the data right through.
|
|
|
|
|
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Encoder {
|
2017-11-20 21:36:18 -07:00
|
|
|
assert(alphabet_chars.len == 64);
|
2019-06-09 19:24:24 -04:00
|
|
|
var char_in_alphabet = [_]bool{false} ** 256;
|
2017-11-20 21:36:18 -07:00
|
|
|
for (alphabet_chars) |c| {
|
|
|
|
|
assert(!char_in_alphabet[c]);
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
assert(pad_char == null or c != pad_char.?);
|
2017-11-20 21:36:18 -07:00
|
|
|
char_in_alphabet[c] = true;
|
|
|
|
|
}
|
2018-11-13 05:08:37 -08:00
|
|
|
return Base64Encoder{
|
2017-11-20 21:36:18 -07:00
|
|
|
.alphabet_chars = alphabet_chars,
|
|
|
|
|
.pad_char = pad_char,
|
|
|
|
|
};
|
|
|
|
|
}
|
2017-04-17 19:08:41 -04:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// Compute the encoded length
|
|
|
|
|
pub fn calcSize(encoder: *const Base64Encoder, source_len: usize) usize {
|
|
|
|
|
if (encoder.pad_char != null) {
|
|
|
|
|
return @divTrunc(source_len + 2, 3) * 4;
|
|
|
|
|
} else {
|
|
|
|
|
const leftover = source_len % 3;
|
|
|
|
|
return @divTrunc(source_len, 3) * 4 + @divTrunc(leftover * 4 + 2, 3);
|
|
|
|
|
}
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 10:10:12 +02:00
|
|
|
// dest must be compatible with std.io.Writer's writeAll interface
|
|
|
|
|
pub fn encodeWriter(encoder: *const Base64Encoder, dest: anytype, source: []const u8) !void {
|
|
|
|
|
var chunker = window(u8, source, 3, 3);
|
|
|
|
|
while (chunker.next()) |chunk| {
|
|
|
|
|
var temp: [5]u8 = undefined;
|
|
|
|
|
const s = encoder.encode(&temp, chunk);
|
|
|
|
|
try dest.writeAll(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// destWriter must be compatible with std.io.Writer's writeAll interface
|
|
|
|
|
// sourceReader must be compatible with std.io.Reader's read interface
|
|
|
|
|
pub fn encodeFromReaderToWriter(encoder: *const Base64Encoder, destWriter: anytype, sourceReader: anytype) !void {
|
|
|
|
|
while (true) {
|
|
|
|
|
var tempSource: [3]u8 = undefined;
|
|
|
|
|
const bytesRead = try sourceReader.read(&tempSource);
|
|
|
|
|
if (bytesRead == 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var temp: [5]u8 = undefined;
|
|
|
|
|
const s = encoder.encode(&temp, tempSource[0..bytesRead]);
|
|
|
|
|
try destWriter.writeAll(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// dest.len must at least be what you get from ::calcSize.
|
2020-11-16 09:38:32 -05:00
|
|
|
pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const out_len = encoder.calcSize(source.len);
|
|
|
|
|
assert(dest.len >= out_len);
|
|
|
|
|
|
2023-08-28 20:30:49 -04:00
|
|
|
var idx: usize = 0;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
var out_idx: usize = 0;
|
2023-10-13 00:38:55 +01:00
|
|
|
while (idx + 15 < source.len) : (idx += 12) {
|
2023-10-31 13:02:38 -07:00
|
|
|
const bits = std.mem.readInt(u128, source[idx..][0..16], .big);
|
2023-10-13 00:38:55 +01:00
|
|
|
inline for (0..16) |i| {
|
|
|
|
|
dest[out_idx + i] = encoder.alphabet_chars[@truncate((bits >> (122 - i * 6)) & 0x3f)];
|
|
|
|
|
}
|
|
|
|
|
out_idx += 16;
|
|
|
|
|
}
|
|
|
|
|
while (idx + 3 < source.len) : (idx += 3) {
|
2023-10-31 13:02:38 -07:00
|
|
|
const bits = std.mem.readInt(u32, source[idx..][0..4], .big);
|
2023-10-13 00:38:55 +01:00
|
|
|
dest[out_idx] = encoder.alphabet_chars[(bits >> 26) & 0x3f];
|
|
|
|
|
dest[out_idx + 1] = encoder.alphabet_chars[(bits >> 20) & 0x3f];
|
|
|
|
|
dest[out_idx + 2] = encoder.alphabet_chars[(bits >> 14) & 0x3f];
|
|
|
|
|
dest[out_idx + 3] = encoder.alphabet_chars[(bits >> 8) & 0x3f];
|
|
|
|
|
out_idx += 4;
|
|
|
|
|
}
|
|
|
|
|
if (idx + 2 < source.len) {
|
2023-08-28 20:30:49 -04:00
|
|
|
dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2];
|
|
|
|
|
dest[out_idx + 1] = encoder.alphabet_chars[((source[idx] & 0x3) << 4) | (source[idx + 1] >> 4)];
|
|
|
|
|
dest[out_idx + 2] = encoder.alphabet_chars[(source[idx + 1] & 0xf) << 2 | (source[idx + 2] >> 6)];
|
|
|
|
|
dest[out_idx + 3] = encoder.alphabet_chars[source[idx + 2] & 0x3f];
|
|
|
|
|
out_idx += 4;
|
2023-10-13 00:38:55 +01:00
|
|
|
} else if (idx + 1 < source.len) {
|
2023-08-28 20:30:49 -04:00
|
|
|
dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2];
|
|
|
|
|
dest[out_idx + 1] = encoder.alphabet_chars[((source[idx] & 0x3) << 4) | (source[idx + 1] >> 4)];
|
|
|
|
|
dest[out_idx + 2] = encoder.alphabet_chars[(source[idx + 1] & 0xf) << 2];
|
|
|
|
|
out_idx += 3;
|
|
|
|
|
} else if (idx < source.len) {
|
|
|
|
|
dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2];
|
|
|
|
|
dest[out_idx + 1] = encoder.alphabet_chars[(source[idx] & 0x3) << 4];
|
|
|
|
|
out_idx += 2;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
}
|
|
|
|
|
if (encoder.pad_char) |pad_char| {
|
2023-03-23 18:01:21 +01:00
|
|
|
for (dest[out_idx..out_len]) |*pad| {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pad.* = pad_char;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
return dest[0..out_len];
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
2017-11-20 21:36:18 -07:00
|
|
|
};
|
2017-11-17 23:42:21 -07:00
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
pub const Base64Decoder = struct {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const invalid_char: u8 = 0xff;
|
2023-10-13 00:38:55 +01:00
|
|
|
const invalid_char_tst: u32 = 0xff000000;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
2017-11-17 23:42:21 -07:00
|
|
|
/// e.g. 'A' => 0.
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// `invalid_char` for any value not in the 64 alphabet chars.
|
2017-11-17 23:42:21 -07:00
|
|
|
char_to_index: [256]u8,
|
2023-10-13 00:38:55 +01:00
|
|
|
fast_char_to_index: [4][256]u32,
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pad_char: ?u8,
|
2018-05-28 20:23:55 -04:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Decoder {
|
2018-11-13 05:08:37 -08:00
|
|
|
var result = Base64Decoder{
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
.char_to_index = [_]u8{invalid_char} ** 256,
|
2023-10-13 00:38:55 +01:00
|
|
|
.fast_char_to_index = .{[_]u32{invalid_char_tst} ** 256} ** 4,
|
2017-11-17 23:42:21 -07:00
|
|
|
.pad_char = pad_char,
|
|
|
|
|
};
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
var char_in_alphabet = [_]bool{false} ** 256;
|
2023-02-18 09:02:57 -07:00
|
|
|
for (alphabet_chars, 0..) |c, i| {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
assert(!char_in_alphabet[c]);
|
|
|
|
|
assert(pad_char == null or c != pad_char.?);
|
2017-11-17 23:42:21 -07:00
|
|
|
|
2023-10-13 00:38:55 +01:00
|
|
|
const ci = @as(u32, @intCast(i));
|
|
|
|
|
result.fast_char_to_index[0][c] = ci << 2;
|
|
|
|
|
result.fast_char_to_index[1][c] = (ci >> 4) | ((ci & 0x0f) << 12);
|
|
|
|
|
result.fast_char_to_index[2][c] = ((ci & 0x3) << 22) | ((ci & 0x3c) << 6);
|
|
|
|
|
result.fast_char_to_index[3][c] = ci << 16;
|
|
|
|
|
|
2023-06-22 18:46:56 +01:00
|
|
|
result.char_to_index[c] = @as(u8, @intCast(i));
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
char_in_alphabet[c] = true;
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding.
|
|
|
|
|
/// `InvalidPadding` is returned if the input length is not valid.
|
|
|
|
|
pub fn calcSizeUpperBound(decoder: *const Base64Decoder, source_len: usize) Error!usize {
|
|
|
|
|
var result = source_len / 4 * 3;
|
|
|
|
|
const leftover = source_len % 4;
|
|
|
|
|
if (decoder.pad_char != null) {
|
|
|
|
|
if (leftover % 4 != 0) return error.InvalidPadding;
|
|
|
|
|
} else {
|
|
|
|
|
if (leftover % 4 == 1) return error.InvalidPadding;
|
|
|
|
|
result += leftover * 3 / 4;
|
|
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// Return the exact decoded size for a slice.
|
|
|
|
|
/// `InvalidPadding` is returned if the input length is not valid.
|
|
|
|
|
pub fn calcSizeForSlice(decoder: *const Base64Decoder, source: []const u8) Error!usize {
|
|
|
|
|
const source_len = source.len;
|
|
|
|
|
var result = try decoder.calcSizeUpperBound(source_len);
|
|
|
|
|
if (decoder.pad_char) |pad_char| {
|
|
|
|
|
if (source_len >= 1 and source[source_len - 1] == pad_char) result -= 1;
|
|
|
|
|
if (source_len >= 2 and source[source_len - 2] == pad_char) result -= 1;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
|
2017-11-20 21:36:18 -07:00
|
|
|
/// dest.len must be what you get from ::calcSize.
|
Fix simple doc mistakes. (#17624)
* Add missing period in Stack's description
This looks fine in the source, but looks bad when seen on the documentation website.
* Correct documentation for attachSegfaultHandler()
The description for attachSegfaultHandler() looks pretty bad without indicating that the stuff at the end is code
* Added missing 'the's in Queue.put's documentation
* Fixed several errors in Stack's documentation
`push()` and `pop()` were not styled as code
There was no period after `pop()`, which looks bad on the documentation.
* Fix multiple problems in base64.zig
Both "invalid"s in Base64.decoder were not capitalized.
Missing period in documentation of Base64DecoderWithIgnore.calcSizeUpperBound.
* Fix capitalization typos in bit_set.zig
In DynamicBitSetUnmanaged.deinit's and DynamicBitSet.deinit's documentation, "deinitializes" was uncapitalized.
* Fix typos in fifo.zig's documentation
Added a previously missing period to the end of the first line of LinearFifo.writableSlice's documentation.
Added missing periods to both lines of LinearFifo.pump's documentation.
* Fix typos in fmt.bufPrint's documentation
The starts of both lines were not capitalized.
* Fix minor documentation problems in fs/file.zig
Missing periods in documentation for Permissions.setReadOnly, PermissionsWindows.setReadOnly, MetadataUnix.created, MetadataLinux.created, and MetadataWindows.created.
* Fix a glaring typo in enums.zig
* Correct errors in fs.zig
* Fixed documentation problems in hash_map.zig
The added empty line in verify_context's documentation is needed, otherwise autodoc for some reason assumes that the list hasn't been terminated and continues reading off the rest of the documentation as if it were part of the second list item.
* Added lines between consecutive URLs in http.zig
Makes the documentation conform closer to what was intended.
* Fix wrongfully ended sentence in Uri.zig
* Handle wrongly entered comma in valgrind.zig.
* Add missing periods in wasm.zig's documentation
* Fix odd spacing in event/loop.zig
* Add missing period in http/Headers.zig
* Added missing period in io/limited_reader.zig
This isn't in the documentation due to what I guess is a limitation of autodoc, but it's clearly supposed to be. If it was, it would look pretty bad.
* Correct documentation in math/big/int.zig
* Correct formatting in math/big/rational.zig
* Create an actual link to ZIGNOR's paper.
* Fixed grammatical issues in sort/block.zig
This will not show up in the documentation currently.
* Fix typo in hash_map.zig
2023-10-21 17:24:55 -04:00
|
|
|
/// Invalid characters result in `error.InvalidCharacter`.
|
|
|
|
|
/// Invalid padding results in `error.InvalidPadding`.
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub fn decode(decoder: *const Base64Decoder, dest: []u8, source: []const u8) Error!void {
|
|
|
|
|
if (decoder.pad_char != null and source.len % 4 != 0) return error.InvalidPadding;
|
2023-10-13 00:38:55 +01:00
|
|
|
var dest_idx: usize = 0;
|
|
|
|
|
var fast_src_idx: usize = 0;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
var acc: u12 = 0;
|
|
|
|
|
var acc_len: u4 = 0;
|
|
|
|
|
var leftover_idx: ?usize = null;
|
2023-10-13 00:38:55 +01:00
|
|
|
while (fast_src_idx + 16 < source.len and dest_idx + 15 < dest.len) : ({
|
|
|
|
|
fast_src_idx += 16;
|
|
|
|
|
dest_idx += 12;
|
|
|
|
|
}) {
|
|
|
|
|
var bits: u128 = 0;
|
|
|
|
|
inline for (0..4) |i| {
|
|
|
|
|
var new_bits: u128 = decoder.fast_char_to_index[0][source[fast_src_idx + i * 4]];
|
|
|
|
|
new_bits |= decoder.fast_char_to_index[1][source[fast_src_idx + 1 + i * 4]];
|
|
|
|
|
new_bits |= decoder.fast_char_to_index[2][source[fast_src_idx + 2 + i * 4]];
|
|
|
|
|
new_bits |= decoder.fast_char_to_index[3][source[fast_src_idx + 3 + i * 4]];
|
|
|
|
|
if ((new_bits & invalid_char_tst) != 0) return error.InvalidCharacter;
|
|
|
|
|
bits |= (new_bits << (24 * i));
|
|
|
|
|
}
|
2023-10-31 13:02:38 -07:00
|
|
|
std.mem.writeInt(u128, dest[dest_idx..][0..16], bits, .little);
|
2023-10-13 00:38:55 +01:00
|
|
|
}
|
|
|
|
|
while (fast_src_idx + 4 < source.len and dest_idx + 3 < dest.len) : ({
|
|
|
|
|
fast_src_idx += 4;
|
|
|
|
|
dest_idx += 3;
|
|
|
|
|
}) {
|
|
|
|
|
var bits = decoder.fast_char_to_index[0][source[fast_src_idx]];
|
|
|
|
|
bits |= decoder.fast_char_to_index[1][source[fast_src_idx + 1]];
|
|
|
|
|
bits |= decoder.fast_char_to_index[2][source[fast_src_idx + 2]];
|
|
|
|
|
bits |= decoder.fast_char_to_index[3][source[fast_src_idx + 3]];
|
|
|
|
|
if ((bits & invalid_char_tst) != 0) return error.InvalidCharacter;
|
2023-10-31 13:02:38 -07:00
|
|
|
std.mem.writeInt(u32, dest[dest_idx..][0..4], bits, .little);
|
2023-10-13 00:38:55 +01:00
|
|
|
}
|
2023-11-10 05:27:17 +00:00
|
|
|
const remaining = source[fast_src_idx..];
|
2023-10-13 00:38:55 +01:00
|
|
|
for (remaining, fast_src_idx..) |c, src_idx| {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const d = decoder.char_to_index[c];
|
|
|
|
|
if (d == invalid_char) {
|
|
|
|
|
if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter;
|
|
|
|
|
leftover_idx = src_idx;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
acc = (acc << 6) + d;
|
|
|
|
|
acc_len += 6;
|
|
|
|
|
if (acc_len >= 8) {
|
|
|
|
|
acc_len -= 8;
|
2023-06-22 18:46:56 +01:00
|
|
|
dest[dest_idx] = @as(u8, @truncate(acc >> acc_len));
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
dest_idx += 1;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) {
|
|
|
|
|
return error.InvalidPadding;
|
|
|
|
|
}
|
|
|
|
|
if (leftover_idx == null) return;
|
2023-11-10 05:27:17 +00:00
|
|
|
const leftover = source[leftover_idx.?..];
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (decoder.pad_char) |pad_char| {
|
|
|
|
|
const padding_len = acc_len / 2;
|
|
|
|
|
var padding_chars: usize = 0;
|
|
|
|
|
for (leftover) |c| {
|
|
|
|
|
if (c != pad_char) {
|
|
|
|
|
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
|
|
|
|
|
}
|
|
|
|
|
padding_chars += 1;
|
|
|
|
|
}
|
|
|
|
|
if (padding_chars != padding_len) return error.InvalidPadding;
|
|
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
2017-11-20 21:36:18 -07:00
|
|
|
};
|
2017-04-17 19:08:41 -04:00
|
|
|
|
2018-11-13 05:08:37 -08:00
|
|
|
pub const Base64DecoderWithIgnore = struct {
|
2017-11-20 21:36:18 -07:00
|
|
|
decoder: Base64Decoder,
|
2017-11-17 23:42:21 -07:00
|
|
|
char_is_ignored: [256]bool,
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
pub fn init(alphabet_chars: [64]u8, pad_char: ?u8, ignore_chars: []const u8) Base64DecoderWithIgnore {
|
2018-11-13 05:08:37 -08:00
|
|
|
var result = Base64DecoderWithIgnore{
|
2017-11-20 21:36:18 -07:00
|
|
|
.decoder = Base64Decoder.init(alphabet_chars, pad_char),
|
2019-06-09 19:24:24 -04:00
|
|
|
.char_is_ignored = [_]bool{false} ** 256,
|
2017-11-17 23:42:21 -07:00
|
|
|
};
|
|
|
|
|
for (ignore_chars) |c| {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
assert(result.decoder.char_to_index[c] == Base64Decoder.invalid_char);
|
2017-11-17 23:42:21 -07:00
|
|
|
assert(!result.char_is_ignored[c]);
|
2017-11-20 21:36:18 -07:00
|
|
|
assert(result.decoder.pad_char != c);
|
2017-11-17 23:42:21 -07:00
|
|
|
result.char_is_ignored[c] = true;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
Fix simple doc mistakes. (#17624)
* Add missing period in Stack's description
This looks fine in the source, but looks bad when seen on the documentation website.
* Correct documentation for attachSegfaultHandler()
The description for attachSegfaultHandler() looks pretty bad without indicating that the stuff at the end is code
* Added missing 'the's in Queue.put's documentation
* Fixed several errors in Stack's documentation
`push()` and `pop()` were not styled as code
There was no period after `pop()`, which looks bad on the documentation.
* Fix multiple problems in base64.zig
Both "invalid"s in Base64.decoder were not capitalized.
Missing period in documentation of Base64DecoderWithIgnore.calcSizeUpperBound.
* Fix capitalization typos in bit_set.zig
In DynamicBitSetUnmanaged.deinit's and DynamicBitSet.deinit's documentation, "deinitializes" was uncapitalized.
* Fix typos in fifo.zig's documentation
Added a previously missing period to the end of the first line of LinearFifo.writableSlice's documentation.
Added missing periods to both lines of LinearFifo.pump's documentation.
* Fix typos in fmt.bufPrint's documentation
The starts of both lines were not capitalized.
* Fix minor documentation problems in fs/file.zig
Missing periods in documentation for Permissions.setReadOnly, PermissionsWindows.setReadOnly, MetadataUnix.created, MetadataLinux.created, and MetadataWindows.created.
* Fix a glaring typo in enums.zig
* Correct errors in fs.zig
* Fixed documentation problems in hash_map.zig
The added empty line in verify_context's documentation is needed, otherwise autodoc for some reason assumes that the list hasn't been terminated and continues reading off the rest of the documentation as if it were part of the second list item.
* Added lines between consecutive URLs in http.zig
Makes the documentation conform closer to what was intended.
* Fix wrongfully ended sentence in Uri.zig
* Handle wrongly entered comma in valgrind.zig.
* Add missing periods in wasm.zig's documentation
* Fix odd spacing in event/loop.zig
* Add missing period in http/Headers.zig
* Added missing period in io/limited_reader.zig
This isn't in the documentation due to what I guess is a limitation of autodoc, but it's clearly supposed to be. If it was, it would look pretty bad.
* Correct documentation in math/big/int.zig
* Correct formatting in math/big/rational.zig
* Create an actual link to ZIGNOR's paper.
* Fixed grammatical issues in sort/block.zig
This will not show up in the documentation currently.
* Fix typo in hash_map.zig
2023-10-21 17:24:55 -04:00
|
|
|
/// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding.
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// `InvalidPadding` is returned if the input length is not valid.
|
|
|
|
|
pub fn calcSizeUpperBound(decoder_with_ignore: *const Base64DecoderWithIgnore, source_len: usize) Error!usize {
|
|
|
|
|
var result = source_len / 4 * 3;
|
|
|
|
|
if (decoder_with_ignore.decoder.pad_char == null) {
|
|
|
|
|
const leftover = source_len % 4;
|
|
|
|
|
result += leftover * 3 / 4;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
2017-04-17 19:08:41 -04:00
|
|
|
|
2017-11-20 21:36:18 -07:00
|
|
|
/// Invalid characters that are not ignored result in error.InvalidCharacter.
|
|
|
|
|
/// Invalid padding results in error.InvalidPadding.
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
/// Decoding more data than can fit in dest results in error.NoSpaceLeft. See also ::calcSizeUpperBound.
|
2018-11-16 19:33:58 +01:00
|
|
|
/// Returns the number of bytes written to dest.
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8) Error!usize {
|
2017-12-13 21:53:52 -05:00
|
|
|
const decoder = &decoder_with_ignore.decoder;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
var acc: u12 = 0;
|
|
|
|
|
var acc_len: u4 = 0;
|
|
|
|
|
var dest_idx: usize = 0;
|
|
|
|
|
var leftover_idx: ?usize = null;
|
2023-02-18 09:02:57 -07:00
|
|
|
for (source, 0..) |c, src_idx| {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (decoder_with_ignore.char_is_ignored[c]) continue;
|
|
|
|
|
const d = decoder.char_to_index[c];
|
|
|
|
|
if (d == Base64Decoder.invalid_char) {
|
|
|
|
|
if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter;
|
|
|
|
|
leftover_idx = src_idx;
|
|
|
|
|
break;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
acc = (acc << 6) + d;
|
|
|
|
|
acc_len += 6;
|
|
|
|
|
if (acc_len >= 8) {
|
|
|
|
|
if (dest_idx == dest.len) return error.NoSpaceLeft;
|
|
|
|
|
acc_len -= 8;
|
2023-06-22 18:46:56 +01:00
|
|
|
dest[dest_idx] = @as(u8, @truncate(acc >> acc_len));
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
dest_idx += 1;
|
2017-11-20 21:36:18 -07:00
|
|
|
}
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) {
|
|
|
|
|
return error.InvalidPadding;
|
|
|
|
|
}
|
|
|
|
|
const padding_len = acc_len / 2;
|
|
|
|
|
if (leftover_idx == null) {
|
|
|
|
|
if (decoder.pad_char != null and padding_len != 0) return error.InvalidPadding;
|
|
|
|
|
return dest_idx;
|
|
|
|
|
}
|
2023-11-10 05:27:17 +00:00
|
|
|
const leftover = source[leftover_idx.?..];
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (decoder.pad_char) |pad_char| {
|
|
|
|
|
var padding_chars: usize = 0;
|
|
|
|
|
for (leftover) |c| {
|
|
|
|
|
if (decoder_with_ignore.char_is_ignored[c]) continue;
|
|
|
|
|
if (c != pad_char) {
|
|
|
|
|
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
|
|
|
|
|
}
|
|
|
|
|
padding_chars += 1;
|
|
|
|
|
}
|
|
|
|
|
if (padding_chars != padding_len) return error.InvalidPadding;
|
|
|
|
|
}
|
|
|
|
|
return dest_idx;
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
2017-11-20 21:36:18 -07:00
|
|
|
};
|
2017-11-17 23:42:21 -07:00
|
|
|
|
|
|
|
|
test "base64" {
|
2018-03-12 12:56:25 -04:00
|
|
|
@setEvalBranchQuota(8000);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testBase64();
|
2023-06-05 14:29:28 +06:00
|
|
|
try comptime testAllApis(standard, "comptime", "Y29tcHRpbWU=");
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-23 18:01:21 +01:00
|
|
|
test "base64 padding dest overflow" {
|
|
|
|
|
const input = "foo";
|
|
|
|
|
|
|
|
|
|
var expect: [128]u8 = undefined;
|
2023-04-26 13:57:08 -07:00
|
|
|
@memset(&expect, 0);
|
2023-03-23 18:01:21 +01:00
|
|
|
_ = url_safe.Encoder.encode(expect[0..url_safe.Encoder.calcSize(input.len)], input);
|
|
|
|
|
|
|
|
|
|
var got: [128]u8 = undefined;
|
2023-04-26 13:57:08 -07:00
|
|
|
@memset(&got, 0);
|
2023-03-23 18:01:21 +01:00
|
|
|
_ = url_safe.Encoder.encode(&got, input);
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqualSlices(u8, &expect, &got);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 16:01:44 +01:00
|
|
|
test "base64 url_safe_no_pad" {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
@setEvalBranchQuota(8000);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testBase64UrlSafeNoPad();
|
2023-06-05 14:29:28 +06:00
|
|
|
try comptime testAllApis(url_safe_no_pad, "comptime", "Y29tcHRpbWU");
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
2018-01-31 22:48:40 -05:00
|
|
|
fn testBase64() !void {
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const codecs = standard;
|
|
|
|
|
|
|
|
|
|
try testAllApis(codecs, "", "");
|
|
|
|
|
try testAllApis(codecs, "f", "Zg==");
|
|
|
|
|
try testAllApis(codecs, "fo", "Zm8=");
|
|
|
|
|
try testAllApis(codecs, "foo", "Zm9v");
|
|
|
|
|
try testAllApis(codecs, "foob", "Zm9vYg==");
|
|
|
|
|
try testAllApis(codecs, "fooba", "Zm9vYmE=");
|
|
|
|
|
try testAllApis(codecs, "foobar", "Zm9vYmFy");
|
2023-10-13 00:38:55 +01:00
|
|
|
try testAllApis(codecs, "foobarfoobarfoo", "Zm9vYmFyZm9vYmFyZm9v");
|
|
|
|
|
try testAllApis(codecs, "foobarfoobarfoob", "Zm9vYmFyZm9vYmFyZm9vYg==");
|
|
|
|
|
try testAllApis(codecs, "foobarfoobarfooba", "Zm9vYmFyZm9vYmFyZm9vYmE=");
|
|
|
|
|
try testAllApis(codecs, "foobarfoobarfoobar", "Zm9vYmFyZm9vYmFyZm9vYmFy");
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "", " ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "f", "Z g= =");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "fo", " Zm8=");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foo", "Zm9v ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg = = ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE=");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y ");
|
|
|
|
|
|
|
|
|
|
// test getting some api errors
|
|
|
|
|
try testError(codecs, "A", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "AA", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "AAA", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "A..A", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "AA=A", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "AA/=", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "A/==", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "A===", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "====", error.InvalidPadding);
|
2023-10-13 00:38:55 +01:00
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyA..A", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyAA=A", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyAA/=", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyA/==", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyA===", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "A..AZm9vYmFyZm9vYmFy", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vAA=A", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vAA/=", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vA/==", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "Zm9vYmFyZm9vA===", error.InvalidPadding);
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AA==");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAA=");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAAA");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAAAAA==");
|
2023-10-13 00:38:55 +01:00
|
|
|
|
|
|
|
|
try testFourBytesDestNoSpaceLeftError(codecs, "AAAAAAAAAAAAAAAA");
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-26 16:01:44 +01:00
|
|
|
fn testBase64UrlSafeNoPad() !void {
|
|
|
|
|
const codecs = url_safe_no_pad;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
try testAllApis(codecs, "", "");
|
|
|
|
|
try testAllApis(codecs, "f", "Zg");
|
|
|
|
|
try testAllApis(codecs, "fo", "Zm8");
|
|
|
|
|
try testAllApis(codecs, "foo", "Zm9v");
|
|
|
|
|
try testAllApis(codecs, "foob", "Zm9vYg");
|
|
|
|
|
try testAllApis(codecs, "fooba", "Zm9vYmE");
|
|
|
|
|
try testAllApis(codecs, "foobar", "Zm9vYmFy");
|
2023-10-13 00:38:55 +01:00
|
|
|
try testAllApis(codecs, "foobarfoobarfoobar", "Zm9vYmFyZm9vYmFyZm9vYmFy");
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "", " ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "f", "Z g ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "fo", " Zm8");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foo", "Zm9v ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg ");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE");
|
|
|
|
|
try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y ");
|
2017-11-17 23:42:21 -07:00
|
|
|
|
|
|
|
|
// test getting some api errors
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
try testError(codecs, "A", error.InvalidPadding);
|
|
|
|
|
try testError(codecs, "AAA=", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "A..A", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "AA=A", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "AA/=", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "A/==", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "A===", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "====", error.InvalidCharacter);
|
2023-10-13 00:38:55 +01:00
|
|
|
try testError(codecs, "Zm9vYmFyZm9vYmFyA..A", error.InvalidCharacter);
|
|
|
|
|
try testError(codecs, "A..AZm9vYmFyZm9vYmFy", error.InvalidCharacter);
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AA");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAA");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAAA");
|
|
|
|
|
try testNoSpaceLeftError(codecs, "AAAAAA");
|
2023-10-13 00:38:55 +01:00
|
|
|
|
|
|
|
|
try testFourBytesDestNoSpaceLeftError(codecs, "AAAAAAAAAAAAAAAA");
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
fn testAllApis(codecs: Codecs, expected_decoded: []const u8, expected_encoded: []const u8) !void {
|
2017-11-20 21:36:18 -07:00
|
|
|
// Base64Encoder
|
2017-11-17 23:42:21 -07:00
|
|
|
{
|
2024-09-04 10:10:12 +02:00
|
|
|
// raw encode
|
2017-11-17 23:42:21 -07:00
|
|
|
var buffer: [0x100]u8 = undefined;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const encoded = codecs.Encoder.encode(&buffer, expected_decoded);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testing.expectEqualSlices(u8, expected_encoded, encoded);
|
2024-09-04 10:10:12 +02:00
|
|
|
|
|
|
|
|
// stream encode
|
|
|
|
|
var list = try std.BoundedArray(u8, 0x100).init(0);
|
|
|
|
|
try codecs.Encoder.encodeWriter(list.writer(), expected_decoded);
|
|
|
|
|
try testing.expectEqualSlices(u8, expected_encoded, list.slice());
|
|
|
|
|
|
|
|
|
|
// reader to writer encode
|
|
|
|
|
var stream = std.io.fixedBufferStream(expected_decoded);
|
|
|
|
|
list = try std.BoundedArray(u8, 0x100).init(0);
|
|
|
|
|
try codecs.Encoder.encodeFromReaderToWriter(list.writer(), stream.reader());
|
|
|
|
|
try testing.expectEqualSlices(u8, expected_encoded, list.slice());
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
2017-04-17 19:08:41 -04:00
|
|
|
|
2017-11-20 21:36:18 -07:00
|
|
|
// Base64Decoder
|
2017-11-17 23:42:21 -07:00
|
|
|
{
|
|
|
|
|
var buffer: [0x100]u8 = undefined;
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0..try codecs.Decoder.calcSizeForSlice(expected_encoded)];
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
try codecs.Decoder.decode(decoded, expected_encoded);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testing.expectEqualSlices(u8, expected_decoded, decoded);
|
2017-11-17 23:42:21 -07:00
|
|
|
}
|
2017-04-17 19:08:41 -04:00
|
|
|
|
2017-11-20 21:36:18 -07:00
|
|
|
// Base64DecoderWithIgnore
|
2017-11-17 23:42:21 -07:00
|
|
|
{
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
const decoder_ignore_nothing = codecs.decoderWithIgnore("");
|
2017-11-17 23:42:21 -07:00
|
|
|
var buffer: [0x100]u8 = undefined;
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0..try decoder_ignore_nothing.calcSizeUpperBound(expected_encoded.len)];
|
|
|
|
|
const written = try decoder_ignore_nothing.decode(decoded, expected_encoded);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testing.expect(written <= decoded.len);
|
|
|
|
|
try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
fn testDecodeIgnoreSpace(codecs: Codecs, expected_decoded: []const u8, encoded: []const u8) !void {
|
|
|
|
|
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
|
2017-11-17 23:42:21 -07:00
|
|
|
var buffer: [0x100]u8 = undefined;
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0..try decoder_ignore_space.calcSizeUpperBound(encoded.len)];
|
|
|
|
|
const written = try decoder_ignore_space.decode(decoded, encoded);
|
2021-05-04 20:47:26 +03:00
|
|
|
try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]);
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
fn testError(codecs: Codecs, encoded: []const u8, expected_err: anyerror) !void {
|
|
|
|
|
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
|
2017-11-17 23:42:21 -07:00
|
|
|
var buffer: [0x100]u8 = undefined;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (codecs.Decoder.calcSizeForSlice(encoded)) |decoded_size| {
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0..decoded_size];
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (codecs.Decoder.decode(decoded, encoded)) |_| {
|
2017-11-17 23:42:21 -07:00
|
|
|
return error.ExpectedError;
|
|
|
|
|
} else |err| if (err != expected_err) return err;
|
|
|
|
|
} else |err| if (err != expected_err) return err;
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (decoder_ignore_space.decode(buffer[0..], encoded)) |_| {
|
2017-11-17 23:42:21 -07:00
|
|
|
return error.ExpectedError;
|
|
|
|
|
} else |err| if (err != expected_err) return err;
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
|
|
|
|
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
fn testNoSpaceLeftError(codecs: Codecs, encoded: []const u8) !void {
|
|
|
|
|
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
|
2017-11-17 23:42:21 -07:00
|
|
|
var buffer: [0x100]u8 = undefined;
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0 .. (try codecs.Decoder.calcSizeForSlice(encoded)) - 1];
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
if (decoder_ignore_space.decode(decoded, encoded)) |_| {
|
2017-11-17 23:42:21 -07:00
|
|
|
return error.ExpectedError;
|
std/base64: cleanups & support url-safe and other non-padded variants
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
2021-03-19 19:26:30 +01:00
|
|
|
} else |err| if (err != error.NoSpaceLeft) return err;
|
2017-04-17 19:08:41 -04:00
|
|
|
}
|
2023-10-13 00:38:55 +01:00
|
|
|
|
|
|
|
|
fn testFourBytesDestNoSpaceLeftError(codecs: Codecs, encoded: []const u8) !void {
|
|
|
|
|
const decoder_ignore_space = codecs.decoderWithIgnore(" ");
|
|
|
|
|
var buffer: [0x100]u8 = undefined;
|
2023-11-10 05:27:17 +00:00
|
|
|
const decoded = buffer[0..4];
|
2023-10-13 00:38:55 +01:00
|
|
|
if (decoder_ignore_space.decode(decoded, encoded)) |_| {
|
|
|
|
|
return error.ExpectedError;
|
|
|
|
|
} else |err| if (err != error.NoSpaceLeft) return err;
|
|
|
|
|
}
|