36 Commits
1.7.5 ... 1.8.0

Author SHA1 Message Date
Matt Nadareski
16b238539b Bump version 2025-10-27 22:09:15 -04:00
Matt Nadareski
68f49eeb48 Add Bitwise Binary Operators tests 2025-10-27 16:47:36 -04:00
Matt Nadareski
c5ecd41a8f Add Shift Binary Operators tests 2025-10-27 16:43:05 -04:00
Matt Nadareski
9ab9dd4ff8 Add Bitwise Unary Operators tests 2025-10-27 16:38:45 -04:00
Matt Nadareski
867c8d11da Fix unary operator tests 2025-10-27 16:28:14 -04:00
Matt Nadareski
65dbb7a31a Add Arithmetic Binary Operators tests 2025-10-27 16:18:45 -04:00
Matt Nadareski
1eaf7954fe Add Arithmetic Unary Operators tests 2025-10-27 16:12:12 -04:00
Matt Nadareski
a602a07514 Fill out bitwise operators for both-endian 2025-10-27 16:06:01 -04:00
Matt Nadareski
466b0e90e7 Fill out arithmetic operators for both-endian 2025-10-27 15:52:48 -04:00
Matt Nadareski
abdf50c9e0 Add bitwise AND and OR operations to both-endian 2025-10-27 15:34:32 -04:00
Matt Nadareski
12341ba6aa Simplify Numerics namespace 2025-10-27 14:12:52 -04:00
Matt Nadareski
70b78f861c Revert "Add base type operator support to both-endian"
This reverts commit 5b306ce9e8.
2025-10-27 14:07:01 -04:00
Matt Nadareski
5b306ce9e8 Add base type operator support to both-endian 2025-10-27 14:02:52 -04:00
Matt Nadareski
2b6fc200e2 Add Latin1 and BigEndianUnicode extensions 2025-10-27 12:22:02 -04:00
Matt Nadareski
7c63f44c75 Add both-endian write extensions 2025-10-27 12:01:52 -04:00
Matt Nadareski
edd3e6eef2 Add both-endian try read extensions 2025-10-27 11:21:29 -04:00
Matt Nadareski
244b7411d4 Add both-endian peek read extensions 2025-10-27 10:43:54 -04:00
Matt Nadareski
fb60f1fed5 Add both-endian exact read extensions 2025-10-27 10:03:17 -04:00
Matt Nadareski
8f06bf5859 Add both-endian numeric types 2025-10-27 09:09:00 -04:00
Matt Nadareski
2c5d7ad56b Update rolling tag 2025-10-26 20:31:52 -04:00
Matt Nadareski
46996c10e5 Add Peek implementations for reading 2025-10-15 09:59:07 -04:00
Matt Nadareski
7491821679 Add origin-based SeekIfPossible 2025-10-15 09:37:41 -04:00
Matt Nadareski
8fe404e732 Remove some nonsensical endian methods 2025-10-14 20:45:02 -04:00
Matt Nadareski
793168fbe5 Add TryGet implementations for reading 2025-10-14 20:42:32 -04:00
Matt Nadareski
67b6118cc1 Add functionality from Transform tool 2025-10-14 13:58:40 -04:00
Matt Nadareski
b12d122721 Bump version 2025-10-07 09:28:17 -04:00
Matt Nadareski
20f1679557 Update Hashing to 1.5.1 2025-10-07 09:23:21 -04:00
Matt Nadareski
7ccedbeac5 Move Compare to better namespace 2025-09-30 21:25:56 -04:00
Matt Nadareski
72910cc1c0 Add AES/CTR encryption helpers 2025-09-30 19:33:28 -04:00
Matt Nadareski
8f4ea0da16 Add BouncyCastle as a dependency 2025-09-30 19:30:23 -04:00
Matt Nadareski
eb4975b261 Fix namespace in readme 2025-09-30 18:29:30 -04:00
Matt Nadareski
995c19d903 Add byte array math operations from NDecrypt; fix issues and add tests 2025-09-30 18:02:05 -04:00
Matt Nadareski
f0fe9af467 Require exact versions for build 2025-09-30 11:06:54 -04:00
Matt Nadareski
d33b47d15a Revert "Start allowing larger numeric types for reads"
This reverts commit e4a0a08d13.
2025-09-25 12:24:06 -04:00
Matt Nadareski
e4a0a08d13 Start allowing larger numeric types for reads 2025-09-25 12:08:22 -04:00
Matt Nadareski
24a69166f0 Add more info about namespaces to the readme 2025-09-25 09:43:38 -04:00
52 changed files with 15383 additions and 120 deletions

View File

@@ -11,7 +11,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
@@ -27,6 +27,14 @@ jobs:
- name: Run publish script
run: ./publish-nix.sh
- name: Update rolling tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -f rolling
git push origin :refs/tags/rolling || true
git push origin rolling --force
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:

View File

@@ -39,16 +39,40 @@ Various compression implementations that are used across multiple projects. Most
| [DotNetZip](https://github.com/DinoChiesa/DotNetZip) | BZip2 and DEFLATE implementations; minor edits have been made |
| [ZLibPort](https://github.com/Nanook/zlib-C-To-CSharp-Port) | Adds zlib code for internal and external use; minor edits have been made |
### `SabreTools.IO.Encryption`
Various encryption implementations that are used across multiple projects. Most of the implementations are be ports of existing C and C++ code.
#### Supported Encryption Schemes
| Encryption Scheme | Encrypt | Decrypt | Notes |
| --- | --- | --- | --- |
| AES/CTR | Yes | Yes | Subset of functionality exposed from [The Bouncy Castle Cryptography Library For .NET](https://github.com/bcgit/bc-csharp) |
| MoPaQ | No | Yes | Used to encrypt and decrypt MoPaQ tables for processing |
### `SabreTools.IO.Extensions`
Extensions for `BinaryReader`, `byte[]`, and `Stream` to help with reading and writing various data types. Some data types are locked behind .NET version support.
This namespace also contains other various extensions that help with common functionality and safe access.
### `SabreTools.IO.Interfaces`
Common interfaces used mainly internal to the library.
| Interface | Notes |
| --- | --- |
| `IMatch<T>` | Represents a matcher for a generic type |
| `IMatchSet<T, U>` | Represents a set of `IMatch<T>` types |
### `SabreTools.IO.Logging`
Logic for a logging system, including writing to console and textfile outputs. There are 4 possible log levels for logging statements to be invoked with. There is also a stopwatch implementation included for logging statements with automatic timespan tracking.
### `SabreTools.IO.Matching`
Classes designed to make matching contents and paths easier. These classes allow for both grouped and single matching as well as post-processing of matched information.
### `SabreTools.IO.Readers` and `SabreTools.IO.Writers`
Reading and writing support for the following file types:
@@ -63,8 +87,41 @@ For a generic INI implementation, see `SabreTools.IO.IniFile`.
Custom `Stream` implementations that are required for specialized use:
- `BufferedStream`: A format that is not a true stream implementation used for buffered, single-byte reads
- `ReadOnlyBitStream`: A readonly stream implementation allowing bitwise reading
- `ReadOnlyCompositeStream`: A readonly stream implementation that wraps multiple source streams in a set order
- `ViewStream`: A readonly stream implementation representing a view into source data
### `SabreTools.IO.Transform`
File and stream implementations of common data transformations:
- Combine using either ordered concatenation or interleaving
- Split by even/odd chunks or based on block size
- Convert data either by bit-swapping, byte-swapping, word-swapping, or word/byte-swapping
### `SabreTools.Numerics`
Custom numeric types and related functionality.
#### Supported Numeric Types
| Type Name | Description |
| --- | --- |
| `BothInt8` | Both-endian `Int8` value |
| `BothUInt8` | Both-endian `UInt8` value |
| `BothInt16` | Both-endian `Int16` value |
| `BothUInt16` | Both-endian `UInt16` value |
| `BothInt32` | Both-endian `Int32` value |
| `BothUInt32` | Both-endian `UInt32` value |
| `BothInt64` | Both-endian `Int64` value |
| `BothUInt64` | Both-endian `UInt64` value |
**Both-endian** or **bi-endian** numbers are represented by a little-endian value followed by a big-endian value, where both values are the same number.
### `SabreTools.Text.Compare`
Classes focused on string comparison by natural sorting. For example, "5" would be sorted before "100".
## Releases

View File

@@ -1,6 +1,6 @@
using System;
using System.Linq;
using SabreTools.IO.Compare;
using SabreTools.Text.Compare;
using Xunit;
namespace SabreTools.IO.Test.Compare

View File

@@ -1,4 +1,4 @@
using SabreTools.IO.Compare;
using SabreTools.Text.Compare;
using Xunit;
namespace SabreTools.IO.Test.Compare

View File

@@ -1,6 +1,6 @@
using System;
using System.Linq;
using SabreTools.IO.Compare;
using SabreTools.Text.Compare;
using Xunit;
namespace SabreTools.IO.Test.Compare

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteByteBothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(2).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadByteBothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteBytesTest()
{
@@ -68,6 +80,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteSByteBothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(2).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadSByteBothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteCharTest()
{
@@ -109,6 +133,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt16BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(4).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadInt16BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt16Test()
{
@@ -130,6 +166,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt16BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(4).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadUInt16BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteHalfTest()
{
@@ -214,6 +262,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt32BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(8).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadInt32BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt32Test()
{
@@ -235,6 +295,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt32BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(8).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadUInt32BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteSingleTest()
{
@@ -319,6 +391,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt64BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(16).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadInt64BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt64Test()
{
@@ -340,6 +424,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt64BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
var bw = new BinaryWriter(stream);
byte[] expected = _bytes.Take(16).ToArray();
int offset = 0;
bw.WriteBothEndian(_bytes.ReadUInt64BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteDoubleTest()
{

View File

@@ -424,6 +424,86 @@ namespace SabreTools.IO.Test.Extensions
#endregion
#region Add
[Theory]
[InlineData(new byte[0], 0, new byte[0])]
[InlineData(new byte[0], 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })]
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })]
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA4 })]
public void Add_NumericInput(byte[] self, uint add, byte[] expected)
{
byte[] actual = self.Add(add);
Assert.Equal(expected.Length, actual.Length);
if (actual.Length > 0)
Assert.True(actual.EqualsExactly(expected));
}
[Theory]
[InlineData(new byte[0], new byte[0], new byte[0])]
[InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x09, 0xA4 })]
[InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })]
public void Add_ArrayInput(byte[] self, byte[] add, byte[] expected)
{
byte[] actual = self.Add(add);
Assert.Equal(expected.Length, actual.Length);
if (actual.Length > 0)
Assert.True(actual.EqualsExactly(expected));
}
#endregion
#region RotateLeft
[Theory]
[InlineData(new byte[0], 0, new byte[0])]
[InlineData(new byte[] { 0x01 }, 0, new byte[] { 0x01 })]
[InlineData(new byte[] { 0x01 }, 1, new byte[] { 0x02 })]
[InlineData(new byte[] { 0x80 }, 1, new byte[] { 0x01 })]
[InlineData(new byte[] { 0x00, 0x01 }, 0, new byte[] { 0x00, 0x01 })]
[InlineData(new byte[] { 0x00, 0x01 }, 1, new byte[] { 0x00, 0x02 })]
[InlineData(new byte[] { 0x00, 0x80 }, 1, new byte[] { 0x01, 0x00 })]
[InlineData(new byte[] { 0x80, 0x00 }, 1, new byte[] { 0x00, 0x01 })]
public void RotateLeftTest(byte[] self, int numBits, byte[] expected)
{
byte[] actual = self.RotateLeft(numBits);
Assert.Equal(expected.Length, actual.Length);
if (actual.Length > 0)
Assert.True(actual.EqualsExactly(expected));
}
#endregion
#region Xor
[Theory]
[InlineData(new byte[0], new byte[0], new byte[0])]
[InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 })]
[InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })]
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })]
public void XorTest(byte[] self, byte[] add, byte[] expected)
{
byte[] actual = self.Xor(add);
Assert.Equal(expected.Length, actual.Length);
if (actual.Length > 0)
Assert.True(actual.EqualsExactly(expected));
}
#endregion
#region ToHexString
[Fact]

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteByteBothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(2).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadByteBothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteBytesTest()
{
@@ -71,6 +83,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteSByteBothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(2).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadSByteBothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteCharTest()
{
@@ -115,6 +139,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteInt16BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(4).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadInt16BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt16Test()
{
@@ -137,6 +173,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt16BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(4).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt16BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteHalfTest()
{
@@ -225,6 +273,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteInt32BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(8).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadInt32BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt32Test()
{
@@ -247,6 +307,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt32BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(8).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt32BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteSingleTest()
{
@@ -335,6 +407,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteInt64BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(16).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadInt64BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt64Test()
{
@@ -357,6 +441,18 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteUInt64BothEndianTest()
{
byte[] buffer = new byte[16];
int offset = 0;
byte[] expected = _bytes.Take(16).ToArray();
int readOffset = 0;
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt64BothEndian(ref readOffset));
ValidateBytes(expected, buffer);
}
[Fact]
public void WriteDoubleTest()
{

View File

@@ -313,6 +313,52 @@ namespace SabreTools.IO.Test.Extensions
Assert.Equal(13, actual);
}
[Theory]
[InlineData(SeekOrigin.Begin)]
[InlineData(SeekOrigin.Current)]
[InlineData(SeekOrigin.End)]
public void SeekIfPossible_NonSeekable_OriginTest(SeekOrigin origin)
{
var stream = new NonSeekableStream();
long actual = stream.SeekIfPossible(0, origin);
Assert.Equal(8, actual);
}
[Theory]
[InlineData(SeekOrigin.Begin)]
[InlineData(SeekOrigin.Current)]
[InlineData(SeekOrigin.End)]
public void SeekIfPossible_NonPositionable_OriginTest(SeekOrigin origin)
{
var stream = new NonPositionableStream();
long actual = stream.SeekIfPossible(0, origin);
Assert.Equal(-1, actual);
}
[Theory]
[InlineData(SeekOrigin.Begin)]
[InlineData(SeekOrigin.Current)]
[InlineData(SeekOrigin.End)]
public void SeekIfPossible_HiddenNonSeekable_OriginTest(SeekOrigin origin)
{
var stream = new HiddenNonSeekableStream();
long actual = stream.SeekIfPossible(0, origin);
Assert.Equal(-1, actual);
}
[Theory]
[InlineData(SeekOrigin.Begin, 5, 5)]
[InlineData(SeekOrigin.Current, 5, 7)]
[InlineData(SeekOrigin.End, -5, 11)]
public void SeekIfPossible_Seekable_OriginTest(SeekOrigin origin, long offset, long expected)
{
var stream = new MemoryStream(new byte[16], 0, 16, false, true);
stream.Position = 2;
long actual = stream.SeekIfPossible(offset, origin);
Assert.Equal(expected, actual);
}
#endregion
#region SegmentValid

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteByteBothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(2).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadByteBothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteBytesTest()
{
@@ -67,6 +78,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteSByteBothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(2).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadSByteBothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteCharTest()
{
@@ -106,6 +128,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt16BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(4).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadInt16BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt16Test()
{
@@ -126,6 +159,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt16BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(4).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadUInt16BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteHalfTest()
{
@@ -206,6 +250,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt32BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(8).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadInt32BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt32Test()
{
@@ -226,6 +281,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt32BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(8).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadUInt32BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteSingleTest()
{
@@ -306,6 +372,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteInt64BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(16).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadInt64BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt64Test()
{
@@ -326,6 +403,17 @@ namespace SabreTools.IO.Test.Extensions
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteUInt64BothEndianTest()
{
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
byte[] expected = _bytes.Take(16).ToArray();
int offset = 0;
stream.WriteBothEndian(_bytes.ReadUInt64BothEndian(ref offset));
ValidateBytes(expected, stream.GetBuffer());
}
[Fact]
public void WriteDoubleTest()
{

View File

@@ -0,0 +1,249 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothInt16Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(short le, short be, bool expected)
{
var val = new BothInt16(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
short expected = 1;
var val = new BothInt16(expected, expected);
short to = (short)val;
Assert.Equal(expected, to);
BothInt16 back = (BothInt16)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(short le, int expected)
{
short compare = 1;
var val = new BothInt16(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((short)1).GetTypeCode();
var val = new BothInt16(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothInt16(1, 1);
bool expectedBool = Convert.ToBoolean((short)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((short)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((short)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((short)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((short)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((short)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((short)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((short)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((short)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((short)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((short)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((short)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((short)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((short)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((short)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(short le, short be, bool expected)
{
var val = new BothInt16(le, be);
var equalTo = new BothInt16(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(short le, short be, bool expected)
{
var val = new BothInt16(le, be);
short equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothInt16(2, 2);
short expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt16(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt16(2, 2);
expected = 2;
BothInt16 actual = +valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = -2;
actual = -valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothInt16(3, 3);
var valB = new BothInt16(2, 2);
short expected = 6;
BothInt16 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothInt16(2, 2);
short expected = ~2;
BothInt16 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothInt16(2, 2);
var valB = new BothInt16(1, 1);
short expected = 2 << 1;
BothInt16 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothInt16(3, 3);
var valB = new BothInt16(2, 2);
short expected = 3 & 2;
BothInt16 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,249 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothInt32Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(int le, int be, bool expected)
{
var val = new BothInt32(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
int expected = 1;
var val = new BothInt32(expected, expected);
int to = (int)val;
Assert.Equal(expected, to);
BothInt32 back = (BothInt32)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(int le, int expected)
{
int compare = 1;
var val = new BothInt32(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((int)1).GetTypeCode();
var val = new BothInt32(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothInt32(1, 1);
bool expectedBool = Convert.ToBoolean((int)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((int)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((int)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((int)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((int)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((int)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((int)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((int)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((int)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((int)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((int)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((int)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((int)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((int)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((int)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(int le, int be, bool expected)
{
var val = new BothInt32(le, be);
var equalTo = new BothInt32(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(int le, int be, bool expected)
{
var val = new BothInt32(le, be);
int equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothInt32(2, 2);
int expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt32(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt32(2, 2);
expected = 2;
BothInt32 actual = +valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = -2;
actual = -valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothInt32(3, 3);
var valB = new BothInt32(2, 2);
int expected = 6;
BothInt32 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothInt32(2, 2);
int expected = ~2;
BothInt32 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothInt32(2, 2);
var valB = new BothInt32(1, 1);
int expected = 2 << 1;
BothInt32 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothInt32(3, 3);
var valB = new BothInt32(2, 2);
int expected = 3 & 2;
BothInt32 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,249 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothInt64Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(long le, long be, bool expected)
{
var val = new BothInt64(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
long expected = 1;
var val = new BothInt64(expected, expected);
long to = (long)val;
Assert.Equal(expected, to);
BothInt64 back = (BothInt64)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(long le, int expected)
{
long compare = 1;
var val = new BothInt64(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((long)1).GetTypeCode();
var val = new BothInt64(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothInt64(1, 1);
bool expectedBool = Convert.ToBoolean((long)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((long)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((long)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((long)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((long)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((long)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((long)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((long)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((long)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((long)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((long)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((long)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((long)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((long)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((long)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(long le, long be, bool expected)
{
var val = new BothInt64(le, be);
var equalTo = new BothInt64(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(long le, long be, bool expected)
{
var val = new BothInt64(le, be);
long equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothInt64(2, 2);
long expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt64(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt64(2, 2);
expected = 2;
BothInt64 actual = +valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = -2;
actual = -valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothInt64(3, 3);
var valB = new BothInt64(2, 2);
long expected = 6;
BothInt64 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothInt64(2, 2);
long expected = ~2;
BothInt64 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothInt64(2, 2);
var valB = new BothInt32(1, 1);
long expected = 2 << 1;
BothInt64 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothInt64(3, 3);
var valB = new BothInt64(2, 2);
long expected = 3 & 2;
BothInt64 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,249 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothInt8Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(sbyte le, sbyte be, bool expected)
{
var val = new BothInt8(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
sbyte expected = 1;
var val = new BothInt8(expected, expected);
sbyte to = (sbyte)val;
Assert.Equal(expected, to);
BothInt8 back = (BothInt8)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(sbyte le, int expected)
{
sbyte compare = 1;
var val = new BothInt8(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((sbyte)1).GetTypeCode();
var val = new BothInt8(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothInt8(1, 1);
bool expectedBool = Convert.ToBoolean((sbyte)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((sbyte)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((sbyte)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((sbyte)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((sbyte)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((sbyte)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((sbyte)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((sbyte)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((sbyte)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((sbyte)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((sbyte)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((sbyte)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((sbyte)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((sbyte)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((sbyte)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(sbyte le, sbyte be, bool expected)
{
var val = new BothInt8(le, be);
var equalTo = new BothInt8(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(sbyte le, sbyte be, bool expected)
{
var val = new BothInt8(le, be);
sbyte equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothInt8(2, 2);
sbyte expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt8(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothInt8(2, 2);
expected = 2;
BothInt8 actual = +valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = -2;
actual = -valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothInt8(3, 3);
var valB = new BothInt8(2, 2);
sbyte expected = 6;
BothInt8 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothInt8(2, 2);
sbyte expected = ~2;
BothInt8 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothInt8(2, 2);
var valB = new BothInt8(1, 1);
sbyte expected = 2 << 1;
BothInt8 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothInt8(3, 3);
var valB = new BothInt8(2, 2);
sbyte expected = 3 & 2;
BothInt8 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,238 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothUInt16Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(ushort le, ushort be, bool expected)
{
var val = new BothUInt16(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
ushort expected = 1;
var val = new BothUInt16(expected, expected);
ushort to = (ushort)val;
Assert.Equal(expected, to);
BothUInt16 back = (BothUInt16)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(ushort le, int expected)
{
ushort compare = 1;
var val = new BothUInt16(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((ushort)1).GetTypeCode();
var val = new BothUInt16(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothUInt16(1, 1);
bool expectedBool = Convert.ToBoolean((ushort)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((ushort)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((ushort)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((ushort)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((ushort)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((ushort)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((ushort)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((ushort)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((ushort)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((ushort)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((ushort)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((ushort)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((ushort)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((ushort)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((ushort)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(ushort le, ushort be, bool expected)
{
var val = new BothUInt16(le, be);
var equalTo = new BothUInt16(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(ushort le, ushort be, bool expected)
{
var val = new BothUInt16(le, be);
ushort equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothUInt16(2, 2);
ushort expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothUInt16(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothUInt16(3, 3);
var valB = new BothUInt16(2, 2);
ushort expected = 6;
BothUInt16 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothUInt16(2, 2);
ushort expected = 65533;
BothUInt16 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothUInt16(2, 2);
var valB = new BothUInt16(1, 1);
ushort expected = 2 << 1;
BothUInt16 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothUInt16(3, 3);
var valB = new BothUInt16(2, 2);
ushort expected = 3 & 2;
BothUInt16 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,238 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothUInt32Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(uint le, uint be, bool expected)
{
var val = new BothUInt32(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
uint expected = 1;
var val = new BothUInt32(expected, expected);
uint to = (uint)val;
Assert.Equal(expected, to);
BothUInt32 back = (BothUInt32)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(uint le, int expected)
{
uint compare = 1;
var val = new BothUInt32(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((uint)1).GetTypeCode();
var val = new BothUInt32(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothUInt32(1, 1);
bool expectedBool = Convert.ToBoolean((uint)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((uint)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((uint)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((uint)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((uint)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((uint)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((uint)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((uint)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((uint)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((uint)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((uint)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((uint)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((uint)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((uint)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((uint)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(uint le, uint be, bool expected)
{
var val = new BothUInt32(le, be);
var equalTo = new BothUInt32(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(uint le, uint be, bool expected)
{
var val = new BothUInt32(le, be);
uint equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothUInt32(2, 2);
uint expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothUInt32(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothUInt32(3, 3);
var valB = new BothUInt32(2, 2);
uint expected = 6;
BothUInt32 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothUInt32(2, 2);
uint expected = ~((uint)2);
BothUInt32 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothUInt32(2, 2);
var valB = new BothInt32(1, 1);
uint expected = 2 << 1;
BothUInt32 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothUInt32(3, 3);
var valB = new BothUInt32(2, 2);
uint expected = 3 & 2;
BothUInt32 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,238 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothUInt64Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(ulong le, ulong be, bool expected)
{
var val = new BothUInt64(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
ulong expected = 1;
var val = new BothUInt64(expected, expected);
ulong to = (ulong)val;
Assert.Equal(expected, to);
BothUInt64 back = (BothUInt64)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(ulong le, int expected)
{
ulong compare = 1;
var val = new BothUInt64(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((ulong)1).GetTypeCode();
var val = new BothUInt64(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothUInt64(1, 1);
bool expectedBool = Convert.ToBoolean((ulong)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((ulong)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((ulong)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((ulong)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((ulong)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((ulong)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((ulong)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((ulong)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((ulong)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((ulong)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((ulong)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((ulong)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((ulong)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((ulong)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((ulong)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(ulong le, ulong be, bool expected)
{
var val = new BothUInt64(le, be);
var equalTo = new BothUInt64(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(ulong le, ulong be, bool expected)
{
var val = new BothUInt64(le, be);
ulong equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothUInt64(2, 2);
ulong expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothUInt64(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothUInt64(3, 3);
var valB = new BothUInt64(2, 2);
ulong expected = 6;
BothUInt64 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothUInt64(2, 2);
ulong expected = ~((ulong)2);
BothUInt64 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothUInt64(2, 2);
var valB = new BothInt32(1, 1);
ulong expected = 2 << 1;
BothUInt64 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothUInt64(3, 3);
var valB = new BothUInt64(2, 2);
ulong expected = 3 & 2;
BothUInt64 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -0,0 +1,238 @@
using System;
using SabreTools.Numerics;
using Xunit;
namespace SabreTools.IO.Test.Numerics
{
public class BothUInt8Tests
{
[Theory]
[InlineData(0, 0, true)]
[InlineData(0, 1, false)]
public void IsValidTest(byte le, byte be, bool expected)
{
var val = new BothUInt8(le, be);
Assert.Equal(le, val.LittleEndian);
Assert.Equal(be, val.BigEndian);
Assert.Equal(expected, val.IsValid);
}
[Fact]
public void ImplicitConversionTest()
{
byte expected = 1;
var val = new BothUInt8(expected, expected);
byte to = (byte)val;
Assert.Equal(expected, to);
BothUInt8 back = (BothUInt8)to;
Assert.Equal(expected, back.LittleEndian);
Assert.Equal(expected, back.BigEndian);
}
[Theory]
[InlineData(0, -1)]
[InlineData(1, 0)]
[InlineData(2, 1)]
public void CompareToTest(byte le, int expected)
{
byte compare = 1;
var val = new BothUInt8(le, le);
int actual = val.CompareTo(compare);
Assert.Equal(expected, actual);
}
[Fact]
public void GetTypeCodeTest()
{
TypeCode expected = ((byte)1).GetTypeCode();
var val = new BothUInt8(1, 1);
Assert.Equal(expected, val.GetTypeCode());
}
[Fact]
public void ToTypesTest()
{
var val = new BothUInt8(1, 1);
bool expectedBool = Convert.ToBoolean((byte)1);
Assert.Equal(expectedBool, val.ToBoolean(null));
char expectedChar = Convert.ToChar((byte)1);
Assert.Equal(expectedChar, val.ToChar(null));
sbyte expectedSByte = Convert.ToSByte((byte)1);
Assert.Equal(expectedSByte, val.ToSByte(null));
byte expectedByte = Convert.ToByte((byte)1);
Assert.Equal(expectedByte, val.ToByte(null));
short expectedInt16 = Convert.ToInt16((byte)1);
Assert.Equal(expectedInt16, val.ToInt16(null));
ushort expectedUInt16 = Convert.ToUInt16((byte)1);
Assert.Equal(expectedUInt16, val.ToUInt16(null));
int expectedInt32 = Convert.ToInt32((byte)1);
Assert.Equal(expectedInt32, val.ToInt32(null));
uint expectedUInt32 = Convert.ToUInt32((byte)1);
Assert.Equal(expectedUInt32, val.ToUInt32(null));
long expectedInt64 = Convert.ToInt64((byte)1);
Assert.Equal(expectedInt64, val.ToInt64(null));
ulong expectedUInt64 = Convert.ToUInt64((byte)1);
Assert.Equal(expectedUInt64, val.ToUInt64(null));
float expectedSingle = Convert.ToSingle((byte)1);
Assert.Equal(expectedSingle, val.ToSingle(null));
double expectedDouble = Convert.ToDouble((byte)1);
Assert.Equal(expectedDouble, val.ToDouble(null));
decimal expectedDecimal = Convert.ToDecimal((byte)1);
Assert.Equal(expectedDecimal, val.ToDecimal(null));
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
string expectedString = Convert.ToString((byte)1);
Assert.Equal(expectedString, val.ToString(null));
ulong expectedObject = Convert.ToUInt64((byte)1);
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(0, 1, false)]
[InlineData(1, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BothEndian(byte le, byte be, bool expected)
{
var val = new BothUInt8(le, be);
var equalTo = new BothUInt8(1, 1);
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(0, 0, false)]
[InlineData(1, 1, true)]
public void Equals_BaseType(byte le, byte be, bool expected)
{
var val = new BothUInt8(le, be);
byte equalTo = 1;
bool actual = val.Equals(equalTo);
Assert.Equal(expected, actual);
}
[Fact]
public void ArithmeticUnaryOperatorsTest()
{
var valA = new BothUInt8(2, 2);
byte expected = 3;
valA++;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
valA = new BothUInt8(2, 2);
expected = 1;
valA--;
Assert.Equal(expected, valA.LittleEndian);
Assert.Equal(expected, valA.BigEndian);
}
[Fact]
public void ArithmeticBinaryOperatorsTest()
{
var valA = new BothUInt8(3, 3);
var valB = new BothUInt8(2, 2);
byte expected = 6;
BothUInt8 actual = valA * valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA / valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA % valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 5;
actual = valA + valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 1;
actual = valA - valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseUnaryOperatorsTest()
{
var valA = new BothUInt8(2, 2);
byte expected = 253;
BothUInt8 actual = ~valA;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void ShiftBinaryOperatorsTest()
{
var valA = new BothUInt8(2, 2);
var valB = new BothUInt8(1, 1);
byte expected = 2 << 1;
BothUInt8 actual = valA << valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >> 1;
actual = valA >> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 2 >>> 1;
actual = valA >>> valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
[Fact]
public void BitwiseBinaryOperatorsTest()
{
var valA = new BothUInt8(3, 3);
var valB = new BothUInt8(2, 2);
byte expected = 3 & 2;
BothUInt8 actual = valA & valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 | 2;
actual = valA | valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
expected = 3 ^ 2;
actual = valA ^ valB;
Assert.Equal(expected, actual.LittleEndian);
Assert.Equal(expected, actual.BigEndian);
}
}
}

View File

@@ -26,7 +26,7 @@
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.IO.Transform;
using Xunit;
namespace SabreTools.IO.Test.Transform
{
public class CombineTests
{
#region Concatenate
[Fact]
public void Concatenate_EmptyList_False()
{
List<string> paths = [];
string output = string.Empty;
bool actual = Combine.Concatenate(paths, output);
Assert.False(actual);
}
[Fact]
public void Concatenate_InvalidOutput_False()
{
List<string> paths = ["a"];
string output = string.Empty;
bool actual = Combine.Concatenate(paths, output);
Assert.False(actual);
}
[Fact]
public void Concatenate_FilledList_True()
{
List<string> paths = [
Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt"),
Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin"),
];
string output = Guid.NewGuid().ToString();
bool actual = Combine.Concatenate(paths, output);
Assert.True(actual);
string text = File.ReadAllText(output);
Assert.Equal("This doesn't match anythingThis is just a file that has a known set of hashes to make sure that everything with hashing is still working as anticipated.", text);
File.Delete(output);
}
#endregion
#region Interleave
[Fact]
public void Interleave_EvenNotExists_False()
{
string even = "NOT A REAL PATH";
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string output = Guid.NewGuid().ToString();
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
Assert.False(actual);
}
[Fact]
public void Interleave_OddNotExists_False()
{
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string odd = "NOT A REAL PATH";
string output = Guid.NewGuid().ToString();
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
Assert.False(actual);
}
[Fact]
public void Interleave_InvalidType_False()
{
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string output = Guid.NewGuid().ToString();
bool actual = Combine.Interleave(even, odd, output, (BlockSize)int.MaxValue);
Assert.False(actual);
}
[Theory]
[InlineData(BlockSize.Byte, "TThhiiss ddooeessnn''tt mmaattcchh aannyytthhiinngg")]
[InlineData(BlockSize.Word, "ThThisis d doeoesnsn't't m matatchch a anynyththiningg")]
[InlineData(BlockSize.Dword, "ThisThis doe doesn'tsn't mat match ach anythnythinging")]
[InlineData(BlockSize.Qword, "This doeThis doesn't matsn't match anythch anythinging")]
public void Interleave_SameLength_True(BlockSize type, string expected)
{
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string output = Guid.NewGuid().ToString();
bool actual = Combine.Interleave(even, odd, output, type);
Assert.True(actual);
string text = File.ReadAllText(output);
Assert.Equal(expected, text);
File.Delete(output);
}
[Fact]
public void Interleave_DifferentLength_True()
{
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin");
string output = Guid.NewGuid().ToString();
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
Assert.True(actual);
string text = File.ReadAllText(output);
Assert.Equal("TThhiiss diose sjnu'stt maa tfcihl ea ntyhtahti nhgas a known set of hashes to make sure that everything with hashing is still working as anticipated.", text);
File.Delete(output);
}
#endregion
}
}

View File

@@ -0,0 +1,124 @@
using System;
using System.IO;
using SabreTools.IO.Transform;
using Xunit;
namespace SabreTools.IO.Test.Transform
{
public class SplitTests
{
#region BlockSplit
[Fact]
public void BlockSplit_EmptyFileName_False()
{
string input = string.Empty;
string outputDir = string.Empty;
bool actual = Split.BlockSplit(input, outputDir, BlockSize.Byte);
Assert.False(actual);
}
[Fact]
public void BlockSplit_InvalidFile_False()
{
string input = "INVALID";
string outputDir = string.Empty;
bool actual = Split.BlockSplit(input, outputDir, BlockSize.Byte);
Assert.False(actual);
}
[Fact]
public void BlockSplit_InvalidType_False()
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string outputDir = Guid.NewGuid().ToString();
bool actual = Split.BlockSplit(input, outputDir, (BlockSize)int.MaxValue);
Assert.False(actual);
}
[Theory]
[InlineData(BlockSize.Byte, "Ti os' ac ntig", "hsdentmthayhn")]
[InlineData(BlockSize.Word, "Th dsn mchnyin", "isoe'tat athg")]
[InlineData(BlockSize.Dword, "Thissn'tch aing", " doe matnyth")]
[InlineData(BlockSize.Qword, "This doech anyth", "sn't mating")]
public void BlockSplit_ValidFile_True(BlockSize type, string expectedEven, string expectedOdd)
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string outputDir = Guid.NewGuid().ToString();
bool actual = Split.BlockSplit(input, outputDir, type);
Assert.True(actual);
string baseFilename = Path.GetFileName(input);
string text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.even"));
Assert.Equal(expectedEven, text);
text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.odd"));
Assert.Equal(expectedOdd, text);
File.Delete($"{baseFilename}.even");
File.Delete($"{baseFilename}.odd");
}
#endregion
#region SizeSplit
[Fact]
public void SizeSplit_EmptyFileName_False()
{
string input = string.Empty;
string outputDir = string.Empty;
int size = 1;
bool actual = Split.SizeSplit(input, outputDir, size);
Assert.False(actual);
}
[Fact]
public void SizeSplit_InvalidFile_False()
{
string input = "INVALID";
string outputDir = string.Empty;
int size = 1;
bool actual = Split.SizeSplit(input, outputDir, size);
Assert.False(actual);
}
[Fact]
public void SizeSplit_InvalidSize_False()
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string outputDir = string.Empty;
int size = 0;
bool actual = Split.SizeSplit(input, outputDir, size);
Assert.False(actual);
}
[Fact]
public void SizeSplit_Valid_True()
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string outputDir = Guid.NewGuid().ToString();
int size = 16;
bool actual = Split.SizeSplit(input, outputDir, size);
Assert.True(actual);
Assert.Equal(2, Directory.GetFiles(outputDir).Length);
string baseFilename = Path.GetFileName(input);
string text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.0"));
Assert.Equal("This doesn't mat", text);
text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.1"));
Assert.Equal("ch anything", text);
File.Delete($"{baseFilename}.0");
File.Delete($"{baseFilename}.1");
}
#endregion
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.IO;
using SabreTools.IO.Extensions;
using SabreTools.IO.Transform;
using Xunit;
namespace SabreTools.IO.Test.Transform
{
public class SwapTests
{
#region Process
[Fact]
public void Process_EmptyFileName_False()
{
string input = string.Empty;
string output = string.Empty;
bool actual = Swap.Process(input, output, Operation.Byteswap);
Assert.False(actual);
}
[Fact]
public void Process_InvalidFile_False()
{
string input = "INVALID";
string output = string.Empty;
bool actual = Swap.Process(input, output, Operation.Byteswap);
Assert.False(actual);
}
[Fact]
public void Process_InvalidType_False()
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string output = Guid.NewGuid().ToString();
bool actual = Swap.Process(input, output, (Operation)int.MaxValue);
Assert.False(actual);
}
[Fact]
public void Process_Valid_True()
{
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
string output = Guid.NewGuid().ToString();
// Bitswap
bool actual = Swap.Process(input, output, Operation.Bitswap);
Assert.True(actual);
byte[] actualBytes = File.ReadAllBytes(output);
Assert.True(new byte[] { 0x2A, 0x16, 0x96, 0xCE, 0x04, 0x26, 0xF6, 0xA6, 0xCE, 0x76, 0xE4, 0x2E, 0x04, 0xB6, 0x86, 0x2E, 0xC6, 0x16, 0x04, 0x86, 0x76, 0x9E, 0x2E, 0x16, 0x96, 0x76, 0xE6 }.EqualsExactly(actualBytes));
// Byteswap
actual = Swap.Process(input, output, Operation.Byteswap);
Assert.True(actual);
actualBytes = File.ReadAllBytes(output);
Assert.True(new byte[] { 0x68, 0x54, 0x73, 0x69, 0x64, 0x20, 0x65, 0x6F, 0x6E, 0x73, 0x74, 0x27, 0x6D, 0x20, 0x74, 0x61, 0x68, 0x63, 0x61, 0x20, 0x79, 0x6E, 0x68, 0x74, 0x6E, 0x69, 0x67 }.EqualsExactly(actualBytes));
// Wordswap
actual = Swap.Process(input, output, Operation.Wordswap);
Assert.True(actual);
actualBytes = File.ReadAllBytes(output);
Assert.True(new byte[] { 0x69, 0x73, 0x54, 0x68, 0x6F, 0x65, 0x20, 0x64, 0x27, 0x74, 0x73, 0x6E, 0x61, 0x74, 0x20, 0x6D, 0x20, 0x61, 0x63, 0x68, 0x74, 0x68, 0x6E, 0x79, 0x69, 0x6E, 0x67 }.EqualsExactly(actualBytes));
// WordByteswap
actual = Swap.Process(input, output, Operation.WordByteswap);
Assert.True(actual);
actualBytes = File.ReadAllBytes(output);
Assert.True(new byte[] { 0x73, 0x69, 0x68, 0x54, 0x65, 0x6F, 0x64, 0x20, 0x74, 0x27, 0x6E, 0x73, 0x74, 0x61, 0x6D, 0x20, 0x61, 0x20, 0x68, 0x63, 0x68, 0x74, 0x79, 0x6E, 0x69, 0x6E, 0x67 }.EqualsExactly(actualBytes));
File.Delete(output);
}
#endregion
}
}

View File

@@ -13,7 +13,7 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SabreTools.IO.Compare
namespace SabreTools.Text.Compare
{
public class NaturalComparer : Comparer<string>, IDisposable
{

View File

@@ -1,4 +1,4 @@
namespace SabreTools.IO.Compare
namespace SabreTools.Text.Compare
{
internal static class NaturalComparerUtil
{

View File

@@ -13,7 +13,7 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SabreTools.IO.Compare
namespace SabreTools.Text.Compare
{
public class NaturalReversedComparer : Comparer<string>, IDisposable
{

View File

@@ -0,0 +1,125 @@
using System;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using SabreTools.IO.Extensions;
namespace SabreTools.IO.Encryption
{
public static class AESCTR
{
/// <summary>
/// Create AES decryption cipher and intialize
/// </summary>
/// <param name="key">Byte array representation of 128-bit encryption key</param>
/// <param name="iv">AES initial value for counter</param>
/// <returns>Initialized AES cipher</returns>
public static IBufferedCipher CreateDecryptionCipher(byte[] key, byte[] iv)
{
if (key.Length != 16)
throw new ArgumentOutOfRangeException(nameof(key));
var keyParam = new KeyParameter(key);
var cipher = CipherUtilities.GetCipher("AES/CTR");
cipher.Init(forEncryption: false, new ParametersWithIV(keyParam, iv));
return cipher;
}
/// <summary>
/// Create AES encryption cipher and intialize
/// </summary>
/// <param name="key">Byte array representation of 128-bit encryption key</param>
/// <param name="iv">AES initial value for counter</param>
/// <returns>Initialized AES cipher</returns>
public static IBufferedCipher CreateEncryptionCipher(byte[] key, byte[] iv)
{
if (key.Length != 16)
throw new ArgumentOutOfRangeException(nameof(key));
var keyParam = new KeyParameter(key);
var cipher = CipherUtilities.GetCipher("AES/CTR");
cipher.Init(forEncryption: true, new ParametersWithIV(keyParam, iv));
return cipher;
}
/// <summary>
/// Perform an AES operation using an existing cipher
/// </summary>
public static void PerformOperation(uint size,
IBufferedCipher cipher,
Stream input,
Stream output,
Action<string>? progress = null)
{
// Get MiB-aligned block count and extra byte count
int blockCount = (int)((long)size / (1024 * 1024));
int extraBytes = (int)((long)size % (1024 * 1024));
// Process MiB-aligned data
if (blockCount > 0)
{
for (int i = 0; i < blockCount; i++)
{
byte[] readBytes = input.ReadBytes(1024 * 1024);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
output.Write(processedBytes);
output.Flush();
progress?.Invoke($"{i} / {blockCount + 1} MB");
}
}
// Process additional data
if (extraBytes > 0)
{
byte[] readBytes = input.ReadBytes(extraBytes);
byte[] finalBytes = cipher.DoFinal(readBytes);
output.Write(finalBytes);
output.Flush();
}
progress?.Invoke($"{blockCount + 1} / {blockCount + 1} MB... Done!\r\n");
}
/// <summary>
/// Perform an AES operation using two existing ciphers
/// </summary>
public static void PerformOperation(uint size,
IBufferedCipher firstCipher,
IBufferedCipher secondCipher,
Stream input,
Stream output,
Action<string>? progress = null)
{
// Get MiB-aligned block count and extra byte count
int blockCount = (int)((long)size / (1024 * 1024));
int extraBytes = (int)((long)size % (1024 * 1024));
// Process MiB-aligned data
if (blockCount > 0)
{
for (int i = 0; i < blockCount; i++)
{
byte[] readBytes = input.ReadBytes(1024 * 1024);
byte[] firstProcessedBytes = firstCipher.ProcessBytes(readBytes);
byte[] secondProcessedBytes = secondCipher.ProcessBytes(firstProcessedBytes);
output.Write(secondProcessedBytes);
output.Flush();
progress?.Invoke($"{i} / {blockCount + 1} MB");
}
}
// Process additional data
if (extraBytes > 0)
{
byte[] readBytes = input.ReadBytes(extraBytes);
byte[] firstFinalBytes = firstCipher.DoFinal(readBytes);
byte[] secondFinalBytes = secondCipher.DoFinal(firstFinalBytes);
output.Write(secondFinalBytes);
output.Flush();
}
progress?.Invoke($"{blockCount + 1} / {blockCount + 1} MB... Done!\r\n");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using SabreTools.Numerics;
namespace SabreTools.IO.Extensions
{
@@ -15,6 +16,24 @@ namespace SabreTools.IO.Extensions
/// TODO: Handle proper negative values for Int24 and Int48
public static class BinaryWriterExtensions
{
/// <inheritdoc cref="BinaryWriter.Write(byte)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothUInt8 value)
{
writer.Write(value.LittleEndian);
writer.Write(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(sbyte)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothInt8 value)
{
writer.Write(value.LittleEndian);
writer.Write(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(byte[])"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, byte[] value)
@@ -39,6 +58,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(short)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothInt16 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(ushort)"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, ushort value)
@@ -48,6 +76,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(ushort)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothUInt16 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <inheritdoc cref="BinaryWriter.Write(Half)"/>
@@ -125,6 +162,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(int)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothInt32 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(uint)"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, uint value)
@@ -134,6 +180,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(uint)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothUInt32 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(float)"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, float value)
@@ -208,6 +263,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(long)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothInt64 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(ulong)"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, ulong value)
@@ -217,6 +281,15 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <inheritdoc cref="BinaryWriter.Write(ulong)"/>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this BinaryWriter writer, BothUInt64 value)
{
writer.Write(value.LittleEndian);
writer.WriteBigEndian(value.BigEndian);
return true;
}
/// <inheritdoc cref="BinaryWriter.Write(double)"/>
/// <remarks>Writes in big-endian format</remarks>
public static bool WriteBigEndian(this BinaryWriter writer, double value)
@@ -342,6 +415,14 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedAnsiString(this BinaryWriter writer, string? value)
=> writer.WriteNullTerminatedString(value, Encoding.ASCII);
#if NET5_0_OR_GREATER
/// <summary>
/// Write a null-terminated Latin1 string to the underlying stream
/// </summary>
public static bool WriteNullTerminatedLatin1String(this BinaryWriter writer, string? value)
=> writer.WriteNullTerminatedString(value, Encoding.Latin1);
#endif
/// <summary>
/// Write a null-terminated UTF-8 string to the underlying stream
/// </summary>
@@ -354,6 +435,12 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedUnicodeString(this BinaryWriter writer, string? value)
=> writer.WriteNullTerminatedString(value, Encoding.Unicode);
/// <summary>
/// Write a null-terminated UTF-16 (Unicode) string to the underlying stream
/// </summary>
public static bool WriteNullTerminatedBigEndianUnicodeString(this BinaryWriter writer, string? value)
=> writer.WriteNullTerminatedString(value, Encoding.BigEndianUnicode);
/// <summary>
/// Write a null-terminated UTF-32 string to the underlying stream
/// </summary>
@@ -379,6 +466,27 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
#if NET5_0_OR_GREATER
/// <summary>
/// Write a byte-prefixed Latin1 string to the underlying stream
/// </summary>
public static bool WritePrefixedLatin1String(this BinaryWriter writer, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.Latin1.GetBytes(value);
// Write the length as a byte
writer.Write((byte)value.Length);
// Write the buffer
return WriteFromBuffer(writer, buffer);
}
#endif
/// <summary>
/// Write a ushort-prefixed Unicode string to the underlying stream
/// </summary>
@@ -398,6 +506,25 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(writer, buffer);
}
/// <summary>
/// Write a ushort-prefixed Unicode string to the underlying stream
/// </summary>
public static bool WritePrefixedBigEndianUnicodeString(this BinaryWriter writer, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.BigEndianUnicode.GetBytes(value);
// Write the length as a ushort
writer.Write((ushort)value.Length);
// Write the buffer
return WriteFromBuffer(writer, buffer);
}
/// <summary>
/// Write a <typeparamref name="T"/> to the underlying stream
/// </summary>
@@ -437,7 +564,7 @@ namespace SabreTools.IO.Extensions
{
writer.Write((Half)value);
return true;
}
}
#endif
#if NET7_0_OR_GREATER
else if (type == typeof(Int128))

View File

@@ -237,6 +237,176 @@ namespace SabreTools.IO.Extensions
#endregion
#region Math
/// <summary>
/// Add an integer value to a number represented by a byte array
/// </summary>
/// <param name="self">Byte array to add to</param>
/// <param name="add">Amount to add</param>
/// <returns>Byte array representing the new value</returns>
/// <remarks>Assumes array values are in big-endian format</remarks>
public static byte[] Add(this byte[] self, uint add)
{
// If nothing is being added, just return
if (add == 0)
return self;
// Get the big-endian representation of the value
byte[] addBytes = BitConverter.GetBytes(add);
Array.Reverse(addBytes);
// Pad the array out to 16 bytes
byte[] paddedBytes = new byte[16];
Array.Copy(addBytes, 0, paddedBytes, 12, 4);
// If the input is empty, just return the added value
if (self.Length == 0)
return paddedBytes;
return self.Add(paddedBytes);
}
/// <summary>
/// Add two numbers represented by byte arrays
/// </summary>
/// <param name="self">Byte array to add to</param>
/// <param name="add">Amount to add</param>
/// <returns>Byte array representing the new value</returns>
/// <remarks>Assumes array values are in big-endian format</remarks>
public static byte[] Add(this byte[] self, byte[] add)
{
// If either input is empty
if (self.Length == 0 && add.Length == 0)
return [];
else if (self.Length > 0 && add.Length == 0)
return self;
else if (self.Length == 0 && add.Length > 0)
return add;
// Setup the output array
int outLength = Math.Max(self.Length, add.Length);
byte[] output = new byte[outLength];
// Loop adding with carry
uint carry = 0;
for (int i = 0; i < outLength; i++)
{
int selfIndex = self.Length - i - 1;
uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u;
int addIndex = add.Length - i - 1;
uint addValue = addIndex >= 0 ? add[addIndex] : 0u;
uint next = selfValue + addValue + carry;
carry = next >> 8;
int outputIndex = output.Length - i - 1;
output[outputIndex] = (byte)(next & 0xFF);
}
return output;
}
/// <summary>
/// Perform a rotate left on a byte array
/// </summary>
/// <param name="self">Byte array value to rotate</param>
/// <param name="numBits">Number of bits to rotate</param>
/// <returns>Rotated byte array value</returns>
/// <remarks>Assumes array values are in big-endian format</remarks>
public static byte[] RotateLeft(this byte[] self, int numBits)
{
// If either input is empty
if (self.Length == 0)
return [];
else if (numBits == 0)
return self;
byte[] output = new byte[self.Length];
Array.Copy(self, output, output.Length);
// Shift by bytes
while (numBits >= 8)
{
byte temp = output[0];
for (int i = 0; i < output.Length - 1; i++)
{
output[i] = output[i + 1];
}
output[output.Length - 1] = temp;
numBits -= 8;
}
// Shift by bits
if (numBits > 0)
{
byte bitMask = (byte)(8 - numBits), carry, wrap = 0;
for (int i = 0; i < output.Length; i++)
{
carry = (byte)((255 << bitMask & output[i]) >> bitMask);
// Make sure the first byte carries to the end
if (i == 0)
wrap = carry;
// Otherwise, move to the last byte
else
output[i - 1] |= carry;
// Shift the current bits
output[i] <<= numBits;
}
// Make sure the wrap happens
output[output.Length - 1] |= wrap;
}
return output;
}
/// <summary>
/// XOR two numbers represented by byte arrays
/// </summary>
/// <param name="self">Byte array to XOR to</param>
/// <param name="xor">Amount to XOR</param>
/// <returns>Byte array representing the new value</returns>
/// <remarks>Assumes array values are in big-endian format</remarks>
public static byte[] Xor(this byte[] self, byte[] xor)
{
// If either input is empty
if (self.Length == 0 && xor.Length == 0)
return [];
else if (self.Length > 0 && xor.Length == 0)
return self;
else if (self.Length == 0 && xor.Length > 0)
return xor;
// Setup the output array
int outLength = Math.Max(self.Length, xor.Length);
byte[] output = new byte[outLength];
// Loop XOR
for (int i = 0; i < outLength; i++)
{
int selfIndex = self.Length - i - 1;
uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u;
int xorIndex = xor.Length - i - 1;
uint xorValue = xorIndex >= 0 ? xor[xorIndex] : 0u;
uint next = selfValue ^ xorValue;
int outputIndex = output.Length - i - 1;
output[outputIndex] = (byte)(next & 0xFF);
}
return output;
}
#endregion
#region Strings
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@ using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using SabreTools.Numerics;
namespace SabreTools.IO.Extensions
{
@@ -20,6 +21,17 @@ namespace SabreTools.IO.Extensions
public static bool Write(this byte[] content, ref int offset, byte value)
=> WriteFromBuffer(content, ref offset, [value]);
/// <summary>
/// Write a UInt8 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothUInt8 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.Write(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt8[] and increment the pointer to an array
/// </summary>
@@ -42,6 +54,17 @@ namespace SabreTools.IO.Extensions
public static bool Write(this byte[] content, ref int offset, sbyte value)
=> WriteFromBuffer(content, ref offset, [(byte)value]);
/// <summary>
/// Write a Int8 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothInt8 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.Write(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a Char and increment the pointer to an array
/// </summary>
@@ -80,6 +103,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a Int16 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothInt16 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt16 and increment the pointer to an array
/// </summary>
@@ -100,6 +134,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a UInt16 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothUInt16 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <summary>
@@ -199,6 +244,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a Int32 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothInt32 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt32 and increment the pointer to an array
/// </summary>
@@ -219,6 +275,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a UInt32 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothUInt32 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a Single and increment the pointer to an array
/// </summary>
@@ -315,6 +382,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a Int64 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothInt64 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt64 and increment the pointer to an array
/// </summary>
@@ -335,6 +413,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a UInt64 and increment the pointer to an array
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this byte[] content, ref int offset, BothUInt64 value)
{
bool actual = content.Write(ref offset, value.LittleEndian);
actual &= content.WriteBigEndian(ref offset, value.BigEndian);
return actual;
}
/// <summary>
/// Write a Double and increment the pointer to an array
/// </summary>
@@ -426,7 +515,7 @@ namespace SabreTools.IO.Extensions
public static bool Write(this byte[] content, ref int offset, Int128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
@@ -440,7 +529,7 @@ namespace SabreTools.IO.Extensions
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
@@ -452,7 +541,7 @@ namespace SabreTools.IO.Extensions
public static bool Write(this byte[] content, ref int offset, UInt128 value)
{
byte[] buffer = ((BigInteger)value).ToByteArray();
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
@@ -466,7 +555,7 @@ namespace SabreTools.IO.Extensions
{
byte[] buffer = ((BigInteger)value).ToByteArray();
Array.Reverse(buffer);
byte[] padded = new byte[16];
Array.Copy(buffer, 0, padded, 16 - buffer.Length, buffer.Length);
return WriteFromBuffer(content, ref offset, padded);
@@ -494,6 +583,14 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedAnsiString(this byte[] content, ref int offset, string? value)
=> content.WriteNullTerminatedString(ref offset, value, Encoding.ASCII);
#if NET5_0_OR_GREATER
/// <summary>
/// Write a null-terminated Latin1 string to the byte array
/// </summary>
public static bool WriteNullTerminatedLatin1String(this byte[] content, ref int offset, string? value)
=> content.WriteNullTerminatedString(ref offset, value, Encoding.Latin1);
#endif
/// <summary>
/// Write a null-terminated UTF-8 string to the byte array
/// </summary>
@@ -506,6 +603,12 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedUnicodeString(this byte[] content, ref int offset, string? value)
=> content.WriteNullTerminatedString(ref offset, value, Encoding.Unicode);
/// <summary>
/// Write a null-terminated UTF-16 (Unicode) string to the byte array
/// </summary>
public static bool WriteNullTerminatedBigEndianUnicodeString(this byte[] content, ref int offset, string? value)
=> content.WriteNullTerminatedString(ref offset, value, Encoding.BigEndianUnicode);
/// <summary>
/// Write a null-terminated UTF-32 string to the byte array
/// </summary>
@@ -532,6 +635,28 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
#if NET5_0_OR_GREATER
/// <summary>
/// Write a byte-prefixed Latin1 string to the byte array
/// </summary>
public static bool WritePrefixedLatin1String(this byte[] content, ref int offset, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.Latin1.GetBytes(value);
// Write the length as a byte
if (!content.Write(ref offset, (byte)value.Length))
return false;
// Write the buffer
return WriteFromBuffer(content, ref offset, buffer);
}
#endif
/// <summary>
/// Write a ushort-prefixed Unicode string to the byte array
/// </summary>
@@ -552,6 +677,26 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a ushort-prefixed Unicode string to the byte array
/// </summary>
public static bool WritePrefixedBigEndianUnicodeString(this byte[] content, ref int offset, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.BigEndianUnicode.GetBytes(value);
// Write the length as a ushort
if (!content.Write(ref offset, (ushort)value.Length))
return false;
// Write the buffer
return WriteFromBuffer(content, ref offset, buffer);
}
/// <summary>
/// Write a <typeparamref name="T"/> to the byte array
/// </summary>

View File

@@ -100,6 +100,14 @@ namespace SabreTools.IO.Extensions
/// <param name="input">Input stream to try seeking on</param>
/// <param name="offset">Optional offset to seek to</param>
public static long SeekIfPossible(this Stream input, long offset = 0)
=> input.SeekIfPossible(offset, offset < 0 ? SeekOrigin.End : SeekOrigin.Begin);
/// <summary>
/// Seek to a specific point in the stream, if possible
/// </summary>
/// <param name="input">Input stream to try seeking on</param>
/// <param name="offset">Optional offset to seek to</param>
public static long SeekIfPossible(this Stream input, long offset, SeekOrigin origin)
{
// If the input is not seekable, just return the current position
if (!input.CanSeek)
@@ -116,10 +124,7 @@ namespace SabreTools.IO.Extensions
// Attempt to seek to the offset
try
{
if (offset < 0)
return input.Seek(offset, SeekOrigin.End);
else
return input.Seek(offset, SeekOrigin.Begin);
return input.Seek(offset, origin);
}
catch
{

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using SabreTools.Numerics;
namespace SabreTools.IO.Extensions
{
@@ -21,6 +22,17 @@ namespace SabreTools.IO.Extensions
public static bool Write(this Stream stream, byte value)
=> WriteFromBuffer(stream, [value]);
/// <summary>
/// Write a UInt8
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothUInt8 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.Write(value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt8[]
/// </summary>
@@ -43,6 +55,17 @@ namespace SabreTools.IO.Extensions
public static bool Write(this Stream stream, sbyte value)
=> WriteFromBuffer(stream, [(byte)value]);
/// <summary>
/// Write a Int8
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothInt8 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.Write(value.BigEndian);
return actual;
}
/// <summary>
/// Write a Char
/// </summary>
@@ -81,6 +104,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a Int16
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothInt16 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt16
/// </summary>
@@ -101,6 +135,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a UInt16
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothUInt16 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
// Half was introduced in net5.0 but doesn't have a BitConverter implementation until net6.0
#if NET6_0_OR_GREATER
/// <summary>
@@ -200,6 +245,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a Int32
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothInt32 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt32
/// </summary>
@@ -220,6 +276,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a UInt32
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothUInt32 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
/// <summary>
/// Write a Single
/// </summary>
@@ -316,6 +383,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a Int64
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothInt64 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
/// <summary>
/// Write a UInt64
/// </summary>
@@ -336,6 +414,17 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a UInt64
/// </summary>
/// <remarks>Writes in both-endian format</remarks>
public static bool WriteBothEndian(this Stream stream, BothUInt64 value)
{
bool actual = stream.Write(value.LittleEndian);
actual &= stream.WriteBigEndian(value.BigEndian);
return actual;
}
/// <summary>
/// Write a Double
/// </summary>
@@ -495,6 +584,14 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedAnsiString(this Stream stream, string? value)
=> stream.WriteNullTerminatedString(value, Encoding.ASCII);
#if NET5_0_OR_GREATER
/// <summary>
/// Write a null-terminated Latin1 string to the stream
/// </summary>
public static bool WriteNullTerminatedLatin1String(this Stream stream, string? value)
=> stream.WriteNullTerminatedString(value, Encoding.Latin1);
#endif
/// <summary>
/// Write a null-terminated UTF-8 string to the stream
/// </summary>
@@ -507,6 +604,12 @@ namespace SabreTools.IO.Extensions
public static bool WriteNullTerminatedUnicodeString(this Stream stream, string? value)
=> stream.WriteNullTerminatedString(value, Encoding.Unicode);
/// <summary>
/// Write a null-terminated UTF-16 (Unicode) string to the stream
/// </summary>
public static bool WriteNullTerminatedBigEndianUnicodeString(this Stream stream, string? value)
=> stream.WriteNullTerminatedString(value, Encoding.BigEndianUnicode);
/// <summary>
/// Write a null-terminated UTF-32 string to the stream
/// </summary>
@@ -533,6 +636,28 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
#if NET5_0_OR_GREATER
//// <summary>
/// Write a byte-prefixed Latin1 string to the stream
/// </summary>
public static bool WritePrefixedLatin1String(this Stream stream, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.Latin1.GetBytes(value);
// Write the length as a byte
if (!stream.Write((byte)value.Length))
return false;
// Write the buffer
return WriteFromBuffer(stream, buffer);
}
#endif
/// <summary>
/// Write a ushort-prefixed Unicode string to the stream
/// </summary>
@@ -553,6 +678,26 @@ namespace SabreTools.IO.Extensions
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a ushort-prefixed Unicode string to the stream
/// </summary>
public static bool WritePrefixedBigEndianUnicodeString(this Stream stream, string? value)
{
// If the value is null
if (value == null)
return false;
// Get the buffer
byte[] buffer = Encoding.BigEndianUnicode.GetBytes(value);
// Write the length as a ushort
if (!stream.Write((ushort)value.Length))
return false;
// Write the buffer
return WriteFromBuffer(stream, buffer);
}
/// <summary>
/// Write a <typeparamref name="T"/> to the stream
/// </summary>

View File

@@ -0,0 +1,234 @@
using System;
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian numeric value
/// </summary>
public abstract class BothEndian<T>(T le, T be) : IComparable, IConvertible, IEquatable<BothEndian<T>>, IEquatable<T>
where T : notnull, IComparable, IConvertible, IEquatable<T>
{
#region Properties
/// <summary>
/// Little-endian representation of the number
/// </summary>
/// <remarks>Value should match <see cref="BigEndian"/></remarks>
public readonly T LittleEndian = le;
/// <summary>
/// Big-endian representation of the number
/// </summary>
/// <remarks>Value should match <see cref="LittleEndian"/></remarks>
public readonly T BigEndian = be;
/// <summary>
/// Indicates if the value is valid
/// </summary>
/// <remarks>
/// Validity of a both-endian value is determined based on if both
/// endianness values match. These values should always match, based
/// on all implementations.
/// </remarks>
public bool IsValid => LittleEndian.Equals(BigEndian);
#endregion
#region Operators
/// <remarks>
/// Returns either <see cref="LittleEndian"/> or <see cref="BigEndian"/>
/// depending on the system endianness.
/// </remarks>
public static implicit operator T(BothEndian<T> val)
=> BitConverter.IsLittleEndian ? val.LittleEndian : val.BigEndian;
public static bool operator ==(BothEndian<T> a, BothEndian<T> b) => a.Equals(b);
public static bool operator !=(BothEndian<T> a, BothEndian<T> b) => !a.Equals(b);
#endregion
#region Object
#if NETCOREAPP
/// <inheritdoc/>
public override bool Equals(object? obj)
{
if (obj is BothEndian<T> be)
return Equals(be);
if (obj is T t)
return Equals(t);
return base.Equals(obj);
}
#else
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is BothEndian<T> be)
return Equals(be);
if (obj is T t)
return Equals(t);
return base.Equals(obj);
}
#endif
/// <inheritdoc/>
public override int GetHashCode() => ((T)this).GetHashCode();
#if NETCOREAPP
/// <inheritdoc/>
public override string? ToString() => ((T)this).ToString();
#else
/// <inheritdoc/>
public override string ToString() => ((T)this).ToString();
#endif
#endregion
#region IComparable
/// <inheritdoc/>
#if NETCOREAPP
public int CompareTo(object? obj) => ((T)this).CompareTo(obj);
#else
public int CompareTo(object obj) => ((T)this).CompareTo(obj);
#endif
#endregion
#region IConvertible
/// <inheritdoc/>
public TypeCode GetTypeCode() => ((T)this).GetTypeCode();
#if NETCOREAPP
/// <inheritdoc/>
public bool ToBoolean(IFormatProvider? provider) => ((T)this).ToBoolean(provider);
/// <inheritdoc/>
public char ToChar(IFormatProvider? provider) => ((T)this).ToChar(provider);
/// <inheritdoc/>
public sbyte ToSByte(IFormatProvider? provider) => ((T)this).ToSByte(provider);
/// <inheritdoc/>
public byte ToByte(IFormatProvider? provider) => ((T)this).ToByte(provider);
/// <inheritdoc/>
public short ToInt16(IFormatProvider? provider) => ((T)this).ToInt16(provider);
/// <inheritdoc/>
public ushort ToUInt16(IFormatProvider? provider) => ((T)this).ToUInt16(provider);
/// <inheritdoc/>
public int ToInt32(IFormatProvider? provider) => ((T)this).ToInt32(provider);
/// <inheritdoc/>
public uint ToUInt32(IFormatProvider? provider) => ((T)this).ToUInt32(provider);
/// <inheritdoc/>
public long ToInt64(IFormatProvider? provider) => ((T)this).ToInt64(provider);
/// <inheritdoc/>
public ulong ToUInt64(IFormatProvider? provider) => ((T)this).ToUInt64(provider);
/// <inheritdoc/>
public float ToSingle(IFormatProvider? provider) => ((T)this).ToSingle(provider);
/// <inheritdoc/>
public double ToDouble(IFormatProvider? provider) => ((T)this).ToDouble(provider);
/// <inheritdoc/>
public decimal ToDecimal(IFormatProvider? provider) => ((T)this).ToDecimal(provider);
/// <inheritdoc/>
public DateTime ToDateTime(IFormatProvider? provider) => ((T)this).ToDateTime(provider);
/// <inheritdoc/>
public string ToString(IFormatProvider? provider) => ((T)this).ToString(provider);
/// <inheritdoc/>
public object ToType(Type conversionType, IFormatProvider? provider) => ((T)this).ToType(conversionType, provider);
#else
/// <inheritdoc/>
public bool ToBoolean(IFormatProvider provider) => ((T)this).ToBoolean(provider);
/// <inheritdoc/>
public char ToChar(IFormatProvider provider) => ((T)this).ToChar(provider);
/// <inheritdoc/>
public sbyte ToSByte(IFormatProvider provider) => ((T)this).ToSByte(provider);
/// <inheritdoc/>
public byte ToByte(IFormatProvider provider) => ((T)this).ToByte(provider);
/// <inheritdoc/>
public short ToInt16(IFormatProvider provider) => ((T)this).ToInt16(provider);
/// <inheritdoc/>
public ushort ToUInt16(IFormatProvider provider) => ((T)this).ToUInt16(provider);
/// <inheritdoc/>
public int ToInt32(IFormatProvider provider) => ((T)this).ToInt32(provider);
/// <inheritdoc/>
public uint ToUInt32(IFormatProvider provider) => ((T)this).ToUInt32(provider);
/// <inheritdoc/>
public long ToInt64(IFormatProvider provider) => ((T)this).ToInt64(provider);
/// <inheritdoc/>
public ulong ToUInt64(IFormatProvider provider) => ((T)this).ToUInt64(provider);
/// <inheritdoc/>
public float ToSingle(IFormatProvider provider) => ((T)this).ToSingle(provider);
/// <inheritdoc/>
public double ToDouble(IFormatProvider provider) => ((T)this).ToDouble(provider);
/// <inheritdoc/>
public decimal ToDecimal(IFormatProvider provider) => ((T)this).ToDecimal(provider);
/// <inheritdoc/>
public DateTime ToDateTime(IFormatProvider provider) => ((T)this).ToDateTime(provider);
/// <inheritdoc/>
public string ToString(IFormatProvider provider) => ((T)this).ToString(provider);
/// <inheritdoc/>
public object ToType(Type conversionType, IFormatProvider provider) => ((T)this).ToType(conversionType, provider);
#endif
#endregion
#region IEquatable
#if NETCOREAPP
/// <inheritdoc/>
public bool Equals(BothEndian<T>? other)
{
if (other is null)
return false;
return LittleEndian.Equals(other.LittleEndian) && BigEndian.Equals(other.BigEndian);
}
/// <inheritdoc/>
public bool Equals(T? other) => ((T)this).Equals(other);
#else
/// <inheritdoc/>
public bool Equals(BothEndian<T> other)
=> LittleEndian.Equals(other.LittleEndian) && BigEndian.Equals(other.BigEndian);
/// <inheritdoc/>
public bool Equals(T other) => ((T)this).Equals(other);
#endif
#endregion
}
}

View File

@@ -0,0 +1,143 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 16-bit signed value
/// </summary>
public sealed class BothInt16(short le, short be) : BothEndian<short>(le, be)
{
public static implicit operator BothInt16(short val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothInt16 operator ++(BothInt16 a)
{
short le = (short)(a.LittleEndian + 1);
short be = (short)(a.BigEndian + 1);
return new BothInt16(le, be);
}
public static BothInt16 operator --(BothInt16 a)
{
short le = (short)(a.LittleEndian - 1);
short be = (short)(a.BigEndian - 1);
return new BothInt16(le, be);
}
public static BothInt16 operator +(BothInt16 a)
{
short le = (short)(+a.LittleEndian);
short be = (short)(+a.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator -(BothInt16 a)
{
short le = (short)(-a.LittleEndian);
short be = (short)(-a.BigEndian);
return new BothInt16(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothInt16 operator *(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian * b.LittleEndian);
short be = (short)(a.BigEndian * b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator /(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian / b.LittleEndian);
short be = (short)(a.BigEndian / b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator %(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian % b.LittleEndian);
short be = (short)(a.BigEndian % b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator +(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian + b.LittleEndian);
short be = (short)(a.BigEndian + b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator -(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian - b.LittleEndian);
short be = (short)(a.BigEndian - b.BigEndian);
return new BothInt16(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothInt16 operator ~(BothInt16 a)
{
short le = (short)(~a.LittleEndian);
short be = (short)(~a.BigEndian);
return new BothInt16(le, be);
}
#endregion
#region Shift Binary Operators
public static BothInt16 operator <<(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian << b.LittleEndian);
short be = (short)(a.BigEndian << b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator >>(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian >> b.LittleEndian);
short be = (short)(a.BigEndian >> b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator >>>(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian >>> b.LittleEndian);
short be = (short)(a.BigEndian >>> b.BigEndian);
return new BothInt16(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothInt16 operator &(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian & b.LittleEndian);
short be = (short)(a.BigEndian & b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator |(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian | b.LittleEndian);
short be = (short)(a.BigEndian | b.BigEndian);
return new BothInt16(le, be);
}
public static BothInt16 operator ^(BothInt16 a, BothInt16 b)
{
short le = (short)(a.LittleEndian ^ b.LittleEndian);
short be = (short)(a.BigEndian ^ b.BigEndian);
return new BothInt16(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,143 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 32-bit signed value
/// </summary>
public sealed class BothInt32(int le, int be) : BothEndian<int>(le, be)
{
public static implicit operator BothInt32(int val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothInt32 operator ++(BothInt32 a)
{
int le = (int)(a.LittleEndian + 1);
int be = (int)(a.BigEndian + 1);
return new BothInt32(le, be);
}
public static BothInt32 operator --(BothInt32 a)
{
int le = (int)(a.LittleEndian - 1);
int be = (int)(a.BigEndian - 1);
return new BothInt32(le, be);
}
public static BothInt32 operator +(BothInt32 a)
{
int le = (int)(+a.LittleEndian);
int be = (int)(+a.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator -(BothInt32 a)
{
int le = (int)(-a.LittleEndian);
int be = (int)(-a.BigEndian);
return new BothInt32(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothInt32 operator *(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian * b.LittleEndian);
int be = (int)(a.BigEndian * b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator /(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian / b.LittleEndian);
int be = (int)(a.BigEndian / b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator %(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian % b.LittleEndian);
int be = (int)(a.BigEndian % b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator +(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian + b.LittleEndian);
int be = (int)(a.BigEndian + b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator -(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian - b.LittleEndian);
int be = (int)(a.BigEndian - b.BigEndian);
return new BothInt32(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothInt32 operator ~(BothInt32 a)
{
int le = (int)(~a.LittleEndian);
int be = (int)(~a.BigEndian);
return new BothInt32(le, be);
}
#endregion
#region Shift Binary Operators
public static BothInt32 operator <<(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian << b.LittleEndian);
int be = (int)(a.BigEndian << b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator >>(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian >> b.LittleEndian);
int be = (int)(a.BigEndian >> b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator >>>(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian >>> b.LittleEndian);
int be = (int)(a.BigEndian >>> b.BigEndian);
return new BothInt32(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothInt32 operator &(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian & b.LittleEndian);
int be = (int)(a.BigEndian & b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator |(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian | b.LittleEndian);
int be = (int)(a.BigEndian | b.BigEndian);
return new BothInt32(le, be);
}
public static BothInt32 operator ^(BothInt32 a, BothInt32 b)
{
int le = (int)(a.LittleEndian ^ b.LittleEndian);
int be = (int)(a.BigEndian ^ b.BigEndian);
return new BothInt32(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,143 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 64-bit signed value
/// </summary>
public sealed class BothInt64(long le, long be) : BothEndian<long>(le, be)
{
public static implicit operator BothInt64(long val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothInt64 operator ++(BothInt64 a)
{
long le = (long)(a.LittleEndian + 1);
long be = (long)(a.BigEndian + 1);
return new BothInt64(le, be);
}
public static BothInt64 operator --(BothInt64 a)
{
long le = (long)(a.LittleEndian - 1);
long be = (long)(a.BigEndian - 1);
return new BothInt64(le, be);
}
public static BothInt64 operator +(BothInt64 a)
{
long le = (long)(+a.LittleEndian);
long be = (long)(+a.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator -(BothInt64 a)
{
long le = (long)(-a.LittleEndian);
long be = (long)(-a.BigEndian);
return new BothInt64(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothInt64 operator *(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian * b.LittleEndian);
long be = (long)(a.BigEndian * b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator /(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian / b.LittleEndian);
long be = (long)(a.BigEndian / b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator %(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian % b.LittleEndian);
long be = (long)(a.BigEndian % b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator +(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian + b.LittleEndian);
long be = (long)(a.BigEndian + b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator -(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian - b.LittleEndian);
long be = (long)(a.BigEndian - b.BigEndian);
return new BothInt64(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothInt64 operator ~(BothInt64 a)
{
long le = (long)(~a.LittleEndian);
long be = (long)(~a.BigEndian);
return new BothInt64(le, be);
}
#endregion
#region Shift Binary Operators
public static BothInt64 operator <<(BothInt64 a, BothInt32 b)
{
long le = (long)(a.LittleEndian << b.LittleEndian);
long be = (long)(a.BigEndian << b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator >>(BothInt64 a, BothInt32 b)
{
long le = (long)(a.LittleEndian >> b.LittleEndian);
long be = (long)(a.BigEndian >> b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator >>>(BothInt64 a, BothInt32 b)
{
long le = (long)(a.LittleEndian >>> b.LittleEndian);
long be = (long)(a.BigEndian >>> b.BigEndian);
return new BothInt64(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothInt64 operator &(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian & b.LittleEndian);
long be = (long)(a.BigEndian & b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator |(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian | b.LittleEndian);
long be = (long)(a.BigEndian | b.BigEndian);
return new BothInt64(le, be);
}
public static BothInt64 operator ^(BothInt64 a, BothInt64 b)
{
long le = (long)(a.LittleEndian ^ b.LittleEndian);
long be = (long)(a.BigEndian ^ b.BigEndian);
return new BothInt64(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,143 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 8-bit signed value
/// </summary>
public sealed class BothInt8(sbyte le, sbyte be) : BothEndian<sbyte>(le, be)
{
public static implicit operator BothInt8(sbyte val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothInt8 operator ++(BothInt8 a)
{
sbyte le = (sbyte)(a.LittleEndian + 1);
sbyte be = (sbyte)(a.BigEndian + 1);
return new BothInt8(le, be);
}
public static BothInt8 operator --(BothInt8 a)
{
sbyte le = (sbyte)(a.LittleEndian - 1);
sbyte be = (sbyte)(a.BigEndian - 1);
return new BothInt8(le, be);
}
public static BothInt8 operator +(BothInt8 a)
{
sbyte le = (sbyte)(+a.LittleEndian);
sbyte be = (sbyte)(+a.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator -(BothInt8 a)
{
sbyte le = (sbyte)(-a.LittleEndian);
sbyte be = (sbyte)(-a.BigEndian);
return new BothInt8(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothInt8 operator *(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian * b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian * b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator /(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian / b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian / b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator %(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian % b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian % b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator +(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian + b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian + b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator -(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian - b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian - b.BigEndian);
return new BothInt8(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothInt8 operator ~(BothInt8 a)
{
sbyte le = (sbyte)(~a.LittleEndian);
sbyte be = (sbyte)(~a.BigEndian);
return new BothInt8(le, be);
}
#endregion
#region Shift Binary Operators
public static BothInt8 operator <<(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian << b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian << b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator >>(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian >> b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian >> b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator >>>(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian >>> b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian >>> b.BigEndian);
return new BothInt8(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothInt8 operator &(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian & b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian & b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator |(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian | b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian | b.BigEndian);
return new BothInt8(le, be);
}
public static BothInt8 operator ^(BothInt8 a, BothInt8 b)
{
sbyte le = (sbyte)(a.LittleEndian ^ b.LittleEndian);
sbyte be = (sbyte)(a.BigEndian ^ b.BigEndian);
return new BothInt8(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,129 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 16-bit unsigned value
/// </summary>
public sealed class BothUInt16(ushort le, ushort be) : BothEndian<ushort>(le, be)
{
public static implicit operator BothUInt16(ushort val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothUInt16 operator ++(BothUInt16 a)
{
ushort le = (ushort)(a.LittleEndian + 1);
ushort be = (ushort)(a.BigEndian + 1);
return new BothUInt16(le, be);
}
public static BothUInt16 operator --(BothUInt16 a)
{
ushort le = (ushort)(a.LittleEndian - 1);
ushort be = (ushort)(a.BigEndian - 1);
return new BothUInt16(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothUInt16 operator *(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian * b.LittleEndian);
ushort be = (ushort)(a.BigEndian * b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator /(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian / b.LittleEndian);
ushort be = (ushort)(a.BigEndian / b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator %(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian % b.LittleEndian);
ushort be = (ushort)(a.BigEndian % b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator +(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian + b.LittleEndian);
ushort be = (ushort)(a.BigEndian + b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator -(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian - b.LittleEndian);
ushort be = (ushort)(a.BigEndian - b.BigEndian);
return new BothUInt16(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothUInt16 operator ~(BothUInt16 a)
{
ushort le = (ushort)(~a.LittleEndian);
ushort be = (ushort)(~a.BigEndian);
return new BothUInt16(le, be);
}
#endregion
#region Shift Binary Operators
public static BothUInt16 operator <<(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian << b.LittleEndian);
ushort be = (ushort)(a.BigEndian << b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator >>(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian >> b.LittleEndian);
ushort be = (ushort)(a.BigEndian >> b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator >>>(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian >>> b.LittleEndian);
ushort be = (ushort)(a.BigEndian >>> b.BigEndian);
return new BothUInt16(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothUInt16 operator &(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian & b.LittleEndian);
ushort be = (ushort)(a.BigEndian & b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator |(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian | b.LittleEndian);
ushort be = (ushort)(a.BigEndian | b.BigEndian);
return new BothUInt16(le, be);
}
public static BothUInt16 operator ^(BothUInt16 a, BothUInt16 b)
{
ushort le = (ushort)(a.LittleEndian ^ b.LittleEndian);
ushort be = (ushort)(a.BigEndian ^ b.BigEndian);
return new BothUInt16(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,129 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 32-bit unsigned value
/// </summary>
public sealed class BothUInt32(uint le, uint be) : BothEndian<uint>(le, be)
{
public static implicit operator BothUInt32(uint val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothUInt32 operator ++(BothUInt32 a)
{
uint le = (uint)(a.LittleEndian + 1);
uint be = (uint)(a.BigEndian + 1);
return new BothUInt32(le, be);
}
public static BothUInt32 operator --(BothUInt32 a)
{
uint le = (uint)(a.LittleEndian - 1);
uint be = (uint)(a.BigEndian - 1);
return new BothUInt32(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothUInt32 operator *(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian * b.LittleEndian);
uint be = (uint)(a.BigEndian * b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator /(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian / b.LittleEndian);
uint be = (uint)(a.BigEndian / b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator %(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian % b.LittleEndian);
uint be = (uint)(a.BigEndian % b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator +(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian + b.LittleEndian);
uint be = (uint)(a.BigEndian + b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator -(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian - b.LittleEndian);
uint be = (uint)(a.BigEndian - b.BigEndian);
return new BothUInt32(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothUInt32 operator ~(BothUInt32 a)
{
uint le = (uint)(~a.LittleEndian);
uint be = (uint)(~a.BigEndian);
return new BothUInt32(le, be);
}
#endregion
#region Shift Binary Operators
public static BothUInt32 operator <<(BothUInt32 a, BothInt32 b)
{
uint le = (uint)(a.LittleEndian << b.LittleEndian);
uint be = (uint)(a.BigEndian << b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator >>(BothUInt32 a, BothInt32 b)
{
uint le = (uint)(a.LittleEndian >> b.LittleEndian);
uint be = (uint)(a.BigEndian >> b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator >>>(BothUInt32 a, BothInt32 b)
{
uint le = (uint)(a.LittleEndian >>> b.LittleEndian);
uint be = (uint)(a.BigEndian >>> b.BigEndian);
return new BothUInt32(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothUInt32 operator &(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian & b.LittleEndian);
uint be = (uint)(a.BigEndian & b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator |(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian | b.LittleEndian);
uint be = (uint)(a.BigEndian | b.BigEndian);
return new BothUInt32(le, be);
}
public static BothUInt32 operator ^(BothUInt32 a, BothUInt32 b)
{
uint le = (uint)(a.LittleEndian ^ b.LittleEndian);
uint be = (uint)(a.BigEndian ^ b.BigEndian);
return new BothUInt32(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,129 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 64-bit unsigned value
/// </summary>
public sealed class BothUInt64(ulong le, ulong be) : BothEndian<ulong>(le, be)
{
public static implicit operator BothUInt64(ulong val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothUInt64 operator ++(BothUInt64 a)
{
ulong le = (ulong)(a.LittleEndian + 1);
ulong be = (ulong)(a.BigEndian + 1);
return new BothUInt64(le, be);
}
public static BothUInt64 operator --(BothUInt64 a)
{
ulong le = (ulong)(a.LittleEndian - 1);
ulong be = (ulong)(a.BigEndian - 1);
return new BothUInt64(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothUInt64 operator *(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian * b.LittleEndian);
ulong be = (ulong)(a.BigEndian * b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator /(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian / b.LittleEndian);
ulong be = (ulong)(a.BigEndian / b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator %(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian % b.LittleEndian);
ulong be = (ulong)(a.BigEndian % b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator +(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian + b.LittleEndian);
ulong be = (ulong)(a.BigEndian + b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator -(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian - b.LittleEndian);
ulong be = (ulong)(a.BigEndian - b.BigEndian);
return new BothUInt64(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothUInt64 operator ~(BothUInt64 a)
{
ulong le = (ulong)(~a.LittleEndian);
ulong be = (ulong)(~a.BigEndian);
return new BothUInt64(le, be);
}
#endregion
#region Shift Binary Operators
public static BothUInt64 operator <<(BothUInt64 a, BothInt32 b)
{
ulong le = (ulong)(a.LittleEndian << b.LittleEndian);
ulong be = (ulong)(a.BigEndian << b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator >>(BothUInt64 a, BothInt32 b)
{
ulong le = (ulong)(a.LittleEndian >> b.LittleEndian);
ulong be = (ulong)(a.BigEndian >> b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator >>>(BothUInt64 a, BothInt32 b)
{
ulong le = (ulong)(a.LittleEndian >>> b.LittleEndian);
ulong be = (ulong)(a.BigEndian >>> b.BigEndian);
return new BothUInt64(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothUInt64 operator &(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian & b.LittleEndian);
ulong be = (ulong)(a.BigEndian & b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator |(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian | b.LittleEndian);
ulong be = (ulong)(a.BigEndian | b.BigEndian);
return new BothUInt64(le, be);
}
public static BothUInt64 operator ^(BothUInt64 a, BothUInt64 b)
{
ulong le = (ulong)(a.LittleEndian ^ b.LittleEndian);
ulong be = (ulong)(a.BigEndian ^ b.BigEndian);
return new BothUInt64(le, be);
}
#endregion
}
}

View File

@@ -0,0 +1,129 @@
namespace SabreTools.Numerics
{
/// <summary>
/// Both-endian 8-bit unsigned value
/// </summary>
public sealed class BothUInt8(byte le, byte be) : BothEndian<byte>(le, be)
{
public static implicit operator BothUInt8(byte val)
=> new(val, val);
#region Arithmetic Unary Operators
public static BothUInt8 operator ++(BothUInt8 a)
{
byte le = (byte)(a.LittleEndian + 1);
byte be = (byte)(a.BigEndian + 1);
return new BothUInt8(le, be);
}
public static BothUInt8 operator --(BothUInt8 a)
{
byte le = (byte)(a.LittleEndian - 1);
byte be = (byte)(a.BigEndian - 1);
return new BothUInt8(le, be);
}
#endregion
#region Arithmetic Binary Operators
public static BothUInt8 operator *(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian * b.LittleEndian);
byte be = (byte)(a.BigEndian * b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator /(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian / b.LittleEndian);
byte be = (byte)(a.BigEndian / b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator %(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian % b.LittleEndian);
byte be = (byte)(a.BigEndian % b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator +(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian + b.LittleEndian);
byte be = (byte)(a.BigEndian + b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator -(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian - b.LittleEndian);
byte be = (byte)(a.BigEndian - b.BigEndian);
return new BothUInt8(le, be);
}
#endregion
#region Bitwise Unary Operators
public static BothUInt8 operator ~(BothUInt8 a)
{
byte le = (byte)(~a.LittleEndian);
byte be = (byte)(~a.BigEndian);
return new BothUInt8(le, be);
}
#endregion
#region Shift Binary Operators
public static BothUInt8 operator <<(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian << b.LittleEndian);
byte be = (byte)(a.BigEndian << b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator >>(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian >> b.LittleEndian);
byte be = (byte)(a.BigEndian >> b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator >>>(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian >>> b.LittleEndian);
byte be = (byte)(a.BigEndian >>> b.BigEndian);
return new BothUInt8(le, be);
}
#endregion
#region Bitwise Binary Operators
public static BothUInt8 operator &(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian & b.LittleEndian);
byte be = (byte)(a.BigEndian & b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator |(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian | b.LittleEndian);
byte be = (byte)(a.BigEndian | b.BigEndian);
return new BothUInt8(le, be);
}
public static BothUInt8 operator ^(BothUInt8 a, BothUInt8 b)
{
byte le = (byte)(a.LittleEndian ^ b.LittleEndian);
byte be = (byte)(a.BigEndian ^ b.BigEndian);
return new BothUInt8(le, be);
}
#endregion
}
}

View File

@@ -2,8 +2,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using SabreTools.IO.Compare;
using SabreTools.IO.Extensions;
using SabreTools.Text.Compare;
namespace SabreTools.IO
{

View File

@@ -11,7 +11,7 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.7.5</Version>
<Version>1.8.0</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
@@ -34,7 +34,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))" />
<PackageReference Include="BouncyCastle.NetCore" Version="2.2.1" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))" />
<PackageReference Include="SabreTools.Hashing" Version="[1.5.1]" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SabreTools.IO.Transform
{
/// <summary>
/// Helpers to combine inputs
/// </summary>
public static class Combine
{
/// <summary>
/// Concatenate all files in the order provided, if possible
/// </summary>
/// <param name="paths">List of paths to combine</param>
/// <param name="output">Path to the output file</param>
/// <returns>True if the files were concatenated successfully, false otherwise</returns>
public static bool Concatenate(List<string> paths, string output)
{
// If the path list is empty
if (paths.Count == 0)
return false;
// If the output filename is invalid
if (string.IsNullOrEmpty(output))
return false;
try
{
// Try to build the new output file
using var ofs = File.Open(output, FileMode.Create, FileAccess.Write, FileShare.None);
for (int i = 0; i < paths.Count; i++)
{
// Get the next file
string next = paths[i];
if (!File.Exists(next))
break;
// Copy the next input to the output
using var ifs = File.Open(next, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Write in blocks
int read = 0;
do
{
byte[] buffer = new byte[3 * 1024 * 1024];
read = ifs.Read(buffer, 0, buffer.Length);
if (read == 0)
break;
ofs.Write(buffer, 0, read);
ofs.Flush();
} while (read > 0);
}
return true;
}
catch
{
// Absorb the exception right now
return false;
}
}
/// <summary>
/// Interleave two files into a single output
/// </summary>
/// <param name="even">First file to interleave</param>
/// <param name="odd">Second file to interleave</param>
/// <param name="output">Path to the output file</param>
/// <param name="type"><see cref="BlockSize"> representing how to process the inputs</param>
/// <returns>True if the files were interleaved successfully, false otherwise</returns>
public static bool Interleave(string even, string odd, string output, BlockSize type)
{
// If either file does not exist
if (!File.Exists(even) || !File.Exists(odd))
return false;
try
{
// Get the input streams
using var evenStream = File.Open(even, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var oddStream = File.Open(odd, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Interleave the streams
using var interleaved = Interleave(evenStream, oddStream, type);
if (interleaved == null)
return false;
// Open the output file
using var outputStream = File.Open(output, FileMode.Create, FileAccess.Write, FileShare.None);
// Write the interleaved data
interleaved.CopyTo(outputStream);
outputStream.Flush();
}
catch
{
// Absorb all errors for now
return false;
}
return true;
}
/// <summary>
/// Interleave two streams into a single output
/// </summary>
/// <param name="even">First stream to interleave</param>
/// <param name="odd">Second stream to interleave</param>
/// <param name="output">Path to the output file</param>
/// <param name="type"><see cref="BlockSize"> representing how to process the inputs</param>
/// <returns>A filled stream on success, null otherwise</returns>
public static Stream? Interleave(Stream even, Stream odd, BlockSize type)
{
// If either stream is unreadable
if (!even.CanRead || !odd.CanRead)
return null;
// Get the number of bytes to process
int byteCount = type switch
{
BlockSize.Byte => 1,
BlockSize.Word => 2,
BlockSize.Dword => 4,
BlockSize.Qword => 8,
_ => throw new ArgumentOutOfRangeException(nameof(type)),
};
try
{
// Create an output stream
var outputStream = new MemoryStream();
// Alternate between inputs during reading
bool useEven = true;
while (even.Position < even.Length || odd.Position < odd.Length)
{
byte[] read = new byte[byteCount];
int actual = (useEven ? even : odd).Read(read, 0, byteCount);
outputStream.Write(read, 0, actual);
outputStream.Flush();
useEven = !useEven;
}
outputStream.Seek(0, SeekOrigin.Begin);
return outputStream;
}
catch
{
// Absorb all errors for now
return null;
}
}
}
}

View File

@@ -0,0 +1,54 @@
namespace SabreTools.IO.Transform
{
/// <summary>
/// Determines the block size of an operation
/// </summary>
public enum BlockSize
{
/// <summary>
/// 1 byte blocks
/// </summary>
Byte = 1,
/// <summary>
/// 2 byte blocks
/// </summary>
Word = 2,
/// <summary>
/// 4 byte blocks
/// </summary>
Dword = 4,
/// <summary>
/// 8 byte blocks
/// </summary>
Qword = 8,
}
/// <summary>
/// Determines the swapping operation
/// </summary>
public enum Operation
{
/// <summary>
/// Reverse endianness of each byte
/// </summary>
Bitswap,
/// <summary>
/// Swap every 1 byte
/// </summary>
Byteswap,
/// <summary>
/// Swap every 2 bytes
/// </summary>
Wordswap,
/// <summary>
/// Swap every 2 bytes and bytes within the 2 bytes
/// </summary>
WordByteswap,
}
}

View File

@@ -0,0 +1,177 @@
using System;
using System.IO;
namespace SabreTools.IO.Transform
{
/// <summary>
/// Helpers to split inputs
/// </summary>
public static class Split
{
/// <summary>
/// Split an input file into two outputs
/// </summary>
/// <param name="input">Input file name</param>
/// <param name="outputDir">Path to the output directory</param>
/// <param name="type"><see cref="BlockSize"> representing how to process the inputs</param>
/// <returns>True if the file could be split, false otherwise</returns>
public static bool BlockSplit(string input, string? outputDir, BlockSize type)
{
// If the file does not exist
if (!File.Exists(input))
return false;
try
{
// Get the input stream
using var inputStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Split the stream
if (!BlockSplit(inputStream, type, out Stream? evenStream, out Stream? oddStream))
return false;
else if (evenStream == null || oddStream == null)
return false;
// Get the base filename for output files
outputDir ??= Path.GetDirectoryName(input);
string baseFilename = Path.GetFileName(input);
if (!string.IsNullOrEmpty(outputDir))
baseFilename = Path.Combine(outputDir, baseFilename);
// Create the output directory, if possible
if (outputDir != null && !Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
// Open the output files
using var outEvenStream = File.Open($"{baseFilename}.even", FileMode.Create, FileAccess.Write, FileShare.None);
using var outOddStream = File.Open($"{baseFilename}.odd", FileMode.Create, FileAccess.Write, FileShare.None);
// Write the split data
evenStream.CopyTo(outEvenStream);
outEvenStream.Flush();
oddStream.CopyTo(outOddStream);
outOddStream.Flush();
}
catch
{
// Absorb all errors for now
return false;
}
return true;
}
/// <summary>
/// Split an input stream into two output streams
/// </summary>
/// <param name="input">Input stream</param>
/// <param name="type"><see cref="BlockSize"> representing how to process the inputs</param>
/// <param name="even">Even block output stream on success, null otherwise</param>
/// <param name="odd">Odd block output stream on success, null otherwise</param>
/// <returns>True if the stream could be split, false otherwise</returns>
public static bool BlockSplit(Stream input, BlockSize type, out Stream? even, out Stream? odd)
{
// Set default values for the outputs
even = null;
odd = null;
// If the stream is unreadable
if (!input.CanRead)
return false;
// Get the number of bytes to process
int byteCount = type switch
{
BlockSize.Byte => 1,
BlockSize.Word => 2,
BlockSize.Dword => 4,
BlockSize.Qword => 8,
_ => throw new ArgumentOutOfRangeException(nameof(type)),
};
try
{
// Create the output streams
even = new MemoryStream();
odd = new MemoryStream();
// Alternate between inputs during reading
bool useEven = true;
while (input.Position < input.Length)
{
byte[] read = new byte[byteCount];
int actual = input.Read(read, 0, byteCount);
(useEven ? even : odd).Write(read, 0, actual);
(useEven ? even : odd).Flush();
useEven = !useEven;
}
even.Seek(0, SeekOrigin.Begin);
odd.Seek(0, SeekOrigin.Begin);
return true;
}
catch
{
// Absorb all errors for now
even = null;
odd = null;
return false;
}
}
/// <summary>
/// Split an input file into files of up to <paramref name="size"/> bytes
/// </summary>
/// <param name="input">Input file name</param>
/// <param name="outputDir">Path to the output directory</param>
/// <param name="size">Maximum number of bytes to split on</param>
/// <returns>True if the file could be split, false otherwise</returns>
public static bool SizeSplit(string input, string? outputDir, int size)
{
// If the file does not exist
if (!File.Exists(input))
return false;
// If the size is invalid
if (size <= 0)
return false;
try
{
// Get the input stream
using var inputStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Get the base filename for output files
outputDir ??= Path.GetDirectoryName(input);
string baseFilename = Path.GetFileName(input);
if (!string.IsNullOrEmpty(outputDir))
baseFilename = Path.Combine(outputDir, baseFilename);
// Create the output directory, if possible
if (outputDir != null && !Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
// Loop while there is data left
int part = 0;
while (inputStream.Position < inputStream.Length)
{
// Create the next output file
using var partStream = File.Open($"{baseFilename}.{part++}", FileMode.Create, FileAccess.Write, FileShare.None);
// Process the next block of data
byte[] data = new byte[size];
int actual = inputStream.Read(data, 0, size);
partStream.Write(data, 0, actual);
partStream.Flush();
}
return true;
}
catch
{
// Absorb all errors for now
return false;
}
}
}
}

View File

@@ -0,0 +1,162 @@
using System;
using System.IO;
using SabreTools.IO.Extensions;
namespace SabreTools.IO.Transform
{
/// <summary>
/// Helpers to perform swapping operations
/// </summary>
public static class Swap
{
/// <summary>
/// Transform an input file using the given rule
/// </summary>
/// <param name="input">Input file name</param>
/// <param name="output">Output file name</param>
/// <param name="operation">Transform operation to carry out</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
public static bool Process(string input, string output, Operation operation)
{
// If the file does not exist
if (!File.Exists(input))
return false;
// Create the output directory if it doesn't already
string? outputDirectory = Path.GetDirectoryName(Path.GetFullPath(output));
if (outputDirectory != null && !Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory);
try
{
// Get the input stream
using var inputStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Transform the stream
var transformed = Process(inputStream, operation);
if (transformed == null)
return false;
// Open the output file
using var outputStream = File.Open(output, FileMode.Create, FileAccess.Write, FileShare.None);
// Write the transformed data
transformed.CopyTo(outputStream);
outputStream.Flush();
}
catch
{
// Absorb all errors for now
return false;
}
return true;
}
/// <summary>
/// Transform an input stream using the given rule
/// </summary>
/// <param name="input">Input stream</param>
/// <param name="operation">Transform operation to carry out</param>
/// <returns>True if the file was transformed properly, false otherwise</returns>
public static Stream? Process(Stream input, Operation operation)
{
// If the stream is unreadable
if (!input.CanRead)
return null;
// If the operation is not defined
if (!Enum.IsDefined(typeof(Operation), operation))
return null;
try
{
// Create an output stream
var output = new MemoryStream();
// Determine the cutoff boundary for the operation
long endBoundary = operation switch
{
Operation.Bitswap => input.Length,
Operation.Byteswap => input.Length - (input.Length % 2),
Operation.Wordswap => input.Length - (input.Length % 4),
Operation.WordByteswap => input.Length - (input.Length % 4),
_ => throw new ArgumentOutOfRangeException(nameof(operation)),
};
// Loop over the input and process in blocks
byte[] buffer = new byte[4];
int pos = 0;
while (input.Position < endBoundary)
{
byte b = input.ReadByteValue();
switch (operation)
{
case Operation.Bitswap:
uint r = b;
int s = 7;
for (b >>= 1; b != 0; b >>= 1)
{
r <<= 1;
r |= (byte)(b & 1);
s--;
}
r <<= s;
buffer[pos] = (byte)r;
break;
case Operation.Byteswap:
if (pos % 2 == 1)
buffer[pos - 1] = b;
else
buffer[pos + 1] = b;
break;
case Operation.Wordswap:
buffer[(pos + 2) % 4] = b;
break;
case Operation.WordByteswap:
buffer[3 - pos] = b;
break;
default:
buffer[pos] = b;
break;
}
// Set the buffer position to default write to
pos = (pos + 1) % 4;
// If the buffer pointer has been reset
if (pos == 0)
{
output.Write(buffer);
output.Flush();
buffer = new byte[4];
}
}
// If there's anything more in the buffer
for (int i = 0; i < pos; i++)
{
output.Write(buffer[i]);
}
// If the stream still has data
if (input.Position < input.Length)
{
byte[] bytes = input.ReadBytes((int)(input.Length - input.Position));
output.Write(bytes);
output.Flush();
}
output.Seek(0, SeekOrigin.Begin);
return output;
}
catch
{
// Absorb all errors for now
return null;
}
}
}
}