Skip to content

Commit

Permalink
添加强制使用长流模式的方法,并修复不可 Seek 的流无法正常编解码的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
lc6464 committed Oct 12, 2023
1 parent 886c53d commit bf589ba
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 75 deletions.
31 changes: 31 additions & 0 deletions File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
/// Base16384 编解码器。
/// </summary>
public static partial class Base16384 {
/// <summary>
/// 强制使用长流模式(分段编码)编码二进制数据流中的数据到 Base16384 UTF-16 BE 编码文件。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">二进制数据流</param>
/// <param name="fileInfo">创建的 Base16384 UTF-16 BE 编码文件信息</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer0Length"/>)</param>
/// <param name="encodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="EncodeLength"/>(<see cref="Buffer0Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static long EncodeFromLongStreamToNewFile(Stream stream, FileInfo fileInfo, Span<byte> buffer, Span<byte> encodingBuffer) {
using var file = fileInfo.Create();
file.Write(Utf16BEPreamble);
return EncodeFromLongStreamToStream(stream, file, buffer, encodingBuffer);
}

/// <summary>
/// 编码二进制数据流中的数据到 Base16384 UTF-16 BE 编码文件。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
Expand All @@ -20,6 +36,21 @@ public static long EncodeToNewFile(Stream stream, FileInfo fileInfo, Span<byte>
return EncodeToStream(stream, file, buffer, encodingBuffer);
}

/// <summary>
/// 强制使用长流模式(分段编码)解码 Base16384 UTF-16 BE 编码数据流中的数据到二进制文件。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">Base16384 UTF-16 BE 编码数据流</param>
/// <param name="fileInfo">创建的二进制文件信息</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer1Length"/> + 2)</param>
/// <param name="decodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="DecodeLength"/>(<see cref="Buffer1Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static long DecodeFromLongStreamToNewFile(Stream stream, FileInfo fileInfo, Span<byte> buffer, Span<byte> decodingBuffer) {
using var file = fileInfo.Create();
return DecodeFromLongStreamToStream(stream, file, buffer, decodingBuffer);
}

/// <summary>
/// 解码 Base16384 UTF-16 BE 编码数据流中的数据到二进制文件。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
Expand Down
26 changes: 24 additions & 2 deletions FileInternalBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,34 @@
/// Base16384 编解码器。
/// </summary>
public static partial class Base16384 {
/// <summary>
/// 强制使用长流模式(分段编码)编码二进制数据流中的数据到 Base16384 UTF-16 BE 编码文件。
/// </summary>
/// <param name="stream">二进制数据流</param>
/// <param name="fileInfo">创建的 Base16384 UTF-16 BE 编码文件信息</param>
/// <returns>已写入的数据长度</returns>
public static long EncodeFromLongStreamToNewFile(Stream stream, FileInfo fileInfo) =>
EncodeFromLongStreamToNewFile(stream, fileInfo, new byte[Buffer0Length], new byte[EncodeLength(Buffer0Length)]);

/// <summary>
/// 编码二进制数据流中的数据到 Base16384 UTF-16 BE 编码文件。
/// </summary>
/// <param name="stream">二进制数据流</param>
/// <param name="fileInfo">创建的 Base16384 UTF-16 BE 编码文件信息</param>
/// <returns>已写入的数据长度</returns>
public static long EncodeToNewFile(Stream stream, FileInfo fileInfo) =>
EncodeToNewFile(stream, fileInfo, new byte[stream.Length > Buffer0Length ? Buffer0Length : stream.Length - stream.Position], new byte[EncodeLength(stream.Length > Buffer0Length ? Buffer0Length : stream.Length - stream.Position)]);
!stream.CanSeek || stream.Length > Buffer0Length
? EncodeFromLongStreamToNewFile(stream, fileInfo)
: EncodeToNewFile(stream, fileInfo, new byte[stream.Length - stream.Position], new byte[EncodeLength(stream.Length - stream.Position)]);

/// <summary>
/// 强制使用长流模式(分段编码)解码 Base16384 UTF-16 BE 编码数据流中的数据到二进制文件。
/// </summary>
/// <param name="stream">Base16384 UTF-16 BE 编码数据流</param>
/// <param name="fileInfo">创建的二进制文件信息</param>
/// <returns>已写入的数据长度</returns>
public static long DecodeFromLongStreamToNewFile(Stream stream, FileInfo fileInfo) =>
DecodeFromLongStreamToNewFile(stream, fileInfo, new byte[Buffer1Length + 2], new byte[DecodeLength(Buffer1Length)]);

/// <summary>
/// 解码 Base16384 UTF-16 BE 编码数据流中的数据到二进制文件。
Expand All @@ -20,7 +40,9 @@ public static long EncodeToNewFile(Stream stream, FileInfo fileInfo) =>
/// <param name="fileInfo">创建的二进制文件信息</param>
/// <returns>已写入的数据长度</returns>
public static long DecodeToNewFile(Stream stream, FileInfo fileInfo) =>
DecodeToNewFile(stream, fileInfo, new byte[stream.Length > Buffer1Length ? Buffer1Length + 2 : stream.Length - stream.Position], new byte[DecodeLength(stream.Length > Buffer1Length ? Buffer1Length : stream.Length - stream.Position)]);
!stream.CanSeek || stream.Length > Buffer1Length
? DecodeFromLongStreamToNewFile(stream, fileInfo)
: DecodeToNewFile(stream, fileInfo, new byte[stream.Length - stream.Position], new byte[DecodeLength(stream.Length - stream.Position)]);


/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions LC6464.Base16384.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<Authors>LC</Authors>
<Version>2.0.0</Version>
<PackageReleaseNotes>修复 ConvertFromUtf16BEBytesToUtf8BOMBytes 无法正常使用的问题。</PackageReleaseNotes>
<Version>2.1.0-Preview.1</Version>
<PackageReleaseNotes>添加强制使用长流模式的方法,并修复不可 Seek 的流无法正常编解码的问题。</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Runtime.InteropServices" />
Expand Down
194 changes: 125 additions & 69 deletions Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@
/// Base16384 编解码器。
/// </summary>
public static partial class Base16384 {
/// <summary>
/// 强制使用长流模式(分段编码)编码二进制数据流中的数据至 Base16384 UTF-16 BE 编码数据,追加到输出数据流。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">二进制数据流</param>
/// <param name="output">输出数据流</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer0Length"/>)</param>
/// <param name="encodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="EncodeLength"/>(<see cref="Buffer0Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static unsafe long EncodeFromLongStreamToStream(Stream stream, Stream output, Span<byte> buffer, Span<byte> encodingBuffer) {
if (buffer.Length < Buffer0Length) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(buffer));
}
var encodeLength = (int)EncodeLength(Buffer0Length);
if (encodingBuffer.Length < encodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(encodingBuffer));
}

var readingBuffer = buffer[..Buffer0Length]; // 防止一次读入过多数据,此处使用切片
int readCount = stream.Read(readingBuffer),
writeCount = 0;
do {
var encodedLength = Encode(buffer[..readCount], encodingBuffer); // 编码结果写入缓冲区
output.Write(encodingBuffer[..encodedLength]); // 将缓冲区中指定长度的数据写入输出流
writeCount += encodedLength;
} while ((readCount = stream.Read(readingBuffer)) > 0);
output.Flush();

return writeCount;
}

/// <summary>
/// 编码二进制数据流中的数据至 Base16384 UTF-16 BE 编码数据,追加到输出数据流。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
Expand All @@ -15,42 +47,60 @@ public static partial class Base16384 {
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static unsafe long EncodeToStream(Stream stream, Stream output, Span<byte> buffer, Span<byte> encodingBuffer) {
if (stream.Length > Buffer0Length) {
if (buffer.Length < Buffer0Length) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(buffer));
}
var encodeLength = (int)EncodeLength(Buffer0Length);
if (encodingBuffer.Length < encodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(encodingBuffer));
}
if (!stream.CanSeek || stream.Length > Buffer0Length) {
return EncodeFromLongStreamToStream(stream, output, buffer, encodingBuffer);
}

var readingBuffer = buffer[..Buffer0Length]; // 防止一次读入过多数据,此处使用切片
int readCount = stream.Read(readingBuffer),
writeCount = 0;
do {
var encodedLength = Encode(buffer[..readCount], encodingBuffer); // 编码结果写入缓冲区
output.Write(encodingBuffer[..encodedLength]); // 将缓冲区中指定长度的数据写入输出流
writeCount += encodedLength;
} while ((readCount = stream.Read(readingBuffer)) > 0);
output.Flush();
var remainingLength = stream.Length - stream.Position;
if (buffer.Length < remainingLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(buffer));
}
var encodeLength = (int)EncodeLength(remainingLength);
if (encodingBuffer.Length < encodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(encodingBuffer));
}

return writeCount;
var encodedLength = Encode(buffer[..stream.Read(buffer)], encodingBuffer);
output.Write(encodingBuffer[..encodedLength]); // 将缓冲区中指定长度的数据写入输出流
output.Flush();
return encodedLength;
}

/// <summary>
/// 强制使用长流模式(分段编码)解码 Base16384 UTF-16 BE 编码数据流中的数据至二进制数据,追加到输出数据流。<br/>
/// 特别提醒:若使用外部提供的缓存空间,必须保证其长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">Base16384 UTF-16 BE 编码数据流</param>
/// <param name="output">输出数据流</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer1Length"/> + 2)</param>
/// <param name="decodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="DecodeLength"/>(<see cref="Buffer1Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static unsafe long DecodeFromLongStreamToStream(Stream stream, Stream output, Span<byte> buffer, Span<byte> decodingBuffer) {
if (buffer.Length < Buffer1Length + 2) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(buffer));
}
{
var remainingLength = stream.Length - stream.Position;
if (buffer.Length < remainingLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(buffer));
}
var encodeLength = (int)EncodeLength(remainingLength);
if (encodingBuffer.Length < encodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成编码。", nameof(encodingBuffer));
var decodeLength = (int)DecodeLength(Buffer1Length);
if (decodingBuffer.Length < decodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(decodingBuffer));
}

var readingBuffer = buffer[..Buffer1Length]; // 防止一次读入过多数据,此处使用切片
byte end; // skipcq: CS-W1022 对 end 赋值的确是不必要的
int readCount = stream.Read(readingBuffer),
writeCount = 0;
do {
if (Convert.ToBoolean(end = IsNextEnd(stream))) {
buffer[readCount++] = 61; // (byte)'=' // skipcq: CS-W1082 readCount 值已递增,61 不会被后续语句覆盖
buffer[readCount++] = end;
}
var decodedLength = Decode(buffer[..readCount], decodingBuffer); // 解码结果写入缓冲区
output.Write(decodingBuffer[..decodedLength]); // 将缓冲区中指定长度的数据写入输出流
writeCount += decodedLength;
} while ((readCount = stream.Read(readingBuffer)) > 0);
output.Flush();

var encodedLength = Encode(buffer[..stream.Read(buffer)], encodingBuffer);
output.Write(encodingBuffer[..encodedLength]); // 将缓冲区中指定长度的数据写入输出流
output.Flush();
return encodedLength;
}
return writeCount;
}

/// <summary>
Expand All @@ -64,47 +114,23 @@ public static unsafe long EncodeToStream(Stream stream, Stream output, Span<byte
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>已写入的数据长度</returns>
public static unsafe long DecodeToStream(Stream stream, Stream output, Span<byte> buffer, Span<byte> decodingBuffer) {
if (stream.Length > Buffer1Length) {
if (buffer.Length < Buffer1Length + 2) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(buffer));
}
var decodeLength = (int)DecodeLength(Buffer1Length);
if (decodingBuffer.Length < decodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(decodingBuffer));
}

var readingBuffer = buffer[..Buffer1Length]; // 防止一次读入过多数据,此处使用切片
byte end; // skipcq: CS-W1022 对 end 赋值的确是不必要的
int readCount = stream.Read(readingBuffer),
writeCount = 0;
do {
if (Convert.ToBoolean(end = IsNextEnd(stream))) {
buffer[readCount++] = 61; // (byte)'=' // skipcq: CS-W1082 readCount 值已递增,61 不会被后续语句覆盖
buffer[readCount++] = end;
}
var decodedLength = Decode(buffer[..readCount], decodingBuffer); // 解码结果写入缓冲区
output.Write(decodingBuffer[..decodedLength]); // 将缓冲区中指定长度的数据写入输出流
writeCount += decodedLength;
} while ((readCount = stream.Read(readingBuffer)) > 0);
output.Flush();

return writeCount;
if (!stream.CanSeek || stream.Length > Buffer1Length) {
return DecodeFromLongStreamToStream(stream, output, buffer, decodingBuffer);
}
{
var remainingLength = stream.Length - stream.Position;
if (buffer.Length < remainingLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(buffer));
}
var decodeLength = (int)DecodeLength(remainingLength);
if (decodingBuffer.Length < decodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(decodingBuffer));
}

var decodedLength = Decode(buffer[..stream.Read(buffer)], decodingBuffer);
output.Write(decodingBuffer[..decodedLength]);
output.Flush();
return decodedLength;
var remainingLength = stream.Length - stream.Position;
if (buffer.Length < remainingLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(buffer));
}
var decodeLength = (int)DecodeLength(remainingLength);
if (decodingBuffer.Length < decodeLength) {
throw new ArgumentException("外部提供的缓存空间不足,无法完成解码。", nameof(decodingBuffer));
}

var decodedLength = Decode(buffer[..stream.Read(buffer)], decodingBuffer);
output.Write(decodingBuffer[..decodedLength]);
output.Flush();
return decodedLength;
}


Expand Down Expand Up @@ -213,6 +239,21 @@ public static unsafe long DecodeToStream(ReadOnlySpan<byte> data, Stream output,
}


/// <summary>
/// 强制使用长流模式(分段编码)编码二进制数据流中的数据到新的 Base16384 UTF-16 BE 编码数据流。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">二进制数据流</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer0Length"/>)</param>
/// <param name="encodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="EncodeLength"/>(<see cref="Buffer0Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>Base16384 UTF-16 BE 编码数据流</returns>
public static MemoryStream EncodeFromLongStreamToNewMemoryStream(Stream stream, Span<byte> buffer, Span<byte> encodingBuffer) {
var output = new MemoryStream();
_ = EncodeFromLongStreamToStream(stream, output, buffer, encodingBuffer);
return output;
}

/// <summary>
/// 编码二进制数据流中的数据到新的 Base16384 UTF-16 BE 编码数据流。<br/>
/// 特别提醒:必须保证外部提供的缓存空间长度足够大,否则将会引发异常。
Expand All @@ -228,6 +269,21 @@ public static MemoryStream EncodeToNewMemoryStream(Stream stream, Span<byte> buf
return output;
}

/// <summary>
/// 强制使用长流模式(分段编码)解码 Base16384 UTF-16 BE 编码数据流中的数据到新的二进制数据流。<br/>
/// 特别提醒:若使用外部提供的缓存空间,必须保证其长度足够大,否则将会引发异常。
/// </summary>
/// <param name="stream">Base16384 UTF-16 BE 编码数据流</param>
/// <param name="buffer">外部提供的缓存空间(长度必须大于等于 <see cref="Buffer1Length"/> + 2)</param>
/// <param name="decodingBuffer">外部提供的用于编码的缓存空间(长度必须大于等于 <see cref="DecodeLength"/>(<see cref="Buffer1Length"/>))</param>
/// <exception cref="ArgumentException">外部提供的缓存空间不足</exception>
/// <returns>二进制数据流</returns>
public static MemoryStream DecodeFromLongStreamToNewMemorySteam(Stream stream, Span<byte> buffer, Span<byte> decodingBuffer) {
var output = new MemoryStream();
_ = DecodeFromLongStreamToStream(stream, output, buffer, decodingBuffer);
return output;
}

/// <summary>
/// 解码 Base16384 UTF-16 BE 编码数据流中的数据到新的二进制数据流。<br/>
/// 特别提醒:若使用外部提供的缓存空间,必须保证其长度足够大,否则将会引发异常。
Expand Down
Loading

1 comment on commit bf589ba

@lc6464
Copy link
Owner Author

@lc6464 lc6464 commented on bf589ba Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#6

Please sign in to comment.