diff --git a/Directory.Packages.props b/Directory.Packages.props
index f0ae33c3a..031dc894f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -12,7 +12,6 @@
-
diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs
index c979b7000..870092f1a 100644
--- a/src/SharpCompress/Archives/ArchiveFactory.cs
+++ b/src/SharpCompress/Archives/ArchiveFactory.cs
@@ -45,7 +45,7 @@ public static IWritableArchive Create(ArchiveType type)
///
public static IArchive Open(string filePath, ReaderOptions? options = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), options);
}
@@ -68,7 +68,7 @@ public static IArchive Open(FileInfo fileInfo, ReaderOptions? options = null)
///
public static IArchive Open(IEnumerable fileInfos, ReaderOptions? options = null)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var filesArray = fileInfos.ToArray();
if (filesArray.Length == 0)
{
@@ -81,7 +81,7 @@ public static IArchive Open(IEnumerable fileInfos, ReaderOptions? opti
return Open(fileInfo, options);
}
- fileInfo.CheckNotNull(nameof(fileInfo));
+ fileInfo.NotNull(nameof(fileInfo));
options ??= new ReaderOptions { LeaveStreamOpen = false };
return FindFactory(fileInfo).Open(filesArray, options);
@@ -94,7 +94,7 @@ public static IArchive Open(IEnumerable fileInfos, ReaderOptions? opti
///
public static IArchive Open(IEnumerable streams, ReaderOptions? options = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var streamsArray = streams.ToArray();
if (streamsArray.Length == 0)
{
@@ -107,7 +107,7 @@ public static IArchive Open(IEnumerable streams, ReaderOptions? options
return Open(firstStream, options);
}
- firstStream.CheckNotNull(nameof(firstStream));
+ firstStream.NotNull(nameof(firstStream));
options ??= new ReaderOptions();
return FindFactory(firstStream).Open(streamsArray, options);
@@ -129,7 +129,7 @@ public static void WriteToDirectory(
private static T FindFactory(FileInfo finfo)
where T : IFactory
{
- finfo.CheckNotNull(nameof(finfo));
+ finfo.NotNull(nameof(finfo));
using Stream stream = finfo.OpenRead();
return FindFactory(stream);
}
@@ -137,7 +137,7 @@ private static T FindFactory(FileInfo finfo)
private static T FindFactory(Stream stream)
where T : IFactory
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
@@ -172,7 +172,7 @@ public static bool IsArchive(
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
using Stream s = File.OpenRead(filePath);
return IsArchive(s, out type, bufferSize);
}
@@ -184,7 +184,7 @@ public static bool IsArchive(
)
{
type = null;
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (!stream.CanRead || !stream.CanSeek)
{
@@ -215,7 +215,7 @@ public static bool IsArchive(
///
public static IEnumerable GetFileParts(string part1)
{
- part1.CheckNotNullOrEmpty(nameof(part1));
+ part1.NotNullOrEmpty(nameof(part1));
return GetFileParts(new FileInfo(part1)).Select(a => a.FullName);
}
@@ -226,7 +226,7 @@ public static IEnumerable GetFileParts(string part1)
///
public static IEnumerable GetFileParts(FileInfo part1)
{
- part1.CheckNotNull(nameof(part1));
+ part1.NotNull(nameof(part1));
yield return part1;
foreach (var factory in Factory.Factories.OfType())
diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs
index 4437ff57d..a0345cdf9 100644
--- a/src/SharpCompress/Archives/GZip/GZipArchive.cs
+++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs
@@ -21,7 +21,7 @@ public class GZipArchive : AbstractWritableArchive
///
public static GZipArchive Open(string filePath, ReaderOptions? readerOptions = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
@@ -32,7 +32,7 @@ public static GZipArchive Open(string filePath, ReaderOptions? readerOptions = n
///
public static GZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
- fileInfo.CheckNotNull(nameof(fileInfo));
+ fileInfo.NotNull(nameof(fileInfo));
return new GZipArchive(
new SourceStream(
fileInfo,
@@ -52,7 +52,7 @@ public static GZipArchive Open(
ReaderOptions? readerOptions = null
)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var files = fileInfos.ToArray();
return new GZipArchive(
new SourceStream(
@@ -70,7 +70,7 @@ public static GZipArchive Open(
///
public static GZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var strms = streams.ToArray();
return new GZipArchive(
new SourceStream(
@@ -88,7 +88,7 @@ public static GZipArchive Open(IEnumerable streams, ReaderOptions? reade
///
public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
index 3d1daa1a3..bda1e3580 100644
--- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs
@@ -25,7 +25,7 @@ public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWrite
using (entryStream)
{
using Stream s = new ListeningStream(streamListener, entryStream);
- s.TransferTo(streamToWriteTo);
+ s.CopyTo(streamToWriteTo);
}
streamListener.FireEntryExtractionEnd(archiveEntry);
}
diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs
index ee4be60e9..b3689a9f5 100644
--- a/src/SharpCompress/Archives/Rar/RarArchive.cs
+++ b/src/SharpCompress/Archives/Rar/RarArchive.cs
@@ -95,7 +95,7 @@ protected override IReader CreateReaderForSolidExtraction()
///
public static RarArchive Open(string filePath, ReaderOptions? options = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
var fileInfo = new FileInfo(filePath);
return new RarArchive(
new SourceStream(
@@ -113,7 +113,7 @@ public static RarArchive Open(string filePath, ReaderOptions? options = null)
///
public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null)
{
- fileInfo.CheckNotNull(nameof(fileInfo));
+ fileInfo.NotNull(nameof(fileInfo));
return new RarArchive(
new SourceStream(
fileInfo,
@@ -130,7 +130,7 @@ public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null)
///
public static RarArchive Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
@@ -150,7 +150,7 @@ public static RarArchive Open(
ReaderOptions? readerOptions = null
)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var files = fileInfos.ToArray();
return new RarArchive(
new SourceStream(
@@ -168,7 +168,7 @@ public static RarArchive Open(
///
public static RarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var strms = streams.ToArray();
return new RarArchive(
new SourceStream(
diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
index 323f07ac7..ea763409d 100644
--- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
+++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs
@@ -21,7 +21,7 @@ public class SevenZipArchive : AbstractArchive
public static SevenZipArchive Open(string filePath, ReaderOptions? readerOptions = null)
{
- filePath.CheckNotNullOrEmpty("filePath");
+ filePath.NotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
@@ -32,7 +32,7 @@ public static SevenZipArchive Open(string filePath, ReaderOptions? readerOptions
///
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
- fileInfo.CheckNotNull("fileInfo");
+ fileInfo.NotNull("fileInfo");
return new SevenZipArchive(
new SourceStream(
fileInfo,
@@ -52,7 +52,7 @@ public static SevenZipArchive Open(
ReaderOptions? readerOptions = null
)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var files = fileInfos.ToArray();
return new SevenZipArchive(
new SourceStream(
@@ -73,7 +73,7 @@ public static SevenZipArchive Open(
ReaderOptions? readerOptions = null
)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var strms = streams.ToArray();
return new SevenZipArchive(
new SourceStream(
@@ -91,7 +91,7 @@ public static SevenZipArchive Open(
///
public static SevenZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
- stream.CheckNotNull("stream");
+ stream.NotNull("stream");
if (stream is not { CanSeek: true })
{
diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs
index 2c9c64c72..39f0fce6a 100644
--- a/src/SharpCompress/Archives/Tar/TarArchive.cs
+++ b/src/SharpCompress/Archives/Tar/TarArchive.cs
@@ -22,7 +22,7 @@ public class TarArchive : AbstractWritableArchive
///
public static TarArchive Open(string filePath, ReaderOptions? readerOptions = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
@@ -33,7 +33,7 @@ public static TarArchive Open(string filePath, ReaderOptions? readerOptions = nu
///
public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
- fileInfo.CheckNotNull(nameof(fileInfo));
+ fileInfo.NotNull(nameof(fileInfo));
return new TarArchive(
new SourceStream(
fileInfo,
@@ -53,7 +53,7 @@ public static TarArchive Open(
ReaderOptions? readerOptions = null
)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var files = fileInfos.ToArray();
return new TarArchive(
new SourceStream(
@@ -71,7 +71,7 @@ public static TarArchive Open(
///
public static TarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var strms = streams.ToArray();
return new TarArchive(
new SourceStream(
@@ -89,7 +89,7 @@ public static TarArchive Open(IEnumerable streams, ReaderOptions? reader
///
public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
@@ -178,7 +178,7 @@ var header in TarHeaderFactory.ReadHeader(
using (var entryStream = entry.OpenEntryStream())
{
using var memoryStream = new MemoryStream();
- entryStream.TransferTo(memoryStream);
+ entryStream.CopyTo(memoryStream);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs
index a75b40954..35b8e0cb1 100644
--- a/src/SharpCompress/Archives/Zip/ZipArchive.cs
+++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs
@@ -43,7 +43,7 @@ internal ZipArchive(SourceStream sourceStream)
///
public static ZipArchive Open(string filePath, ReaderOptions? readerOptions = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
@@ -54,7 +54,7 @@ public static ZipArchive Open(string filePath, ReaderOptions? readerOptions = nu
///
public static ZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
{
- fileInfo.CheckNotNull(nameof(fileInfo));
+ fileInfo.NotNull(nameof(fileInfo));
return new ZipArchive(
new SourceStream(
fileInfo,
@@ -74,7 +74,7 @@ public static ZipArchive Open(
ReaderOptions? readerOptions = null
)
{
- fileInfos.CheckNotNull(nameof(fileInfos));
+ fileInfos.NotNull(nameof(fileInfos));
var files = fileInfos.ToArray();
return new ZipArchive(
new SourceStream(
@@ -92,7 +92,7 @@ public static ZipArchive Open(
///
public static ZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
var strms = streams.ToArray();
return new ZipArchive(
new SourceStream(
@@ -110,7 +110,7 @@ public static ZipArchive Open(IEnumerable streams, ReaderOptions? reader
///
public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs
index 2ba0d80cc..106caff9c 100644
--- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs
+++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs
@@ -413,7 +413,7 @@ private void UnpWriteBuf()
else
//x memcpy(Mem,Window+BlockStart,BlockLength);
{
- Utility.Copy(Window, BlockStart, Mem, 0, BlockLength);
+ Buffer.BlockCopy(Window, (int)BlockStart, Mem, 0, (int)BlockLength);
}
}
else
@@ -427,9 +427,21 @@ private void UnpWriteBuf()
else
{
//x memcpy(Mem,Window+BlockStart,FirstPartLength);
- Utility.Copy(Window, BlockStart, Mem, 0, FirstPartLength);
+ Buffer.BlockCopy(
+ Window,
+ (int)BlockStart,
+ Mem,
+ 0,
+ (int)FirstPartLength
+ );
//x memcpy(Mem+FirstPartLength,Window,BlockEnd);
- Utility.Copy(Window, 0, Mem, FirstPartLength, BlockEnd);
+ Buffer.BlockCopy(
+ Window,
+ 0,
+ Mem,
+ (int)FirstPartLength,
+ (int)BlockEnd
+ );
}
}
diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs
index 1b9e23e96..2462f6148 100644
--- a/src/SharpCompress/Factories/Factory.cs
+++ b/src/SharpCompress/Factories/Factory.cs
@@ -34,7 +34,7 @@ static Factory()
/// must not be null.
public static void RegisterFactory(Factory factory)
{
- factory.CheckNotNull(nameof(factory));
+ factory.NotNull(nameof(factory));
_factories.Add(factory);
}
diff --git a/src/SharpCompress/LazyReadOnlyCollection.cs b/src/SharpCompress/LazyReadOnlyCollection.cs
index 9c1b35ebc..cc9cb3fdc 100644
--- a/src/SharpCompress/LazyReadOnlyCollection.cs
+++ b/src/SharpCompress/LazyReadOnlyCollection.cs
@@ -4,7 +4,7 @@
using System.Collections;
using System.Collections.Generic;
-namespace SharpCompress.Helpers;
+namespace SharpCompress;
internal sealed class LazyReadOnlyCollection : ICollection
{
diff --git a/src/SharpCompress/NotNullExtensions.cs b/src/SharpCompress/NotNullExtensions.cs
index 2245612e9..38e6d6d6d 100644
--- a/src/SharpCompress/NotNullExtensions.cs
+++ b/src/SharpCompress/NotNullExtensions.cs
@@ -4,20 +4,19 @@
using System.Linq;
using System.Runtime.CompilerServices;
-namespace SharpCompress.Helpers;
+namespace SharpCompress;
internal static class NotNullExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IEnumerable Empty(this IEnumerable? source) =>
- source ?? Enumerable.Empty();
+ public static IEnumerable Empty(this IEnumerable? source) => source ?? [];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable Empty(this T? source)
{
if (source is null)
{
- return Enumerable.Empty();
+ return [];
}
return source.AsEnumerable();
}
@@ -68,4 +67,14 @@ public static T NotNull(
return obj.Value;
}
#endif
+
+ public static string NotNullOrEmpty(this string obj, string name)
+ {
+ obj.NotNull(name);
+ if (obj.Length == 0)
+ {
+ throw new ArgumentException("String is empty.", name);
+ }
+ return obj;
+ }
}
diff --git a/src/SharpCompress/Readers/Arc/ArcReader.cs b/src/SharpCompress/Readers/Arc/ArcReader.cs
index 7d58b8d42..b7cf54675 100644
--- a/src/SharpCompress/Readers/Arc/ArcReader.cs
+++ b/src/SharpCompress/Readers/Arc/ArcReader.cs
@@ -24,7 +24,7 @@ private ArcReader(Stream stream, ReaderOptions options)
///
public static ArcReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
return new ArcReader(stream, options ?? new ReaderOptions());
}
diff --git a/src/SharpCompress/Readers/GZip/GZipReader.cs b/src/SharpCompress/Readers/GZip/GZipReader.cs
index 73bc4a9d3..e10d509a6 100644
--- a/src/SharpCompress/Readers/GZip/GZipReader.cs
+++ b/src/SharpCompress/Readers/GZip/GZipReader.cs
@@ -22,7 +22,7 @@ private GZipReader(Stream stream, ReaderOptions options)
///
public static GZipReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
return new GZipReader(stream, options ?? new ReaderOptions());
}
diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs
index 2a56ee35d..79842e6ab 100644
--- a/src/SharpCompress/Readers/Rar/RarReader.cs
+++ b/src/SharpCompress/Readers/Rar/RarReader.cs
@@ -42,7 +42,7 @@ public override void Dispose()
public static RarReader Open(string filePath, ReaderOptions? options = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), options);
}
@@ -71,7 +71,7 @@ public static RarReader Open(IEnumerable fileInfos, ReaderOptions? opt
///
public static RarReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
return new SingleVolumeRarReader(stream, options ?? new ReaderOptions());
}
@@ -83,7 +83,7 @@ public static RarReader Open(Stream stream, ReaderOptions? options = null)
///
public static RarReader Open(IEnumerable streams, ReaderOptions? options = null)
{
- streams.CheckNotNull(nameof(streams));
+ streams.NotNull(nameof(streams));
return new MultiVolumeRarReader(streams, options ?? new ReaderOptions());
}
diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs
index 9830c8fb5..97846380c 100644
--- a/src/SharpCompress/Readers/ReaderFactory.cs
+++ b/src/SharpCompress/Readers/ReaderFactory.cs
@@ -11,7 +11,7 @@ public static class ReaderFactory
{
public static IReader Open(string filePath, ReaderOptions? options = null)
{
- filePath.CheckNotNullOrEmpty(nameof(filePath));
+ filePath.NotNullOrEmpty(nameof(filePath));
return Open(new FileInfo(filePath), options);
}
@@ -29,7 +29,7 @@ public static IReader Open(FileInfo fileInfo, ReaderOptions? options = null)
///
public static IReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
options ??= new ReaderOptions() { LeaveStreamOpen = false };
var bStream = new SharpCompressStream(stream, bufferSize: options.BufferSize);
diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs
index aaa0005ca..c92188856 100644
--- a/src/SharpCompress/Readers/Tar/TarReader.cs
+++ b/src/SharpCompress/Readers/Tar/TarReader.cs
@@ -55,7 +55,7 @@ protected override Stream RequestInitialStream()
///
public static TarReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
options = options ?? new ReaderOptions();
var rewindableStream = new SharpCompressStream(stream);
diff --git a/src/SharpCompress/Readers/Zip/ZipReader.cs b/src/SharpCompress/Readers/Zip/ZipReader.cs
index cda3f3f86..5e82479ce 100644
--- a/src/SharpCompress/Readers/Zip/ZipReader.cs
+++ b/src/SharpCompress/Readers/Zip/ZipReader.cs
@@ -44,7 +44,7 @@ private ZipReader(Stream stream, ReaderOptions options, IEnumerable en
///
public static ZipReader Open(Stream stream, ReaderOptions? options = null)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
return new ZipReader(stream, options ?? new ReaderOptions());
}
@@ -54,7 +54,7 @@ public static ZipReader Open(
IEnumerable entries
)
{
- stream.CheckNotNull(nameof(stream));
+ stream.NotNull(nameof(stream));
return new ZipReader(stream, options ?? new ReaderOptions(), entries);
}
diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs
index 74974850c..19e132d59 100644
--- a/src/SharpCompress/Utility.cs
+++ b/src/SharpCompress/Utility.cs
@@ -1,4 +1,3 @@
-global using SharpCompress.Helpers;
using System;
using System.Buffers;
using System.Collections.Generic;
@@ -7,10 +6,14 @@
using System.Text;
using SharpCompress.Readers;
-namespace SharpCompress.Helpers;
+namespace SharpCompress;
internal static class Utility
{
+ //80kb is a good industry standard temporary buffer size
+ private const int TEMP_BUFFER_SIZE = 81920;
+ private static readonly HashSet invalidChars = new(Path.GetInvalidFileNameChars());
+
public static ReadOnlyCollection ToReadOnly(this IList items) => new(items);
///
@@ -68,60 +71,11 @@ public static void ForEach(this IEnumerable items, Action action)
}
}
- public static void Copy(
- Array sourceArray,
- long sourceIndex,
- Array destinationArray,
- long destinationIndex,
- long length
- )
- {
- if (sourceIndex > int.MaxValue || sourceIndex < int.MinValue)
- {
- throw new ArgumentOutOfRangeException(nameof(sourceIndex));
- }
-
- if (destinationIndex > int.MaxValue || destinationIndex < int.MinValue)
- {
- throw new ArgumentOutOfRangeException(nameof(destinationIndex));
- }
-
- if (length > int.MaxValue || length < int.MinValue)
- {
- throw new ArgumentOutOfRangeException(nameof(length));
- }
-
- Array.Copy(
- sourceArray,
- (int)sourceIndex,
- destinationArray,
- (int)destinationIndex,
- (int)length
- );
- }
-
public static IEnumerable AsEnumerable(this T item)
{
yield return item;
}
- public static void CheckNotNull(this object obj, string name)
- {
- if (obj is null)
- {
- throw new ArgumentNullException(name);
- }
- }
-
- public static void CheckNotNullOrEmpty(this string obj, string name)
- {
- obj.CheckNotNull(name);
- if (obj.Length == 0)
- {
- throw new ArgumentException("String is empty.", name);
- }
- }
-
public static void Skip(this Stream source, long advanceAmount)
{
if (source.CanSeek)
@@ -130,79 +84,23 @@ public static void Skip(this Stream source, long advanceAmount)
return;
}
- var buffer = GetTransferByteArray();
- try
+ using var buffer = MemoryPool.Shared.Rent(TEMP_BUFFER_SIZE);
+ while (advanceAmount > 0)
{
- var read = 0;
- var readCount = 0;
- do
+ var toRead = (int)Math.Min(buffer.Memory.Length, advanceAmount);
+ var read = source.Read(buffer.Memory.Slice(0, toRead).Span);
+ if (read <= 0)
{
- readCount = buffer.Length;
- if (readCount > advanceAmount)
- {
- readCount = (int)advanceAmount;
- }
- read = source.Read(buffer, 0, readCount);
- if (read <= 0)
- {
- break;
- }
- advanceAmount -= read;
- if (advanceAmount == 0)
- {
- break;
- }
- } while (true);
- }
- finally
- {
- ArrayPool.Shared.Return(buffer);
+ break;
+ }
+ advanceAmount -= read;
}
}
public static void Skip(this Stream source)
{
- var buffer = GetTransferByteArray();
- try
- {
- do { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length);
- }
- finally
- {
- ArrayPool.Shared.Return(buffer);
- }
- }
-
- public static bool Find(this Stream source, byte[] array)
- {
- var buffer = GetTransferByteArray();
- try
- {
- var count = 0;
- var len = source.Read(buffer, 0, buffer.Length);
-
- do
- {
- for (var i = 0; i < len; i++)
- {
- if (array[count] == buffer[i])
- {
- count++;
- if (count == array.Length)
- {
- source.Position = source.Position - len + i - array.Length + 1;
- return true;
- }
- }
- }
- } while ((len = source.Read(buffer, 0, buffer.Length)) > 0);
- }
- finally
- {
- ArrayPool.Shared.Return(buffer);
- }
-
- return false;
+ using var buffer = MemoryPool.Shared.Rent(TEMP_BUFFER_SIZE);
+ while (source.Read(buffer.Memory.Span) > 0) { }
}
public static DateTime DosDateToDateTime(ushort iDate, ushort iTime)
@@ -271,31 +169,12 @@ public static DateTime UnixTimeToDateTime(long unixtime)
return sTime.AddSeconds(unixtime);
}
- public static long TransferTo(this Stream source, Stream destination)
- {
- var array = GetTransferByteArray();
- try
- {
- long total = 0;
- while (ReadTransferBlock(source, array, out var count))
- {
- destination.Write(array, 0, count);
- total += count;
- }
- return total;
- }
- finally
- {
- ArrayPool.Shared.Return(array);
- }
- }
-
public static long TransferTo(this Stream source, Stream destination, long maxLength)
{
- var array = GetTransferByteArray();
- var maxReadSize = array.Length;
+ var array = ArrayPool.Shared.Rent(TEMP_BUFFER_SIZE);
try
{
+ var maxReadSize = array.Length;
long total = 0;
var remaining = maxLength;
if (remaining < maxReadSize)
@@ -331,12 +210,13 @@ public static long TransferTo(
IReaderExtractionListener readerExtractionListener
)
{
- var array = GetTransferByteArray();
+ var array = ArrayPool.Shared.Rent(TEMP_BUFFER_SIZE);
try
{
var iterations = 0;
long total = 0;
- while (ReadTransferBlock(source, array, out var count))
+ int count;
+ while ((count = source.Read(array, 0, array.Length)) != 0)
{
total += count;
destination.Write(array, 0, count);
@@ -351,12 +231,10 @@ IReaderExtractionListener readerExtractionListener
}
}
- private static bool ReadTransferBlock(Stream source, byte[] array, out int count) =>
- (count = source.Read(array, 0, array.Length)) != 0;
-
- private static bool ReadTransferBlock(Stream source, byte[] array, int size, out int count)
+ private static bool ReadTransferBlock(Stream source, byte[] array, int maxSize, out int count)
{
- if (size > array.Length)
+ var size = maxSize;
+ if (maxSize > array.Length)
{
size = array.Length;
}
@@ -364,8 +242,34 @@ private static bool ReadTransferBlock(Stream source, byte[] array, int size, out
return count != 0;
}
- private static byte[] GetTransferByteArray() => ArrayPool.Shared.Rent(81920);
+#if NET60_OR_GREATER
+ public static bool ReadFully(this Stream stream, byte[] buffer)
+ {
+ try
+ {
+ stream.ReadExactly(buffer);
+ return true;
+ }
+ catch (EndOfStreamException)
+ {
+ return false;
+ }
+ }
+
+ public static bool ReadFully(this Stream stream, Span buffer)
+ {
+ try
+ {
+ stream.ReadExactly(buffer);
+ return true;
+ }
+ catch (EndOfStreamException)
+ {
+ return false;
+ }
+ }
+#else
public static bool ReadFully(this Stream stream, byte[] buffer)
{
var total = 0;
@@ -395,6 +299,7 @@ public static bool ReadFully(this Stream stream, Span buffer)
}
return (total >= buffer.Length);
}
+#endif
public static string TrimNulls(this string source) => source.Replace('\0', ' ').Trim();
@@ -439,7 +344,6 @@ public static void SetBigUInt32(ref byte[] buffer, uint number, long offset)
public static string ReplaceInvalidFileNameChars(string fileName)
{
- var invalidChars = new HashSet(Path.GetInvalidFileNameChars());
var sb = new StringBuilder(fileName.Length);
foreach (var c in fileName)
{
diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.cs b/src/SharpCompress/Writers/GZip/GZipWriter.cs
index 4fbf1bb90..7dd4a7de0 100644
--- a/src/SharpCompress/Writers/GZip/GZipWriter.cs
+++ b/src/SharpCompress/Writers/GZip/GZipWriter.cs
@@ -47,7 +47,7 @@ public override void Write(string filename, Stream source, DateTime? modificatio
var stream = (GZipStream)OutputStream;
stream.FileName = filename;
stream.LastModified = modificationTime;
- source.TransferTo(stream);
+ source.CopyTo(stream);
_wroteToStream = true;
}
}
diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs
index 55abe4405..f15728230 100644
--- a/src/SharpCompress/Writers/Zip/ZipWriter.cs
+++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs
@@ -83,7 +83,7 @@ public override void Write(string entryPath, Stream source, DateTime? modificati
public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions)
{
using var output = WriteToStream(entryPath, zipWriterEntryOptions);
- source.TransferTo(output);
+ source.CopyTo(output);
}
public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options)
diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs
index d7c02d2d7..64d69d545 100644
--- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs
+++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs
@@ -223,7 +223,7 @@ private void DoRar_Entry_Stream(string filename)
var destinationFileName = Path.Combine(destdir, file);
using var fs = File.OpenWrite(destinationFileName);
- entryStream.TransferTo(fs);
+ entryStream.CopyTo(fs);
}
}
}
diff --git a/tests/SharpCompress.Test/SharpCompress.Test.csproj b/tests/SharpCompress.Test/SharpCompress.Test.csproj
index f5516b915..2afb99380 100644
--- a/tests/SharpCompress.Test/SharpCompress.Test.csproj
+++ b/tests/SharpCompress.Test/SharpCompress.Test.csproj
@@ -9,6 +9,9 @@
$(DefineConstants);DEBUG_STREAMS
+
+ $(DefineConstants);WINDOWS
+
@@ -17,7 +20,6 @@
-
diff --git a/tests/SharpCompress.Test/Tar/TarReaderTests.cs b/tests/SharpCompress.Test/Tar/TarReaderTests.cs
index a676d2dae..88c30cfa9 100644
--- a/tests/SharpCompress.Test/Tar/TarReaderTests.cs
+++ b/tests/SharpCompress.Test/Tar/TarReaderTests.cs
@@ -85,7 +85,7 @@ public void Tar_BZip2_Entry_Stream()
var destinationFileName = Path.Combine(destdir, file.NotNull());
using var fs = File.OpenWrite(destinationFileName);
- entryStream.TransferTo(fs);
+ entryStream.CopyTo(fs);
}
}
}
diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs
index f9cfb8a3b..184e64420 100644
--- a/tests/SharpCompress.Test/TestBase.cs
+++ b/tests/SharpCompress.Test/TestBase.cs
@@ -1,4 +1,3 @@
-global using SharpCompress.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/tests/SharpCompress.Test/UtilityTests.cs b/tests/SharpCompress.Test/UtilityTests.cs
new file mode 100644
index 000000000..cbd573042
--- /dev/null
+++ b/tests/SharpCompress.Test/UtilityTests.cs
@@ -0,0 +1,754 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace SharpCompress.Test;
+
+public class UtilityTests
+{
+ #region URShift Tests
+
+ [Fact]
+ public void URShift_Int_PositiveNumber_ShiftsCorrectly()
+ {
+ var result = Utility.URShift(16, 2);
+ Assert.Equal(4, result);
+ }
+
+ [Fact]
+ public void URShift_Int_NegativeNumber_PerformsUnsignedShift()
+ {
+ // -1 in binary is all 1s (0xFFFFFFFF), shifted right by 1 should be 0x7FFFFFFF
+ var result = Utility.URShift(-1, 1);
+ Assert.Equal(int.MaxValue, result);
+ }
+
+ [Fact]
+ public void URShift_Int_Zero_ReturnsZero()
+ {
+ var result = Utility.URShift(0, 5);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public void URShift_Long_PositiveNumber_ShiftsCorrectly()
+ {
+ var result = Utility.URShift(32L, 3);
+ Assert.Equal(4L, result);
+ }
+
+ [Fact]
+ public void URShift_Long_NegativeNumber_PerformsUnsignedShift()
+ {
+ var result = Utility.URShift(-1L, 1);
+ Assert.Equal(long.MaxValue, result);
+ }
+
+ [Fact]
+ public void URShift_Long_Zero_ReturnsZero()
+ {
+ var result = Utility.URShift(0L, 10);
+ Assert.Equal(0L, result);
+ }
+
+ #endregion
+
+ #region ReadFully Tests
+
+ [Fact]
+ public void ReadFully_ByteArray_ReadsExactlyRequiredBytes()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+ var buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.True(result);
+ Assert.Equal(data, buffer);
+ }
+
+ [Fact]
+ public void ReadFully_ByteArray_ReturnsFalseWhenNotEnoughData()
+ {
+ var data = new byte[] { 1, 2, 3 };
+ using var stream = new MemoryStream(data);
+ var buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void ReadFully_ByteArray_EmptyStream_ReturnsFalse()
+ {
+ using var stream = new MemoryStream();
+ var buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void ReadFully_ByteArray_EmptyBuffer_ReturnsTrue()
+ {
+ var data = new byte[] { 1, 2, 3 };
+ using var stream = new MemoryStream(data);
+ var buffer = new byte[0];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void ReadFully_Span_ReadsExactlyRequiredBytes()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+ Span buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.True(result);
+ Assert.Equal(data, buffer.ToArray());
+ }
+
+ [Fact]
+ public void ReadFully_Span_ReturnsFalseWhenNotEnoughData()
+ {
+ var data = new byte[] { 1, 2, 3 };
+ using var stream = new MemoryStream(data);
+ Span buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void ReadFully_Span_EmptyStream_ReturnsFalse()
+ {
+ using var stream = new MemoryStream();
+ Span buffer = new byte[5];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void ReadFully_Span_EmptyBuffer_ReturnsTrue()
+ {
+ var data = new byte[] { 1, 2, 3 };
+ using var stream = new MemoryStream(data);
+ Span buffer = new byte[0];
+
+ var result = stream.ReadFully(buffer);
+
+ Assert.True(result);
+ }
+
+ #endregion
+
+ #region Skip Tests
+
+ [Fact]
+ public void Skip_SeekableStream_UsesSeek()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+
+ stream.Skip(3);
+
+ Assert.Equal(3, stream.Position);
+ }
+
+ [Fact]
+ public void Skip_SeekableStream_SkipsCorrectAmount()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+
+ stream.Skip(2);
+ var buffer = new byte[2];
+ stream.Read(buffer);
+
+ Assert.Equal(new byte[] { 3, 4 }, buffer);
+ }
+
+ [Fact]
+ public void Skip_NonSeekableStream_SkipsCorrectAmount()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var seekableStream = new MemoryStream(data);
+ using var nonSeekableStream = new NonSeekableStream(seekableStream);
+
+ nonSeekableStream.Skip(2);
+ var buffer = new byte[2];
+ nonSeekableStream.Read(buffer);
+
+ Assert.Equal(new byte[] { 3, 4 }, buffer);
+ }
+
+ [Fact]
+ public void Skip_NonSeekableStream_SkipsBeyondStreamEnd()
+ {
+ var data = new byte[] { 1, 2, 3 };
+ using var seekableStream = new MemoryStream(data);
+ using var nonSeekableStream = new NonSeekableStream(seekableStream);
+
+ // Should not throw, just skip what's available
+ nonSeekableStream.Skip(10);
+
+ Assert.Equal(-1, nonSeekableStream.ReadByte());
+ }
+
+ [Fact]
+ public void Skip_Parameterless_SkipsEntireStream()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+
+ stream.Skip();
+
+ Assert.Equal(-1, stream.ReadByte());
+ }
+
+ [Fact]
+ public void Skip_Zero_DoesNotMove()
+ {
+ var data = new byte[] { 1, 2, 3, 4, 5 };
+ using var stream = new MemoryStream(data);
+ stream.Position = 2;
+
+ stream.Skip(0);
+
+ Assert.Equal(2, stream.Position);
+ }
+
+ #endregion
+
+ #region SetSize Tests
+
+ [Fact]
+ public void SetSize_GrowsList_AddsZeroBytes()
+ {
+ var list = new List { 1, 2, 3 };
+
+ Utility.SetSize(list, 5);
+
+ Assert.Equal(5, list.Count);
+ Assert.Equal(new byte[] { 1, 2, 3, 0, 0 }, list);
+ }
+
+ [Fact]
+ public void SetSize_ShrinksListByOne()
+ {
+ var list = new List { 1, 2, 3, 4, 5 };
+
+ Utility.SetSize(list, 3);
+
+ Assert.Equal(3, list.Count);
+ Assert.Equal(new byte[] { 1, 2, 3 }, list);
+ }
+
+ [Fact]
+ public void SetSize_ToZero_ClearsAllItems()
+ {
+ var list = new List { 1, 2, 3 };
+
+ Utility.SetSize(list, 0);
+
+ Assert.Empty(list);
+ }
+
+ [Fact]
+ public void SetSize_SameSize_NoChange()
+ {
+ var list = new List { 1, 2, 3 };
+
+ Utility.SetSize(list, 3);
+
+ Assert.Equal(3, list.Count);
+ Assert.Equal(new byte[] { 1, 2, 3 }, list);
+ }
+
+ #endregion
+
+ #region ForEach Tests
+
+ [Fact]
+ public void ForEach_ExecutesActionForEachItem()
+ {
+ var items = new[] { 1, 2, 3, 4, 5 };
+ var results = new List();
+
+ items.ForEach(x => results.Add(x));
+
+ Assert.Equal(items, results);
+ }
+
+ [Fact]
+ public void ForEach_EmptyCollection_NoExecutions()
+ {
+ var items = Array.Empty();
+ var count = 0;
+
+ items.ForEach(x => count++);
+
+ Assert.Equal(0, count);
+ }
+
+ #endregion
+
+ #region AsEnumerable Tests
+
+ [Fact]
+ public void AsEnumerable_SingleItem_YieldsItem()
+ {
+ var item = 42;
+
+ var result = item.AsEnumerable().ToList();
+
+ Assert.Single(result);
+ Assert.Equal(42, result[0]);
+ }
+
+ [Fact]
+ public void AsEnumerable_String_YieldsString()
+ {
+ var item = "test";
+
+ var result = item.AsEnumerable().ToList();
+
+ Assert.Single(result);
+ Assert.Equal("test", result[0]);
+ }
+
+ #endregion
+
+ #region DosDateToDateTime Tests
+
+ [Fact]
+ public void DosDateToDateTime_ValidDate_ConvertsCorrectly()
+ {
+ // DOS date format: year (7 bits) | month (4 bits) | day (5 bits)
+ // DOS time format: hour (5 bits) | minute (6 bits) | second (5 bits, in 2-second increments)
+ // This represents: 2020-01-15 10:30:20 (approximately)
+ ushort dosDate = (ushort)(((2020 - 1980) << 9) | (1 << 5) | 15); // 2020-01-15
+ ushort dosTime = (ushort)((10 << 11) | (30 << 5) | 10); // 10:30:20
+
+ var result = Utility.DosDateToDateTime(dosDate, dosTime);
+
+ Assert.Equal(2020, result.Year);
+ Assert.Equal(1, result.Month);
+ Assert.Equal(15, result.Day);
+ Assert.Equal(10, result.Hour);
+ Assert.Equal(30, result.Minute);
+ Assert.Equal(20, result.Second);
+ }
+
+ [Fact]
+ public void DosDateToDateTime_InvalidDate_DefaultsTo1980_01_01()
+ {
+ ushort dosDate = ushort.MaxValue;
+ ushort dosTime = (ushort)((10 << 11) | (30 << 5) | 10);
+
+ var result = Utility.DosDateToDateTime(dosDate, dosTime);
+
+ Assert.Equal(1980, result.Year);
+ Assert.Equal(1, result.Month);
+ Assert.Equal(1, result.Day);
+ }
+
+ [Fact]
+ public void DosDateToDateTime_InvalidTime_DefaultsToMidnight()
+ {
+ ushort dosDate = (ushort)(((2020 - 1980) << 9) | (1 << 5) | 15);
+ ushort dosTime = ushort.MaxValue;
+
+ var result = Utility.DosDateToDateTime(dosDate, dosTime);
+
+ Assert.Equal(0, result.Hour);
+ Assert.Equal(0, result.Minute);
+ Assert.Equal(0, result.Second);
+ }
+
+ [Fact]
+ public void DosDateToDateTime_FromUint_ConvertsCorrectly()
+ {
+ ushort dosDate = (ushort)(((2020 - 1980) << 9) | (6 << 5) | 20); // 2020-06-20
+ ushort dosTime = (ushort)((14 << 11) | (45 << 5) | 15); // 14:45:30
+ uint combined = (uint)(dosDate << 16) | dosTime;
+
+ var result = Utility.DosDateToDateTime(combined);
+
+ Assert.Equal(2020, result.Year);
+ Assert.Equal(6, result.Month);
+ Assert.Equal(20, result.Day);
+ Assert.Equal(14, result.Hour);
+ Assert.Equal(45, result.Minute);
+ }
+
+ #endregion
+
+ #region DateTimeToDosTime Tests
+
+ [Fact]
+ public void DateTimeToDosTime_ValidDateTime_ConvertsCorrectly()
+ {
+ //always do local time
+ var dt = new DateTime(2020, 6, 15, 14, 30, 20, DateTimeKind.Local);
+
+ var result = Utility.DateTimeToDosTime(dt);
+
+ // Verify we can convert back
+ var reversed = Utility.DosDateToDateTime(result);
+ Assert.Equal(2020, reversed.Year);
+ Assert.Equal(6, reversed.Month);
+ Assert.Equal(15, reversed.Day);
+ Assert.Equal(14, reversed.Hour);
+ Assert.Equal(30, reversed.Minute);
+ // Seconds are rounded down to nearest even number in DOS format
+ Assert.True(reversed.Second == 20 || reversed.Second == 18);
+ }
+
+ [Fact]
+ public void DateTimeToDosTime_NullDateTime_ReturnsZero()
+ {
+ DateTime? dt = null;
+
+ var result = Utility.DateTimeToDosTime(dt);
+
+ Assert.Equal(0u, result);
+ }
+
+ #endregion
+
+ #region UnixTimeToDateTime Tests
+
+ [Fact]
+ public void UnixTimeToDateTime_Zero_Returns1970_01_01()
+ {
+ var result = Utility.UnixTimeToDateTime(0);
+
+ Assert.Equal(1970, result.Year);
+ Assert.Equal(1, result.Month);
+ Assert.Equal(1, result.Day);
+ Assert.Equal(0, result.Hour);
+ Assert.Equal(0, result.Minute);
+ Assert.Equal(0, result.Second);
+ }
+
+ [Fact]
+ public void UnixTimeToDateTime_ValidTimestamp_ConvertsCorrectly()
+ {
+ // January 1, 2000 00:00:00 UTC is 946684800 seconds after epoch
+ var result = Utility.UnixTimeToDateTime(946684800);
+
+ Assert.Equal(2000, result.Year);
+ Assert.Equal(1, result.Month);
+ Assert.Equal(1, result.Day);
+ }
+
+ [Fact]
+ public void UnixTimeToDateTime_NegativeTimestamp_ReturnsBeforeEpoch()
+ {
+ // -86400 is one day before epoch
+ var result = Utility.UnixTimeToDateTime(-86400);
+
+ Assert.Equal(1969, result.Year);
+ Assert.Equal(12, result.Month);
+ Assert.Equal(31, result.Day);
+ }
+
+ #endregion
+
+ #region TransferTo Tests
+
+ [Fact]
+ public void TransferTo_WithMaxLength_TransfersCorrectAmount()
+ {
+ var sourceData = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ using var source = new MemoryStream(sourceData);
+ using var destination = new MemoryStream();
+
+ var transferred = source.TransferTo(destination, 5);
+
+ Assert.Equal(5, transferred);
+ Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, destination.ToArray());
+ }
+
+ [Fact]
+ public void TransferTo_SourceSmallerThanMax_TransfersAll()
+ {
+ var sourceData = new byte[] { 1, 2, 3 };
+ using var source = new MemoryStream(sourceData);
+ using var destination = new MemoryStream();
+
+ var transferred = source.TransferTo(destination, 100);
+
+ Assert.Equal(3, transferred);
+ Assert.Equal(sourceData, destination.ToArray());
+ }
+
+ [Fact]
+ public void TransferTo_EmptySource_TransfersNothing()
+ {
+ using var source = new MemoryStream();
+ using var destination = new MemoryStream();
+
+ var transferred = source.TransferTo(destination, 100);
+
+ Assert.Equal(0, transferred);
+ Assert.Empty(destination.ToArray());
+ }
+
+ #endregion
+
+ #region SwapUINT32 Tests
+
+ [Fact]
+ public void SwapUINT32_SimpleValue_SwapsEndianness()
+ {
+ uint value = 0x12345678;
+
+ var result = Utility.SwapUINT32(value);
+
+ Assert.Equal(0x78563412u, result);
+ }
+
+ [Fact]
+ public void SwapUINT32_Zero_ReturnsZero()
+ {
+ var result = Utility.SwapUINT32(0);
+
+ Assert.Equal(0u, result);
+ }
+
+ [Fact]
+ public void SwapUINT32_MaxValue_SwapsCorrectly()
+ {
+ var result = Utility.SwapUINT32(uint.MaxValue);
+
+ Assert.Equal(uint.MaxValue, result);
+ }
+
+ [Fact]
+ public void SwapUINT32_Involution_SwappingTwiceReturnsOriginal()
+ {
+ uint value = 0x12345678;
+
+ var result = Utility.SwapUINT32(Utility.SwapUINT32(value));
+
+ Assert.Equal(value, result);
+ }
+
+ #endregion
+
+ #region SetLittleUInt32 Tests
+
+ [Fact]
+ public void SetLittleUInt32_InsertsValueCorrectly()
+ {
+ byte[] buffer = new byte[10];
+ uint value = 0x12345678;
+
+ Utility.SetLittleUInt32(ref buffer, value, 2);
+
+ Assert.Equal(0x78, buffer[2]);
+ Assert.Equal(0x56, buffer[3]);
+ Assert.Equal(0x34, buffer[4]);
+ Assert.Equal(0x12, buffer[5]);
+ }
+
+ [Fact]
+ public void SetLittleUInt32_AtOffset_InsertsBehindOffset()
+ {
+ byte[] buffer = new byte[10];
+ uint value = 0xDEADBEEF;
+
+ Utility.SetLittleUInt32(ref buffer, value, 5);
+
+ Assert.Equal(0xEF, buffer[5]);
+ Assert.Equal(0xBE, buffer[6]);
+ Assert.Equal(0xAD, buffer[7]);
+ Assert.Equal(0xDE, buffer[8]);
+ }
+
+ #endregion
+
+ #region SetBigUInt32 Tests
+
+ [Fact]
+ public void SetBigUInt32_InsertsValueCorrectly()
+ {
+ byte[] buffer = new byte[10];
+ uint value = 0x12345678;
+
+ Utility.SetBigUInt32(ref buffer, value, 2);
+
+ Assert.Equal(0x12, buffer[2]);
+ Assert.Equal(0x34, buffer[3]);
+ Assert.Equal(0x56, buffer[4]);
+ Assert.Equal(0x78, buffer[5]);
+ }
+
+ [Fact]
+ public void SetBigUInt32_AtOffset_InsertsBehindOffset()
+ {
+ byte[] buffer = new byte[10];
+ uint value = 0xDEADBEEF;
+
+ Utility.SetBigUInt32(ref buffer, value, 5);
+
+ Assert.Equal(0xDE, buffer[5]);
+ Assert.Equal(0xAD, buffer[6]);
+ Assert.Equal(0xBE, buffer[7]);
+ Assert.Equal(0xEF, buffer[8]);
+ }
+
+ #endregion
+
+ #region ReplaceInvalidFileNameChars Tests
+
+#if WINDOWS
+ [Theory]
+ [InlineData("valid_filename.txt", "valid_filename.txt")]
+ [InlineData("filetest.txt", "file_name_test.txt")]
+ [InlineData("<>:\"|?*", "_______")]
+ public void ReplaceInvalidFileNameChars_Windows(string fileName, string expected)
+ {
+ var result = Utility.ReplaceInvalidFileNameChars(fileName);
+
+ Assert.Equal(expected, result);
+ }
+
+#else
+ [Theory]
+ [InlineData("valid_filename.txt", "valid_filename.txt")]
+ [InlineData("filetest.txt", "filetest.txt")]
+ [InlineData("<>:\"|?*", "<>:\"|?*")]
+ public void ReplaceInvalidFileNameChars_NonWindows(string fileName, string expected)
+ {
+ var result = Utility.ReplaceInvalidFileNameChars(fileName);
+
+ Assert.Equal(expected, result);
+ }
+#endif
+
+ #endregion
+
+ #region ToReadOnly Tests
+
+ [Fact]
+ public void ToReadOnly_IList_ReturnsReadOnlyCollection()
+ {
+ var list = new List { 1, 2, 3, 4, 5 };
+
+ var result = list.ToReadOnly();
+
+ Assert.Equal(5, result.Count);
+ Assert.Equal(1, result[0]);
+ Assert.Equal(5, result[4]);
+ }
+
+ [Fact]
+ public void ToReadOnly_EmptyList_ReturnsEmptyReadOnlyCollection()
+ {
+ var list = new List();
+
+ var result = list.ToReadOnly();
+
+ Assert.Empty(result);
+ }
+
+ #endregion
+
+ #region TrimNulls Tests
+
+ [Fact]
+ public void TrimNulls_StringWithNulls_ReplacesAndTrims()
+ {
+ var input = " hello\0world\0 ";
+
+ var result = Utility.TrimNulls(input);
+
+ Assert.Equal("hello world", result);
+ }
+
+ [Fact]
+ public void TrimNulls_StringWithoutNulls_TrimsWhitespace()
+ {
+ var input = " hello world ";
+
+ var result = Utility.TrimNulls(input);
+
+ Assert.Equal("hello world", result);
+ }
+
+ [Fact]
+ public void TrimNulls_OnlyNulls_ReturnsEmpty()
+ {
+ var input = "\0\0\0";
+
+ var result = Utility.TrimNulls(input);
+
+ Assert.Empty(result);
+ }
+
+ #endregion
+}
+
+///
+/// Helper class for testing non-seekable streams
+///
+internal class NonSeekableStream : Stream
+{
+ private readonly Stream _inner;
+
+ public NonSeekableStream(Stream inner)
+ {
+ _inner = inner;
+ }
+
+ public override bool CanRead => _inner.CanRead;
+ public override bool CanSeek => false; // Force non-seekable
+ public override bool CanWrite => _inner.CanWrite;
+ public override long Length => _inner.Length;
+ public override long Position
+ {
+ get => _inner.Position;
+ set => throw new NotSupportedException("Stream is not seekable");
+ }
+
+ public override void Flush() => _inner.Flush();
+
+ public override int Read(byte[] buffer, int offset, int count) =>
+ _inner.Read(buffer, offset, count);
+
+ public override long Seek(long offset, SeekOrigin origin) =>
+ throw new NotSupportedException("Stream is not seekable");
+
+ public override void SetLength(long value) =>
+ throw new NotSupportedException("Stream is not seekable");
+
+ public override void Write(byte[] buffer, int offset, int count) =>
+ _inner.Write(buffer, offset, count);
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _inner.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+}
diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
index 53849e468..a2a1c0cca 100644
--- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
+++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
@@ -589,12 +589,10 @@ public void Zip_Deflate_PKWear_Multipy_Entry_Access()
}
}
- [SkippableFact]
- public void Zip_Evil_Throws_Exception()
+#if WINDOWS
+ [Fact]
+ public void Zip_Evil_Throws_Exception_Windows()
{
- //windows only because of the paths
- Skip.IfNot(Environment.OSVersion.Platform == PlatformID.Win32NT);
-
var zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.Evil.zip");
Assert.ThrowsAny(() =>
@@ -609,6 +607,7 @@ public void Zip_Evil_Throws_Exception()
}
});
}
+#endif
private class NonSeekableMemoryStream : MemoryStream
{
diff --git a/tests/SharpCompress.Test/packages.lock.json b/tests/SharpCompress.Test/packages.lock.json
index b789ce764..01daed881 100644
--- a/tests/SharpCompress.Test/packages.lock.json
+++ b/tests/SharpCompress.Test/packages.lock.json
@@ -49,16 +49,6 @@
"Microsoft.TestPlatform.ObjectModel": "17.13.0"
}
},
- "Xunit.SkippableFact": {
- "type": "Direct",
- "requested": "[1.5.23, )",
- "resolved": "1.5.23",
- "contentHash": "JlKobLTlsGcuJ8OtoodxL63bUagHSVBnF+oQ2GgnkwNqK+XYjeYyhQasULi5Ebx1MNDGNbOMplQYr89mR+nItQ==",
- "dependencies": {
- "Validation": "2.5.51",
- "xunit.extensibility.execution": "2.4.0"
- }
- },
"Microsoft.CodeCoverage": {
"type": "Transitive",
"resolved": "17.13.0",
@@ -108,11 +98,6 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
- "Validation": {
- "type": "Transitive",
- "resolved": "2.5.51",
- "contentHash": "g/Aug7PVWaenlJ0QUyt/mEetngkQNsMCuNeRVXbcJED1nZS7JcK+GTU4kz3jcQ7bFuKfi8PF4ExXH7XSFNuSLQ=="
- },
"xunit.abstractions": {
"type": "Transitive",
"resolved": "2.0.3",
@@ -247,16 +232,6 @@
"resolved": "3.1.5",
"contentHash": "tKi7dSTwP4m5m9eXPM2Ime4Kn7xNf4x4zT9sdLO/G4hZVnQCRiMTWoSZqI/pYTVeI27oPPqHBKYI/DjJ9GsYgA=="
},
- "Xunit.SkippableFact": {
- "type": "Direct",
- "requested": "[1.5.23, )",
- "resolved": "1.5.23",
- "contentHash": "JlKobLTlsGcuJ8OtoodxL63bUagHSVBnF+oQ2GgnkwNqK+XYjeYyhQasULi5Ebx1MNDGNbOMplQYr89mR+nItQ==",
- "dependencies": {
- "Validation": "2.5.51",
- "xunit.extensibility.execution": "2.4.0"
- }
- },
"Microsoft.CodeCoverage": {
"type": "Transitive",
"resolved": "17.13.0",
@@ -294,11 +269,6 @@
"resolved": "1.6.0",
"contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
},
- "Validation": {
- "type": "Transitive",
- "resolved": "2.5.51",
- "contentHash": "g/Aug7PVWaenlJ0QUyt/mEetngkQNsMCuNeRVXbcJED1nZS7JcK+GTU4kz3jcQ7bFuKfi8PF4ExXH7XSFNuSLQ=="
- },
"xunit.abstractions": {
"type": "Transitive",
"resolved": "2.0.3",