Last active
July 14, 2017 20:42
-
-
Save goelze/b2c3e58631abfbabaa1d5f2480b96376 to your computer and use it in GitHub Desktop.
A struct containing a string in z-base-32 encoding.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ZBase32String.cs by Garrett Oelze <garrett@oelze.com> | |
* | |
* This work is licensed under a Creative Commons Attribution 4.0 International License. | |
* http://creativecommons.org/licenses/by/4.0/ | |
* | |
* z-base-32 encoding is derived from the specification at http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
namespace Oelze.Garrett | |
{ | |
public struct ZBase32String | |
{ | |
public ZBase32String(byte[] bytes) | |
{ | |
_bytes = bytes; | |
_string = ConvertFromBytes(bytes); | |
} | |
public ZBase32String(string text, Encoding encoding) : this(encoding.GetBytes(text)) { } | |
public ZBase32String(string zBase32) | |
{ | |
_string = zBase32.ToLower(); | |
_bytes = ConvertToBytes(zBase32); | |
} | |
readonly byte[] _bytes; | |
readonly string _string; | |
const string ZBase32Chars = "ybndrfg8ejkmcpqxot1uwisza345h769"; | |
static string ConvertFromBytes(byte[] bytes) | |
{ | |
if (bytes == null) | |
return null; | |
if (bytes.Length == 0) | |
return string.Empty; | |
var sb = new StringBuilder((int)Math.Ceiling(bytes.Length * 8.0 / 5)); | |
for (int i = 0; i < bytes.Length; i += 5) | |
{ | |
int bytesLeft = Math.Min(5, bytes.Length - i); | |
ulong buffer = 0; | |
for (int j = 0; j < bytesLeft; j++) | |
{ | |
buffer = (buffer << 8) | bytes[i + j]; | |
} | |
int bitsLeft = bytesLeft * 8; | |
for (; bitsLeft > 0; bitsLeft -= 5) | |
{ | |
int zBaseValue; | |
if (bitsLeft >= 5) | |
zBaseValue = (int)(buffer >> (bitsLeft - 5)) & 0x1f; | |
else | |
zBaseValue = (int)(buffer & (ulong)(0x1f >> (5 - bitsLeft))) << (5 - bitsLeft); | |
sb.Append(ZBase32Chars[zBaseValue]); | |
} | |
} | |
return sb.ToString(); | |
} | |
static byte[] ConvertToBytes(string s) | |
{ | |
if (s == null) | |
return null; | |
if (s == string.Empty) | |
return new byte[0]; | |
var result = new List<byte>((int)Math.Ceiling(s.Length * 5.0 / 8)); | |
for (int i = 0; i < s.Length; i += 8) | |
{ | |
int subLength = Math.Min(8, s.Length - i); | |
ulong buffer = 0; | |
for (int j = 0; j < subLength; j++) | |
{ | |
int index = ZBase32Chars.IndexOf(s[i + j]); | |
if (index < 0) | |
throw new ArgumentException("String is not a valid z-base-32 string."); | |
buffer = (buffer << 5) | (byte)index; | |
} | |
int bitsLeft = subLength * 5; | |
for (; bitsLeft >= 8; bitsLeft -= 8) | |
{ | |
result.Add((byte)((buffer >> (bitsLeft - 8)) & 0xff)); | |
} | |
} | |
return result.ToArray(); | |
} | |
/// <summary> | |
/// Returns the value encoded in zbase32. | |
/// </summary> | |
public override string ToString() | |
{ | |
return _string; | |
} | |
/// <summary> | |
/// Returns the value with the specified encoding. | |
/// </summary> | |
public string ToString(Encoding enc) | |
{ | |
return enc.GetString(_bytes); | |
} | |
public byte[] ToByteArray() | |
{ | |
return _bytes; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment