![]() |
VOOZH | about |
dotnet add package gfoidl.Base64 --version 2.0.0
NuGet\Install-Package gfoidl.Base64 -Version 2.0.0
<PackageReference Include="gfoidl.Base64" Version="2.0.0" />
<PackageVersion Include="gfoidl.Base64" Version="2.0.0" />Directory.Packages.props
<PackageReference Include="gfoidl.Base64" />Project file
paket add gfoidl.Base64 --version 2.0.0
#r "nuget: gfoidl.Base64, 2.0.0"
#:package gfoidl.Base64@2.0.0
#addin nuget:?package=gfoidl.Base64&version=2.0.0Install as a Cake Addin
#tool nuget:?package=gfoidl.Base64&version=2.0.0Install as a Cake Tool
| CI | NuGet |
|---|---|
| 👁 Build Status |
👁 NuGet |
A .NET library for base64 encoding / decoding, as well as base64Url support.
Encoding can be done to buffers of type byte (for UTF-8) or char.
Decoding can read from buffers of type byte (for UTF-8) or char.
Encoding / decoding supports buffer-chains, for example for very large data or when the data arrives in chunks.
In .NET Core 3.0 onwards encoding / decoding is done with SIMD-support:
| Framework | scalar | SSSE3 | AVX2 |
|---|---|---|---|
| .NET Core 3.0 | ✔️ | ✔️ | ✔️ |
| .NET Standard 2.0 / .NET 4.5 | ✔️ | ❌ | ❌ |
If available AVX will "eat" up as much as possible, then SSE will "eat" up as much as possible, finally scalar code processes the rest (including padding).
Basically the entry to encoder / decoder is Base64.Default for base64, and Base64.Url for base64Url.
See for further examples.
byte[] guid = Guid.NewGuid().ToByteArray();
string guidBase64 = Base64.Default.Encode(guid);
string guidBases64Url = Base64.Url.Encode(guid);
or Span<byte> based (for UTF-8 encoded output):
int guidBase64EncodedLength = Base64.Default.GetEncodedLength(guid.Length);
Span<byte> guidBase64UTF8 = stackalloc byte[guidBase64EncodedLength];
OperationStatus status = Base64.Default.Encode(guid, guidBase64UTF8, out int consumed, out int written);
int guidBase64UrlEncodedLength = Base64.Url.GetEncodedLength(guid.Length);
Span<byte> guidBase64UrlUTF8 = stackalloc byte[guidBase64UrlEncodedLength];
status = Base64.Url.Encode(guid, guidBase64UrlUTF8, out consumed, out written);
Guid guid = Guid.NewGuid();
string guidBase64 = Convert.ToBase64String(guid.ToByteArray());
string guidBase64Url = guidBase64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
byte[] guidBase64Decoded = Base64.Default.Decode(guidBase64);
byte[] guidBase64UrlDecoded = Base64.Url.Decode(guidBase64Url);
or Span<char> based:
int guidBase64DecodedLen = Base64.Default.GetDecodedLength(guidBase64);
int guidBase64UrlDecodedLen = Base64.Url.GetDecodedLength(guidBase64Url);
Span<byte> guidBase64DecodedBuffer = stackalloc byte[guidBase64DecodedLen];
Span<byte> guidBase64UrlDecodedBuffer = stackalloc byte[guidBase64UrlDecodedLen];
OperationStatus status = Base64.Default.Decode(guidBase64, guidBase64DecodedBuffer, out int consumed, out int written);
status = Base64.Url.Decode(guidBase64Url, guidBase64UrlDecodedBuffer, out consumed, out written);
Buffer chains are handy when for encoding / decoding
var rnd = new Random();
Span<byte> data = new byte[1000];
rnd.NextBytes(data);
// exact length could be computed by Base64.Default.GetEncodedLength, here for demo exzessive size
Span<char> base64 = new char[5000];
OperationStatus status = Base64.Default.Encode(data.Slice(0, 400), base64, out int consumed, out int written, isFinalBlock: false);
status = Base64.Default.Encode(data.Slice(consumed), base64.Slice(written), out consumed, out int written1, isFinalBlock: true);
base64 = base64.Slice(0, written + written1);
Span<byte> decoded = new byte[5000];
status = Base64.Default.Decode(base64.Slice(0, 100), decoded, out consumed, out written, isFinalBlock: false);
status = Base64.Default.Decode(base64.Slice(consumed), decoded.Slice(written), out consumed, out written1, isFinalBlock: true);
decoded = decoded.Slice(0, written + written1);
Encoding / decoding with ReadOnlySequence<byte> and IBufferWriter<byte> can be used together with System.IO.Pipelines.
var pipeOptions = PipeOptions.Default;
var pipe = new Pipe(pipeOptions);
var rnd = new Random(42);
var data = new byte[4097];
rnd.NextBytes(data);
pipe.Writer.Write(data);
await pipe.Writer.CompleteAsync();
ReadResult readResult = await pipe.Reader.ReadAsync();
var resultPipe = new Pipe();
Base64.Default.Encode(readResult.Buffer, resultPipe.Writer, out long consumed, out long written);
await resultPipe.Writer.CompleteAsync();
.NET provides the classes System.Convert and System.Buffers.Text.Base64 for base64 operations.
base64Url isn't supported, so hacky solutions like
string base64 = Convert.ToBase64String(data);
string base64Url = base64.Replace('+', '-').Replace('/', '_').TrimEnd('=');
are needed. This isn't ideal, as there are avoidable allocations and several iterations over the encoded string (see and for benchmark results).
gfoidl.Base64 supports encoding / decoding to / from base64Url in a direct way.
Encoding byte[] -> byte[] for UTF-8 is supported, as well as byte[] -> char[].
Decoding byte[] -> byte[] for UTF-8 is supported, as well as char[] -> byte[].
Further SIMD isn't utilized in the .NET classes. (Note: I've opened an issue to add SIMD-support to these classes).
These methods only support byte[] -> char[] as types for encoding,
and char[] -> byte[] as types for decoding, where char[] can also be string or (ReadOnly)Span<char>.
To support UTF-8 another method call like
byte[] utf8Encoded = Encoding.ASCII.GetBytes(base64String);
is needed.
An potential advantage of this class is that it allows the insertion of line-breaks (cf. Base64FormattingOptions.InsertLineBreaks).
This class only supports byte[] -> byte[] for encoding / decoding. So in order to get a string
Encoding has to be used.
An potential advantage of this class is the support for in-place encoding / decoding (cf. Base64.EncodeToUtf8InPlace, Base64.DecodeFromUtf8InPlace )
For all benchmarks see .
Performance gain depends, among a lot of other things, on the workload size, so here no table will with superior results will be shown.
is for small inputs slower than Convert.ToBase64String (has less overhead, and can write to string-buffer in a direct way).
But the larger the workload, the better this library works. For data-length of 1000 speedup can be ~5x with AVX2 encoding.
is generally (a lot) faster than Convert.ConvertFromBase64CharArray, also depending on workload size, but in the benchmark the speedup is from 1.5 to 12x.
For UTF-8 and speedups for input-length 1000 can be in the height of 5 to 12x.
Note: please measure / profile in your real usecase, as this are just micro-benchmarks.
The scalar version of the base64 encoding / decoding is based on System.Buffers.Text.Base64.
The scalar version of the base64Url encoding / decoding is based on https://github.com/aspnet/Extensions/pull/334 and https://github.com/aspnet/Extensions/pull/338.
Vectorized versions (SSE, AVX) for base64 encoding / decoding is based on https://github.com/aklomp/base64 (see also Acknowledgements in that repository).
Vectorized versions (SSE, AVX) for base64Url encoding / decoding is based on https://github.com/aklomp/base64 (see Acknowledgements in that repository). For decoding (SSE, AVX) code is based on Vector lookup (pshufb) by Wojciech Mula.
To get packages from the development channel use a nuget.config similar to this one:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="gfoidl-public" value="https://pkgs.dev.azure.com/gh-gfoidl/github-Projects/_packaging/gfoidl-public/nuget/v3/index.json" />
</packageSources>
</configuration>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net7.0 net7.0 is compatible. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 5 NuGet packages that depend on gfoidl.Base64:
| Package | Downloads |
|---|---|
|
JsonWebToken
High-performance JWT library. Provides Json Web Token primitives. |
|
|
BD.Common
次元超越通用基类库 |
|
|
Arc.Crypto
Arc.Crypto is a library equipped with various features related to cryptography. |
|
|
BD.Common.AspNetCore.Blazor.BackManage
次元超越通用多租户后台 UI 库 |
|
|
BD.Common8.Bcl
提供对基类库的扩展 |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0 | 276,973 | 12/20/2022 |
| 1.1.2 | 31,008 | 9/30/2022 |
| 1.1.1 | 513,015 | 6/18/2020 |
| 1.1.0 | 1,362 | 6/18/2020 |
| 1.0.1 | 4,319 | 11/8/2019 |
| 1.0.0 | 1,404 | 9/24/2019 |
| 1.0.0-preview-3 | 1,314 | 12/26/2018 |
| 1.0.0-preview-2 | 1,332 | 12/2/2018 |
| 1.0.0-preview-1 | 1,322 | 11/29/2018 |