Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
- name: Pack
run: dotnet pack --configuration Release --no-build --no-restore --nologo --output ./artifacts -p:AssemblyVersion=${{ steps.semver.outputs.AssemblyVersion }} -p:FileVersion=${{ steps.semver.outputs.FileVersion }} -p:InformationalVersion=${{ steps.semver.outputs.InformationalVersion }} -p:PackageVersion=${{ steps.semver.outputs.PackageVersion }}
- name: Upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}.${{ steps.semver.outputs.ArtifactsVersion }}
path: ./artifacts
Expand Down
44 changes: 44 additions & 0 deletions src/DataFormat.Base32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,49 @@ public static Guid FromBase32Guid(ReadOnlySpan<char> value)

return ReadGuidBigEndian(guidBytes);
}

/// <summary>
/// Verifies if the provided span <paramref name="value"/> is
/// a valid base32 representation.
/// </summary>
/// <param name="value">
/// The span to verify.
/// </param>
/// <returns>
/// <c>true</c> if the span <paramref name="value"/> has
/// correct number of base32 digits; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// This method returns <c>true</c> for an empty span.
/// </remarks>
public static bool IsBase32(ReadOnlySpan<char> value)
{
int length = value.Length;

if (length == 0)
{
return true;
}

switch (length % 8)
{
case 1:
case 3:
case 6:
return false;
}

for (int i = 0; i < value.Length; i++)
{
int ch = value[i];

if (ch >= MC || ((ch = Base32Map[ch]) >= MC))
{
return false;
}
}

return true;
}
}
}
35 changes: 35 additions & 0 deletions src/DataFormat.Hex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,40 @@ public static Guid FromHexGuid(ReadOnlySpan<char> value)

return ReadGuidBigEndian(guidBytes);
}

/// <summary>
/// Verifies if the provided span <paramref name="value"/> is
/// a valid hexadecimal representation.
/// </summary>
/// <param name="value">
/// The span to verify.
/// </param>
/// <returns>
/// <c>true</c> if the span <paramref name="value"/> has
/// an even number of hexadecimal digits; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// This method returns <c>true</c> for an empty span.
/// </remarks>
public static bool IsHex(ReadOnlySpan<char> value)
{
if ((value.Length & 1) != 0)
{
return false;
}

for (int i = 0; i < value.Length; i += 2)
{
int c1 = value[i];
int c2 = value[i + 1];

if ((c1 >= MC) || ((c1 = HexMap[c1]) >= MC) || (c2 >= MC) || ((c2 = HexMap[c2]) >= MC))
{
return false;
}
}

return true;
}
}
}
13 changes: 12 additions & 1 deletion tests/DataFormatBase32Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public void FullRangeRoundTripPass()

string base32StrUpper = base32StrLower.ToUpperInvariant();

Assert.IsTrue(DataFormat.IsBase32(base32StrLower));
Assert.IsTrue(DataFormat.IsBase32(base32StrUpper));

var base32Lower = DataFormat.FromBase32(base32StrLower);
var base32Upper = DataFormat.FromBase32(base32StrUpper);

Expand All @@ -51,6 +54,8 @@ public void FullRangeRoundTripPass()
[TestMethod]
public void FromBase32EmptyStringPass()
{
Assert.IsTrue(DataFormat.IsBase32(string.Empty));

var actual = DataFormat.FromBase32(string.Empty);

Assert.AreEqual(Array.Empty<byte>(), actual);
Expand All @@ -59,7 +64,9 @@ public void FromBase32EmptyStringPass()
[TestMethod]
public void FromBase32NullStringPass()
{
var actual = DataFormat.FromBase32(null);
Assert.IsTrue(DataFormat.IsBase32((string)null));

var actual = DataFormat.FromBase32((string)null);

Assert.AreEqual(Array.Empty<byte>(), actual);
}
Expand Down Expand Up @@ -89,6 +96,8 @@ public void ToBase32NullArrayPass()
[DataRow("DSJPRTBPC40")]
public void FromBase32InvalidInputLengthFail(string invalidLengthBase32)
{
Assert.IsFalse(DataFormat.IsBase32(invalidLengthBase32));

var ex = Assert.ThrowsException<FormatException>(() => DataFormat.FromBase32(invalidLengthBase32));
Assert.AreEqual("The input is not a valid base32 string as its length is not correct.", ex.Message);
}
Expand Down Expand Up @@ -128,6 +137,8 @@ public void FromBase32InvalidInputLengthFail(string invalidLengthBase32)
[DataRow("d\u0308jprtbpc4")]
public void FromBase32InvalidInputCharFail(string invalidCharInBase32)
{
Assert.IsFalse(DataFormat.IsBase32(invalidCharInBase32));

var ex = Assert.ThrowsException<FormatException>(() => DataFormat.FromBase32(invalidCharInBase32));
Assert.AreEqual("The input is not a valid base32 string as it contains a non-base32 character.", ex.Message);
}
Expand Down
13 changes: 12 additions & 1 deletion tests/DataFormatHexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public void FullRangeRoundTripPass()

string hexStrUpper = hexStrLower.ToUpperInvariant();

Assert.IsTrue(DataFormat.IsHex(hexStrLower));
Assert.IsTrue(DataFormat.IsHex(hexStrUpper));

var hexLower = DataFormat.FromHex(hexStrLower);
var hexUpper = DataFormat.FromHex(hexStrUpper);

Expand All @@ -54,6 +57,8 @@ public void FullRangeRoundTripPass()
[TestMethod]
public void FromHexEmptyStringPass()
{
Assert.IsTrue(DataFormat.IsHex(string.Empty));

var actual = DataFormat.FromHex(string.Empty);

Assert.AreEqual(Array.Empty<byte>(), actual);
Expand All @@ -62,7 +67,9 @@ public void FromHexEmptyStringPass()
[TestMethod]
public void FromHexNullStringPass()
{
var actual = DataFormat.FromHex(null);
Assert.IsTrue(DataFormat.IsHex((string)null));

var actual = DataFormat.FromHex((string)null);

Assert.AreEqual(Array.Empty<byte>(), actual);
}
Expand Down Expand Up @@ -91,6 +98,8 @@ public void ToHexNullArrayPass()
[DataRow("6E656C69766")]
public void FromHexInvalidInputLengthFail(string invalidLengthHex)
{
Assert.IsFalse(DataFormat.IsHex(invalidLengthHex));

var ex = Assert.ThrowsException<FormatException>(() => DataFormat.FromHex(invalidLengthHex));
Assert.AreEqual("The input is not a valid hex string as its length is not a multiple of 2.", ex.Message);
}
Expand Down Expand Up @@ -118,6 +127,8 @@ public void FromHexInvalidInputLengthFail(string invalidLengthHex)
[DataRow("n0")]
public void FromHexInvalidInputCharFail(string invalidCharInHex)
{
Assert.IsFalse(DataFormat.IsHex(invalidCharInHex));

var ex = Assert.ThrowsException<FormatException>(() => DataFormat.FromHex(invalidCharInHex));
Assert.AreEqual("The input is not a valid hex string as it contains a non-hex character.", ex.Message);
}
Expand Down