mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 13:34:59 +00:00
Compare commits
83 Commits
0.22
...
recycle-me
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6a6085d75 | ||
|
|
b5a897819d | ||
|
|
9e842ee8ec | ||
|
|
a04a0a5912 | ||
|
|
9540b01bcc | ||
|
|
446d6914c1 | ||
|
|
637223aa53 | ||
|
|
17d5565120 | ||
|
|
4b54187b4c | ||
|
|
cfb1421367 | ||
|
|
5072a0f6f5 | ||
|
|
357dff1403 | ||
|
|
a2bd66ded8 | ||
|
|
6bfa3c25a4 | ||
|
|
1ea9ab72c1 | ||
|
|
07c42b8725 | ||
|
|
70392c32e2 | ||
|
|
9b4b2a9f7c | ||
|
|
d3dd708b58 | ||
|
|
af264cdc58 | ||
|
|
cfd6df976f | ||
|
|
b2bd20b47e | ||
|
|
ffea093e95 | ||
|
|
78eb8fcf92 | ||
|
|
a052956881 | ||
|
|
9319ea6992 | ||
|
|
4e5b70dbfa | ||
|
|
c68eaa8397 | ||
|
|
bbb7c85ba7 | ||
|
|
8174359228 | ||
|
|
acf66c5195 | ||
|
|
880c9fa97a | ||
|
|
e5c111f2be | ||
|
|
4e9cd064dd | ||
|
|
12a6d3977e | ||
|
|
a95bbaf820 | ||
|
|
70bafa653b | ||
|
|
3f4338489c | ||
|
|
d91e58f2cc | ||
|
|
192b9c1e8b | ||
|
|
0941239454 | ||
|
|
53ad00cdc4 | ||
|
|
6dd5da48f7 | ||
|
|
efae8328a9 | ||
|
|
f1facc51de | ||
|
|
a471ca6a76 | ||
|
|
83f6690576 | ||
|
|
1850ea67f6 | ||
|
|
2fd6178aa9 | ||
|
|
ec044e6f42 | ||
|
|
bd96279649 | ||
|
|
f7ad595945 | ||
|
|
93c0b91de9 | ||
|
|
138038b08f | ||
|
|
e9a6fed607 | ||
|
|
87a1440382 | ||
|
|
3c2f4ebe9b | ||
|
|
933ffe7828 | ||
|
|
7d20ba5243 | ||
|
|
44dc36af48 | ||
|
|
98558c5ba9 | ||
|
|
6c25322465 | ||
|
|
6d1d62fd32 | ||
|
|
ee4ae661d7 | ||
|
|
0473ec1626 | ||
|
|
c6cf0d40ee | ||
|
|
4cd80e96f3 | ||
|
|
16524717ba | ||
|
|
cab1ce3d0c | ||
|
|
6c2e5e1164 | ||
|
|
c2bf540057 | ||
|
|
a35c66e166 | ||
|
|
084c5e2686 | ||
|
|
6ae715b153 | ||
|
|
9c8692806a | ||
|
|
2d87351d2a | ||
|
|
3114afde0e | ||
|
|
7b338511cc | ||
|
|
09c27681e1 | ||
|
|
4ebc1f82b7 | ||
|
|
4640ca497a | ||
|
|
bebccaae28 | ||
|
|
7ee53373c6 |
@@ -2,14 +2,15 @@ version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: microsoft/dotnet:2.1.301-sdk
|
||||
- image: mcr.microsoft.com/dotnet/core/sdk:2.2-alpine
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install unzip
|
||||
name: Install Cake
|
||||
command: |
|
||||
apt-get update
|
||||
apt-get install -y unzip
|
||||
dotnet tool install -g Cake.Tool
|
||||
echo 'export PATH=$PATH:/root/.dotnet/tools' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
- run:
|
||||
name: Build
|
||||
command: ./build.sh
|
||||
command: dotnet cake build.cake
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SharpCompress
|
||||
|
||||
SharpCompress is a compression library in pure C# for .NET 3.5, 4.5, .NET Standard 1.0, 1.3 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
|
||||
SharpCompress is a compression library in pure C# for .NET Standard 1.4 and 2.0 and .NET 4.6 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
|
||||
|
||||
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
54
build.cake
54
build.cake
@@ -11,32 +11,23 @@ Task("Build")
|
||||
.IsDependentOn("Restore")
|
||||
.Does(() =>
|
||||
{
|
||||
var settings = new DotNetCoreBuildSettings
|
||||
{
|
||||
Framework = "netstandard1.4",
|
||||
Configuration = "Release",
|
||||
NoRestore = true
|
||||
};
|
||||
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
|
||||
if (IsRunningOnWindows())
|
||||
{
|
||||
MSBuild("./sharpcompress.sln", c =>
|
||||
{
|
||||
c.SetConfiguration("Release")
|
||||
.SetVerbosity(Verbosity.Minimal)
|
||||
.UseToolVersion(MSBuildToolVersion.VS2017);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var settings = new DotNetCoreBuildSettings
|
||||
{
|
||||
Framework = "netstandard1.0",
|
||||
Configuration = "Release",
|
||||
NoRestore = true
|
||||
};
|
||||
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
|
||||
settings.Framework = "netstandard1.3";
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
|
||||
settings.Framework = "netstandard2.0";
|
||||
settings.Framework = "net46";
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
}
|
||||
|
||||
settings.Framework = "netstandard2.0";
|
||||
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
|
||||
});
|
||||
|
||||
Task("Test")
|
||||
@@ -49,7 +40,7 @@ Task("Test")
|
||||
var settings = new DotNetCoreTestSettings
|
||||
{
|
||||
Configuration = "Release",
|
||||
Framework = "netcoreapp2.1"
|
||||
Framework = "netcoreapp2.2"
|
||||
};
|
||||
DotNetCoreTest(file.ToString(), settings);
|
||||
}
|
||||
@@ -58,16 +49,17 @@ Task("Test")
|
||||
Task("Pack")
|
||||
.IsDependentOn("Build")
|
||||
.Does(() =>
|
||||
{
|
||||
{
|
||||
if (IsRunningOnWindows())
|
||||
{
|
||||
MSBuild("src/SharpCompress/SharpCompress.csproj", c => c
|
||||
.SetConfiguration("Release")
|
||||
.SetVerbosity(Verbosity.Minimal)
|
||||
.UseToolVersion(MSBuildToolVersion.VS2017)
|
||||
.WithProperty("NoBuild", "true")
|
||||
.WithTarget("Pack"));
|
||||
}
|
||||
var settings = new DotNetCorePackSettings
|
||||
{
|
||||
Configuration = "Release",
|
||||
NoBuild = true
|
||||
};
|
||||
|
||||
DotNetCorePack("src/SharpCompress/SharpCompress.csproj", settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
Information("Skipping Pack as this is not Windows");
|
||||
|
||||
@@ -23,8 +23,7 @@ namespace SharpCompress.Archives
|
||||
protected ReaderOptions ReaderOptions { get; }
|
||||
|
||||
private bool disposed;
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
{
|
||||
Type = type;
|
||||
@@ -40,7 +39,6 @@ namespace SharpCompress.Archives
|
||||
|
||||
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file);
|
||||
#endif
|
||||
|
||||
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, ReaderOptions readerOptions)
|
||||
{
|
||||
|
||||
@@ -28,12 +28,10 @@ namespace SharpCompress.Archives
|
||||
{
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerFactoryOptions)
|
||||
: base(type, fileInfo, readerFactoryOptions)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
public override ICollection<TEntry> Entries
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using SharpCompress.Archives.SevenZip;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives
|
||||
@@ -21,7 +20,7 @@ namespace SharpCompress.Archives
|
||||
/// <returns></returns>
|
||||
public static IArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
if (!stream.CanRead || !stream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("Stream should be readable and seekable");
|
||||
@@ -82,8 +81,6 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -91,8 +88,8 @@ namespace SharpCompress.Archives
|
||||
/// <param name="options"></param>
|
||||
public static IArchive Open(string filePath, ReaderOptions options = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options ?? new ReaderOptions());
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
return Open(new FileInfo(filePath), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,37 +99,32 @@ namespace SharpCompress.Archives
|
||||
/// <param name="options"></param>
|
||||
public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
options = options ?? new ReaderOptions();
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
options = options ?? new ReaderOptions { LeaveStreamOpen = false };
|
||||
using (var stream = fileInfo.OpenRead())
|
||||
{
|
||||
if (ZipArchive.IsZipFile(stream, null))
|
||||
{
|
||||
stream.Dispose();
|
||||
return ZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return SevenZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (GZipArchive.IsGZipFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return GZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, options))
|
||||
{
|
||||
stream.Dispose();
|
||||
return RarArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return TarArchive.Open(fileInfo, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
@@ -153,6 +145,5 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace SharpCompress.Archives.GZip
|
||||
{
|
||||
public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
{
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -22,7 +20,7 @@ namespace SharpCompress.Archives.GZip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -33,10 +31,9 @@ namespace SharpCompress.Archives.GZip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new GZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
@@ -45,7 +42,7 @@ namespace SharpCompress.Archives.GZip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new GZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -54,8 +51,6 @@ namespace SharpCompress.Archives.GZip
|
||||
return new GZipArchive();
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
@@ -100,7 +95,6 @@ namespace SharpCompress.Archives.GZip
|
||||
SaveTo(stream, new WriterOptions(CompressionType.GZip));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool IsGZipFile(Stream stream)
|
||||
{
|
||||
@@ -185,4 +179,4 @@ namespace SharpCompress.Archives.GZip
|
||||
return GZipReader.Open(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,10 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
streamListener.FireEntryExtractionEnd(archiveEntry);
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
@@ -65,6 +63,5 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
#if !NO_FILE
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IArchiveExtensions
|
||||
{
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchive archive, string destinationDirectory,
|
||||
ExtractionOptions options = null)
|
||||
{
|
||||
@@ -21,6 +16,5 @@ namespace SharpCompress.Archives
|
||||
entry.WriteToDirectory(destinationDirectory, options);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
#if !NO_FILE
|
||||
using System;
|
||||
#endif
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Writers;
|
||||
|
||||
@@ -8,8 +6,6 @@ namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IWritableArchiveExtensions
|
||||
{
|
||||
#if !NO_FILE
|
||||
|
||||
public static void AddEntry(this IWritableArchive writableArchive,
|
||||
string entryPath, string filePath)
|
||||
{
|
||||
@@ -39,11 +35,7 @@ namespace SharpCompress.Archives
|
||||
this IWritableArchive writableArchive,
|
||||
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
|
||||
{
|
||||
#if NET35
|
||||
foreach (var path in Directory.GetFiles(filePath, searchPattern, searchOption))
|
||||
#else
|
||||
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
|
||||
#endif
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
|
||||
@@ -58,6 +50,5 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
return writableArchive.AddEntry(key, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
#if !NO_FILE
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.IO;
|
||||
@@ -18,7 +17,7 @@ namespace SharpCompress.Archives.Rar
|
||||
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
|
||||
{
|
||||
FileInfo = fileInfo;
|
||||
FileParts = GetVolumeFileParts().ToReadOnly();
|
||||
FileParts = GetVolumeFileParts().ToArray().ToReadOnly();
|
||||
}
|
||||
|
||||
private static ReaderOptions FixOptions(ReaderOptions options)
|
||||
@@ -43,4 +42,3 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
@@ -25,4 +23,3 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -15,8 +15,6 @@ namespace SharpCompress.Archives.Rar
|
||||
internal Lazy<IRarUnpack> UnpackV2017 { get; } = new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack());
|
||||
internal Lazy<IRarUnpack> UnpackV1 { get; } = new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack());
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
@@ -31,7 +29,6 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
return RarArchiveVolumeFactory.GetParts(file, ReaderOptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes multiple seekable Streams for a multi-part archive
|
||||
@@ -63,9 +60,6 @@ namespace SharpCompress.Archives.Rar
|
||||
public override bool IsSolid => Volumes.First().IsSolidArchive;
|
||||
|
||||
#region Creation
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
@@ -73,7 +67,7 @@ namespace SharpCompress.Archives.Rar
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(string filePath, ReaderOptions options = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
return new RarArchive(new FileInfo(filePath), options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -84,10 +78,9 @@ namespace SharpCompress.Archives.Rar
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(FileInfo fileInfo, ReaderOptions options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new RarArchive(fileInfo, options ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
@@ -96,7 +89,7 @@ namespace SharpCompress.Archives.Rar
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return Open(stream.AsEnumerable(), options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -107,11 +100,10 @@ namespace SharpCompress.Archives.Rar
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, ReaderOptions options = null)
|
||||
{
|
||||
streams.CheckNotNull("streams");
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
return new RarArchive(streams, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
public static bool IsRarFile(string filePath)
|
||||
{
|
||||
return IsRarFile(new FileInfo(filePath));
|
||||
@@ -128,7 +120,6 @@ namespace SharpCompress.Archives.Rar
|
||||
return IsRarFile(stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool IsRarFile(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
@@ -145,4 +136,4 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Readers;
|
||||
#if !NO_FILE
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
@@ -25,8 +23,7 @@ namespace SharpCompress.Archives.Rar
|
||||
yield return part;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, ReaderOptions options)
|
||||
{
|
||||
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
|
||||
@@ -141,7 +138,5 @@ namespace SharpCompress.Archives.Rar
|
||||
throw new ArgumentException("Filename invalid or next archive could not be found:"
|
||||
+ fileInfo.FullName);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,10 @@ namespace SharpCompress.Archives.Rar
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
stream.Position = FileHeader.DataStartPosition;
|
||||
#if !NO_CRYPTO
|
||||
if (FileHeader.R4Salt != null)
|
||||
{
|
||||
return new RarCryptoWrapper(stream, password, FileHeader.R4Salt);
|
||||
}
|
||||
#endif
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace SharpCompress.Archives.SevenZip
|
||||
public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
|
||||
{
|
||||
private ArchiveDatabase database;
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -36,7 +34,6 @@ namespace SharpCompress.Archives.SevenZip
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
@@ -48,7 +45,6 @@ namespace SharpCompress.Archives.SevenZip
|
||||
return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
internal SevenZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.SevenZip, fileInfo, readerOptions)
|
||||
{
|
||||
@@ -75,7 +71,6 @@ namespace SharpCompress.Archives.SevenZip
|
||||
return IsSevenZipFile(stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal SevenZipArchive(Stream stream, ReaderOptions readerOptions)
|
||||
: base(ArchiveType.SevenZip, stream.AsEnumerable(), readerOptions)
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
{
|
||||
#if !NO_FILE
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -24,7 +22,7 @@ namespace SharpCompress.Archives.Tar
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -35,10 +33,9 @@ namespace SharpCompress.Archives.Tar
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new TarArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
@@ -47,12 +44,10 @@ namespace SharpCompress.Archives.Tar
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new TarArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
public static bool IsTarFile(string filePath)
|
||||
{
|
||||
return IsTarFile(new FileInfo(filePath));
|
||||
@@ -69,24 +64,22 @@ namespace SharpCompress.Archives.Tar
|
||||
return IsTarFile(stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool IsTarFile(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
TarHeader tar = new TarHeader(new ArchiveEncoding());
|
||||
tar.Read(new BinaryReader(stream));
|
||||
return tar.Name.Length > 0 && Enum.IsDefined(typeof(EntryType), tar.EntryType);
|
||||
TarHeader tarHeader = new TarHeader(new ArchiveEncoding());
|
||||
bool readSucceeded = tarHeader.Read(new BinaryReader(stream));
|
||||
bool isEmptyArchive = tarHeader.Name.Length == 0 && tarHeader.Size == 0 && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType);
|
||||
return readSucceeded || isEmptyArchive;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
@@ -101,7 +94,6 @@ namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
return new TarVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes multiple seekable Streams for a multi-part archive
|
||||
@@ -146,7 +138,7 @@ namespace SharpCompress.Archives.Tar
|
||||
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
using (var memoryStream = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream())
|
||||
{
|
||||
entryStream.TransferTo(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
@@ -202,4 +194,4 @@ namespace SharpCompress.Archives.Tar
|
||||
return TarReader.Open(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ namespace SharpCompress.Archives.Zip
|
||||
/// if the compression method is set to deflate
|
||||
/// </summary>
|
||||
public CompressionLevel DeflateCompressionLevel { get; set; }
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -32,7 +30,7 @@ namespace SharpCompress.Archives.Zip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(string filePath, ReaderOptions readerOptions = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -43,10 +41,9 @@ namespace SharpCompress.Archives.Zip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new ZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
@@ -55,12 +52,10 @@ namespace SharpCompress.Archives.Zip
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new ZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
|
||||
public static bool IsZipFile(string filePath, string password = null)
|
||||
{
|
||||
return IsZipFile(new FileInfo(filePath), password);
|
||||
@@ -77,7 +72,6 @@ namespace SharpCompress.Archives.Zip
|
||||
return IsZipFile(stream, password);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool IsZipFile(Stream stream, string password = null)
|
||||
{
|
||||
@@ -101,9 +95,7 @@ namespace SharpCompress.Archives.Zip
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
@@ -119,7 +111,6 @@ namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
return new ZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
internal ZipArchive()
|
||||
: base(ArchiveType.Zip)
|
||||
@@ -211,4 +202,4 @@ namespace SharpCompress.Archives.Zip
|
||||
return ZipReader.Open(stream, ReaderOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a resource pool that enables reusing instances of type <see cref="T:T[]"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Renting and returning buffers with an <see cref="ArrayPool{T}"/> can increase performance
|
||||
/// in situations where arrays are created and destroyed frequently, resulting in significant
|
||||
/// memory pressure on the garbage collector.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This class is thread-safe. All members may be used by multiple threads concurrently.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
internal abstract class ArrayPool<T>
|
||||
{
|
||||
/// <summary>The lazily-initialized shared pool instance.</summary>
|
||||
private static ArrayPool<T> s_sharedInstance = null;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a shared <see cref="ArrayPool{T}"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The shared pool provides a default implementation of <see cref="ArrayPool{T}"/>
|
||||
/// that's intended for general applicability. It maintains arrays of multiple sizes, and
|
||||
/// may hand back a larger array than was actually requested, but will never hand back a smaller
|
||||
/// array than was requested. Renting a buffer from it with <see cref="Rent"/> will result in an
|
||||
/// existing buffer being taken from the pool if an appropriate buffer is available or in a new
|
||||
/// buffer being allocated if one is not available.
|
||||
/// </remarks>
|
||||
public static ArrayPool<T> Shared
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return Volatile.Read(ref s_sharedInstance) ?? EnsureSharedCreated(); }
|
||||
}
|
||||
|
||||
/// <summary>Ensures that <see cref="s_sharedInstance"/> has been initialized to a pool and returns it.</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static ArrayPool<T> EnsureSharedCreated()
|
||||
{
|
||||
Interlocked.CompareExchange(ref s_sharedInstance, Create(), null);
|
||||
return s_sharedInstance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ArrayPool{T}"/> instance using default configuration options.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="ArrayPool{T}"/> instance.</returns>
|
||||
public static ArrayPool<T> Create()
|
||||
{
|
||||
return new DefaultArrayPool<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ArrayPool{T}"/> instance using custom configuration options.
|
||||
/// </summary>
|
||||
/// <param name="maxArrayLength">The maximum length of array instances that may be stored in the pool.</param>
|
||||
/// <param name="maxArraysPerBucket">
|
||||
/// The maximum number of array instances that may be stored in each bucket in the pool. The pool
|
||||
/// groups arrays of similar lengths into buckets for faster access.
|
||||
/// </param>
|
||||
/// <returns>A new <see cref="ArrayPool{T}"/> instance with the specified configuration options.</returns>
|
||||
/// <remarks>
|
||||
/// The created pool will group arrays into buckets, with no more than <paramref name="maxArraysPerBucket"/>
|
||||
/// in each bucket and with those arrays not exceeding <paramref name="maxArrayLength"/> in length.
|
||||
/// </remarks>
|
||||
public static ArrayPool<T> Create(int maxArrayLength, int maxArraysPerBucket)
|
||||
{
|
||||
return new DefaultArrayPool<T>(maxArrayLength, maxArraysPerBucket);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a buffer that is at least the requested length.
|
||||
/// </summary>
|
||||
/// <param name="minimumLength">The minimum length of the array needed.</param>
|
||||
/// <returns>
|
||||
/// An <see cref="T:T[]"/> that is at least <paramref name="minimumLength"/> in length.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This buffer is loaned to the caller and should be returned to the same pool via
|
||||
/// <see cref="Return"/> so that it may be reused in subsequent usage of <see cref="Rent"/>.
|
||||
/// It is not a fatal error to not return a rented buffer, but failure to do so may lead to
|
||||
/// decreased application performance, as the pool may need to create a new buffer to replace
|
||||
/// the one lost.
|
||||
/// </remarks>
|
||||
public abstract T[] Rent(int minimumLength);
|
||||
|
||||
/// <summary>
|
||||
/// Returns to the pool an array that was previously obtained via <see cref="Rent"/> on the same
|
||||
/// <see cref="ArrayPool{T}"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// The buffer previously obtained from <see cref="Rent"/> to return to the pool.
|
||||
/// </param>
|
||||
/// <param name="clearArray">
|
||||
/// If <c>true</c> and if the pool will store the buffer to enable subsequent reuse, <see cref="Return"/>
|
||||
/// will clear <paramref name="array"/> of its contents so that a subsequent consumer via <see cref="Rent"/>
|
||||
/// will not see the previous consumer's content. If <c>false</c> or if the pool will release the buffer,
|
||||
/// the array's contents are left unchanged.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Once a buffer has been returned to the pool, the caller gives up all ownership of the buffer
|
||||
/// and must not use it. The reference returned from a given call to <see cref="Rent"/> must only be
|
||||
/// returned via <see cref="Return"/> once. The default <see cref="ArrayPool{T}"/>
|
||||
/// may hold onto the returned buffer in order to rent it again, or it may release the returned buffer
|
||||
/// if it's determined that the pool already has enough buffers stored.
|
||||
/// </remarks>
|
||||
public abstract void Return(T[] array, bool clearArray = false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
|
||||
{
|
||||
/// <summary>The default maximum length of each array in the pool (2^20).</summary>
|
||||
private const int DefaultMaxArrayLength = 1024 * 1024;
|
||||
/// <summary>The default maximum number of arrays per bucket that are available for rent.</summary>
|
||||
private const int DefaultMaxNumberOfArraysPerBucket = 50;
|
||||
/// <summary>Lazily-allocated empty array used when arrays of length 0 are requested.</summary>
|
||||
private static T[] s_emptyArray; // we support contracts earlier than those with Array.Empty<T>()
|
||||
|
||||
private readonly Bucket[] _buckets;
|
||||
|
||||
internal DefaultArrayPool() : this(DefaultMaxArrayLength, DefaultMaxNumberOfArraysPerBucket)
|
||||
{
|
||||
}
|
||||
|
||||
internal DefaultArrayPool(int maxArrayLength, int maxArraysPerBucket)
|
||||
{
|
||||
if (maxArrayLength <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxArrayLength));
|
||||
}
|
||||
if (maxArraysPerBucket <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxArraysPerBucket));
|
||||
}
|
||||
|
||||
// Our bucketing algorithm has a min length of 2^4 and a max length of 2^30.
|
||||
// Constrain the actual max used to those values.
|
||||
const int MinimumArrayLength = 0x10, MaximumArrayLength = 0x40000000;
|
||||
if (maxArrayLength > MaximumArrayLength)
|
||||
{
|
||||
maxArrayLength = MaximumArrayLength;
|
||||
}
|
||||
else if (maxArrayLength < MinimumArrayLength)
|
||||
{
|
||||
maxArrayLength = MinimumArrayLength;
|
||||
}
|
||||
|
||||
// Create the buckets.
|
||||
int poolId = Id;
|
||||
int maxBuckets = Utilities.SelectBucketIndex(maxArrayLength);
|
||||
var buckets = new Bucket[maxBuckets + 1];
|
||||
for (int i = 0; i < buckets.Length; i++)
|
||||
{
|
||||
buckets[i] = new Bucket(Utilities.GetMaxSizeForBucket(i), maxArraysPerBucket, poolId);
|
||||
}
|
||||
_buckets = buckets;
|
||||
}
|
||||
|
||||
/// <summary>Gets an ID for the pool to use with events.</summary>
|
||||
private int Id => GetHashCode();
|
||||
|
||||
public override T[] Rent(int minimumLength)
|
||||
{
|
||||
// Arrays can't be smaller than zero. We allow requesting zero-length arrays (even though
|
||||
// pooling such an array isn't valuable) as it's a valid length array, and we want the pool
|
||||
// to be usable in general instead of using `new`, even for computed lengths.
|
||||
if (minimumLength < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(minimumLength));
|
||||
}
|
||||
else if (minimumLength == 0)
|
||||
{
|
||||
// No need for events with the empty array. Our pool is effectively infinite
|
||||
// and we'll never allocate for rents and never store for returns.
|
||||
return s_emptyArray ?? (s_emptyArray = new T[0]);
|
||||
}
|
||||
|
||||
T[] buffer = null;
|
||||
|
||||
int index = Utilities.SelectBucketIndex(minimumLength);
|
||||
if (index < _buckets.Length)
|
||||
{
|
||||
// Search for an array starting at the 'index' bucket. If the bucket is empty, bump up to the
|
||||
// next higher bucket and try that one, but only try at most a few buckets.
|
||||
const int MaxBucketsToTry = 2;
|
||||
int i = index;
|
||||
do
|
||||
{
|
||||
// Attempt to rent from the bucket. If we get a buffer from it, return it.
|
||||
buffer = _buckets[i].Rent();
|
||||
if (buffer != null)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
while (++i < _buckets.Length && i != index + MaxBucketsToTry);
|
||||
|
||||
// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
|
||||
// to the appropriate bucket.
|
||||
buffer = new T[_buckets[index]._bufferLength];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
|
||||
// When it's returned to the pool, we'll simply throw it away.
|
||||
buffer = new T[minimumLength];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public override void Return(T[] array, bool clearArray = false)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
else if (array.Length == 0)
|
||||
{
|
||||
// Ignore empty arrays. When a zero-length array is rented, we return a singleton
|
||||
// rather than actually taking a buffer out of the lowest bucket.
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine with what bucket this array length is associated
|
||||
int bucket = Utilities.SelectBucketIndex(array.Length);
|
||||
|
||||
// If we can tell that the buffer was allocated, drop it. Otherwise, check if we have space in the pool
|
||||
if (bucket < _buckets.Length)
|
||||
{
|
||||
// Clear the array if the user requests
|
||||
if (clearArray)
|
||||
{
|
||||
Array.Clear(array, 0, array.Length);
|
||||
}
|
||||
|
||||
// Return the buffer to its bucket. In the future, we might consider having Return return false
|
||||
// instead of dropping a bucket, in which case we could try to return to a lower-sized bucket,
|
||||
// just as how in Rent we allow renting from a higher-sized bucket.
|
||||
_buckets[bucket].Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,111 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#if NETCORE
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
|
||||
{
|
||||
/// <summary>Provides a thread-safe bucket containing buffers that can be Rent'd and Return'd.</summary>
|
||||
private sealed class Bucket
|
||||
{
|
||||
internal readonly int _bufferLength;
|
||||
private readonly T[][] _buffers;
|
||||
private readonly int _poolId;
|
||||
|
||||
private SpinLock _lock; // do not make this readonly; it's a mutable struct
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the pool with numberOfBuffers arrays where each buffer is of bufferLength length.
|
||||
/// </summary>
|
||||
internal Bucket(int bufferLength, int numberOfBuffers, int poolId)
|
||||
{
|
||||
_lock = new SpinLock(Debugger.IsAttached); // only enable thread tracking if debugger is attached; it adds non-trivial overheads to Enter/Exit
|
||||
_buffers = new T[numberOfBuffers][];
|
||||
_bufferLength = bufferLength;
|
||||
_poolId = poolId;
|
||||
}
|
||||
|
||||
/// <summary>Gets an ID for the bucket to use with events.</summary>
|
||||
internal int Id => GetHashCode();
|
||||
|
||||
/// <summary>Takes an array from the bucket. If the bucket is empty, returns null.</summary>
|
||||
internal T[] Rent()
|
||||
{
|
||||
T[][] buffers = _buffers;
|
||||
T[] buffer = null;
|
||||
|
||||
// While holding the lock, grab whatever is at the next available index and
|
||||
// update the index. We do as little work as possible while holding the spin
|
||||
// lock to minimize contention with other threads. The try/finally is
|
||||
// necessary to properly handle thread aborts on platforms which have them.
|
||||
bool lockTaken = false, allocateBuffer = false;
|
||||
try
|
||||
{
|
||||
_lock.Enter(ref lockTaken);
|
||||
|
||||
if (_index < buffers.Length)
|
||||
{
|
||||
buffer = buffers[_index];
|
||||
buffers[_index++] = null;
|
||||
allocateBuffer = buffer == null;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) _lock.Exit(false);
|
||||
}
|
||||
|
||||
// While we were holding the lock, we grabbed whatever was at the next available index, if
|
||||
// there was one. If we tried and if we got back null, that means we hadn't yet allocated
|
||||
// for that slot, in which case we should do so now.
|
||||
if (allocateBuffer)
|
||||
{
|
||||
buffer = new T[_bufferLength];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to return the buffer to the bucket. If successful, the buffer will be stored
|
||||
/// in the bucket and true will be returned; otherwise, the buffer won't be stored, and false
|
||||
/// will be returned.
|
||||
/// </summary>
|
||||
internal void Return(T[] array)
|
||||
{
|
||||
// Check to see if the buffer is the correct size for this bucket
|
||||
if (array.Length != _bufferLength)
|
||||
{
|
||||
throw new ArgumentException("Buffer not from pool", nameof(array));
|
||||
}
|
||||
|
||||
// While holding the spin lock, if there's room available in the bucket,
|
||||
// put the buffer into the next available slot. Otherwise, we just drop it.
|
||||
// The try/finally is necessary to properly handle thread aborts on platforms
|
||||
// which have them.
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
_lock.Enter(ref lockTaken);
|
||||
|
||||
if (_index != 0)
|
||||
{
|
||||
_buffers[--_index] = array;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) _lock.Exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#if NETCORE
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SharpCompress.Buffers
|
||||
{
|
||||
internal static class Utilities
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int SelectBucketIndex(int bufferSize)
|
||||
{
|
||||
Debug.Assert(bufferSize > 0);
|
||||
|
||||
uint bitsRemaining = ((uint)bufferSize - 1) >> 4;
|
||||
|
||||
int poolIndex = 0;
|
||||
if (bitsRemaining > 0xFFFF) { bitsRemaining >>= 16; poolIndex = 16; }
|
||||
if (bitsRemaining > 0xFF) { bitsRemaining >>= 8; poolIndex += 8; }
|
||||
if (bitsRemaining > 0xF) { bitsRemaining >>= 4; poolIndex += 4; }
|
||||
if (bitsRemaining > 0x3) { bitsRemaining >>= 2; poolIndex += 2; }
|
||||
if (bitsRemaining > 0x1) { bitsRemaining >>= 1; poolIndex += 1; }
|
||||
|
||||
return poolIndex + (int)bitsRemaining;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetMaxSizeForBucket(int binIndex)
|
||||
{
|
||||
int maxSize = 16 << binIndex;
|
||||
Debug.Assert(maxSize >= 0);
|
||||
return maxSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -28,21 +28,14 @@ namespace SharpCompress.Common
|
||||
|
||||
public ArchiveEncoding()
|
||||
{
|
||||
#if NETSTANDARD1_0
|
||||
Default = Encoding.GetEncoding("cp437");
|
||||
Password = Encoding.GetEncoding("cp437");
|
||||
#else
|
||||
Default = Encoding.GetEncoding(437);
|
||||
Password = Encoding.GetEncoding(437);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_3 || NETSTANDARD2_0
|
||||
static ArchiveEncoding()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
public string Decode(byte[] bytes)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public abstract string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The target of a symlink entry internal to the Archive. Will be null if not a symlink.
|
||||
/// </summary>
|
||||
public abstract string LinkTarget { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The compressed file size
|
||||
/// </summary>
|
||||
|
||||
@@ -47,9 +47,7 @@ namespace SharpCompress.Common
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
public override void Flush() {
|
||||
}
|
||||
|
||||
public override long Length => _stream.Length;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
#if !NO_FILE
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
internal static class ExtractionMethods
|
||||
{
|
||||
|
||||
#if !NO_FILE
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
@@ -68,20 +64,30 @@ namespace SharpCompress.Common
|
||||
ExtractionOptions options,
|
||||
Action<string, FileMode> openAndWrite)
|
||||
{
|
||||
FileMode fm = FileMode.Create;
|
||||
options = options ?? new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
|
||||
if (!options.Overwrite)
|
||||
if (entry.LinkTarget != null)
|
||||
{
|
||||
fm = FileMode.CreateNew;
|
||||
if (null == options.WriteSymbolicLink)
|
||||
{
|
||||
throw new ExtractionException("Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null");
|
||||
}
|
||||
options.WriteSymbolicLink(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileMode fm = FileMode.Create;
|
||||
options = options ?? new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
|
||||
openAndWrite(destinationFileName, fm);
|
||||
entry.PreserveExtractionOptions(destinationFileName, options);
|
||||
if (!options.Overwrite)
|
||||
{
|
||||
fm = FileMode.CreateNew;
|
||||
}
|
||||
|
||||
openAndWrite(destinationFileName, fm);
|
||||
entry.PreserveExtractionOptions(destinationFileName, options);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -21,5 +21,14 @@
|
||||
/// preserve windows file attributes
|
||||
/// </summary>
|
||||
public bool PreserveAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for writing symbolic links to disk.
|
||||
/// sourcePath is where the symlink is created.
|
||||
/// targetPath is what the symlink refers to.
|
||||
/// </summary>
|
||||
public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath);
|
||||
|
||||
public SymbolicLinkWriterDelegate WriteSymbolicLink;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,11 @@ namespace SharpCompress.Common
|
||||
}
|
||||
|
||||
internal ArchiveEncoding ArchiveEncoding { get; }
|
||||
|
||||
|
||||
internal abstract string FilePartName { get; }
|
||||
|
||||
internal abstract Stream GetCompressedStream();
|
||||
internal abstract Stream GetRawStream();
|
||||
internal bool Skipped { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace SharpCompress.Common.GZip
|
||||
|
||||
public override string Key => _filePart.FilePartName;
|
||||
|
||||
public override string LinkTarget => null;
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size => 0;
|
||||
|
||||
@@ -10,13 +10,11 @@ namespace SharpCompress.Common.GZip
|
||||
{
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options)
|
||||
{
|
||||
options.LeaveStreamOpen = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
public override bool IsFirstVolume => true;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
@@ -48,4 +46,3 @@ namespace SharpCompress.Common
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@ namespace SharpCompress.Common
|
||||
long Crc { get; }
|
||||
DateTime? CreatedTime { get; }
|
||||
string Key { get; }
|
||||
string LinkTarget { get; }
|
||||
bool IsDirectory { get; }
|
||||
bool IsEncrypted { get; }
|
||||
bool IsSplitAfter { get; }
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public interface IVolume : IDisposable
|
||||
|
||||
@@ -195,17 +195,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
private static string ConvertPathV5(string path)
|
||||
{
|
||||
#if NO_FILE
|
||||
// not sure what to do here
|
||||
throw new NotImplementedException("TODO");
|
||||
#else
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
{
|
||||
// replace embedded \\ with valid filename char
|
||||
return path.Replace('\\', '-').Replace('/', '\\');
|
||||
}
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -361,9 +356,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
private static string ConvertPathV4(string path)
|
||||
{
|
||||
#if NO_FILE
|
||||
return path.Replace('\\', '/');
|
||||
#else
|
||||
if (Path.DirectorySeparatorChar == '/')
|
||||
{
|
||||
return path.Replace('\\', '/');
|
||||
@@ -373,7 +365,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return path.Replace('/', '\\');
|
||||
}
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -48,15 +48,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !NO_CRYPTO
|
||||
if (Options.Password == null)
|
||||
{
|
||||
throw new CryptographicException("Encrypted Rar archive has no password specified.");
|
||||
}
|
||||
reader = new RarCryptoBinaryReader(stream, Options.Password);
|
||||
#else
|
||||
throw new CryptographicException("Rar encryption unsupported on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
var header = RarHeader.TryReadBase(reader, _isRar5, Options.ArchiveEncoding);
|
||||
@@ -138,11 +134,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !NO_CRYPTO
|
||||
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password, fh.R4Salt);
|
||||
#else
|
||||
throw new NotSupportedException("RarCrypto not supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#if !NO_CRYPTO
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar
|
||||
@@ -111,5 +110,4 @@ namespace SharpCompress.Common.Rar
|
||||
ClearQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -95,5 +93,4 @@ namespace SharpCompress.Common.Rar
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -22,6 +22,8 @@ namespace SharpCompress.Common.Rar
|
||||
/// </summary>
|
||||
public override string Key => FileHeader.FileName;
|
||||
|
||||
public override string LinkTarget => null;
|
||||
|
||||
/// <summary>
|
||||
/// The entry last modified time in the archive, if recorded
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using SharpCompress.Crypto;
|
||||
@@ -23,12 +21,6 @@ namespace SharpCompress.Common.Rar
|
||||
_salt = salt;
|
||||
}
|
||||
|
||||
private byte[] ComputeHash(byte[] input)
|
||||
{
|
||||
var sha = SHA1.Create();
|
||||
return sha.ComputeHash(input);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
|
||||
@@ -47,28 +39,27 @@ namespace SharpCompress.Common.Rar
|
||||
rawPassword[i + rawLength] = _salt[i];
|
||||
}
|
||||
|
||||
|
||||
const int noOfRounds = (1 << 18);
|
||||
IList<byte> bytes = new List<byte>();
|
||||
const int iblock = 3;
|
||||
byte[] digest;
|
||||
byte[] data = new byte[(rawPassword.Length + iblock) * noOfRounds];
|
||||
|
||||
//TODO slow code below, find ways to optimize
|
||||
for (int i = 0; i < noOfRounds; i++)
|
||||
{
|
||||
bytes.AddRange(rawPassword);
|
||||
rawPassword.CopyTo(data, i * (rawPassword.Length + iblock));
|
||||
|
||||
bytes.AddRange(new[]
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 0] = (byte)i;
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 1] = (byte)(i >> 8);
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 2] = (byte)(i >> CRYPTO_BLOCK_SIZE);
|
||||
|
||||
if (i % (noOfRounds / CRYPTO_BLOCK_SIZE) == 0)
|
||||
{
|
||||
(byte) i, (byte) (i >> 8), (byte) (i >> CRYPTO_BLOCK_SIZE)
|
||||
});
|
||||
if (i%(noOfRounds/CRYPTO_BLOCK_SIZE) == 0)
|
||||
{
|
||||
digest = ComputeHash(bytes.ToArray());
|
||||
_aesInitializationVector[i/(noOfRounds/CRYPTO_BLOCK_SIZE)] = digest[19];
|
||||
digest = SHA1.Create().ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock));
|
||||
_aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19];
|
||||
}
|
||||
}
|
||||
|
||||
digest = ComputeHash(bytes.ToArray());
|
||||
digest = SHA1.Create().ComputeHash(data);
|
||||
//slow code ends
|
||||
|
||||
byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE];
|
||||
@@ -118,4 +109,3 @@ namespace SharpCompress.Common.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1396,7 +1396,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = new MemoryStream();
|
||||
_stream = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream();
|
||||
}
|
||||
_rem = _db._files[index].Size;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override string Key => FilePart.Header.Name;
|
||||
|
||||
public override string LinkTarget => null;
|
||||
|
||||
public override long CompressedSize => 0;
|
||||
|
||||
public override long Size => FilePart.Header.Size;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
}
|
||||
|
||||
internal string Name { get; set; }
|
||||
internal string LinkName { get; set; }
|
||||
|
||||
//internal int Mode { get; set; }
|
||||
//internal int UserId { get; set; }
|
||||
@@ -38,16 +39,17 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
WriteOctalBytes(0, buffer, 116, 8); // group ID
|
||||
|
||||
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
|
||||
if (Name.Length > 100)
|
||||
var nameByteCount = ArchiveEncoding.GetEncoding().GetByteCount(Name);
|
||||
if (nameByteCount > 100)
|
||||
{
|
||||
// Set mock filename and filetype to indicate the next block is the actual name of the file
|
||||
WriteStringBytes("././@LongLink", buffer, 0, 100);
|
||||
buffer[156] = (byte)EntryType.LongName;
|
||||
WriteOctalBytes(Name.Length + 1, buffer, 124, 12);
|
||||
WriteOctalBytes(nameByteCount + 1, buffer, 124, 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteStringBytes(Name, buffer, 0, 100);
|
||||
WriteStringBytes(ArchiveEncoding.Encode(Name), buffer, 0, 100);
|
||||
WriteOctalBytes(Size, buffer, 124, 12);
|
||||
var time = (long)(LastModifiedTime.ToUniversalTime() - EPOCH).TotalSeconds;
|
||||
WriteOctalBytes(time, buffer, 136, 12);
|
||||
@@ -68,10 +70,17 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
output.Write(buffer, 0, buffer.Length);
|
||||
|
||||
if (Name.Length > 100)
|
||||
if (nameByteCount > 100)
|
||||
{
|
||||
WriteLongFilenameHeader(output);
|
||||
Name = Name.Substring(0, 100);
|
||||
// update to short name lower than 100 - [max bytes of one character].
|
||||
// subtracting bytes is needed because preventing infinite loop(example code is here).
|
||||
//
|
||||
// var bytes = Encoding.UTF8.GetBytes(new string(0x3042, 100));
|
||||
// var truncated = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(bytes, 0, 100));
|
||||
//
|
||||
// and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102.
|
||||
Name = ArchiveEncoding.Decode(ArchiveEncoding.Encode(Name), 0, 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1));
|
||||
Write(output);
|
||||
}
|
||||
}
|
||||
@@ -98,6 +107,12 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
return false;
|
||||
}
|
||||
|
||||
// for symlinks, additionally read the linkname
|
||||
if (ReadEntryType(buffer) == EntryType.SymLink)
|
||||
{
|
||||
LinkName = ArchiveEncoding.Decode(buffer, 157, 100).TrimNulls();
|
||||
}
|
||||
|
||||
if (ReadEntryType(buffer) == EntryType.LongName)
|
||||
{
|
||||
Name = ReadLongName(reader, buffer);
|
||||
@@ -177,11 +192,22 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static void WriteStringBytes(byte[] name, byte[] buffer, int offset, int length)
|
||||
{
|
||||
int i = Math.Min(length, name.Length);
|
||||
Buffer.BlockCopy(name, 0, buffer, offset, i);
|
||||
// if Span<byte>.Fill can be used, it is more efficient
|
||||
for (; i < length; ++i)
|
||||
{
|
||||
buffer[offset + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteStringBytes(string name, byte[] buffer, int offset, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length - 1 && i < name.Length; ++i)
|
||||
for (i = 0; i < length && i < name.Length; ++i)
|
||||
{
|
||||
buffer[offset + i] = (byte)name[i];
|
||||
}
|
||||
@@ -272,4 +298,4 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
public string Magic { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace SharpCompress.Common.Tar
|
||||
|
||||
public override string Key => _filePart.Header.Name;
|
||||
|
||||
public override string LinkTarget => _filePart.Header.LinkName;
|
||||
|
||||
public override long CompressedSize => _filePart.Header.Size;
|
||||
|
||||
public override long Size => _filePart.Header.Size;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using SharpCompress.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Tar
|
||||
{
|
||||
internal class TarReadOnlySubStream : Stream
|
||||
internal class TarReadOnlySubStream : NonDisposingStream
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private long _amountRead;
|
||||
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead)
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
Stream = stream;
|
||||
BytesLeftToRead = bytesToRead;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,11 @@ namespace SharpCompress.Common.Tar
|
||||
var buffer = new byte[skipBytes];
|
||||
Stream.ReadFully(buffer);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
|
||||
public Stream Stream { get; }
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
@@ -33,15 +34,18 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public virtual bool IsMultiVolume => true;
|
||||
|
||||
private bool _disposed;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_actualStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_actualStream.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,10 +65,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
return encryptionData;
|
||||
}
|
||||
|
||||
#if !NO_CRYPTO
|
||||
|
||||
internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; }
|
||||
#endif
|
||||
|
||||
internal ushort LastModifiedDate { get; set; }
|
||||
|
||||
@@ -87,6 +85,15 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
}
|
||||
|
||||
ushort length = DataConverter.LittleEndian.GetUInt16(extra, i + 2);
|
||||
|
||||
// 7zip has this same kind of check to ignore extras blocks that don't conform to the standard 2-byte ID, 2-byte length, N-byte value.
|
||||
// CPP/7Zip/Zip/ZipIn.cpp: CInArchive::ReadExtra
|
||||
if (length > extra.Length)
|
||||
{
|
||||
// bad extras block
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = new byte[length];
|
||||
Buffer.BlockCopy(extra, i + 4, data, 0, length);
|
||||
Extra.Add(LocalEntryHeaderExtraFactory.Create(type, length, data));
|
||||
@@ -99,4 +106,4 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
internal bool IsZip64 => CompressedSize == uint.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
{
|
||||
@@ -7,11 +8,13 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
private bool _isLocalHeaderLoaded;
|
||||
private readonly SeekableZipHeaderFactory _headerFactory;
|
||||
private readonly DirectoryEntryHeader _directoryEntryHeader;
|
||||
|
||||
internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream)
|
||||
: base(header, stream)
|
||||
{
|
||||
_headerFactory = headerFactory;
|
||||
_directoryEntryHeader = header;
|
||||
}
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
@@ -36,6 +39,15 @@ namespace SharpCompress.Common.Zip
|
||||
protected override Stream CreateBaseStream()
|
||||
{
|
||||
BaseStream.Position = Header.DataStartPosition.Value;
|
||||
|
||||
if ((Header.CompressedSize == 0)
|
||||
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
|
||||
&& (_directoryEntryHeader?.HasData == true)
|
||||
&& (_directoryEntryHeader?.CompressedSize != 0))
|
||||
{
|
||||
return new ReadOnlySubStream(BaseStream, _directoryEntryHeader.CompressedSize);
|
||||
}
|
||||
|
||||
return BaseStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
}
|
||||
|
||||
internal IEnumerable<DirectoryEntryHeader> ReadSeekableHeader(Stream stream)
|
||||
internal IEnumerable<ZipHeader> ReadSeekableHeader(Stream stream)
|
||||
{
|
||||
var reader = new BinaryReader(stream);
|
||||
|
||||
@@ -51,16 +51,22 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
stream.Position = position;
|
||||
uint signature = reader.ReadUInt32();
|
||||
var directoryEntryHeader = ReadHeader(signature, reader, _zip64) as DirectoryEntryHeader;
|
||||
var nextHeader = ReadHeader(signature, reader, _zip64);
|
||||
position = stream.Position;
|
||||
if (directoryEntryHeader == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
//entry could be zero bytes so we need to know that.
|
||||
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
|
||||
yield return directoryEntryHeader;
|
||||
if (nextHeader == null)
|
||||
yield break;
|
||||
|
||||
if (nextHeader is DirectoryEntryHeader entryHeader)
|
||||
{
|
||||
//entry could be zero bytes so we need to know that.
|
||||
entryHeader.HasData = entryHeader.CompressedSize != 0;
|
||||
yield return entryHeader;
|
||||
}
|
||||
else if (nextHeader is DirectoryEndHeader endHeader)
|
||||
{
|
||||
yield return endHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace SharpCompress.Common.Zip
|
||||
_lastEntryHeader = null;
|
||||
uint headerBytes = reader.ReadUInt32();
|
||||
header = ReadHeader(headerBytes, reader);
|
||||
if (header == null) { yield break; }
|
||||
|
||||
//entry could be zero bytes so we need to know that.
|
||||
if (header.ZipHeaderType == ZipHeaderType.LocalEntry)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
@@ -181,4 +179,3 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using SharpCompress.Converters;
|
||||
@@ -76,4 +74,3 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -60,6 +60,8 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
public override string Key => _filePart.Header.Name;
|
||||
|
||||
public override string LinkTarget => null;
|
||||
|
||||
public override long CompressedSize => _filePart.Header.CompressedSize;
|
||||
|
||||
public override long Size => _filePart.Header.UncompressedSize;
|
||||
|
||||
@@ -165,12 +165,10 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
#if !NO_FILE
|
||||
if (Header.WinzipAesEncryptionData != null)
|
||||
{
|
||||
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
|
||||
}
|
||||
#endif
|
||||
return plainStream;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
#if !NO_CRYPTO
|
||||
using System.Linq;
|
||||
#endif
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
using SharpCompress.IO;
|
||||
using System.Text;
|
||||
@@ -91,7 +89,7 @@ namespace SharpCompress.Common.Zip
|
||||
return entry;
|
||||
}
|
||||
default:
|
||||
throw new NotSupportedException("Unknown header: " + headerBytes);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,10 +130,6 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes)
|
||||
{
|
||||
#if NO_CRYPTO
|
||||
throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7.");
|
||||
#else
|
||||
|
||||
ExtraData data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
|
||||
if (data != null)
|
||||
{
|
||||
@@ -150,7 +144,6 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
entryHeader.CompressedSize -= (uint)(salt.Length + 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace SharpCompress.Compressors.ADC
|
||||
position += chunkSize + 1;
|
||||
break;
|
||||
case TWO_BYTE:
|
||||
tempMs = new MemoryStream();
|
||||
tempMs = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream();
|
||||
chunkSize = GetChunkSize((byte)readByte);
|
||||
tempMs.WriteByte((byte)readByte);
|
||||
tempMs.WriteByte((byte)input.ReadByte());
|
||||
@@ -173,7 +173,7 @@ namespace SharpCompress.Compressors.ADC
|
||||
}
|
||||
break;
|
||||
case THREE_BYTE:
|
||||
tempMs = new MemoryStream();
|
||||
tempMs = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream();
|
||||
chunkSize = GetChunkSize((byte)readByte);
|
||||
tempMs.WriteByte((byte)readByte);
|
||||
tempMs.WriteByte((byte)input.ReadByte());
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
#if !NO_CRYPTO
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@@ -195,7 +193,7 @@ namespace SharpCompress.Compressors.LZMA
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
#if NETSTANDARD1_4 || NETSTANDARD2_0
|
||||
using (IncrementalHash sha = IncrementalHash.CreateHash(HashAlgorithmName.SHA256))
|
||||
{
|
||||
byte[] counter = new byte[8];
|
||||
@@ -262,5 +260,3 @@ namespace SharpCompress.Compressors.LZMA
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -34,34 +34,26 @@ namespace SharpCompress.Compressors.LZMA
|
||||
if (NEEDS_INDENT)
|
||||
{
|
||||
NEEDS_INDENT = false;
|
||||
#if !NO_FILE
|
||||
Debug.Write(INDENT.Peek());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(object value)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if !NO_FILE
|
||||
Debug.Write(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Write(string text)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if !NO_FILE
|
||||
Debug.Write(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Write(string format, params object[] args)
|
||||
{
|
||||
EnsureIndent();
|
||||
#if !NO_FILE
|
||||
Debug.Write(string.Format(format, args));
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void WriteLine()
|
||||
|
||||
@@ -36,10 +36,8 @@ namespace SharpCompress.Compressors.LZMA
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
return new LzmaStream(info, inStreams.Single(), -1, limit);
|
||||
#if !NO_CRYPTO
|
||||
case CMethodId.K_AES_ID:
|
||||
return new AesDecoderStream(inStreams.Single(), info, pass, limit);
|
||||
#endif
|
||||
case K_BCJ:
|
||||
return new BCJFilter(false, inStreams.Single());
|
||||
case K_BCJ2:
|
||||
|
||||
@@ -78,7 +78,10 @@ namespace SharpCompress.Compressors.PPMd
|
||||
{
|
||||
if (_compress)
|
||||
{
|
||||
_model.EncodeBlock(_stream, new MemoryStream(), true);
|
||||
using (var stream = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream())
|
||||
{
|
||||
_model.EncodeBlock(_stream, stream, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
#if NET35
|
||||
using System;
|
||||
|
||||
namespace SharpCompress
|
||||
{
|
||||
internal static class EnumExtensions
|
||||
{
|
||||
public static bool HasFlag(this Enum enumRef, Enum flag)
|
||||
{
|
||||
long value = Convert.ToInt64(enumRef);
|
||||
long flagVal = Convert.ToInt64(flag);
|
||||
|
||||
return (value & flagVal) == flagVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
public class ReadOnlyAppendingStream : Stream
|
||||
{
|
||||
private readonly Queue<Stream> streams;
|
||||
private Stream current;
|
||||
|
||||
public ReadOnlyAppendingStream(IEnumerable<Stream> streams)
|
||||
{
|
||||
this.streams = new Queue<Stream>(streams);
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Length => throw new NotImplementedException();
|
||||
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (current == null && streams.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (current == null)
|
||||
{
|
||||
current = streams.Dequeue();
|
||||
}
|
||||
int totalRead = 0;
|
||||
while (totalRead < count)
|
||||
{
|
||||
int read = current.Read(buffer, offset + totalRead, count - totalRead);
|
||||
if (read <= 0)
|
||||
{
|
||||
if (streams.Count == 0)
|
||||
{
|
||||
return totalRead;
|
||||
}
|
||||
current = streams.Dequeue();
|
||||
}
|
||||
totalRead += read;
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,22 @@ using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
internal class BufferedSubStream : Stream
|
||||
internal class BufferedSubStream : NonDisposingStream
|
||||
{
|
||||
private long position;
|
||||
private int cacheOffset;
|
||||
private int cacheLength;
|
||||
private readonly byte[] cache;
|
||||
|
||||
public BufferedSubStream(Stream stream, long origin, long bytesToRead)
|
||||
public BufferedSubStream(Stream stream, long origin, long bytesToRead) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
Stream = stream;
|
||||
position = origin;
|
||||
BytesLeftToRead = bytesToRead;
|
||||
cache = new byte[32 << 10];
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
//Stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
|
||||
public Stream Stream { get; }
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
@@ -3,13 +3,10 @@ using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
internal class CountingWritableSubStream : Stream
|
||||
internal class CountingWritableSubStream : NonDisposingStream
|
||||
{
|
||||
private readonly Stream writableStream;
|
||||
|
||||
internal CountingWritableSubStream(Stream stream)
|
||||
internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
writableStream = stream;
|
||||
}
|
||||
|
||||
public ulong Count { get; private set; }
|
||||
@@ -22,7 +19,7 @@ namespace SharpCompress.IO
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
writableStream.Flush();
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
@@ -46,13 +43,13 @@ namespace SharpCompress.IO
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
writableStream.Write(buffer, offset, count);
|
||||
Stream.Write(buffer, offset, count);
|
||||
Count += (uint)count;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
writableStream.WriteByte(value);
|
||||
Stream.WriteByte(value);
|
||||
++Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public Stream Stream { get; }
|
||||
@@ -74,10 +75,5 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
Stream.WriteByte(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,13 +74,6 @@ namespace SharpCompress.IO
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#if !SILVERLIGHT
|
||||
public override decimal ReadDecimal()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
#endif
|
||||
|
||||
public override double ReadDouble()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
|
||||
@@ -15,10 +15,9 @@ namespace SharpCompress.IO
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (ThrowOnDispose)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException($"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +43,6 @@ namespace SharpCompress.IO
|
||||
return Stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return Stream.ReadByte();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return Stream.Seek(offset, origin);
|
||||
@@ -63,10 +57,5 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
Stream.WriteByte(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace SharpCompress.IO
|
||||
}
|
||||
|
||||
public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead)
|
||||
: base(stream, false)
|
||||
: base(stream, throwOnDispose: false)
|
||||
{
|
||||
if (origin != null)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.IO;
|
||||
using SharpCompress.Compressors.Filters;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
@@ -7,7 +8,7 @@ namespace SharpCompress.IO
|
||||
internal class RewindableStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
private MemoryStream bufferStream = new MemoryStream();
|
||||
private MemoryStream bufferStream = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream();
|
||||
private bool isRewound;
|
||||
private bool isDisposed;
|
||||
|
||||
@@ -29,6 +30,7 @@ namespace SharpCompress.IO
|
||||
if (disposing)
|
||||
{
|
||||
stream.Dispose();
|
||||
bufferStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +53,8 @@ namespace SharpCompress.IO
|
||||
bufferStream.TransferTo(buffer);
|
||||
//create new memorystream to allow proper resizing as memorystream could be a user provided buffer
|
||||
//https://github.com/adamhathcock/sharpcompress/issues/306
|
||||
bufferStream = new MemoryStream();
|
||||
bufferStream.Dispose();
|
||||
bufferStream = Utility.RECYCLABLE_MEMORY_STREAM_MANAGER.GetStream();
|
||||
buffer.Position = 0;
|
||||
buffer.TransferTo(bufferStream);
|
||||
bufferStream.Position = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace SharpCompress.Readers.GZip
|
||||
/// <returns></returns>
|
||||
public static GZipReader Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new GZipReader(stream, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -36,4 +36,4 @@ namespace SharpCompress.Readers.GZip
|
||||
return GZipEntry.GetEntries(stream, Options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#if !NO_FILE
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Readers
|
||||
{
|
||||
public static class IReaderExtensions
|
||||
{
|
||||
#if !NO_FILE
|
||||
public static void WriteEntryTo(this IReader reader, string filePath)
|
||||
{
|
||||
using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write))
|
||||
@@ -61,6 +58,5 @@ namespace SharpCompress.Readers
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace SharpCompress.Readers.Rar
|
||||
/// <returns></returns>
|
||||
public static RarReader Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new SingleVolumeRarReader(stream, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace SharpCompress.Readers.Rar
|
||||
/// <returns></returns>
|
||||
public static RarReader Open(IEnumerable<Stream> streams, ReaderOptions options = null)
|
||||
{
|
||||
streams.CheckNotNull("streams");
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
return new MultiVolumeRarReader(streams, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace SharpCompress.Readers.Rar
|
||||
return Entry.Parts;
|
||||
}
|
||||
|
||||
protected override EntryStream GetEntryStream()
|
||||
protected override EntryStream GetEntryStream()
|
||||
{
|
||||
var stream = new MultiVolumeReadOnlyStream(CreateFilePartEnumerableForCurrentEntry().Cast<RarFilePart>(), this);
|
||||
if (Entry.IsRarV3)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace SharpCompress.Readers
|
||||
/// <returns></returns>
|
||||
public static IReader Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
options = options ?? new ReaderOptions()
|
||||
{
|
||||
LeaveStreamOpen = false
|
||||
@@ -104,4 +104,4 @@ namespace SharpCompress.Readers
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace SharpCompress.Readers.Tar
|
||||
/// <returns></returns>
|
||||
public static TarReader Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
options = options ?? new ReaderOptions();
|
||||
RewindableStream rewindableStream = new RewindableStream(stream);
|
||||
rewindableStream.StartRecording();
|
||||
@@ -121,4 +121,4 @@ namespace SharpCompress.Readers.Tar
|
||||
return TarEntry.GetEntries(StreamingMode.Streaming, stream, compressionType, Options.ArchiveEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace SharpCompress.Readers.Zip
|
||||
/// <returns></returns>
|
||||
public static ZipReader Open(Stream stream, ReaderOptions options = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new ZipReader(stream, options ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
@@ -58,4 +58,4 @@ namespace SharpCompress.Readers.Zip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>SharpCompress - Pure C# Decompression/Compression</AssemblyTitle>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.22.0</VersionPrefix>
|
||||
<AssemblyVersion>0.22.0</AssemblyVersion>
|
||||
<FileVersion>0.22.0</FileVersion>
|
||||
<VersionPrefix>0.24.0</VersionPrefix>
|
||||
<AssemblyVersion>0.24.0</AssemblyVersion>
|
||||
<FileVersion>0.24.0</FileVersion>
|
||||
<Authors>Adam Hathcock</Authors>
|
||||
<TargetFrameworks Condition="'$(LibraryFrameworks)'==''">net45;net35;netstandard1.0;netstandard1.3;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition="'$(LibraryFrameworks)'==''">net46;netstandard1.4;netstandard2.0</TargetFrameworks>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>SharpCompress</AssemblyName>
|
||||
@@ -16,24 +16,15 @@
|
||||
<PackageId>SharpCompress</PackageId>
|
||||
<PackageTags>rar;unrar;zip;unzip;bzip2;gzip;tar;7zip;lzip;xz</PackageTags>
|
||||
<PackageProjectUrl>https://github.com/adamhathcock/sharpcompress</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</PackageLicenseUrl>
|
||||
<PackageLicense>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</PackageLicense>
|
||||
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<Description>SharpCompress is a compression library for NET Standard 1.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</Description>
|
||||
<Description>SharpCompress is a compression library for NET Standard 1.3/2.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</Description>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.0' ">
|
||||
<DefineConstants>$(DefineConstants);NO_FILE;NO_CRYPTO;SILVERLIGHT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
|
||||
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.6.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.6.0" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NETCORE
|
||||
using SharpCompress.Buffers;
|
||||
#endif
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress
|
||||
{
|
||||
internal static class Utility
|
||||
{
|
||||
public static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> items)
|
||||
public static readonly RecyclableMemoryStreamManager RECYCLABLE_MEMORY_STREAM_MANAGER = new RecyclableMemoryStreamManager();
|
||||
public static ReadOnlyCollection<T> ToReadOnly<T>(this ICollection<T> items)
|
||||
{
|
||||
return new ReadOnlyCollection<T>(items.ToList());
|
||||
return new ReadOnlyCollection<T>(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <param name="bits">Amount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static int URShift(int number, int bits)
|
||||
{
|
||||
@@ -38,7 +35,7 @@ namespace SharpCompress
|
||||
/// Performs an unsigned bitwise right shift with the specified number
|
||||
/// </summary>
|
||||
/// <param name="number">Number to operate on</param>
|
||||
/// <param name="bits">Ammount of bits to shift</param>
|
||||
/// <param name="bits">Amount of bits to shift</param>
|
||||
/// <returns>The resulting number from the shift operation</returns>
|
||||
public static long URShift(long number, int bits)
|
||||
{
|
||||
@@ -75,49 +72,15 @@ namespace SharpCompress
|
||||
array[index] = val;
|
||||
}
|
||||
}
|
||||
|
||||
#if NET45
|
||||
// super fast memset, up to 40x faster than for loop on large arrays
|
||||
// see https://stackoverflow.com/questions/1897555/what-is-the-equivalent-of-memset-in-c
|
||||
private static readonly Action<IntPtr, byte, uint> MemsetDelegate = CreateMemsetDelegate();
|
||||
|
||||
private static Action<IntPtr, byte, uint> CreateMemsetDelegate() {
|
||||
var dynamicMethod = new DynamicMethod(
|
||||
"Memset",
|
||||
MethodAttributes.Public | MethodAttributes.Static,
|
||||
CallingConventions.Standard,
|
||||
null,
|
||||
new[] { typeof(IntPtr), typeof(byte), typeof(uint) },
|
||||
typeof(Utility),
|
||||
true);
|
||||
var generator = dynamicMethod.GetILGenerator();
|
||||
generator.Emit(OpCodes.Ldarg_0);
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldarg_2);
|
||||
generator.Emit(OpCodes.Initblk);
|
||||
generator.Emit(OpCodes.Ret);
|
||||
return (Action<IntPtr, byte, uint>)dynamicMethod.CreateDelegate(typeof(Action<IntPtr, byte, uint>));
|
||||
}
|
||||
|
||||
public static void Memset(byte[] array, byte what, int length)
|
||||
{
|
||||
var gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
MemsetDelegate(gcHandle.AddrOfPinnedObject(), what, (uint)length);
|
||||
gcHandle.Free();
|
||||
ref byte ptr = ref array[0];
|
||||
Unsafe.InitBlock(ref ptr, what, (uint)length);
|
||||
}
|
||||
#else
|
||||
public static void Memset(byte[] array, byte what, int length)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = what;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void Memset<T>(T[] array, T what, int length)
|
||||
{
|
||||
for(var i = 0; i < length; i++)
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = what;
|
||||
}
|
||||
@@ -184,7 +147,7 @@ namespace SharpCompress
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
|
||||
{
|
||||
if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue)
|
||||
@@ -215,7 +178,7 @@ namespace SharpCompress
|
||||
obj.CheckNotNull(name);
|
||||
if (obj.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("String is empty.");
|
||||
throw new ArgumentException("String is empty.", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,9 +217,7 @@ namespace SharpCompress
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETCORE
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,9 +233,7 @@ namespace SharpCompress
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETCORE
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,9 +318,7 @@ namespace SharpCompress
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETCORE
|
||||
ArrayPool<byte>.Shared.Return(array);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,9 +341,7 @@ namespace SharpCompress
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETCORE
|
||||
ArrayPool<byte>.Shared.Return(array);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,11 +352,7 @@ namespace SharpCompress
|
||||
|
||||
private static byte[] GetTransferByteArray()
|
||||
{
|
||||
#if NETCORE
|
||||
return ArrayPool<byte>.Shared.Rent(81920);
|
||||
#else
|
||||
return new byte[81920];
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool ReadFully(this Stream stream, byte[] buffer)
|
||||
@@ -440,4 +391,4 @@ namespace SharpCompress
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#if !NO_FILE
|
||||
using System;
|
||||
#endif
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace SharpCompress.Writers
|
||||
{
|
||||
@@ -12,7 +12,6 @@ namespace SharpCompress.Writers
|
||||
writer.Write(entryPath, source, null);
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
public static void Write(this IWriter writer, string entryPath, FileInfo source)
|
||||
{
|
||||
if (!source.Exists)
|
||||
@@ -30,22 +29,30 @@ namespace SharpCompress.Writers
|
||||
writer.Write(entryPath, new FileInfo(source));
|
||||
}
|
||||
|
||||
public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*",
|
||||
public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly)
|
||||
{
|
||||
writer.WriteAll(directory, searchPattern, null, option);
|
||||
}
|
||||
|
||||
public static void WriteAll(this IWriter writer,
|
||||
string directory,
|
||||
string searchPattern = "*",
|
||||
Expression<Func<string, bool>> fileSearchFunc = null,
|
||||
SearchOption option = SearchOption.TopDirectoryOnly)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
throw new ArgumentException("Directory does not exist: " + directory);
|
||||
}
|
||||
#if NET35
|
||||
foreach (var file in Directory.GetDirectories(directory, searchPattern, option))
|
||||
#else
|
||||
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option))
|
||||
#endif
|
||||
|
||||
if (fileSearchFunc == null)
|
||||
{
|
||||
fileSearchFunc = n => true;
|
||||
}
|
||||
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc.Compile()))
|
||||
{
|
||||
writer.Write(file.Substring(directory.Length), file);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Writers.Tar
|
||||
@@ -18,6 +17,7 @@ namespace SharpCompress.Writers.Tar
|
||||
|
||||
internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, true)
|
||||
{
|
||||
ArchiveEncoding = options.ArchiveEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,8 @@ namespace SharpCompress.Writers.Zip
|
||||
byte[] encodedComment = archiveEncoding.Encode(Comment);
|
||||
|
||||
var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue;
|
||||
var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue || Zip64HeaderOffset != 0;
|
||||
var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue;
|
||||
var usedCompression = compression;
|
||||
|
||||
var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed;
|
||||
var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed;
|
||||
@@ -56,17 +57,21 @@ namespace SharpCompress.Writers.Zip
|
||||
if (!zip64_stream)
|
||||
flags |= HeaderFlags.UsePostDataDescriptor;
|
||||
|
||||
if (compression == ZipCompressionMethod.LZMA)
|
||||
if (usedCompression == ZipCompressionMethod.LZMA)
|
||||
{
|
||||
flags |= HeaderFlags.Bit1; // eos marker
|
||||
}
|
||||
}
|
||||
|
||||
// Support for zero byte files
|
||||
if (Decompressed == 0 && Compressed == 0)
|
||||
usedCompression = ZipCompressionMethod.None;
|
||||
|
||||
//constant sig, then version made by, then version to extract
|
||||
outputStream.Write(new byte[] { 80, 75, 1, 2, version, 0, version, 0 }, 0, 8);
|
||||
|
||||
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)flags), 0, 2);
|
||||
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)compression), 0, 2); // zipping method
|
||||
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)usedCompression), 0, 2); // zipping method
|
||||
outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4);
|
||||
|
||||
// zipping date and time
|
||||
|
||||
@@ -383,6 +383,14 @@ namespace SharpCompress.Writers.Zip
|
||||
originalStream.Position = (long)(entry.HeaderOffset + 6);
|
||||
originalStream.WriteByte(0);
|
||||
|
||||
if (counting.Count == 0 && entry.Decompressed == 0)
|
||||
{
|
||||
// set compression to STORED for zero byte files (no compression data)
|
||||
originalStream.Position = (long)(entry.HeaderOffset + 8);
|
||||
originalStream.WriteByte(0);
|
||||
originalStream.WriteByte(0);
|
||||
}
|
||||
|
||||
originalStream.Position = (long)(entry.HeaderOffset + 14);
|
||||
|
||||
writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue);
|
||||
|
||||
@@ -10,7 +10,7 @@ using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class ArchiveTests : TestBase
|
||||
public class ArchiveTests : ReaderTests
|
||||
{
|
||||
protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression)
|
||||
{
|
||||
@@ -23,14 +23,13 @@ namespace SharpCompress.Test
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = new NonDisposingStream(File.OpenRead(path), true))
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
Assert.True(archive.IsSolid);
|
||||
using (var reader = archive.ExtractAllEntries())
|
||||
{
|
||||
ReaderTests.UseReader(this, reader, compression);
|
||||
UseReader(reader, compression);
|
||||
}
|
||||
VerifyFiles();
|
||||
|
||||
@@ -69,7 +68,6 @@ namespace SharpCompress.Test
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = new NonDisposingStream(File.OpenRead(path), true))
|
||||
using (var archive = ArchiveFactory.Open(stream, readerOptions))
|
||||
{
|
||||
@@ -106,118 +104,42 @@ namespace SharpCompress.Test
|
||||
protected void ArchiveFileRead(string testArchive, ReaderOptions readerOptions = null)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileRead(testArchive.AsEnumerable(), readerOptions);
|
||||
}
|
||||
|
||||
protected void ArchiveFileRead(IEnumerable<string> testArchives, ReaderOptions readerOptions = null)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var archive = ArchiveFactory.Open(testArchive, readerOptions))
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = ArchiveFactory.Open(path, readerOptions))
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
//archive.EntryExtractionBegin += archive_EntryExtractionBegin;
|
||||
//archive.FilePartExtractionBegin += archive_FilePartExtractionBegin;
|
||||
//archive.CompressedBytesRead += archive_CompressedBytesRead;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
private void archive_CompressedBytesRead(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
Console.WriteLine("Read Compressed File Part Bytes: {0} Percentage: {1}%",
|
||||
e.CurrentFilePartCompressedBytesRead, CreatePercentage(e.CurrentFilePartCompressedBytesRead, partTotal));
|
||||
|
||||
string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead,
|
||||
entryTotal.Value).ToString() : "Unknown";
|
||||
Console.WriteLine("Read Compressed File Entry Bytes: {0} Percentage: {1}%",
|
||||
e.CompressedBytesRead, percentage);
|
||||
}
|
||||
|
||||
private void archive_FilePartExtractionBegin(object sender, FilePartExtractionBeginEventArgs e)
|
||||
{
|
||||
partTotal = e.Size;
|
||||
Console.WriteLine("Initializing File Part Extraction: " + e.Name);
|
||||
}
|
||||
|
||||
private void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
entryTotal = e.Item.Size;
|
||||
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key);
|
||||
}
|
||||
|
||||
private long? entryTotal;
|
||||
private long partTotal;
|
||||
private long totalSize;
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(string testArchive)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileReadEx(testArchive.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the TotalUncompressSize property, and the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(IEnumerable<string> testArchives)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var archive = ArchiveFactory.Open(testArchive))
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = ArchiveFactory.Open(path))
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
totalSize = archive.TotalUncompressSize;
|
||||
//archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx;
|
||||
//archive.EntryExtractionEnd += Archive_EntryExtractionEndEx;
|
||||
//archive.CompressedBytesRead += Archive_CompressedBytesReadEx;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
PreserveAttributes = true,
|
||||
PreserveFileTime = true
|
||||
});
|
||||
}
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
PreserveAttributes = true,
|
||||
PreserveFileTime = true
|
||||
});
|
||||
}
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
partTotal += e.Item.Size;
|
||||
}
|
||||
|
||||
private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead, entryTotal.Value).ToString() : "-";
|
||||
string tortalPercentage = CreatePercentage(partTotal + e.CompressedBytesRead, totalSize).ToString();
|
||||
Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage);
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
entryTotal = e.Item.Size;
|
||||
}
|
||||
|
||||
private int CreatePercentage(long n, long d)
|
||||
{
|
||||
return (int)(((double)n / (double)d) * 100);
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Archive_Generic()
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
@@ -31,8 +30,7 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Archive()
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
@@ -47,8 +45,7 @@ namespace SharpCompress.Test.GZip
|
||||
public void GZip_Archive_NoAdd()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => archive.AddEntry("jpg\\test.jpg", jpg));
|
||||
@@ -60,9 +57,8 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Archive_Multiple_Reads()
|
||||
{
|
||||
ResetScratch();
|
||||
var inputStream = new MemoryStream();
|
||||
using (var fileStream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
{
|
||||
fileStream.CopyTo(inputStream);
|
||||
inputStream.Position = 0;
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Writer_Generic()
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip))
|
||||
{
|
||||
@@ -30,7 +29,6 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Writer()
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
|
||||
using (var writer = new GZipWriter(stream))
|
||||
{
|
||||
@@ -44,17 +42,12 @@ namespace SharpCompress.Test.GZip
|
||||
public void GZip_Writer_Generic_Bad_Compression()
|
||||
{
|
||||
Assert.Throws<InvalidFormatException>(() =>
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2))
|
||||
{
|
||||
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
}
|
||||
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
|
||||
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
|
||||
|
||||
});
|
||||
{
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2))
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs
Normal file
57
tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test.Mocks
|
||||
{
|
||||
// This is a simplified version of CryptoStream that always flushes the inner stream on Dispose to trigger an error in EntryStream
|
||||
// CryptoStream doesn't always trigger the Flush, so this class is used instead
|
||||
// See https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/cryptostream.cs,141
|
||||
|
||||
public class FlushOnDisposeStream : Stream, IDisposable
|
||||
{
|
||||
private Stream inner;
|
||||
|
||||
public FlushOnDisposeStream(Stream innerStream) {
|
||||
this.inner = innerStream;
|
||||
}
|
||||
|
||||
public override bool CanRead => this.inner.CanRead;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override long Length => this.inner.Length;
|
||||
|
||||
public override long Position { get => this.inner.Position; set => this.inner.Position = value; }
|
||||
|
||||
public override void Flush() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
return this.inner.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
if(disposing) {
|
||||
this.inner.Flush();
|
||||
this.inner.Close();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
namespace SharpCompress.Test.Mocks
|
||||
{
|
||||
public class ForwardOnlyStream : Stream
|
||||
{
|
||||
@@ -16,9 +16,15 @@ namespace SharpCompress.Test
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
@@ -44,11 +50,6 @@ namespace SharpCompress.Test
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return stream.ReadByte();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
69
tests/SharpCompress.Test/Mocks/TestStream.cs
Normal file
69
tests/SharpCompress.Test/Mocks/TestStream.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test.Mocks
|
||||
{
|
||||
public class TestStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
|
||||
public TestStream(Stream stream) : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public TestStream(Stream stream, bool read, bool write, bool seek)
|
||||
{
|
||||
this.stream = stream;
|
||||
CanRead = read;
|
||||
CanWrite = write;
|
||||
CanSeek = seek;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
public override bool CanRead { get; }
|
||||
|
||||
public override bool CanSeek { get; }
|
||||
|
||||
public override bool CanWrite { get; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => stream.Length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => stream.Position;
|
||||
set => stream.Position = value;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void ReadRarPassword(string testArchive, string password)
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
|
||||
using (var archive = RarArchive.Open(stream, new ReaderOptions()
|
||||
{
|
||||
@@ -80,7 +79,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
protected void ArchiveFileReadPassword(string archiveName, string password)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), new ReaderOptions()
|
||||
{
|
||||
Password = password,
|
||||
@@ -131,7 +129,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_test_invalid_exttime_ArchiveStreamRead(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
{
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
@@ -151,7 +148,6 @@ namespace SharpCompress.Test.Rar
|
||||
[Fact]
|
||||
public void Rar_Jpg_ArchiveStreamRead()
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg")))
|
||||
{
|
||||
using (var archive = RarArchive.Open(stream, new ReaderOptions()
|
||||
@@ -185,7 +181,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_IsSolidArchiveCheck(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
{
|
||||
using (var archive = RarArchive.Open(stream))
|
||||
@@ -253,7 +248,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Multi_ArchiveStreamRead(string[] archives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = RarArchive.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
|
||||
.Select(File.OpenRead)))
|
||||
{
|
||||
@@ -305,7 +299,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_ArchiveFileRead_HasDirectories(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
{
|
||||
using (var archive = RarArchive.Open(stream))
|
||||
@@ -319,7 +312,6 @@ namespace SharpCompress.Test.Rar
|
||||
[Fact]
|
||||
public void Rar_Jpg_ArchiveFileRead()
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"), new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
public RarHeaderFactoryTest()
|
||||
{
|
||||
ResetScratch();
|
||||
rarHeaderFactory = new RarHeaderFactory(
|
||||
StreamingMode.Seekable,
|
||||
new ReaderOptions { LeaveStreamOpen = true });
|
||||
@@ -47,7 +46,7 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void ReadEncryptedFlag(string testArchive, bool isEncrypted)
|
||||
{
|
||||
using (var stream = GetReaderStream(testArchive))
|
||||
using (var stream = new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
foreach (var header in rarHeaderFactory.ReadHeaders(stream))
|
||||
{
|
||||
@@ -59,10 +58,5 @@ namespace SharpCompress.Test.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FileStream GetReaderStream(string testArchive)
|
||||
{
|
||||
return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), FileMode.Open);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Multi_Reader(string[] archives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var reader = RarReader.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
|
||||
.Select(p => File.OpenRead(p))))
|
||||
{
|
||||
@@ -64,7 +63,6 @@ namespace SharpCompress.Test.Rar
|
||||
{
|
||||
Assert.Throws<InvalidFormatException>(() =>
|
||||
{
|
||||
ResetScratch();
|
||||
using (var reader = RarReader.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
|
||||
.Select(p => File.OpenRead(p)),
|
||||
new ReaderOptions()
|
||||
@@ -110,7 +108,6 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Multi_Reader_Delete_Files(string[] archives)
|
||||
{
|
||||
ResetScratch();
|
||||
|
||||
foreach (var file in archives)
|
||||
{
|
||||
@@ -202,27 +199,7 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void ReadRar(string testArchive, string password)
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
{
|
||||
Password = password
|
||||
}))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
Read(testArchive, CompressionType.Rar, new ReaderOptions { Password = password });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -237,9 +214,8 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Entry_Stream(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
@@ -271,9 +247,8 @@ namespace SharpCompress.Test.Rar
|
||||
[Fact]
|
||||
public void Rar_Reader_Audio_program()
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar")))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
@@ -295,7 +270,6 @@ namespace SharpCompress.Test.Rar
|
||||
[Fact]
|
||||
public void Rar_Jpg_Reader()
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg")))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
{
|
||||
@@ -339,9 +313,8 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Solid_Skip_Reader(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
@@ -373,9 +346,8 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void DoRar_Reader_Skip(string filename)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
|
||||
@@ -1,52 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class ReaderTests : TestBase
|
||||
public abstract class ReaderTests : TestBase
|
||||
{
|
||||
protected void Read(string testArchive, CompressionType expectedCompression)
|
||||
protected void Read(string testArchive, CompressionType expectedCompression, ReaderOptions options = null)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
Read(testArchive.AsEnumerable(), expectedCompression);
|
||||
|
||||
options = options ?? new ReaderOptions();
|
||||
|
||||
options.LeaveStreamOpen = true;
|
||||
ReadImpl(testArchive, expectedCompression, options);
|
||||
|
||||
options.LeaveStreamOpen = false;
|
||||
ReadImpl(testArchive, expectedCompression, options);
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
protected void Read(IEnumerable<string> testArchives, CompressionType expectedCompression)
|
||||
private void ReadImpl(string testArchive, CompressionType expectedCompression, ReaderOptions options)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var file = File.OpenRead(testArchive))
|
||||
{
|
||||
using (var stream = new NonDisposingStream(new ForwardOnlyStream(File.OpenRead(path)), true))
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LeaveStreamOpen = true
|
||||
}))
|
||||
using (var protectedStream = new NonDisposingStream(new ForwardOnlyStream(file), throwOnDispose: true))
|
||||
{
|
||||
UseReader(this, reader, expectedCompression);
|
||||
stream.ThrowOnDispose = false;
|
||||
using (var testStream = new TestStream(protectedStream))
|
||||
{
|
||||
using (var reader = ReaderFactory.Open(testStream, options))
|
||||
{
|
||||
UseReader(reader, expectedCompression);
|
||||
protectedStream.ThrowOnDispose = false;
|
||||
Assert.False(testStream.IsDisposed, "{nameof(testStream)} prematurely closed");
|
||||
}
|
||||
|
||||
// Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false)
|
||||
// and if the stream should be closed (false), then the stream should be disposed (true)
|
||||
var message = $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}";
|
||||
Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UseReader(TestBase test, IReader reader, CompressionType expectedCompression)
|
||||
public void UseReader(IReader reader, CompressionType expectedCompression)
|
||||
{
|
||||
test.ResetScratch();
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(reader.Entry.CompressionType, expectedCompression);
|
||||
reader.WriteEntryToDirectory(test.SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
test.VerifyFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
|
||||
<AssemblyName>SharpCompress.Test</AssemblyName>
|
||||
<AssemblyOriginatorKeyFile>../../SharpCompress.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
@@ -12,9 +12,10 @@
|
||||
<ProjectReference Include="..\..\src\SharpCompress\SharpCompress.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="Xunit.SkippableFact" Version="1.3.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="Xunit.SkippableFact" Version="1.3.12" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@ using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Streams
|
||||
{
|
||||
public class StreamTests
|
||||
public class LzmaStreamTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestLzma2Decompress1Byte()
|
||||
@@ -2,7 +2,7 @@
|
||||
using SharpCompress.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
namespace SharpCompress.Test.Streams
|
||||
{
|
||||
public class RewindableStreamTest
|
||||
{
|
||||
@@ -5,6 +5,10 @@ using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers;
|
||||
using Xunit;
|
||||
using System.Text;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
using SharpCompress.Readers.Tar;
|
||||
|
||||
namespace SharpCompress.Test.Tar
|
||||
{
|
||||
@@ -27,6 +31,39 @@ namespace SharpCompress.Test.Tar
|
||||
ArchiveFileRead("Tar.tar");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_FileName_Exactly_100_Characters()
|
||||
{
|
||||
string archive = "Tar_FileName_Exactly_100_Characters.tar";
|
||||
|
||||
|
||||
// create the 100 char filename
|
||||
string filename = "filename_with_exactly_100_characters_______________________________________________________________X";
|
||||
|
||||
// Step 1: create a tar file containing a file with the test name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
StreamWriter sw = new StreamWriter(inputStream);
|
||||
sw.Write("dummy filecontent");
|
||||
sw.Flush();
|
||||
|
||||
inputStream.Position = 0;
|
||||
writer.Write(filename, inputStream, null);
|
||||
}
|
||||
|
||||
// Step 2: check if the written tar file can be read correctly
|
||||
string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive);
|
||||
using (var archive2 = TarArchive.Open(unmodified))
|
||||
{
|
||||
Assert.Equal(1, archive2.Entries.Count);
|
||||
Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key));
|
||||
|
||||
foreach (var entry in archive2.Entries)
|
||||
Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne()
|
||||
@@ -48,7 +85,6 @@ namespace SharpCompress.Test.Tar
|
||||
{
|
||||
string archive = "Tar_VeryLongFilepathReadback.tar";
|
||||
|
||||
ResetScratch();
|
||||
|
||||
// create a very long filename
|
||||
string longFilename = "";
|
||||
@@ -103,11 +139,17 @@ namespace SharpCompress.Test.Tar
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
ResetScratch();
|
||||
// var aropt = new Ar
|
||||
|
||||
using (var archive = TarArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = new ArchiveEncoding()
|
||||
{
|
||||
Default = Encoding.GetEncoding(866)
|
||||
};
|
||||
archive.SaveTo(scratchPath, twopt);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
}
|
||||
@@ -119,7 +161,6 @@ namespace SharpCompress.Test.Tar
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
|
||||
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
ResetScratch();
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
archive.AddEntry("jpg\\test.jpg", jpg);
|
||||
@@ -135,7 +176,6 @@ namespace SharpCompress.Test.Tar
|
||||
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
ResetScratch();
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg"));
|
||||
@@ -155,5 +195,51 @@ namespace SharpCompress.Test.Tar
|
||||
Assert.True(archive.Type == ArchiveType.Tar);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_Empty_Archive()
|
||||
{
|
||||
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar");
|
||||
using (Stream stream = File.OpenRead(archiveFullPath))
|
||||
using (IArchive archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
Assert.True(archive.Type == ArchiveType.Tar);
|
||||
}
|
||||
}
|
||||
[Theory]
|
||||
[InlineData(10)]
|
||||
[InlineData(128)]
|
||||
public void Tar_Japanese_Name(int length)
|
||||
{
|
||||
using (var mstm = new MemoryStream())
|
||||
{
|
||||
var enc = new ArchiveEncoding()
|
||||
{
|
||||
Default = Encoding.UTF8
|
||||
};
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = enc;
|
||||
var fname = new string((char)0x3042, length);
|
||||
using (var tw = new TarWriter(mstm, twopt))
|
||||
using (var input = new MemoryStream(new byte[32]))
|
||||
{
|
||||
tw.Write(fname, input, null);
|
||||
}
|
||||
using (var inputMemory = new MemoryStream(mstm.ToArray()))
|
||||
{
|
||||
var tropt = new ReaderOptions()
|
||||
{
|
||||
ArchiveEncoding = enc
|
||||
};
|
||||
using (var tr = TarReader.Open(inputMemory, tropt))
|
||||
{
|
||||
while (tr.MoveToNextEntry())
|
||||
{
|
||||
Assert.Equal(fname, tr.Entry.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Tar
|
||||
@@ -26,7 +27,6 @@ namespace SharpCompress.Test.Tar
|
||||
using (Stream stream = new ForwardOnlyStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))))
|
||||
using (IReader reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
ResetScratch();
|
||||
int x = 0;
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
@@ -74,7 +74,6 @@ namespace SharpCompress.Test.Tar
|
||||
[Fact]
|
||||
public void Tar_BZip2_Entry_Stream()
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2")))
|
||||
using (var reader = TarReader.Open(stream))
|
||||
{
|
||||
@@ -161,5 +160,91 @@ namespace SharpCompress.Test.Tar
|
||||
Assert.True(reader.ArchiveType == ArchiveType.Tar);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_With_TarGz_With_Flushed_EntryStream()
|
||||
{
|
||||
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsTarGz.tar");
|
||||
using(Stream stream = File.OpenRead(archiveFullPath))
|
||||
using(IReader reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.Equal("inner.tar.gz", reader.Entry.Key);
|
||||
|
||||
using(var entryStream = reader.OpenEntryStream()) {
|
||||
|
||||
using(FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream)) {
|
||||
|
||||
// Extract inner.tar.gz
|
||||
using(var innerReader = ReaderFactory.Open(flushingStream)) {
|
||||
|
||||
Assert.True(innerReader.MoveToNextEntry());
|
||||
Assert.Equal("test", innerReader.Entry.Key);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_GZip_With_Symlink_Entries()
|
||||
{
|
||||
var isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
|
||||
System.Runtime.InteropServices.OSPlatform.Windows);
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz")))
|
||||
using (var reader = TarReader.Open(stream))
|
||||
{
|
||||
List<string> names = new List<string>();
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (reader.Entry.IsDirectory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
WriteSymbolicLink = (sourcePath, targetPath) =>
|
||||
{
|
||||
if (!isWindows)
|
||||
{
|
||||
var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath);
|
||||
if (System.IO.File.Exists(sourcePath))
|
||||
{
|
||||
link.Delete(); // equivalent to ln -s -f
|
||||
}
|
||||
link.CreateSymbolicLinkTo(targetPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!isWindows)
|
||||
{
|
||||
if (reader.Entry.LinkTarget != null)
|
||||
{
|
||||
var path = System.IO.Path.Combine(SCRATCH_FILES_PATH, reader.Entry.Key);
|
||||
var link = new Mono.Unix.UnixSymbolicLinkInfo(path);
|
||||
if (link.HasContents)
|
||||
{
|
||||
// need to convert the link to an absolute path for comparison
|
||||
var target = reader.Entry.LinkTarget;
|
||||
var realTarget = System.IO.Path.GetFullPath(
|
||||
System.IO.Path.Combine($"{System.IO.Path.GetDirectoryName(path)}",
|
||||
target)
|
||||
);
|
||||
|
||||
Assert.Equal(realTarget, link.GetContents().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(false, "Symlink has no target");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,23 +3,20 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using SharpCompress.Readers;
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class TestBase
|
||||
public class TestBase : IDisposable
|
||||
{
|
||||
private string SOLUTION_BASE_PATH;
|
||||
protected string TEST_ARCHIVES_PATH;
|
||||
protected string ORIGINAL_FILES_PATH;
|
||||
protected string MISC_TEST_FILES_PATH;
|
||||
private string SCRATCH_BASE_PATH;
|
||||
public string SCRATCH_FILES_PATH;
|
||||
protected string SCRATCH2_FILES_PATH;
|
||||
|
||||
|
||||
public TestBase()
|
||||
{
|
||||
@@ -29,23 +26,18 @@ namespace SharpCompress.Test
|
||||
TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives");
|
||||
ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original");
|
||||
MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest");
|
||||
SCRATCH_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch");
|
||||
SCRATCH2_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch2");
|
||||
}
|
||||
|
||||
public void ResetScratch()
|
||||
{
|
||||
if (Directory.Exists(SCRATCH_FILES_PATH))
|
||||
{
|
||||
Directory.Delete(SCRATCH_FILES_PATH, true);
|
||||
}
|
||||
Directory.CreateDirectory(SCRATCH_FILES_PATH);
|
||||
if (Directory.Exists(SCRATCH2_FILES_PATH))
|
||||
{
|
||||
Directory.Delete(SCRATCH2_FILES_PATH, true);
|
||||
}
|
||||
Directory.CreateDirectory(SCRATCH2_FILES_PATH);
|
||||
|
||||
SCRATCH_BASE_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", Guid.NewGuid().ToString());
|
||||
SCRATCH_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch");
|
||||
SCRATCH2_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch2");
|
||||
|
||||
Directory.CreateDirectory(SCRATCH_FILES_PATH);
|
||||
Directory.CreateDirectory(SCRATCH2_FILES_PATH);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Directory.Delete(SCRATCH_BASE_PATH, true);
|
||||
}
|
||||
|
||||
public void VerifyFiles()
|
||||
@@ -169,14 +161,6 @@ namespace SharpCompress.Test
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFileLocked(new FileInfo(file1)))
|
||||
{
|
||||
throw new InvalidOperationException($"{file1} is not disposed");
|
||||
}
|
||||
if (IsFileLocked(new FileInfo(file2)))
|
||||
{
|
||||
throw new InvalidOperationException($"{file2} is not disposed");
|
||||
}
|
||||
using (var file1Stream = File.OpenRead(file1))
|
||||
using (var file2Stream = File.OpenRead(file2))
|
||||
{
|
||||
@@ -205,8 +189,7 @@ namespace SharpCompress.Test
|
||||
}
|
||||
|
||||
protected void CompareArchivesByPath(string file1, string file2) {
|
||||
ReaderOptions readerOptions = new ReaderOptions();
|
||||
|
||||
ReaderOptions readerOptions = new ReaderOptions { LeaveStreamOpen = false };
|
||||
readerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866);
|
||||
|
||||
//don't compare the order. OS X reads files from the file system in a different order therefore makes the archive ordering different
|
||||
@@ -231,29 +214,5 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
protected bool IsFileLocked(FileInfo file)
|
||||
{
|
||||
FileStream stream = null;
|
||||
|
||||
try
|
||||
{
|
||||
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
//the file is unavailable because it is:
|
||||
//still being written to
|
||||
//or being processed by another thread
|
||||
//or does not exist (has already been processed)
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Close();
|
||||
}
|
||||
|
||||
//file is not locked
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class TestStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
|
||||
public TestStream(Stream stream)
|
||||
: this(stream, true, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public TestStream(Stream stream, bool read, bool write, bool seek)
|
||||
{
|
||||
this.stream = stream;
|
||||
CanRead = read;
|
||||
CanWrite = write;
|
||||
CanSeek = seek;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
public override bool CanRead { get; }
|
||||
|
||||
public override bool CanSeek { get; }
|
||||
|
||||
public override bool CanWrite { get; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => stream.Length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => stream.Position;
|
||||
set => stream.Position = value;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ namespace SharpCompress.Test
|
||||
|
||||
protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst)
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) {
|
||||
WriterOptions writerOptions = new WriterOptions(compressionType)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Zip;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Zip;
|
||||
using Xunit;
|
||||
@@ -100,7 +101,6 @@ namespace SharpCompress.Test.Zip
|
||||
|
||||
public void RunSingleTest(long files, long filesize, bool set_zip64, bool forward_only, long write_chunk_size = 1024 * 1024, string filename = "zip64-test.zip")
|
||||
{
|
||||
ResetScratch();
|
||||
filename = Path.Combine(SCRATCH2_FILES_PATH, filename);
|
||||
|
||||
if (File.Exists(filename))
|
||||
@@ -134,7 +134,7 @@ namespace SharpCompress.Test.Zip
|
||||
var eo = new ZipWriterEntryOptions() { DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None };
|
||||
|
||||
using (var zip = File.OpenWrite(filename))
|
||||
using(var st = forward_only ? (Stream)new NonSeekableStream(zip) : zip)
|
||||
using(var st = forward_only ? (Stream)new ForwardOnlyStream(zip) : zip)
|
||||
using (var zipWriter = (ZipWriter)WriterFactory.Open(st, ArchiveType.Zip, opts))
|
||||
{
|
||||
|
||||
@@ -187,38 +187,5 @@ namespace SharpCompress.Test.Zip
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to create non-seekable streams from filestream
|
||||
/// </summary>
|
||||
private class NonSeekableStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
public NonSeekableStream(Stream s) { stream = s; }
|
||||
public override bool CanRead => stream.CanRead;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => stream.CanWrite;
|
||||
public override long Length => throw new NotImplementedException();
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public override void Flush() { stream.Flush(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{ return stream.Read(buffer, offset, count); }
|
||||
|
||||
public override int ReadByte()
|
||||
{ return stream.ReadByte(); }
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
public override void SetLength(long value)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{ stream.Write(buffer, offset, count); }
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{ stream.WriteByte(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user