Remove dotnet-archive and Microsoft.Dotnet.Archive
This commit is contained in:
parent
7d3461eed4
commit
0e4db81898
|
|
@ -1,6 +1,6 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26507.0
|
||||
VisualStudioVersion = 15.0.26510.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}"
|
||||
EndProject
|
||||
|
|
@ -39,10 +39,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartRequestDelegateUrlApp"
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateDefaultBuilderApp", "test\TestSites\CreateDefaultBuilderApp\CreateDefaultBuilderApp.csproj", "{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-archive", "src\dotnet-archive\dotnet-archive.csproj", "{AE4216BF-D471-471B-82F3-6B6D004F7D17}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Archive", "src\Microsoft.DotNet.Archive\Microsoft.DotNet.Archive.csproj", "{302400A0-98BB-4C04-88D4-C32DC2D4B945}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrimDeps", "tools\TrimDeps\TrimDeps.csproj", "{67E4C92F-6D12-4C52-BB79-B8D11BFC6B82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInjectionApp", "test\TestSites\DependencyInjectionApp\DependencyInjectionApp.csproj", "{65FE2E38-4529-4C93-A7B0-CF12DD7A70C3}"
|
||||
|
|
@ -85,14 +81,6 @@ Global
|
|||
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AE4216BF-D471-471B-82F3-6B6D004F7D17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE4216BF-D471-471B-82F3-6B6D004F7D17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE4216BF-D471-471B-82F3-6B6D004F7D17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AE4216BF-D471-471B-82F3-6B6D004F7D17}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{302400A0-98BB-4C04-88D4-C32DC2D4B945}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{302400A0-98BB-4C04-88D4-C32DC2D4B945}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{302400A0-98BB-4C04-88D4-C32DC2D4B945}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{302400A0-98BB-4C04-88D4-C32DC2D4B945}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67E4C92F-6D12-4C52-BB79-B8D11BFC6B82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67E4C92F-6D12-4C52-BB79-B8D11BFC6B82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67E4C92F-6D12-4C52-BB79-B8D11BFC6B82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -116,8 +104,6 @@ Global
|
|||
{3A85FA52-F601-422E-A42E-9F187DB28492} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||
{401C741B-6C7C-4E08-9F09-C3D43D22C0DE} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||
{79CF58CE-B020-45D8-BDB5-2D8036BEAD14} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||
{AE4216BF-D471-471B-82F3-6B6D004F7D17} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
|
||||
{302400A0-98BB-4C04-88D4-C32DC2D4B945} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
|
||||
{67E4C92F-6D12-4C52-BB79-B8D11BFC6B82} = {ED834E68-51C3-4ADE-ACC8-6BA6D4207C09}
|
||||
{65FE2E38-4529-4C93-A7B0-CF12DD7A70C3} = {EC22261D-0DE1-47DE-8F7C-072675D6F5B4}
|
||||
EndGlobalSection
|
||||
|
|
|
|||
|
|
@ -2,7 +2,5 @@
|
|||
<ItemGroup>
|
||||
<ExcludeFromPack Include="$(RepositoryRoot)src\Microsoft.AspNetCore.RuntimeStore\Microsoft.AspNetCore.RuntimeStore.csproj" />
|
||||
<ExcludeFromPack Include="$(RepositoryRoot)src\Archive.AspNetCore.All\Archive.AspNetCore.All.csproj" />
|
||||
<ExcludeFromPack Include="$(RepositoryRoot)src\dotnet-archive\dotnet-archive.csproj" />
|
||||
<ExcludeFromPack Include="$(RepositoryRoot)src\Microsoft.DotNet.Archive\Microsoft.DotNet.Archive.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
<!-- Project for building the NuGet Fallback Archive (LZMA for CLI) -->
|
||||
<FallbackArchiveDir>$(RepositoryRoot)src\Archive.AspNetCore.All\</FallbackArchiveDir>
|
||||
<FallbackArchiveProj>$(FallbackArchiveDir)Archive.AspNetCore.All.csproj</FallbackArchiveProj>
|
||||
<ArchiverProject>$(RepositoryRoot)src\dotnet-archive\dotnet-archive.csproj</ArchiverProject>
|
||||
<ArchiverBinary>$(RepositoryRoot)src\dotnet-archive\bin\$(Configuration)\netcoreapp2.0\dotnet-archive.dll</ArchiverBinary>
|
||||
|
||||
<!-- Determine ASP.NET Package Version -->
|
||||
<NoTimestampSuffix Condition="'$(TIMESTAMP_FREE_VERSION)' != ''">$(TIMESTAMP_FREE_VERSION)</NoTimestampSuffix>
|
||||
|
|
@ -274,10 +272,6 @@
|
|||
<TimestampSource>$(COHERENCE_SIGNED_DROP_LOCATION)\Signed\Packages</TimestampSource>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Build the dotnet-archiver project -->
|
||||
<MSBuild Projects="$(ArchiverProject)" Targets="Restore" Properties="Configuration=$(Configuration)" />
|
||||
<MSBuild Projects="$(ArchiverProject)" Targets="Build" Properties="Configuration=$(Configuration)" />
|
||||
|
||||
<!-- Run the actual target twice, once for timestamped packages, once for non-timestamped packages -->
|
||||
<!-- Here, we're re-invoking KoreBuild, but limiting it to a specific target. -->
|
||||
<!-- This won't rerun the whole build, but it ensures that the necessary MSBuild Tasks and Properties are initialized -->
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<Import Project="..\..\build\dependencies.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using SevenZip;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.Archive
|
||||
{
|
||||
internal static class CompressionUtility
|
||||
{
|
||||
enum MeasureBy
|
||||
{
|
||||
Input,
|
||||
Output
|
||||
}
|
||||
|
||||
private class LzmaProgress : ICodeProgress
|
||||
{
|
||||
private IProgress<ProgressReport> progress;
|
||||
private long totalSize;
|
||||
private string phase;
|
||||
private MeasureBy measureBy;
|
||||
|
||||
public LzmaProgress(IProgress<ProgressReport> progress, string phase, long totalSize, MeasureBy measureBy)
|
||||
{
|
||||
this.progress = progress;
|
||||
this.totalSize = totalSize;
|
||||
this.phase = phase;
|
||||
this.measureBy = measureBy;
|
||||
}
|
||||
|
||||
public void SetProgress(long inSize, long outSize)
|
||||
{
|
||||
progress.Report(phase, measureBy == MeasureBy.Input ? inSize : outSize, totalSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Compress(Stream inStream, Stream outStream, IProgress<ProgressReport> progress)
|
||||
{
|
||||
SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
|
||||
|
||||
CoderPropID[] propIDs =
|
||||
{
|
||||
CoderPropID.DictionarySize,
|
||||
CoderPropID.PosStateBits,
|
||||
CoderPropID.LitContextBits,
|
||||
CoderPropID.LitPosBits,
|
||||
CoderPropID.Algorithm,
|
||||
CoderPropID.NumFastBytes,
|
||||
CoderPropID.MatchFinder,
|
||||
CoderPropID.EndMarker
|
||||
};
|
||||
object[] properties =
|
||||
{
|
||||
(Int32)(1 << 26),
|
||||
(Int32)(1),
|
||||
(Int32)(8),
|
||||
(Int32)(0),
|
||||
(Int32)(2),
|
||||
(Int32)(96),
|
||||
"bt4",
|
||||
false
|
||||
};
|
||||
|
||||
encoder.SetCoderProperties(propIDs, properties);
|
||||
encoder.WriteCoderProperties(outStream);
|
||||
|
||||
Int64 inSize = inStream.Length;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
outStream.WriteByte((Byte)(inSize >> (8 * i)));
|
||||
}
|
||||
|
||||
var lzmaProgress = new LzmaProgress(progress, "Compressing", inSize, MeasureBy.Input);
|
||||
lzmaProgress.SetProgress(0, 0);
|
||||
encoder.Code(inStream, outStream, -1, -1, lzmaProgress);
|
||||
lzmaProgress.SetProgress(inSize, outStream.Length);
|
||||
}
|
||||
|
||||
public static void Decompress(Stream inStream, Stream outStream, IProgress<ProgressReport> progress)
|
||||
{
|
||||
byte[] properties = new byte[5];
|
||||
|
||||
if (inStream.Read(properties, 0, 5) != 5)
|
||||
throw (new Exception("input .lzma is too short"));
|
||||
|
||||
SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
|
||||
decoder.SetDecoderProperties(properties);
|
||||
|
||||
long outSize = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int v = inStream.ReadByte();
|
||||
if (v < 0)
|
||||
throw (new Exception("Can't Read 1"));
|
||||
outSize |= ((long)(byte)v) << (8 * i);
|
||||
}
|
||||
|
||||
long compressedSize = inStream.Length - inStream.Position;
|
||||
var lzmaProgress = new LzmaProgress(progress, "Decompressing", outSize, MeasureBy.Output);
|
||||
lzmaProgress.SetProgress(0, 0);
|
||||
decoder.Code(inStream, outStream, compressedSize, outSize, lzmaProgress);
|
||||
lzmaProgress.SetProgress(inStream.Length, outSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.DotNet.Archive
|
||||
{
|
||||
public class ConsoleProgressReport : IProgress<ProgressReport>
|
||||
{
|
||||
private string _currentPhase;
|
||||
private int _lastLineLength = 0;
|
||||
private double _lastProgress = -1;
|
||||
private Stopwatch _stopwatch;
|
||||
private object _stateLock = new object();
|
||||
|
||||
public void Report(ProgressReport value)
|
||||
{
|
||||
long progress = (long)(100 * ((double)value.Ticks / value.Total));
|
||||
|
||||
if (progress == _lastProgress && value.Phase == _currentPhase)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lastProgress = progress;
|
||||
|
||||
lock (_stateLock)
|
||||
{
|
||||
string line = $"{value.Phase} {progress}%";
|
||||
if (value.Phase == _currentPhase)
|
||||
{
|
||||
if (Console.IsOutputRedirected)
|
||||
{
|
||||
Console.Write($"...{progress}%");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(new string('\b', _lastLineLength));
|
||||
Console.Write(line);
|
||||
}
|
||||
|
||||
_lastLineLength = line.Length;
|
||||
|
||||
if (progress == 100)
|
||||
{
|
||||
Console.WriteLine($" {_stopwatch.ElapsedMilliseconds} ms");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(line);
|
||||
_currentPhase = value.Phase;
|
||||
_lastLineLength = line.Length;
|
||||
_stopwatch = Stopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,541 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.DotNet.Archive
|
||||
{
|
||||
public class IndexedArchive : IDisposable
|
||||
{
|
||||
private class DestinationFileInfo
|
||||
{
|
||||
public DestinationFileInfo(string destinationPath, string hash)
|
||||
{
|
||||
// Normalize the path
|
||||
DestinationPath = destinationPath.Replace(Path.DirectorySeparatorChar, '/');
|
||||
Hash = hash;
|
||||
}
|
||||
|
||||
public string DestinationPath { get; }
|
||||
public string Hash { get; }
|
||||
}
|
||||
|
||||
private class ArchiveSource
|
||||
{
|
||||
public ArchiveSource(string sourceArchive, string sourceFile, string archivePath, string hash, long size)
|
||||
{
|
||||
Hash = hash;
|
||||
Size = size;
|
||||
|
||||
// Normalize the paths
|
||||
SourceArchive = sourceArchive?.Replace(Path.DirectorySeparatorChar, '/');
|
||||
SourceFile = sourceFile.Replace(Path.DirectorySeparatorChar, '/');
|
||||
ArchivePath = archivePath.Replace(Path.DirectorySeparatorChar, '/');
|
||||
}
|
||||
|
||||
public string SourceArchive { get; set; }
|
||||
public string SourceFile { get; set; }
|
||||
public string ArchivePath { get; }
|
||||
public string Hash { get; }
|
||||
public string FileName { get { return Path.GetFileNameWithoutExtension(ArchivePath); } }
|
||||
public string Extension { get { return Path.GetExtension(ArchivePath); } }
|
||||
public long Size { get; }
|
||||
|
||||
public void CopyTo(Stream destination)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(SourceArchive))
|
||||
{
|
||||
using (var zip = new ZipArchive(File.OpenRead(SourceArchive), ZipArchiveMode.Read))
|
||||
using (var sourceStream = zip.GetEntry(SourceFile)?.Open())
|
||||
{
|
||||
if (sourceStream == null)
|
||||
{
|
||||
throw new Exception($"Couldn't find entry {SourceFile} in archive {SourceArchive}");
|
||||
}
|
||||
|
||||
sourceStream.CopyTo(destination);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var sourceStream = File.OpenRead(SourceFile))
|
||||
{
|
||||
sourceStream.CopyTo(destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string[] ZipExtensions = new[] { ".zip", ".nupkg" };
|
||||
static string IndexFileName = "index.txt";
|
||||
|
||||
// maps file hash to archve path
|
||||
// $ prefix indicates that the file is not in the archive and path is a hash
|
||||
private Dictionary<string, ArchiveSource> _archiveFiles = new Dictionary<string, ArchiveSource>();
|
||||
// maps file hash to external path
|
||||
private Dictionary<string, string> _externalFiles = new Dictionary<string, string>();
|
||||
// lists all extracted files & hashes
|
||||
private List<DestinationFileInfo> _destFiles = new List<DestinationFileInfo>();
|
||||
private bool _disposed = false;
|
||||
private ThreadLocal<SHA256> _sha = new ThreadLocal<SHA256>(() => SHA256.Create());
|
||||
|
||||
public IndexedArchive()
|
||||
{ }
|
||||
|
||||
private static Stream CreateTemporaryStream()
|
||||
{
|
||||
string temp = Path.GetTempPath();
|
||||
string tempFile = Path.Combine(temp, Guid.NewGuid().ToString());
|
||||
return File.Create(tempFile, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
|
||||
private static FileStream CreateTemporaryFileStream()
|
||||
{
|
||||
string temp = Path.GetTempPath();
|
||||
string tempFile = Path.Combine(temp, Guid.NewGuid().ToString());
|
||||
return new FileStream(tempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Read | FileShare.Delete, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
|
||||
public void Save(string archivePath, IProgress<ProgressReport> progress)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
using (var archiveStream = CreateTemporaryStream())
|
||||
{
|
||||
using (var archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
BuildArchive(archive, progress);
|
||||
} // close archive
|
||||
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using (var lzmaStream = File.Create(archivePath))
|
||||
{
|
||||
CompressionUtility.Compress(archiveStream, lzmaStream, progress);
|
||||
}
|
||||
} // close archiveStream
|
||||
}
|
||||
|
||||
private void BuildArchive(ZipArchive archive, IProgress<ProgressReport> progress)
|
||||
{
|
||||
// write the file index
|
||||
var indexEntry = archive.CreateEntry(IndexFileName, CompressionLevel.NoCompression);
|
||||
|
||||
using (var stream = indexEntry.Open())
|
||||
using (var textWriter = new StreamWriter(stream))
|
||||
{
|
||||
foreach (var entry in _destFiles)
|
||||
{
|
||||
var archiveFile = _archiveFiles[entry.Hash];
|
||||
string archivePath = _archiveFiles[entry.Hash].ArchivePath;
|
||||
if (archiveFile.SourceFile == null)
|
||||
{
|
||||
archivePath = "$" + archivePath;
|
||||
}
|
||||
|
||||
textWriter.WriteLine($"{entry.DestinationPath}|{archivePath}");
|
||||
}
|
||||
}
|
||||
|
||||
// sort the files so that similar files are close together
|
||||
var filesToArchive = _archiveFiles.Values.ToList();
|
||||
filesToArchive.Sort((f1, f2) =>
|
||||
{
|
||||
// first sort by extension
|
||||
var comp = String.Compare(f1.Extension, f2.Extension, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (comp == 0)
|
||||
{
|
||||
// then sort by filename
|
||||
comp = String.Compare(f1.FileName, f2.FileName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (comp == 0)
|
||||
{
|
||||
// sort by file size (helps differentiate ref/lib/facade)
|
||||
comp = f1.Size.CompareTo(f2.Size);
|
||||
}
|
||||
|
||||
if (comp == 0)
|
||||
{
|
||||
// finally sort by full archive path so we have stable output
|
||||
comp = String.Compare(f1.ArchivePath, f2.ArchivePath, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return comp;
|
||||
});
|
||||
|
||||
int filesAdded = 0;
|
||||
// add all the files
|
||||
foreach (var fileToArchive in filesToArchive)
|
||||
{
|
||||
var entry = archive.CreateEntry(fileToArchive.ArchivePath, CompressionLevel.NoCompression);
|
||||
using (var entryStream = entry.Open())
|
||||
{
|
||||
fileToArchive.CopyTo(entryStream);
|
||||
}
|
||||
|
||||
progress.Report("Archiving files", ++filesAdded, filesToArchive.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class ExtractOperation
|
||||
{
|
||||
public ExtractOperation(string destinationPath)
|
||||
{
|
||||
DestinationPath = destinationPath;
|
||||
}
|
||||
|
||||
public string DestinationPath { get; }
|
||||
public virtual void DoOperation()
|
||||
{
|
||||
string directory = Path.GetDirectoryName(DestinationPath);
|
||||
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
Execute();
|
||||
}
|
||||
protected abstract void Execute();
|
||||
}
|
||||
|
||||
private class CopyOperation : ExtractOperation
|
||||
{
|
||||
public CopyOperation(ExtractSource source, string destinationPath) : base(destinationPath)
|
||||
{
|
||||
Source = source;
|
||||
}
|
||||
public ExtractSource Source { get; }
|
||||
protected override void Execute()
|
||||
{
|
||||
if (Source.LocalPath != null)
|
||||
{
|
||||
File.Copy(Source.LocalPath, DestinationPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var destinationStream = File.Create(DestinationPath))
|
||||
{
|
||||
Source.CopyToStream(destinationStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ZipOperation : ExtractOperation
|
||||
{
|
||||
public ZipOperation(string destinationPath) : base(destinationPath)
|
||||
{
|
||||
}
|
||||
|
||||
private List<Tuple<string, ExtractSource>> entries = new List<Tuple<string, ExtractSource>>();
|
||||
|
||||
public void AddEntry(string entryName, ExtractSource source)
|
||||
{
|
||||
entries.Add(Tuple.Create(entryName, source));
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
{
|
||||
using (var archiveStream = File.Create(DestinationPath))
|
||||
using (var archive = new ZipArchive(archiveStream, ZipArchiveMode.Create))
|
||||
{
|
||||
foreach (var zipSource in entries)
|
||||
{
|
||||
var entry = archive.CreateEntry(zipSource.Item1, CompressionLevel.Optimal);
|
||||
using (var entryStream = entry.Open())
|
||||
{
|
||||
zipSource.Item2.CopyToStream(entryStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ExtractSource
|
||||
{
|
||||
private string _entryName;
|
||||
private readonly string _localPath;
|
||||
private ThreadLocalZipArchive _archive;
|
||||
|
||||
public ExtractSource(string sourceString, Dictionary<string, string> externalFiles, ThreadLocalZipArchive archive)
|
||||
{
|
||||
if (sourceString[0] == '$')
|
||||
{
|
||||
var externalHash = sourceString.Substring(1);
|
||||
if (!externalFiles.TryGetValue(externalHash, out _localPath))
|
||||
{
|
||||
throw new Exception("Could not find external file with hash {externalHash}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_entryName = sourceString;
|
||||
_archive = archive;
|
||||
}
|
||||
}
|
||||
|
||||
public string LocalPath { get { return _localPath; } }
|
||||
|
||||
public void CopyToStream(Stream destinationStream)
|
||||
{
|
||||
if (_localPath != null)
|
||||
{
|
||||
using (var sourceStream = File.OpenRead(_localPath))
|
||||
{
|
||||
sourceStream.CopyTo(destinationStream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var sourceStream = _archive.Archive.GetEntry(_entryName).Open())
|
||||
{
|
||||
sourceStream.CopyTo(destinationStream);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static char[] pipeSeperator = new[] { '|' };
|
||||
public void Extract(string compressedArchivePath, string outputDirectory, IProgress<ProgressReport> progress)
|
||||
{
|
||||
using (var archiveStream = CreateTemporaryFileStream())
|
||||
{
|
||||
// decompress the LZMA stream
|
||||
using (var lzmaStream = File.OpenRead(compressedArchivePath))
|
||||
{
|
||||
CompressionUtility.Decompress(lzmaStream, archiveStream, progress);
|
||||
}
|
||||
|
||||
var archivePath = ((FileStream)archiveStream).Name;
|
||||
|
||||
// reset the uncompressed stream
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// read as a zip archive
|
||||
using (var archive = new ZipArchive(archiveStream, ZipArchiveMode.Read))
|
||||
using (var tlArchive = new ThreadLocalZipArchive(archivePath, archive))
|
||||
{
|
||||
List<ExtractOperation> extractOperations = new List<ExtractOperation>();
|
||||
Dictionary<string, ExtractSource> sourceCache = new Dictionary<string, ExtractSource>();
|
||||
|
||||
// process the index to determine all extraction operations
|
||||
var indexEntry = archive.GetEntry(IndexFileName);
|
||||
using (var indexReader = new StreamReader(indexEntry.Open()))
|
||||
{
|
||||
Dictionary<string, ZipOperation> zipOperations = new Dictionary<string, ZipOperation>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var line = indexReader.ReadLine(); line != null; line = indexReader.ReadLine())
|
||||
{
|
||||
var lineParts = line.Split(pipeSeperator);
|
||||
if (lineParts.Length != 2)
|
||||
{
|
||||
throw new Exception("Unexpected index line format, too many '|'s.");
|
||||
}
|
||||
|
||||
string target = lineParts[0];
|
||||
string source = lineParts[1];
|
||||
|
||||
ExtractSource extractSource;
|
||||
if (!sourceCache.TryGetValue(source, out extractSource))
|
||||
{
|
||||
sourceCache[source] = extractSource = new ExtractSource(source, _externalFiles, tlArchive);
|
||||
}
|
||||
|
||||
var zipSeperatorIndex = target.IndexOf("::", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (zipSeperatorIndex != -1)
|
||||
{
|
||||
string zipRelativePath = target.Substring(0, zipSeperatorIndex);
|
||||
string zipEntryName = target.Substring(zipSeperatorIndex + 2);
|
||||
string destinationPath = Path.Combine(outputDirectory, zipRelativePath);
|
||||
|
||||
// operations on a zip file will be sequential
|
||||
ZipOperation currentZipOperation;
|
||||
|
||||
if (!zipOperations.TryGetValue(destinationPath, out currentZipOperation))
|
||||
{
|
||||
extractOperations.Add(currentZipOperation = new ZipOperation(destinationPath));
|
||||
zipOperations.Add(destinationPath, currentZipOperation);
|
||||
}
|
||||
currentZipOperation.AddEntry(zipEntryName, extractSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
string destinationPath = Path.Combine(outputDirectory, target);
|
||||
extractOperations.Add(new CopyOperation(extractSource, destinationPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int opsExecuted = 0;
|
||||
// execute all operations
|
||||
//foreach(var extractOperation in extractOperations)
|
||||
extractOperations.AsParallel().ForAll(extractOperation =>
|
||||
{
|
||||
extractOperation.DoOperation();
|
||||
progress.Report("Expanding", Interlocked.Increment(ref opsExecuted), extractOperations.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddExternalDirectory(string externalDirectory)
|
||||
{
|
||||
CheckDisposed();
|
||||
foreach (var externalFile in Directory.EnumerateFiles(externalDirectory, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
AddExternalFile(externalFile);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddExternalFile(string externalFile)
|
||||
{
|
||||
CheckDisposed();
|
||||
using (var fs = File.OpenRead(externalFile))
|
||||
{
|
||||
string hash = GetHash(fs);
|
||||
// $ prefix indicates that the file is not in the archive and path is relative to an external directory
|
||||
_archiveFiles[hash] = new ArchiveSource(null, null, "$" + hash, hash, fs.Length);
|
||||
_externalFiles[hash] = externalFile;
|
||||
}
|
||||
}
|
||||
public void AddDirectory(string sourceDirectory, IProgress<ProgressReport> progress, string destinationDirectory = null)
|
||||
{
|
||||
var sourceFiles = Directory.EnumerateFiles(sourceDirectory, "*", SearchOption.AllDirectories).ToArray();
|
||||
int filesAdded = 0;
|
||||
sourceFiles.AsParallel().ForAll(sourceFile =>
|
||||
{
|
||||
// path relative to the destination/extracted directory to write the file
|
||||
string destinationRelativePath = sourceFile.Substring(sourceDirectory.Length + 1);
|
||||
|
||||
if (destinationDirectory != null)
|
||||
{
|
||||
destinationRelativePath = Path.Combine(destinationDirectory, destinationRelativePath);
|
||||
}
|
||||
|
||||
string extension = Path.GetExtension(sourceFile);
|
||||
|
||||
if (ZipExtensions.Any(ze => ze.Equals(extension, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
AddZip(sourceFile, destinationRelativePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddFile(sourceFile, destinationRelativePath);
|
||||
}
|
||||
|
||||
progress.Report($"Adding {sourceDirectory}", Interlocked.Increment(ref filesAdded), sourceFiles.Length);
|
||||
});
|
||||
}
|
||||
|
||||
public void AddZip(string sourceZipFile, string destinationZipFile)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
using (var sourceArchive = new ZipArchive(File.OpenRead(sourceZipFile), ZipArchiveMode.Read))
|
||||
{
|
||||
foreach (var entry in sourceArchive.Entries)
|
||||
{
|
||||
string hash = null;
|
||||
long size = entry.Length;
|
||||
string destinationPath = $"{destinationZipFile}::{entry.FullName}";
|
||||
using (var stream = entry.Open())
|
||||
{
|
||||
hash = GetHash(stream);
|
||||
}
|
||||
|
||||
AddArchiveSource(sourceZipFile, entry.FullName, destinationPath, hash, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFile(string sourceFilePath, string destinationPath)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
string hash;
|
||||
long size;
|
||||
// lifetime of this stream is managed by AddStream
|
||||
using (var stream = File.Open(sourceFilePath, FileMode.Open))
|
||||
{
|
||||
hash = GetHash(stream);
|
||||
size = stream.Length;
|
||||
}
|
||||
|
||||
AddArchiveSource(null, sourceFilePath, destinationPath, hash, size);
|
||||
}
|
||||
|
||||
private void AddArchiveSource(string sourceArchive, string sourceFile, string destinationPath, string hash, long size)
|
||||
{
|
||||
lock (_archiveFiles)
|
||||
{
|
||||
_destFiles.Add(new DestinationFileInfo(destinationPath, hash));
|
||||
|
||||
// see if we already have this file in the archive/external
|
||||
ArchiveSource existing = null;
|
||||
if (_archiveFiles.TryGetValue(hash, out existing))
|
||||
{
|
||||
// if we have raw source file, prefer that over a zipped source file
|
||||
if (sourceArchive == null && existing.SourceArchive != null)
|
||||
{
|
||||
existing.SourceArchive = null;
|
||||
existing.SourceFile = sourceFile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var archivePath = Path.Combine(hash, Path.GetFileName(destinationPath));
|
||||
|
||||
_archiveFiles.Add(hash, new ArchiveSource(sourceArchive, sourceFile, archivePath, hash, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GetHash(Stream stream)
|
||||
{
|
||||
var hashBytes = _sha.Value.ComputeHash(stream);
|
||||
|
||||
return GetHashString(hashBytes);
|
||||
}
|
||||
|
||||
private static string GetHashString(byte[] hashBytes)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(hashBytes.Length * 2);
|
||||
foreach (var b in hashBytes)
|
||||
{
|
||||
builder.AppendFormat("{0:x2}", b);
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (_sha != null)
|
||||
{
|
||||
_sha.Dispose();
|
||||
_sha = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(IndexedArchive));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// Common/CRC.cs
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
Table = new uint[256];
|
||||
const uint kPoly = 0xEDB88320;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((r & 1) != 0)
|
||||
r = (r >> 1) ^ kPoly;
|
||||
else
|
||||
r >>= 1;
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
uint _value = 0xFFFFFFFF;
|
||||
|
||||
public void Init() { _value = 0xFFFFFFFF; }
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
_value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public void Update(byte[] data, uint offset, uint size)
|
||||
{
|
||||
for (uint i = 0; i < size; i++)
|
||||
_value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
|
||||
|
||||
static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
CRC crc = new CRC();
|
||||
// crc.Init();
|
||||
crc.Update(data, offset, size);
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return (CalculateDigest(data, offset, size) == digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// InBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class InBuffer
|
||||
{
|
||||
byte[] m_Buffer;
|
||||
uint m_Pos;
|
||||
uint m_Limit;
|
||||
uint m_BufferSize;
|
||||
System.IO.Stream m_Stream;
|
||||
bool m_StreamWasExhausted;
|
||||
ulong m_ProcessedSize;
|
||||
|
||||
public InBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Limit = 0;
|
||||
m_Pos = 0;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
public bool ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
return false;
|
||||
m_ProcessedSize += m_Pos;
|
||||
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
|
||||
m_Pos = 0;
|
||||
m_Limit = (uint)aNumProcessedBytes;
|
||||
m_StreamWasExhausted = (aNumProcessedBytes == 0);
|
||||
return (!m_StreamWasExhausted);
|
||||
}
|
||||
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// m_Stream.Close();
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
public bool ReadByte(byte b) // check it
|
||||
{
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return false;
|
||||
b = m_Buffer[m_Pos++];
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
// return (byte)m_Stream.ReadByte();
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return 0xFF;
|
||||
return m_Buffer[m_Pos++];
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// OutBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class OutBuffer
|
||||
{
|
||||
byte[] m_Buffer;
|
||||
uint m_Pos;
|
||||
uint m_BufferSize;
|
||||
System.IO.Stream m_Stream;
|
||||
ulong m_ProcessedSize;
|
||||
|
||||
public OutBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
|
||||
public void FlushStream() { m_Stream.Flush(); }
|
||||
public void CloseStream() { m_Stream.Dispose(); }
|
||||
public void ReleaseStream() { m_Stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_ProcessedSize = 0;
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
m_Buffer[m_Pos++] = b;
|
||||
if (m_Pos >= m_BufferSize)
|
||||
FlushData();
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
if (m_Pos == 0)
|
||||
return;
|
||||
m_Stream.Write(m_Buffer, 0, (int)m_Pos);
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// IMatchFinder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
interface IInWindowStream
|
||||
{
|
||||
void SetStream(System.IO.Stream inStream);
|
||||
void Init();
|
||||
void ReleaseStream();
|
||||
Byte GetIndexByte(Int32 index);
|
||||
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
|
||||
UInt32 GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
interface IMatchFinder : IInWindowStream
|
||||
{
|
||||
void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
|
||||
UInt32 GetMatches(UInt32[] distances);
|
||||
void Skip(UInt32 num);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,370 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// LzBinTree.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class BinTree : InWindow, IMatchFinder
|
||||
{
|
||||
UInt32 _cyclicBufferPos;
|
||||
UInt32 _cyclicBufferSize = 0;
|
||||
UInt32 _matchMaxLen;
|
||||
|
||||
UInt32[] _son;
|
||||
UInt32[] _hash;
|
||||
|
||||
UInt32 _cutValue = 0xFF;
|
||||
UInt32 _hashMask;
|
||||
UInt32 _hashSizeSum = 0;
|
||||
|
||||
bool HASH_ARRAY = true;
|
||||
|
||||
const UInt32 kHash2Size = 1 << 10;
|
||||
const UInt32 kHash3Size = 1 << 16;
|
||||
const UInt32 kBT2HashSize = 1 << 16;
|
||||
const UInt32 kStartMaxLen = 1;
|
||||
const UInt32 kHash3Offset = kHash2Size;
|
||||
const UInt32 kEmptyHashValue = 0;
|
||||
const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
|
||||
|
||||
UInt32 kNumHashDirectBytes = 0;
|
||||
UInt32 kMinMatchCheck = 4;
|
||||
UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = (numHashBytes > 2);
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
|
||||
public new void ReleaseStream() { base.ReleaseStream(); }
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
_hash[i] = kEmptyHashValue;
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
_cyclicBufferPos = 0;
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{ return base.GetMatchLen(index, distance, limit); }
|
||||
|
||||
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize > kMaxValForNormalize - 256)
|
||||
throw new Exception();
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = (historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter) / 2 + 256;
|
||||
|
||||
base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
hs >>= 1;
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = temp & (kHash2Size - 1);
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
hash3Value = temp & (kHash3Size - 1);
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
if (curMatch3 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
offset -= 2;
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0)
|
||||
{
|
||||
if (curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while(++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = temp & (kHash2Size - 1);
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
UInt32 hash3Value = temp & (kHash3Size - 1);
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32)subValue);
|
||||
}
|
||||
|
||||
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// LzInWindow.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class InWindow
|
||||
{
|
||||
public Byte[] _bufferBase = null; // pointer to buffer with data
|
||||
System.IO.Stream _stream;
|
||||
UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
UInt32 _pointerToLastSafePosition;
|
||||
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
public UInt32 _blockSize; // Size of Allocated memory block
|
||||
public UInt32 _pos; // offset (from _buffer) of curent byte
|
||||
UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
|
||||
UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
|
||||
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
offset--;
|
||||
|
||||
UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
return;
|
||||
while (true)
|
||||
{
|
||||
int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
return;
|
||||
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
_posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32)numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
|
||||
void Free() { _bufferBase = null; }
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { _stream = stream; }
|
||||
public void ReleaseStream() { _stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
MoveBlock();
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
|
||||
|
||||
// index + limit have not to exceed _keepSizeAfter;
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
if ((_pos + index) + limit > _streamPos)
|
||||
limit = _streamPos - (UInt32)(_pos + index);
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32)subValue;
|
||||
_posLimit -= (UInt32)subValue;
|
||||
_pos -= (UInt32)subValue;
|
||||
_streamPos -= (UInt32)subValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// LzOutWindow.cs
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class OutWindow
|
||||
{
|
||||
byte[] _buffer = null;
|
||||
uint _pos;
|
||||
uint _windowSize = 0;
|
||||
uint _streamPos;
|
||||
System.IO.Stream _stream;
|
||||
|
||||
public uint TrainSize = 0;
|
||||
|
||||
public void Create(uint windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
{
|
||||
// System.GC.Collect();
|
||||
_buffer = new byte[windowSize];
|
||||
}
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream, bool solid)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
if (!solid)
|
||||
{
|
||||
_streamPos = 0;
|
||||
_pos = 0;
|
||||
TrainSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
uint size = (len < _windowSize) ? (uint)len : _windowSize;
|
||||
TrainSize = size;
|
||||
stream.Position = len - size;
|
||||
_streamPos = _pos = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
uint curSize = _windowSize - _pos;
|
||||
if (size < curSize)
|
||||
curSize = size;
|
||||
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
|
||||
if (numReadBytes == 0)
|
||||
return false;
|
||||
size -= (uint)numReadBytes;
|
||||
_pos += (uint)numReadBytes;
|
||||
_streamPos += (uint)numReadBytes;
|
||||
if (_pos == _windowSize)
|
||||
_streamPos = _pos = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
uint size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
return;
|
||||
_stream.Write(_buffer, (int)_streamPos, (int)size);
|
||||
if (_pos >= _windowSize)
|
||||
_pos = 0;
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(uint distance, uint len)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
for (; len > 0; len--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
pos = 0;
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
|
||||
public byte GetByte(uint distance)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
return _buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// LzmaBase.cs
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
|
||||
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
public void Init() { Index = 0; }
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4) Index = 0;
|
||||
else if (Index < 10) Index -= 3;
|
||||
else Index -= 6;
|
||||
}
|
||||
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
|
||||
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
|
||||
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
|
||||
public bool IsCharState() { return Index < 7; }
|
||||
}
|
||||
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
return len;
|
||||
return (uint)(kNumLenToPosStates - 1);
|
||||
}
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const uint kAlignMask = (kAlignTableSize - 1);
|
||||
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
|
||||
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const int kNumHighLenBits = 8;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// LzmaDecoder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
using RangeCoder;
|
||||
|
||||
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
class LenDecoder
|
||||
{
|
||||
BitDecoder m_Choice = new BitDecoder();
|
||||
BitDecoder m_Choice2 = new BitDecoder();
|
||||
BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
|
||||
uint m_NumPosStates = 0;
|
||||
|
||||
public void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LiteralDecoder
|
||||
{
|
||||
struct Decoder2
|
||||
{
|
||||
BitDecoder[] m_Decoders;
|
||||
public void Create() { m_Decoders = new BitDecoder[0x300]; }
|
||||
public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint)(matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
}
|
||||
|
||||
Decoder2[] m_Coders;
|
||||
int m_NumPrevBits;
|
||||
int m_NumPosBits;
|
||||
uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
return;
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint)1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
|
||||
uint GetState(uint pos, byte prevByte)
|
||||
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
|
||||
};
|
||||
|
||||
LZ.OutWindow m_OutWindow = new LZ.OutWindow();
|
||||
RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
|
||||
|
||||
BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
|
||||
BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
|
||||
|
||||
LenDecoder m_LenDecoder = new LenDecoder();
|
||||
LenDecoder m_RepLenDecoder = new LenDecoder();
|
||||
|
||||
LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
|
||||
|
||||
uint m_DictionarySize;
|
||||
uint m_DictionarySizeCheck;
|
||||
|
||||
uint m_PosStateMask;
|
||||
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = 0xFFFFFFFF;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
|
||||
void SetDictionarySize(uint dictionarySize)
|
||||
{
|
||||
if (m_DictionarySize != dictionarySize)
|
||||
{
|
||||
m_DictionarySize = dictionarySize;
|
||||
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
|
||||
uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
throw new InvalidParamException();
|
||||
if (lc > 8)
|
||||
throw new InvalidParamException();
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
uint numPosStates = (uint)1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
bool _solid = false;
|
||||
void Init(System.IO.Stream inStream, System.IO.Stream outStream)
|
||||
{
|
||||
m_RangeDecoder.Init(inStream);
|
||||
m_OutWindow.Init(outStream, _solid);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i].Init();
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
m_PosDecoders[i].Init();
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
}
|
||||
|
||||
public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress)
|
||||
{
|
||||
Init(inStream, outStream);
|
||||
|
||||
Base.State state = new Base.State();
|
||||
state.Init();
|
||||
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
|
||||
|
||||
UInt64 nowPos64 = 0;
|
||||
UInt64 outSize64 = (UInt64)outSize;
|
||||
if (nowPos64 < outSize64)
|
||||
{
|
||||
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
|
||||
throw new DataErrorException();
|
||||
state.UpdateChar();
|
||||
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
|
||||
m_OutWindow.PutByte(b);
|
||||
nowPos64++;
|
||||
}
|
||||
while (nowPos64 < outSize64)
|
||||
{
|
||||
progress.SetProgress(inStream.Position, (long)nowPos64);
|
||||
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
|
||||
// while(nowPos64 < next)
|
||||
{
|
||||
uint posState = (uint)nowPos64 & m_PosStateMask;
|
||||
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = m_OutWindow.GetByte(0);
|
||||
if (!state.IsCharState())
|
||||
b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
|
||||
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
|
||||
else
|
||||
b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
|
||||
m_OutWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
nowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
|
||||
nowPos64++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
distance = rep2;
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = (int)((posSlot >> 1) - 1);
|
||||
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
|
||||
else
|
||||
{
|
||||
rep0 += (m_RangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 = posSlot;
|
||||
}
|
||||
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
break;
|
||||
throw new DataErrorException();
|
||||
}
|
||||
m_OutWindow.CopyBlock(rep0, len);
|
||||
nowPos64 += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_OutWindow.Flush();
|
||||
m_OutWindow.ReleaseStream();
|
||||
m_RangeDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 5)
|
||||
throw new InvalidParamException();
|
||||
int lc = properties[0] % 9;
|
||||
int remainder = properties[0] / 9;
|
||||
int lp = remainder % 5;
|
||||
int pb = remainder / 5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
UInt32 dictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
|
||||
SetDictionarySize(dictionarySize);
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
_solid = true;
|
||||
return m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,237 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
class Encoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
|
||||
System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
uint _cacheSize;
|
||||
byte _cache;
|
||||
|
||||
long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ShiftLow();
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
Low += Range;
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
Range = newBound;
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
public uint Range;
|
||||
public uint Code;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
struct BitEncoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
const int kNumMoveReducingBits = 2;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32)1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
|
||||
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
|
||||
}
|
||||
|
||||
struct BitDecoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> numMoveBits;
|
||||
}
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
struct BitTreeEncoder
|
||||
{
|
||||
BitEncoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BitTreeDecoder
|
||||
{
|
||||
BitDecoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
RangeCoder.Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ICoder.h
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
class DataErrorException : Exception
|
||||
{
|
||||
public DataErrorException(): base("Data Error") { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
class InvalidParamException : Exception
|
||||
{
|
||||
public InvalidParamException(): base("Invalid Parameter") { }
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="SevenZip.DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
|
||||
public interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
public interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
public interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
## LZMA SDK
|
||||
This source came from the C# implementation of LZMA from the LZMA SDK, version 16.02, from http://www.7-zip.org/sdk.html.
|
||||
|
||||
## License
|
||||
LZMA SDK is placed in the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute the original LZMA SDK code, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
## Thanks!
|
||||
Thanks goes to Igor Pavlov for making this available.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\build\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<EnableApiCheck>false</EnableApiCheck>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.Archive
|
||||
{
|
||||
public struct ProgressReport
|
||||
{
|
||||
public ProgressReport(string phase, long ticks, long total)
|
||||
{
|
||||
Phase = phase;
|
||||
Ticks = ticks;
|
||||
Total = total;
|
||||
}
|
||||
public string Phase { get; }
|
||||
public long Ticks { get; }
|
||||
public long Total { get; }
|
||||
}
|
||||
|
||||
public static class ProgressReportExtensions
|
||||
{
|
||||
public static void Report(this IProgress<ProgressReport> progress, string phase, long ticks, long total)
|
||||
{
|
||||
progress.Report(new ProgressReport(phase, ticks, total));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.DotNet.Archive
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps ThreadLocal<ZipArchive> and exposes Dispose semantics that dispose all archives
|
||||
/// </summary>
|
||||
internal class ThreadLocalZipArchive : IDisposable
|
||||
{
|
||||
private ThreadLocal<ZipArchive> _archive;
|
||||
private bool _disposed = false;
|
||||
|
||||
public ThreadLocalZipArchive(string archivePath, ZipArchive local = null)
|
||||
{
|
||||
_archive = new ThreadLocal<ZipArchive>(() =>
|
||||
new ZipArchive(File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete), ZipArchiveMode.Read),
|
||||
trackAllValues:true);
|
||||
|
||||
if (local != null)
|
||||
{
|
||||
// reuse provided one for current thread
|
||||
_archive.Value = local;
|
||||
}
|
||||
}
|
||||
|
||||
public ZipArchive Archive { get { return _archive.Value; } }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (_archive != null)
|
||||
{
|
||||
// dispose all archives
|
||||
if (_archive.Values != null)
|
||||
{
|
||||
foreach (var value in _archive.Values)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dispose ThreadLocal
|
||||
_archive.Dispose();
|
||||
_archive = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandArgument
|
||||
{
|
||||
public CommandArgument()
|
||||
{
|
||||
Values = new List<string>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<string> Values { get; private set; }
|
||||
public bool MultipleValues { get; set; }
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return Values.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,693 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandLineApplication
|
||||
{
|
||||
private enum ParseOptionResult
|
||||
{
|
||||
Succeeded,
|
||||
ShowHelp,
|
||||
ShowVersion,
|
||||
UnexpectedArgs,
|
||||
}
|
||||
|
||||
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
|
||||
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
|
||||
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
|
||||
private readonly bool _throwOnUnexpectedArg;
|
||||
|
||||
public CommandLineApplication(bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
_throwOnUnexpectedArg = throwOnUnexpectedArg;
|
||||
Options = new List<CommandOption>();
|
||||
Arguments = new List<CommandArgument>();
|
||||
Commands = new List<CommandLineApplication>();
|
||||
RemainingArguments = new List<string>();
|
||||
Invoke = () => 0;
|
||||
}
|
||||
|
||||
public CommandLineApplication Parent { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string FullName { get; set; }
|
||||
public string Syntax { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<CommandOption> Options { get; private set; }
|
||||
public CommandOption OptionHelp { get; private set; }
|
||||
public CommandOption OptionVersion { get; private set; }
|
||||
public List<CommandArgument> Arguments { get; private set; }
|
||||
public List<string> RemainingArguments { get; private set; }
|
||||
public bool IsShowingInformation { get; protected set; } // Is showing help or version?
|
||||
public Func<int> Invoke { get; set; }
|
||||
public Func<string> LongVersionGetter { get; set; }
|
||||
public Func<string> ShortVersionGetter { get; set; }
|
||||
public List<CommandLineApplication> Commands { get; private set; }
|
||||
public bool HandleResponseFiles { get; set; }
|
||||
public bool AllowArgumentSeparator { get; set; }
|
||||
public bool HandleRemainingArguments { get; set; }
|
||||
public string ArgumentSeparatorHelpText { get; set; }
|
||||
|
||||
public CommandLineApplication AddCommand(string name, bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
return AddCommand(name, _ => { }, throwOnUnexpectedArg);
|
||||
}
|
||||
|
||||
public CommandLineApplication AddCommand(string name, Action<CommandLineApplication> configuration,
|
||||
bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name };
|
||||
return AddCommand(command, configuration, throwOnUnexpectedArg);
|
||||
}
|
||||
|
||||
public CommandLineApplication AddCommand(CommandLineApplication command, bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
return AddCommand(command, _ => { }, throwOnUnexpectedArg);
|
||||
}
|
||||
|
||||
public CommandLineApplication AddCommand(
|
||||
CommandLineApplication command,
|
||||
Action<CommandLineApplication> configuration,
|
||||
bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
if (command == null || configuration == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
|
||||
command.Parent = this;
|
||||
Commands.Add(command);
|
||||
configuration(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
public CommandOption Option(string template, string description, CommandOptionType optionType)
|
||||
{
|
||||
return Option(template, description, optionType, _ => { });
|
||||
}
|
||||
|
||||
public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
|
||||
{
|
||||
var option = new CommandOption(template, optionType) { Description = description };
|
||||
Options.Add(option);
|
||||
configuration(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
public CommandArgument Argument(string name, string description, bool multipleValues = false)
|
||||
{
|
||||
return Argument(name, description, _ => { }, multipleValues);
|
||||
}
|
||||
|
||||
public CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
|
||||
{
|
||||
var lastArg = Arguments.LastOrDefault();
|
||||
if (lastArg != null && lastArg.MultipleValues)
|
||||
{
|
||||
var message = string.Format(LocalizableStrings.LastArgumentMultiValueError,
|
||||
lastArg.Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
|
||||
Arguments.Add(argument);
|
||||
configuration(argument);
|
||||
return argument;
|
||||
}
|
||||
|
||||
public void OnExecute(Func<int> invoke)
|
||||
{
|
||||
Invoke = invoke;
|
||||
}
|
||||
|
||||
public void OnExecute(Func<Task<int>> invoke)
|
||||
{
|
||||
Invoke = () => invoke().Result;
|
||||
}
|
||||
|
||||
public int Execute(params string[] args)
|
||||
{
|
||||
CommandLineApplication command = this;
|
||||
CommandArgumentEnumerator arguments = null;
|
||||
|
||||
if (HandleResponseFiles)
|
||||
{
|
||||
args = ExpandResponseFiles(args).ToArray();
|
||||
}
|
||||
|
||||
for (var index = 0; index < args.Length; index++)
|
||||
{
|
||||
var arg = args[index];
|
||||
|
||||
bool isLongOption = arg.StartsWith("--");
|
||||
if (arg == "-?" || arg == "/?")
|
||||
{
|
||||
command.ShowHelp();
|
||||
return 0;
|
||||
}
|
||||
else if (isLongOption || arg.StartsWith("-"))
|
||||
{
|
||||
CommandOption option;
|
||||
|
||||
var result = ParseOption(isLongOption, command, args, ref index, out option);
|
||||
|
||||
|
||||
if (result == ParseOptionResult.ShowHelp)
|
||||
{
|
||||
command.ShowHelp();
|
||||
return 0;
|
||||
}
|
||||
else if (result == ParseOptionResult.ShowVersion)
|
||||
{
|
||||
command.ShowVersion();
|
||||
return 0;
|
||||
}
|
||||
else if (result == ParseOptionResult.UnexpectedArgs)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var subcommand = ParseSubCommand(arg, command);
|
||||
if (subcommand != null)
|
||||
{
|
||||
command = subcommand;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arguments == null || arguments.CommandName != command.Name)
|
||||
{
|
||||
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator(), command.Name);
|
||||
}
|
||||
|
||||
if (arguments.MoveNext())
|
||||
{
|
||||
arguments.Current.Values.Add(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Commands.Count > 0 && command == this)
|
||||
{
|
||||
throw new CommandParsingException(
|
||||
command,
|
||||
"Required command missing",
|
||||
isRequiredSubCommandMissing: true);
|
||||
}
|
||||
|
||||
return command.Invoke();
|
||||
}
|
||||
|
||||
private ParseOptionResult ParseOption(
|
||||
bool isLongOption,
|
||||
CommandLineApplication command,
|
||||
string[] args,
|
||||
ref int index,
|
||||
out CommandOption option)
|
||||
{
|
||||
option = null;
|
||||
ParseOptionResult result = ParseOptionResult.Succeeded;
|
||||
var arg = args[index];
|
||||
|
||||
int optionPrefixLength = isLongOption ? 2 : 1;
|
||||
string[] optionComponents = arg.Substring(optionPrefixLength).Split(new[] { ':', '=' }, 2);
|
||||
string optionName = optionComponents[0];
|
||||
|
||||
if (isLongOption)
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.LongName, optionName, StringComparison.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.ShortName, optionName, StringComparison.Ordinal));
|
||||
|
||||
if (option == null)
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.SymbolName, optionName, StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
|
||||
if (option == null)
|
||||
{
|
||||
if (isLongOption && string.IsNullOrEmpty(optionName) &&
|
||||
!command._throwOnUnexpectedArg && AllowArgumentSeparator)
|
||||
{
|
||||
// a stand-alone "--" is the argument separator, so skip it and
|
||||
// handle the rest of the args as unexpected args
|
||||
index++;
|
||||
}
|
||||
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
||||
result = ParseOptionResult.UnexpectedArgs;
|
||||
}
|
||||
else if (command.OptionHelp == option)
|
||||
{
|
||||
result = ParseOptionResult.ShowHelp;
|
||||
}
|
||||
else if (command.OptionVersion == option)
|
||||
{
|
||||
result = ParseOptionResult.ShowVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optionComponents.Length == 2)
|
||||
{
|
||||
if (!option.TryParse(optionComponents[1]))
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command,
|
||||
String.Format(LocalizableStrings.UnexpectedValueForOptionError, optionComponents[1], optionName));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.OptionType == CommandOptionType.NoValue ||
|
||||
option.OptionType == CommandOptionType.BoolValue)
|
||||
{
|
||||
// No value is needed for this option
|
||||
option.TryParse(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
index++;
|
||||
|
||||
if (index < args.Length)
|
||||
{
|
||||
arg = args[index];
|
||||
if (!option.TryParse(arg))
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(
|
||||
command,
|
||||
String.Format(LocalizableStrings.UnexpectedValueForOptionError, arg, optionName));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(
|
||||
command,
|
||||
String.Format(LocalizableStrings.OptionRequiresSingleValueWhichIsMissing, arg, optionName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private CommandLineApplication ParseSubCommand(string arg, CommandLineApplication command)
|
||||
{
|
||||
foreach (var subcommand in command.Commands)
|
||||
{
|
||||
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return subcommand;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper method that adds a help option
|
||||
public CommandOption HelpOption(string template)
|
||||
{
|
||||
// Help option is special because we stop parsing once we see it
|
||||
// So we store it separately for further use
|
||||
OptionHelp = Option(template, LocalizableStrings.ShowHelpInfo, CommandOptionType.NoValue);
|
||||
|
||||
return OptionHelp;
|
||||
}
|
||||
|
||||
public CommandOption VersionOption(string template,
|
||||
string shortFormVersion,
|
||||
string longFormVersion = null)
|
||||
{
|
||||
if (longFormVersion == null)
|
||||
{
|
||||
return VersionOption(template, () => shortFormVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VersionOption(template, () => shortFormVersion, () => longFormVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method that adds a version option
|
||||
public CommandOption VersionOption(string template,
|
||||
Func<string> shortFormVersionGetter,
|
||||
Func<string> longFormVersionGetter = null)
|
||||
{
|
||||
// Version option is special because we stop parsing once we see it
|
||||
// So we store it separately for further use
|
||||
OptionVersion = Option(template, LocalizableStrings.ShowVersionInfo, CommandOptionType.NoValue);
|
||||
ShortVersionGetter = shortFormVersionGetter;
|
||||
LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
|
||||
|
||||
return OptionVersion;
|
||||
}
|
||||
|
||||
// Show short hint that reminds users to use help option
|
||||
public void ShowHint()
|
||||
{
|
||||
if (OptionHelp != null)
|
||||
{
|
||||
Console.WriteLine(string.Format(LocalizableStrings.ShowHintInfo, OptionHelp.LongName));
|
||||
}
|
||||
}
|
||||
|
||||
// Show full help
|
||||
public void ShowHelp(string commandName = null)
|
||||
{
|
||||
var headerBuilder = new StringBuilder(LocalizableStrings.UsageHeader);
|
||||
var usagePrefixLength = headerBuilder.Length;
|
||||
for (var cmd = this; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
cmd.IsShowingInformation = true;
|
||||
if (cmd != this && cmd.Arguments.Any())
|
||||
{
|
||||
var args = string.Join(" ", cmd.Arguments.Select(arg => arg.Name));
|
||||
headerBuilder.Insert(usagePrefixLength, string.Format(" {0} {1}", cmd.Name, args));
|
||||
}
|
||||
else
|
||||
{
|
||||
headerBuilder.Insert(usagePrefixLength, string.Format(" {0}", cmd.Name));
|
||||
}
|
||||
}
|
||||
|
||||
CommandLineApplication target;
|
||||
|
||||
if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
target = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
headerBuilder.AppendFormat(" {0}", commandName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The command name is invalid so don't try to show help for something that doesn't exist
|
||||
target = this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var optionsBuilder = new StringBuilder();
|
||||
var commandsBuilder = new StringBuilder();
|
||||
var argumentsBuilder = new StringBuilder();
|
||||
var argumentSeparatorBuilder = new StringBuilder();
|
||||
|
||||
int maxArgLen = 0;
|
||||
for (var cmd = target; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
if (cmd.Arguments.Any())
|
||||
{
|
||||
if (cmd == target)
|
||||
{
|
||||
headerBuilder.Append(LocalizableStrings.UsageArgumentsToken);
|
||||
}
|
||||
|
||||
if (argumentsBuilder.Length == 0)
|
||||
{
|
||||
argumentsBuilder.AppendLine();
|
||||
argumentsBuilder.AppendLine(LocalizableStrings.UsageArgumentsHeader);
|
||||
}
|
||||
|
||||
maxArgLen = Math.Max(maxArgLen, MaxArgumentLength(cmd.Arguments));
|
||||
}
|
||||
}
|
||||
|
||||
for (var cmd = target; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
if (cmd.Arguments.Any())
|
||||
{
|
||||
foreach (var arg in cmd.Arguments)
|
||||
{
|
||||
argumentsBuilder.AppendFormat(
|
||||
" {0}{1}",
|
||||
arg.Name.PadRight(maxArgLen + 2),
|
||||
arg.Description);
|
||||
argumentsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target.Options.Any())
|
||||
{
|
||||
headerBuilder.Append(LocalizableStrings.UsageOptionsToken);
|
||||
|
||||
optionsBuilder.AppendLine();
|
||||
optionsBuilder.AppendLine(LocalizableStrings.UsageOptionsHeader);
|
||||
var maxOptLen = MaxOptionTemplateLength(target.Options);
|
||||
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2);
|
||||
foreach (var opt in target.Options)
|
||||
{
|
||||
optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
|
||||
optionsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (target.Commands.Any())
|
||||
{
|
||||
headerBuilder.Append(LocalizableStrings.UsageCommandToken);
|
||||
|
||||
commandsBuilder.AppendLine();
|
||||
commandsBuilder.AppendLine(LocalizableStrings.UsageCommandsHeader);
|
||||
var maxCmdLen = MaxCommandLength(target.Commands);
|
||||
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2);
|
||||
foreach (var cmd in target.Commands.OrderBy(c => c.Name))
|
||||
{
|
||||
commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
|
||||
commandsBuilder.AppendLine();
|
||||
}
|
||||
|
||||
if (OptionHelp != null)
|
||||
{
|
||||
commandsBuilder.AppendLine();
|
||||
commandsBuilder.AppendFormat(LocalizableStrings.UsageCommandsDetailHelp, Name);
|
||||
commandsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (target.AllowArgumentSeparator || target.HandleRemainingArguments)
|
||||
{
|
||||
if (target.AllowArgumentSeparator)
|
||||
{
|
||||
headerBuilder.Append(LocalizableStrings.UsageCommandAdditionalArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
headerBuilder.Append(LocalizableStrings.UsageCommandArgs);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(target.ArgumentSeparatorHelpText))
|
||||
{
|
||||
argumentSeparatorBuilder.AppendLine();
|
||||
argumentSeparatorBuilder.AppendLine(LocalizableStrings.UsageCommandsAdditionalArgsHeader);
|
||||
argumentSeparatorBuilder.AppendLine(String.Format(" {0}", target.ArgumentSeparatorHelpText));
|
||||
argumentSeparatorBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
headerBuilder.AppendLine();
|
||||
|
||||
var nameAndVersion = new StringBuilder();
|
||||
nameAndVersion.AppendLine(GetFullNameAndVersion());
|
||||
nameAndVersion.AppendLine();
|
||||
|
||||
Console.Write("{0}{1}{2}{3}{4}{5}", nameAndVersion, headerBuilder, argumentsBuilder, optionsBuilder, commandsBuilder, argumentSeparatorBuilder);
|
||||
}
|
||||
|
||||
public void ShowVersion()
|
||||
{
|
||||
for (var cmd = this; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
cmd.IsShowingInformation = true;
|
||||
}
|
||||
|
||||
Console.WriteLine(FullName);
|
||||
Console.WriteLine(LongVersionGetter());
|
||||
}
|
||||
|
||||
public string GetFullNameAndVersion()
|
||||
{
|
||||
return ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
|
||||
}
|
||||
|
||||
public void ShowRootCommandFullNameAndVersion()
|
||||
{
|
||||
var rootCmd = this;
|
||||
while (rootCmd.Parent != null)
|
||||
{
|
||||
rootCmd = rootCmd.Parent;
|
||||
}
|
||||
|
||||
Console.WriteLine(rootCmd.GetFullNameAndVersion());
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private int MaxOptionTemplateLength(IEnumerable<CommandOption> options)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var opt in options)
|
||||
{
|
||||
maxLen = opt.Template.Length > maxLen ? opt.Template.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private int MaxCommandLength(IEnumerable<CommandLineApplication> commands)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
maxLen = cmd.Name.Length > maxLen ? cmd.Name.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private int MaxArgumentLength(IEnumerable<CommandArgument> arguments)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var arg in arguments)
|
||||
{
|
||||
maxLen = arg.Name.Length > maxLen ? arg.Name.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
|
||||
{
|
||||
if (command._throwOnUnexpectedArg)
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command, String.Format(LocalizableStrings.UnexpectedArgumentError, argTypeName, args[index]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// All remaining arguments are stored for further use
|
||||
command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> ExpandResponseFiles(IEnumerable<string> args)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (!arg.StartsWith("@", StringComparison.Ordinal))
|
||||
{
|
||||
yield return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileName = arg.Substring(1);
|
||||
|
||||
var responseFileArguments = ParseResponseFile(fileName);
|
||||
|
||||
// ParseResponseFile can suppress expanding this response file by
|
||||
// returning null. In that case, we'll treat the response
|
||||
// file token as a regular argument.
|
||||
|
||||
if (responseFileArguments == null)
|
||||
{
|
||||
yield return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var responseFileArgument in responseFileArguments)
|
||||
yield return responseFileArgument.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> ParseResponseFile(string fileName)
|
||||
{
|
||||
if (!HandleResponseFiles)
|
||||
return null;
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(LocalizableStrings.ResponseFileNotFoundError, fileName));
|
||||
}
|
||||
|
||||
return File.ReadLines(fileName);
|
||||
}
|
||||
|
||||
private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
|
||||
{
|
||||
private readonly IEnumerator<CommandArgument> _enumerator;
|
||||
|
||||
public CommandArgumentEnumerator(
|
||||
IEnumerator<CommandArgument> enumerator,
|
||||
string commandName)
|
||||
{
|
||||
CommandName = commandName;
|
||||
_enumerator = enumerator;
|
||||
}
|
||||
|
||||
public string CommandName { get; }
|
||||
|
||||
public CommandArgument Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return _enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_enumerator.Dispose();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (Current == null || !Current.MultipleValues)
|
||||
{
|
||||
return _enumerator.MoveNext();
|
||||
}
|
||||
|
||||
// If current argument allows multiple values, we don't move forward and
|
||||
// all later values will be added to current CommandArgument.Values
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_enumerator.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandOption
|
||||
{
|
||||
public CommandOption(string template, CommandOptionType optionType)
|
||||
{
|
||||
Template = template;
|
||||
OptionType = optionType;
|
||||
Values = new List<string>();
|
||||
|
||||
foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (part.StartsWith("--"))
|
||||
{
|
||||
LongName = part.Substring(2);
|
||||
}
|
||||
else if (part.StartsWith("-"))
|
||||
{
|
||||
var optName = part.Substring(1);
|
||||
|
||||
// If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?")
|
||||
if (optName.Length == 1 && !IsEnglishLetter(optName[0]))
|
||||
{
|
||||
SymbolName = optName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShortName = optName;
|
||||
}
|
||||
}
|
||||
else if (part.StartsWith("<") && part.EndsWith(">"))
|
||||
{
|
||||
ValueName = part.Substring(1, part.Length - 2);
|
||||
}
|
||||
else if (optionType == CommandOptionType.MultipleValue && part.StartsWith("<") && part.EndsWith(">..."))
|
||||
{
|
||||
ValueName = part.Substring(1, part.Length - 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(String.Format(LocalizableStrings.InvalidTemplateError, nameof(template)));
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName))
|
||||
{
|
||||
throw new ArgumentException(LocalizableStrings.InvalidTemplateError, nameof(template));
|
||||
}
|
||||
}
|
||||
|
||||
public string Template { get; set; }
|
||||
public string ShortName { get; set; }
|
||||
public string LongName { get; set; }
|
||||
public string SymbolName { get; set; }
|
||||
public string ValueName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<string> Values { get; private set; }
|
||||
public bool? BoolValue { get; private set; }
|
||||
public CommandOptionType OptionType { get; private set; }
|
||||
|
||||
public bool TryParse(string value)
|
||||
{
|
||||
switch (OptionType)
|
||||
{
|
||||
case CommandOptionType.MultipleValue:
|
||||
Values.Add(value);
|
||||
break;
|
||||
case CommandOptionType.SingleValue:
|
||||
if (Values.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Values.Add(value);
|
||||
break;
|
||||
case CommandOptionType.BoolValue:
|
||||
if (Values.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
// add null to indicate that the option was present, but had no value
|
||||
Values.Add(null);
|
||||
BoolValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool boolValue;
|
||||
if (!bool.TryParse(value, out boolValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Values.Add(value);
|
||||
BoolValue = boolValue;
|
||||
}
|
||||
break;
|
||||
case CommandOptionType.NoValue:
|
||||
if (value != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Add a value to indicate that this option was specified
|
||||
Values.Add("on");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasValue()
|
||||
{
|
||||
return Values.Any();
|
||||
}
|
||||
|
||||
public string Value()
|
||||
{
|
||||
return HasValue() ? Values[0] : null;
|
||||
}
|
||||
|
||||
private bool IsEnglishLetter(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal enum CommandOptionType
|
||||
{
|
||||
MultipleValue,
|
||||
SingleValue,
|
||||
BoolValue,
|
||||
NoValue
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.Tools;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandParsingException : Exception
|
||||
{
|
||||
private readonly bool _isRequiredSubCommandMissing;
|
||||
|
||||
public CommandParsingException(
|
||||
string message,
|
||||
string helpText = null) : base(message)
|
||||
{
|
||||
HelpText = helpText ?? "";
|
||||
Data.Add("CLI_User_Displayed_Exception", true);
|
||||
}
|
||||
|
||||
public CommandParsingException(
|
||||
CommandLineApplication command,
|
||||
string message,
|
||||
bool isRequiredSubCommandMissing = false)
|
||||
: this(message)
|
||||
{
|
||||
Command = command;
|
||||
_isRequiredSubCommandMissing = isRequiredSubCommandMissing;
|
||||
}
|
||||
|
||||
public CommandLineApplication Command { get; }
|
||||
|
||||
public string HelpText { get; } = "";
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isRequiredSubCommandMissing
|
||||
? CommonLocalizableStrings.RequiredCommandNotPassed
|
||||
: base.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class HelpMessageStrings
|
||||
{
|
||||
internal const string MSBuildAdditionalArgsHelpText = LocalizableStrings.MSBuildAdditionalArgsHelpText;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class LocalizableStrings
|
||||
{
|
||||
public const string LastArgumentMultiValueError = "The last argument '{0}' accepts multiple values. No more argument can be added.";
|
||||
|
||||
public const string OptionRequiresSingleValueWhichIsMissing = "Required value for option '{0}' was not provided.";
|
||||
|
||||
public const string UnexpectedValueForOptionError = "Unexpected value '{0}' for option '{1}'";
|
||||
|
||||
public const string UnexpectedArgumentError = "Unrecognized {0} '{1}'";
|
||||
|
||||
public const string ResponseFileNotFoundError = "Response file '{0}' doesn't exist.";
|
||||
|
||||
public const string ShowHelpInfo = "Show help information";
|
||||
|
||||
public const string ShowVersionInfo = "Show version information";
|
||||
|
||||
public const string ShowHintInfo = "Specify --{0} for a list of available options and commands.";
|
||||
|
||||
public const string UsageHeader = "Usage:";
|
||||
|
||||
public const string UsageArgumentsToken = " [arguments]";
|
||||
|
||||
public const string UsageArgumentsHeader = "Arguments:";
|
||||
|
||||
public const string UsageOptionsToken = " [options]";
|
||||
|
||||
public const string UsageOptionsHeader = "Options:";
|
||||
|
||||
public const string UsageCommandToken = " [command]";
|
||||
|
||||
public const string UsageCommandsHeader = "Commands:";
|
||||
|
||||
public const string UsageCommandsDetailHelp = "Use \"{0} [command] --help\" for more information about a command.";
|
||||
|
||||
public const string UsageCommandArgs = " [args]";
|
||||
|
||||
public const string UsageCommandAdditionalArgs = " [[--] <additional arguments>...]]";
|
||||
|
||||
public const string UsageCommandsAdditionalArgsHeader = "Additional Arguments:";
|
||||
|
||||
public const string InvalidTemplateError = "Invalid template pattern '{0}'";
|
||||
|
||||
public const string MSBuildAdditionalArgsHelpText = "Any extra options that should be passed to MSBuild. See 'dotnet msbuild -h' for available options.";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.Tools
|
||||
{
|
||||
internal class CommonLocalizableStrings
|
||||
{
|
||||
public const string UnsupportedProjectType = "Unsupported project type. Please check with your sdk provider.";
|
||||
public const string ProjectAlreadyHasAreference = "Project already has a reference to `{0}`.";
|
||||
public const string ProjectReferenceCouldNotBeFound = "Project reference `{0}` could not be found.";
|
||||
public const string ProjectReferenceRemoved = "Project reference `{0}` removed.";
|
||||
|
||||
// Project related
|
||||
public const string Project = "Project";
|
||||
public const string ProjectFile = "Project file";
|
||||
public const string Reference = "Reference";
|
||||
public const string ProjectReference = "Project reference";
|
||||
public const string ProjectReferenceOneOrMore = "Project reference(s)";
|
||||
public const string PackageReference = "Package reference";
|
||||
public const string P2P = "Project to Project";
|
||||
public const string P2PReference = "Project to Project reference";
|
||||
public const string Package = "Package";
|
||||
public const string Solution = "Solution";
|
||||
public const string SolutionFile = "Solution file";
|
||||
public const string Executable = "Executable";
|
||||
public const string Library = "Library";
|
||||
public const string Program = "Program";
|
||||
public const string Application = "Application";
|
||||
public const string ReferenceAddedToTheProject = "Reference `{0}` added to the project.";
|
||||
|
||||
// Verbs
|
||||
public const string Add = "Add";
|
||||
public const string Remove = "Remove";
|
||||
public const string Delete = "Delete";
|
||||
public const string Update = "Update";
|
||||
public const string New = "New";
|
||||
public const string List = "List";
|
||||
public const string Load = "Load";
|
||||
public const string Save = "Save";
|
||||
public const string Find = "Find";
|
||||
|
||||
// Other
|
||||
public const string Error = "Error";
|
||||
public const string Warning = "Warning";
|
||||
|
||||
public const string File = "File";
|
||||
public const string Directory = "Directory";
|
||||
|
||||
public const string Type = "Type";
|
||||
public const string Value = "Value";
|
||||
public const string Group = "Group";
|
||||
|
||||
// General sentences";
|
||||
public const string XAddedToY = "{0} added to {1}.";
|
||||
public const string XRemovedFromY = "{0} removed from {1}.";
|
||||
public const string XDeletedFromY = "{0} deleted from {1}.";
|
||||
public const string XSuccessfullyUpdated = "{0} successfully updated.";
|
||||
|
||||
// General errors
|
||||
/// Invalid
|
||||
public const string XIsInvalid = "{0} is invalid.";
|
||||
public const string XYFoundButInvalid = "{0} `{1}` found but is invalid.";
|
||||
public const string XFoundButInvalid = "`{0}` found but is invalid.";
|
||||
public const string OperationInvalid = "Operation is invalid.";
|
||||
public const string OperationXInvalid = "Operation {0} is invalid.";
|
||||
|
||||
/// Not Found
|
||||
public const string XNotFound = "{0} not found.";
|
||||
public const string XOrYNotFound = "{0} or {1} not found.";
|
||||
public const string XOrYNotFoundInZ = "{0} or {1} not found in `{2}`.";
|
||||
public const string FileNotFound = "File `{0}` not found.";
|
||||
|
||||
/// Does not exist
|
||||
public const string XDoesNotExist = "{0} does not exist.";
|
||||
public const string XYDoesNotExist = "{0} `{1}` does not exist.";
|
||||
|
||||
/// Duplicate
|
||||
public const string MoreThanOneXFound = "More than one {0} found.";
|
||||
public const string XAlreadyContainsY = "{0} already contains {1}.";
|
||||
public const string XAlreadyContainsYZ = "{0} already contains {1} `{2}`.";
|
||||
public const string XAlreadyHasY = "{0} already has {1}.";
|
||||
public const string XAlreadyHasYZ = "{0} already has {1} `{2}`.";
|
||||
|
||||
/// Other
|
||||
public const string XWasNotExpected = "{0} was not expected.";
|
||||
public const string XNotProvided = "{0} not provided.";
|
||||
public const string SpecifyAtLeastOne = "Please specify at least one {0}.";
|
||||
public const string CouldNotConnectWithTheServer = "Could not connect with the server.";
|
||||
|
||||
// Command Line Parsing
|
||||
public const string RequiredArgumentIsInvalid = "Required argument {0} is invalid.";
|
||||
public const string OptionIsInvalid = "Option {0} is invalid.";
|
||||
public const string ArgumentIsInvalid = "Argument {0} is invalid.";
|
||||
public const string RequiredArgumentNotPassed = "Required argument {0} was not provided.";
|
||||
public const string RequiredCommandNotPassed = "Required command was not provided.";
|
||||
|
||||
// dotnet <verb>
|
||||
/// Project
|
||||
public const string CouldNotFindAnyProjectInDirectory = "Could not find any project in `{0}`.";
|
||||
public const string CouldNotFindProjectOrDirectory = "Could not find project or directory `{0}`.";
|
||||
public const string MoreThanOneProjectInDirectory = "Found more than one project in `{0}`. Please specify which one to use.";
|
||||
public const string FoundInvalidProject = "Found a project `{0}` but it is invalid.";
|
||||
public const string InvalidProject = "Invalid project `{0}`.";
|
||||
|
||||
/// Solution
|
||||
public const string CouldNotFindSolutionIn = "Specified solution file {0} does not exist, or there is no solution file in the directory.";
|
||||
public const string CouldNotFindSolutionOrDirectory = "Could not find solution or directory `{0}`.";
|
||||
public const string MoreThanOneSolutionInDirectory = "Found more than one solution file in {0}. Please specify which one to use.";
|
||||
public const string InvalidSolutionFormatString = "Invalid solution `{0}`. {1}"; // {0} is the solution path, {1} is already localized details on the failure
|
||||
public const string SolutionDoesNotExist = "Specified solution file {0} does not exist, or there is no solution file in the directory.";
|
||||
|
||||
/// add p2p
|
||||
public const string ReferenceDoesNotExist = "Reference {0} does not exist.";
|
||||
public const string ReferenceIsInvalid = "Reference `{0}` is invalid.";
|
||||
public const string SpecifyAtLeastOneReferenceToAdd = "You must specify at least one reference to add.";
|
||||
public const string ProjectAlreadyHasAReference = "Project {0} already has a reference `{1}`.";
|
||||
|
||||
/// add package
|
||||
public const string PackageReferenceDoesNotExist = "Package reference `{0}` does not exist.";
|
||||
public const string PackageReferenceIsInvalid = "Package reference `{0}` is invalid.";
|
||||
public const string SpecifyAtLeastOnePackageReferenceToAdd = "You must specify at least one package to add.";
|
||||
public const string PackageReferenceAddedToTheProject = "Package reference `{0}` added to the project.";
|
||||
public const string ProjectAlreadyHasAPackageReference = "Project {0} already has a reference `{1}`.";
|
||||
public const string PleaseSpecifyVersion = "Please specify a version of the package.";
|
||||
|
||||
/// add sln
|
||||
public const string ProjectDoesNotExist = "Project `{0}` does not exist.";
|
||||
public const string ProjectIsInvalid = "Project `{0}` is invalid.";
|
||||
public const string SpecifyAtLeastOneProjectToAdd = "You must specify at least one project to add.";
|
||||
public const string ProjectAddedToTheSolution = "Project `{0}` added to the solution.";
|
||||
public const string SolutionAlreadyContainsProject = "Solution {0} already contains project {1}.";
|
||||
|
||||
/// del p2p
|
||||
public const string ReferenceNotFoundInTheProject = "Specified reference {0} does not exist in project {1}.";
|
||||
public const string ReferenceRemoved = "Reference `{0}` deleted from the project.";
|
||||
public const string SpecifyAtLeastOneReferenceToRemove = "You must specify at least one reference to remove.";
|
||||
public const string ReferenceDeleted = "Reference `{0}` deleted.";
|
||||
|
||||
/// del pkg
|
||||
public const string PackageReferenceNotFoundInTheProject = "Package reference `{0}` could not be found in the project.";
|
||||
public const string PackageReferenceRemoved = "Reference `{0}` deleted from the project.";
|
||||
public const string SpecifyAtLeastOnePackageReferenceToRemove = "You must specify at least one package reference to remove.";
|
||||
public const string PackageReferenceDeleted = "Package reference `{0}` deleted.";
|
||||
|
||||
/// del sln
|
||||
public const string ProjectNotFoundInTheSolution = "Project `{0}` could not be found in the solution.";
|
||||
public const string ProjectRemoved = "Project `{0}` removed from solution.";
|
||||
public const string SpecifyAtLeastOneProjectToRemove = "You must specify at least one project to remove.";
|
||||
public const string ProjectDeleted = "Project `{0}` deleted from solution.";
|
||||
|
||||
/// list
|
||||
public const string NoReferencesFound = "There are no {0} references in project {1}. ;; {0} is the type of the item being requested (project, package, p2p) and {1} is the object operated on (a project file or a solution file). ";
|
||||
public const string NoProjectsFound = "No projects found in the solution.";
|
||||
|
||||
/// arguments
|
||||
public const string ArgumentsProjectOrSolutionDescription = "The project or solution to operation on. If a file is not specified, the current directory is searched.";
|
||||
|
||||
/// sln
|
||||
public const string ArgumentsProjectDescription = "The project file to operate on. If a file is not specified, the command will search the current directory for one.";
|
||||
public const string ArgumentsSolutionDescription = "Solution file to operate on. If not specified, the command will search the current directory for one.";
|
||||
public const string CmdSlnFile = "SLN_FILE";
|
||||
public const string CmdProjectFile = "PROJECT";
|
||||
|
||||
/// commands
|
||||
public const string CmdFramework = "FRAMEWORK";
|
||||
|
||||
/// update pkg
|
||||
public const string PleaseSpecifyNewVersion = "Please specify new version of the package.";
|
||||
public const string PleaseSpecifyWhichPackageToUpdate = "Please specify which package to update.";
|
||||
public const string NothingToUpdate = "Nothing to update.";
|
||||
public const string EverythingUpToDate = "Everything is already up-to-date.";
|
||||
public const string PackageVersionUpdatedTo = "Version of package `{0}` updated to `{1}`.";
|
||||
public const string PackageVersionUpdated = "Version of package `{0}` updated.";
|
||||
public const string CouldNotUpdateTheVersion = "Could not update the version of the package `{0}`.";
|
||||
|
||||
/// new
|
||||
public const string TemplateCreatedSuccessfully = "The template {0} created successfully. Please run \"dotnet restore\" to get started!";
|
||||
public const string TemplateInstalledSuccesfully = "The template {0} installed successfully. You can use \"dotnet new {0}\" to get started with the new template.";
|
||||
public const string TemplateCreateError = "Template {0} could not be created. Error returned was: {1}.";
|
||||
public const string TemplateInstallError = "Template {0} could not be installed. Error returned was: {1}.";
|
||||
public const string SpecifiedNameExists = "Specified name {0} already exists. Please specify a different name.";
|
||||
public const string SpecifiedAliasExists = "Specified alias {0} already exists. Please specify a different alias.";
|
||||
public const string MandatoryParameterMissing = "Mandatory parameter {0} missing for template {1}. ";
|
||||
|
||||
public const string ProjectNotCompatibleWithFrameworks = "Project `{0}` cannot be added due to incompatible targeted frameworks between the two projects. Please review the project you are trying to add and verify that is compatible with the following targets:";
|
||||
public const string ProjectDoesNotTargetFramework = "Project `{0}` does not target framework `{1}`.";
|
||||
public const string ProjectCouldNotBeEvaluated = "Project `{0}` could not be evaluated. Evaluation failed with following error:\n{1}";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
//using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Archive;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Archive
|
||||
{
|
||||
|
||||
public partial class ArchiveCommand
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
//DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
var app = new CommandLineApplication();
|
||||
app.Name = "archive";
|
||||
app.FullName = ".NET archiver";
|
||||
app.Description = "Archives and expands sets of files";
|
||||
app.HelpOption("-h|--help");
|
||||
|
||||
var extract = app.Option("-x|--extract <outputDirectory>", "Directory to extract to", CommandOptionType.SingleValue);
|
||||
var archiveFile = app.Option("-a|--archive <file>", "Archive to operate on", CommandOptionType.SingleValue);
|
||||
var externals = app.Option("--external <external>...", "External files and directories to consider for extraction", CommandOptionType.MultipleValue);
|
||||
var sources = app.Argument("<sources>...", "Files & directory to include in the archive", multipleValues: true);
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
|
||||
if (extract.HasValue() && sources.Values.Any())
|
||||
{
|
||||
Console.WriteLine("Extract '-x' can only be specified when no '<sources>' are specified to add to the archive.");
|
||||
return 1;
|
||||
}
|
||||
else if (!extract.HasValue() && !sources.Values.Any())
|
||||
{
|
||||
Console.WriteLine("Either extract '-x' or '<sources>' must be specified.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!archiveFile.HasValue())
|
||||
{
|
||||
Console.WriteLine("Archive '-a' must be specified.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var progress = new ConsoleProgressReport();
|
||||
|
||||
var archive = new IndexedArchive();
|
||||
foreach (var external in externals.Values)
|
||||
{
|
||||
if (Directory.Exists(external))
|
||||
{
|
||||
archive.AddExternalDirectory(external);
|
||||
}
|
||||
else
|
||||
{
|
||||
archive.AddExternalFile(external);
|
||||
}
|
||||
}
|
||||
|
||||
if (sources.Values.Any())
|
||||
{
|
||||
foreach (var source in sources.Values)
|
||||
{
|
||||
if (Directory.Exists(source))
|
||||
{
|
||||
archive.AddDirectory(source, progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
archive.AddFile(source, Path.GetFileName(source));
|
||||
}
|
||||
}
|
||||
|
||||
archive.Save(archiveFile.Value(), progress);
|
||||
}
|
||||
else // sources not specified, extract must have been specified
|
||||
{
|
||||
archive.Extract(archiveFile.Value(), extract.Value(), progress);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return app.Execute(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="..\..\build\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<EnableApiCheck>false</EnableApiCheck>
|
||||
<RuntimeIdentifiers>win7-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.DotNet.Archive\Microsoft.DotNet.Archive.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Loading…
Reference in New Issue