Sync Compress and RVIO with latest from RVWorld

This commit is contained in:
Matt Nadareski
2023-04-21 15:04:31 -04:00
parent de59a91bef
commit ac718efa78
116 changed files with 5197 additions and 3669 deletions

View File

@@ -9,7 +9,7 @@ using SabreTools.Core.Tools;
using SabreTools.IO;
using Compress;
using Compress.gZip;
using Compress.ZipFile.ZLib;
using Compress.Support.Compression.Deflate;
namespace SabreTools.FileTypes.Archives
{
@@ -240,7 +240,7 @@ namespace SabreTools.FileTypes.Archives
ZipReturn ret = gz.ZipFileOpen(this.Filename);
ret = gz.ZipFileOpenReadStream(0, out Stream gzstream, out ulong streamSize);
gzipEntryRom = GetInfo(gzstream, hashes: this.AvailableHashes);
gzipEntryRom.Filename = gz.Filename(0);
gzipEntryRom.Filename = gz.GetLocalFile(0).Filename;
gzipEntryRom.Parent = gamename;
gzipEntryRom.Date = (gz.TimeStamp > 0 ? gz.TimeStamp.ToString() : null);
gzstream.Dispose();

View File

@@ -7,8 +7,6 @@ using SabreTools.Core;
using SabreTools.Core.Tools;
using Compress;
using Compress.SevenZip;
using Compress.Utils;
using Compress.ZipFile;
using NaturalSort;
namespace SabreTools.FileTypes.Archives
@@ -75,7 +73,7 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
@@ -84,19 +82,19 @@ namespace SabreTools.FileTypes.Archives
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
// Create the rest of the path, if needed
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(zf.Filename(i))))
Directory.CreateDirectory(Path.Combine(outDir, Path.GetDirectoryName(zf.Filename(i))));
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(zf.GetLocalFile(i).Filename)))
Directory.CreateDirectory(Path.Combine(outDir, Path.GetDirectoryName(zf.GetLocalFile(i).Filename)));
// If the entry ends with a directory separator, continue to the next item, if any
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
if (zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
{
zf.ZipFileCloseReadStream();
continue;
}
FileStream writeStream = File.Create(Path.Combine(outDir, zf.Filename(i)));
FileStream writeStream = File.Create(Path.Combine(outDir, zf.GetLocalFile(i).Filename));
// If the stream is smaller than the buffer, just run one loop through to avoid issues
if (streamsize < _bufferSize)
@@ -198,15 +196,15 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
{
if (zf.Filename(i).Contains(entryName))
if (zf.GetLocalFile(i).Filename.Contains(entryName))
{
// Open the read stream
realEntry = zf.Filename(i);
realEntry = zf.GetLocalFile(i).Filename;
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
// If the stream is smaller than the buffer, just run one loop through to avoid issues
@@ -267,16 +265,16 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount(); i++)
{
// If the entry is a directory (or looks like a directory), we don't want to open it
if (zf.IsDirectory(i)
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
if (zf.GetLocalFile(i).IsDirectory
|| zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
{
continue;
}
@@ -298,17 +296,17 @@ namespace SabreTools.FileTypes.Archives
// Perform a quickscan, if flagged to
if (this.AvailableHashes == Hash.CRC)
{
zipEntryRom.Size = (long)zf.UncompressedSize(i);
zipEntryRom.CRC = zf.CRC32(i);
zipEntryRom.Size = (long)zf.GetLocalFile(i).UncompressedSize;
zipEntryRom.CRC = zf.GetLocalFile(i).CRC;
}
// Otherwise, use the stream directly
else
{
zipEntryRom = GetInfo(readStream, size: (long)zf.UncompressedSize(i), hashes: this.AvailableHashes, keepReadOpen: true);
zipEntryRom = GetInfo(readStream, size: (long)zf.GetLocalFile(i).UncompressedSize, hashes: this.AvailableHashes, keepReadOpen: true);
}
// Fill in comon details and add to the list
zipEntryRom.Filename = zf.Filename(i);
zipEntryRom.Filename = zf.GetLocalFile(i).Filename;
zipEntryRom.Parent = gamename;
found.Add(zipEntryRom);
}
@@ -337,13 +335,13 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
List<(string, bool)> zipEntries = new();
for (int i = 0; i < zf.LocalFilesCount(); i++)
{
zipEntries.Add((zf.Filename(i), zf.IsDirectory(i)));
zipEntries.Add((zf.GetLocalFile(i).Filename, zf.GetLocalFile(i).IsDirectory));
}
zipEntries = zipEntries.OrderBy(p => p.Item1, new NaturalReversedComparer()).ToList();
@@ -381,7 +379,7 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
return zf.ZipStatus == ZipStatus.Trrnt7Zip;
@@ -474,7 +472,7 @@ namespace SabreTools.FileTypes.Archives
var oldZipFileContents = new List<string>();
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
oldZipFileContents.Add(oldZipFile.Filename(i));
oldZipFileContents.Add(oldZipFile.GetLocalFile(i).Filename);
}
// If the old one doesn't contain the new file, then add it
@@ -486,7 +484,7 @@ namespace SabreTools.FileTypes.Archives
// Then add all of the old entries to it too
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
inputIndexMap.Add(oldZipFile.Filename(i), i);
inputIndexMap.Add(oldZipFile.GetLocalFile(i).Filename, i);
}
// If the number of entries is the same as the old archive, skip out
@@ -501,7 +499,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)
@@ -544,7 +542,7 @@ namespace SabreTools.FileTypes.Archives
{
// Instantiate the streams
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, 0, out writeStream, null);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.GetLocalFile(index).Filename, istreamSize, 0, out writeStream, null);
// Copy the input stream to the output
byte[] ibuffer = new byte[_bufferSize];
@@ -556,7 +554,7 @@ namespace SabreTools.FileTypes.Archives
}
oldZipFile.ZipFileCloseReadStream();
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
zipFile.ZipFileCloseWriteStream(oldZipFile.GetLocalFile(index).CRC);
}
}
}
@@ -643,7 +641,7 @@ namespace SabreTools.FileTypes.Archives
// Sort the keys in TZIP order
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Now add all of the files in order
foreach (string key in keys)
@@ -694,7 +692,7 @@ namespace SabreTools.FileTypes.Archives
var oldZipFileContents = new List<string>();
for (int j = 0; j < oldZipFile.LocalFilesCount(); j++)
{
oldZipFileContents.Add(oldZipFile.Filename(j));
oldZipFileContents.Add(oldZipFile.GetLocalFile(j).Filename);
}
// If the old one contains the new file, then just skip out
@@ -709,7 +707,7 @@ namespace SabreTools.FileTypes.Archives
// Then add all of the old entries to it too
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
inputIndexMap.Add(oldZipFile.Filename(i), i);
inputIndexMap.Add(oldZipFile.GetLocalFile(i).Filename, i);
}
// If the number of entries is the same as the old archive, skip out
@@ -724,7 +722,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)
@@ -768,7 +766,7 @@ namespace SabreTools.FileTypes.Archives
{
// Instantiate the streams
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, 0, out writeStream, null);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.GetLocalFile(index).Filename, istreamSize, 0, out writeStream, null);
// Copy the input stream to the output
byte[] ibuffer = new byte[_bufferSize];
@@ -779,7 +777,7 @@ namespace SabreTools.FileTypes.Archives
writeStream.Flush();
}
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
zipFile.ZipFileCloseWriteStream(oldZipFile.GetLocalFile(index).CRC);
}
}
}

View File

@@ -5,7 +5,7 @@ using System.Linq;
using SabreTools.Core;
using SabreTools.Core.Tools;
using Compress.ZipFile;
using Compress;
using SharpCompress.Archives;
using SharpCompress.Archives.Tar;
using SharpCompress.Common;
@@ -330,7 +330,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)
@@ -444,7 +444,7 @@ namespace SabreTools.FileTypes.Archives
// Sort the keys in TZIP order
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Now add all of the files in order
foreach (string key in keys)
@@ -499,7 +499,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)

View File

@@ -6,7 +6,6 @@ using System.Linq;
using SabreTools.Core;
using SabreTools.Core.Tools;
using Compress;
using Compress.Utils;
using Compress.ZipFile;
using NaturalSort;
@@ -84,7 +83,7 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
@@ -93,21 +92,21 @@ namespace SabreTools.FileTypes.Archives
zr = zf.ZipFileOpenReadStream(i, false, out Stream readStream, out ulong streamsize, out ushort cm);
// Create the rest of the path, if needed
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(zf.Filename(i))))
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(zf.GetLocalFile(i).Filename)))
{
Directory.CreateDirectory(Path.Combine(outDir, Path.GetDirectoryName(zf.Filename(i))));
Directory.CreateDirectory(Path.Combine(outDir, Path.GetDirectoryName(zf.GetLocalFile(i).Filename)));
}
// If the entry ends with a directory separator, continue to the next item, if any
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
if (zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
{
zf.ZipFileCloseReadStream();
continue;
}
FileStream writeStream = File.Create(Path.Combine(outDir, zf.Filename(i)));
FileStream writeStream = File.Create(Path.Combine(outDir, zf.GetLocalFile(i).Filename));
// If the stream is smaller than the buffer, just run one loop through to avoid issues
if (streamsize < _bufferSize)
@@ -209,15 +208,15 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
{
if (zf.Filename(i).Contains(entryName))
if (zf.GetLocalFile(i).Filename.Contains(entryName))
{
// Open the read stream
realEntry = zf.Filename(i);
realEntry = zf.GetLocalFile(i).Filename;
zr = zf.ZipFileOpenReadStream(i, false, out Stream readStream, out ulong streamsize, out ushort cm);
// If the stream is smaller than the buffer, just run one loop through to avoid issues
@@ -278,16 +277,16 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount(); i++)
{
// If the entry is a directory (or looks like a directory), we don't want to open it
if (zf.IsDirectory(i)
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
if (zf.GetLocalFile(i).IsDirectory
|| zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
{
continue;
}
@@ -309,19 +308,19 @@ namespace SabreTools.FileTypes.Archives
// Perform a quickscan, if flagged to
if (this.AvailableHashes == Hash.CRC)
{
zipEntryRom.Size = (long)zf.UncompressedSize(i);
zipEntryRom.CRC = zf.CRC32(i);
zipEntryRom.Size = (long)zf.GetLocalFile(i).UncompressedSize;
zipEntryRom.CRC = zf.GetLocalFile(i).CRC;
}
// Otherwise, use the stream directly
else
{
zipEntryRom = GetInfo(readStream, size: (long)zf.UncompressedSize(i), hashes: this.AvailableHashes, keepReadOpen: true);
zipEntryRom = GetInfo(readStream, size: (long)zf.GetLocalFile(i).UncompressedSize, hashes: this.AvailableHashes, keepReadOpen: true);
}
// Fill in comon details and add to the list
zipEntryRom.Filename = zf.Filename(i);
zipEntryRom.Filename = zf.GetLocalFile(i).Filename;
zipEntryRom.Parent = gamename;
zipEntryRom.Date = zf.LastModified(i).ToString("yyyy/MM/dd hh:mm:ss");
zipEntryRom.Date = zf.GetLocalFile(i).LastModified.ToString("yyyy/MM/dd hh:mm:ss");
found.Add(zipEntryRom);
}
@@ -349,13 +348,13 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
List<(string, bool)> zipEntries = new();
for (int i = 0; i < zf.LocalFilesCount(); i++)
{
zipEntries.Add((zf.Filename(i), zf.IsDirectory(i)));
zipEntries.Add((zf.GetLocalFile(i).Filename, zf.GetLocalFile(i).IsDirectory));
}
zipEntries = zipEntries.OrderBy(p => p.Item1, new NaturalReversedComparer()).ToList();
@@ -393,7 +392,7 @@ namespace SabreTools.FileTypes.Archives
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
return zf.ZipStatus == ZipStatus.TrrntZip;
@@ -486,7 +485,7 @@ namespace SabreTools.FileTypes.Archives
var oldZipFileContents = new List<string>();
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
oldZipFileContents.Add(oldZipFile.Filename(i));
oldZipFileContents.Add(oldZipFile.GetLocalFile(i).Filename);
}
// If the old one doesn't contain the new file, then add it
@@ -496,7 +495,7 @@ namespace SabreTools.FileTypes.Archives
// Then add all of the old entries to it too
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
inputIndexMap.Add(oldZipFile.Filename(i), i);
inputIndexMap.Add(oldZipFile.GetLocalFile(i).Filename, i);
}
// If the number of entries is the same as the old archive, skip out
@@ -511,7 +510,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)
@@ -554,9 +553,9 @@ namespace SabreTools.FileTypes.Archives
{
// Instantiate the streams
oldZipFile.ZipFileOpenReadStream(index, false, out Stream zreadStream, out ulong istreamSize, out ushort icompressionMethod);
long msDosDateTime = oldZipFile.LastModified(index);
long msDosDateTime = oldZipFile.GetLocalFile(index).LastModified;
TimeStamps ts = new() { ModTime = msDosDateTime };
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, (ushort)CompressionMethod.Deflated, out writeStream, ts);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.GetLocalFile(index).Filename, istreamSize, (ushort)CompressionMethod.Deflated, out writeStream, ts);
// Copy the input stream to the output
byte[] ibuffer = new byte[_bufferSize];
@@ -568,7 +567,7 @@ namespace SabreTools.FileTypes.Archives
}
oldZipFile.ZipFileCloseReadStream();
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
zipFile.ZipFileCloseWriteStream(oldZipFile.GetLocalFile(index).CRC);
}
}
}
@@ -655,7 +654,7 @@ namespace SabreTools.FileTypes.Archives
// Sort the keys in TZIP order
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Now add all of the files in order
foreach (string key in keys)
@@ -706,7 +705,7 @@ namespace SabreTools.FileTypes.Archives
var oldZipFileContents = new List<string>();
for (int j = 0; j < oldZipFile.LocalFilesCount(); j++)
{
oldZipFileContents.Add(oldZipFile.Filename(j));
oldZipFileContents.Add(oldZipFile.GetLocalFile(j).Filename);
}
// If the old one contains the new file, then just skip out
@@ -721,7 +720,7 @@ namespace SabreTools.FileTypes.Archives
// Then add all of the old entries to it too
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
{
inputIndexMap.Add(oldZipFile.Filename(i), i);
inputIndexMap.Add(oldZipFile.GetLocalFile(i).Filename, i);
}
// If the number of entries is the same as the old archive, skip out
@@ -736,7 +735,7 @@ namespace SabreTools.FileTypes.Archives
// Get the order for the entries with the new file
List<string> keys = inputIndexMap.Keys.ToList();
keys.Sort(ZipUtils.TrrntZipStringCompare);
keys.Sort(CompressUtils.TrrntZipStringCompare);
// Copy over all files to the new archive
foreach (string key in keys)
@@ -780,9 +779,9 @@ namespace SabreTools.FileTypes.Archives
{
// Instantiate the streams
oldZipFile.ZipFileOpenReadStream(index, false, out Stream zreadStream, out ulong istreamSize, out ushort icompressionMethod);
long msDosDateTime = oldZipFile.LastModified(index);
long msDosDateTime = oldZipFile.GetLocalFile(index).LastModified;
TimeStamps ts = new() { ModTime = msDosDateTime };
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.Filename(index), istreamSize, (ushort)CompressionMethod.Deflated, out writeStream, ts);
zipFile.ZipFileOpenWriteStream(false, true, oldZipFile.GetLocalFile(index).Filename, istreamSize, (ushort)CompressionMethod.Deflated, out writeStream, ts);
// Copy the input stream to the output
byte[] ibuffer = new byte[_bufferSize];
@@ -793,7 +792,7 @@ namespace SabreTools.FileTypes.Archives
writeStream.Flush();
}
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
zipFile.ZipFileCloseWriteStream(oldZipFile.GetLocalFile(index).CRC);
}
}
}

View File

@@ -1,12 +1,31 @@
using System;
using System.Text;
using RVIO;
namespace Compress.ZipFile
namespace Compress
{
public static class ZipUtils
public static class CompressUtils
{
// according to the zip documents, zip filesname are stored as MS-DOS Code Page 437.
// (Unless the uncode flag is set, in which case they are stored as UTF-8.
public static void CreateDirForFile(string sFilename)
{
string strTemp = Path.GetDirectoryName(sFilename);
if (string.IsNullOrEmpty(strTemp))
{
return;
}
if (Directory.Exists(strTemp))
{
return;
}
Directory.CreateDirectory(strTemp);
}
// according to the zip documents, zip filenames are stored as MS-DOS Code Page 437.
// (Unless the unicode flag is set, in which case they are stored as UTF-8.
private static Encoding enc = null;
public static void EncodeSetup()
@@ -154,7 +173,7 @@ namespace Compress.ZipFile
ret = "";
break;
case ZipReturn.ZipFileCountError:
ret = "The number of file in the Zip does not mach the number of files in the Zips Centeral Directory";
ret = "The number of file in the Zip does not mach the number of files in the Zips Central Directory";
break;
case ZipReturn.ZipSignatureError:
ret = "An unknown Signature Block was found in the Zip";
@@ -163,19 +182,19 @@ namespace Compress.ZipFile
ret = "Extra Data was found on the end of the Zip";
break;
case ZipReturn.ZipUnsupportedCompression:
ret = "An unsupported Compression method was found in the Zip, if you recompress this zip it will be usable";
ret = "An unsupported Compression method was found in the Zip, if you re-compress this zip it will be usable";
break;
case ZipReturn.ZipLocalFileHeaderError:
ret = "Error reading a zipped file header information";
break;
case ZipReturn.ZipCentralDirError:
ret = "There is an error in the Zip Centeral Directory";
ret = "There is an error in the Zip Central Directory";
break;
case ZipReturn.ZipReadingFromOutputFile:
ret = "Trying to write to a Zip file open for output only";
break;
case ZipReturn.ZipWritingToInputFile:
ret = "Tring to read from a Zip file open for input only";
ret = "Trying to read from a Zip file open for input only";
break;
case ZipReturn.ZipErrorGettingDataStream:
ret = "Error creating Data Stream";
@@ -190,32 +209,34 @@ namespace Compress.ZipFile
return ret;
}
public const long fileTimeToUTCTime = 504911232000000000;
public const long epochTimeToUTCTime = 621355968000000000;
public const long trrntzipDateTime = 629870671200000000;
private const long FileTimeToUtcTime = 504911232000000000;
private const long EpochTimeToUtcTime = 621355968000000000;
public const long TrrntzipDateTime = 629870671200000000;
private const long TicksPerMillisecond = 10000;
private const long TicksPerSecond = TicksPerMillisecond * 1000;
public static void SetDateTime(long ticks, out ushort DosFileDate, out ushort DosFileTime)
public static void UtcTicksToDosDateTime(long ticks, out ushort dosFileDate, out ushort dosFileTime)
{
DateTime DateTime = new DateTime(ticks, DateTimeKind.Unspecified);
DosFileDate = (ushort)((DateTime.Day & 0x1f) | ((DateTime.Month & 0x0f) << 5) | (((DateTime.Year - 1980) & 0x7f) << 9));
DosFileTime = (ushort)(((DateTime.Second >> 1) & 0x1f) | ((DateTime.Minute & 0x3f) << 5) | ((DateTime.Hour & 0x1f) << 11));
DateTime dateTime = new(ticks, DateTimeKind.Unspecified);
dosFileDate = (ushort)((dateTime.Day & 0x1f) | ((dateTime.Month & 0x0f) << 5) | (((dateTime.Year - 1980) & 0x7f) << 9));
dosFileTime = (ushort)(((dateTime.Second >> 1) & 0x1f) | ((dateTime.Minute & 0x3f) << 5) | ((dateTime.Hour & 0x1f) << 11));
}
public static long SetDateTime(ushort DosFileDate, ushort DosFileTime)
public static long UtcTicksFromDosDateTime(ushort dosFileDate, ushort dosFileTime)
{
if (DosFileDate == 0)
if (dosFileDate == 0)
return 0;
int second = (DosFileTime & 0x1f) << 1;
int minute = (DosFileTime >> 5) & 0x3f;
int hour = (DosFileTime >> 11) & 0x1f;
int second = (dosFileTime & 0x1f) << 1;
int minute = (dosFileTime >> 5) & 0x3f;
int hour = (dosFileTime >> 11) & 0x1f;
int day = DosFileDate & 0x1f;
int month = (DosFileDate >> 5) & 0x0f;
int year = ((DosFileDate >> 9) & 0x7f) + 1980;
int day = dosFileDate & 0x1f;
int month = (dosFileDate >> 5) & 0x0f;
int year = ((dosFileDate >> 9) & 0x7f) + 1980;
// valid hours 0 to 23
// valid minutes 0 to 59
@@ -235,15 +256,24 @@ namespace Compress.ZipFile
return 0;
}
}
public static long FileTimeToUTCTime(long ticks)
public static long UtcTicksToNtfsDateTime(long ticks)
{
return ticks + fileTimeToUTCTime;
return ticks - FileTimeToUtcTime;
}
public static long SetDateTimeFromUnixSeconds(int seconds)
public static long UtcTicksFromNtfsDateTime(long ntfsTicks)
{
return seconds * TicksPerSecond + epochTimeToUTCTime;
return ntfsTicks + FileTimeToUtcTime;
}
public static int UtcTicksToUnixDateTime(long ticks)
{
return (int)((ticks - EpochTimeToUtcTime) / TicksPerSecond);
}
public static long UtcTicksFromUnixDateTime(int linuxSeconds)
{
return linuxSeconds * TicksPerSecond + EpochTimeToUtcTime;
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.IO;
using Compress.Utils;
using Compress.Support.Utils;
using Path = RVIO.Path;
using FileInfo = RVIO.FileInfo;
using FileStream = RVIO.FileStream;
@@ -27,39 +27,20 @@ namespace Compress.File
return 1;
}
public string Filename(int i)
public LocalFile GetLocalFile(int i)
{
return Path.GetFileName(ZipFilename);
}
LocalFile lf = new()
{
Filename = Path.GetFileName(ZipFilename),
UncompressedSize = _fileInfo != null ? (ulong)_fileInfo.Length : (ulong)_inStream.Length,
CRC = _crc,
IsDirectory = RVIO.Directory.Exists(ZipFilename),
ModifiedTime = _fileInfo?.LastWriteTime,
AccessedTime = _fileInfo?.LastAccessTime,
CreatedTime = _fileInfo?.CreationTime
public bool IsDirectory(int i)
{
return RVIO.Directory.Exists(ZipFilename);
}
public ulong UncompressedSize(int i)
{
return _fileInfo != null ? (ulong)_fileInfo.Length : (ulong)_inStream.Length;
}
public ulong? LocalHeader(int i)
{
return 0;
}
public ZipReturn FileStatus(int i)
{
return ZipReturn.ZipGood;
}
public byte[] CRC32(int i)
{
return _crc;
}
public long LastModified(int i)
{
return _fileInfo.LastWriteTime;
};
return lf;
}
public ZipReturn ZipFileCreate(string newFilename)
@@ -69,7 +50,7 @@ namespace Compress.File
return ZipReturn.ZipFileAlreadyOpen;
}
DirUtil.CreateDirForFile(newFilename);
CompressUtils.CreateDirForFile(newFilename);
_fileInfo = new FileInfo(newFilename);
int errorCode = FileStream.OpenFileWrite(newFilename, out _inStream);
@@ -139,7 +120,7 @@ namespace Compress.File
if (errorCode != 0)
{
ZipFileClose();
if (errorCode == 32)
if (errorCode == 32 || errorCode==5)
{
return ZipReturn.ZipFileLocked;
}
@@ -158,12 +139,6 @@ namespace Compress.File
}
ZipOpen = ZipOpenType.OpenRead;
if (!readHeaders)
{
return ZipReturn.ZipGood;
}
//return ZipFileReadHeaders();
return ZipReturn.ZipGood;
}
@@ -195,7 +170,7 @@ namespace Compress.File
public void ZipFileCloseFailed()
{
throw new NotImplementedException();
//throw new NotImplementedException();
}
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize)

View File

@@ -1,6 +1,6 @@
using System;
using System.IO;
using Compress.Utils;
using Compress.Support.Utils;
namespace Compress
{
@@ -8,14 +8,7 @@ namespace Compress
{
int LocalFilesCount();
string Filename(int i);
ulong? LocalHeader(int i);
ulong UncompressedSize(int i);
byte[] CRC32(int i);
long LastModified(int i);
bool IsDirectory(int i);
LocalFile GetLocalFile(int i);
ZipOpenType ZipOpen { get; }

View File

@@ -0,0 +1,52 @@
using System;
namespace Compress
{
public class LocalFile
{
internal LocalFile()
{ }
public string Filename { get; internal set; }
public ulong UncompressedSize { get; internal set; }
public byte[] CRC { get; internal set; }
public bool IsDirectory { get; internal set; }
public long LastModified => ModifiedTime ?? HeaderLastModified;
internal long HeaderLastModified { get; set; }
internal long? ModifiedTime { get; set; }
public long? CreatedTime { get; internal set; }
public long? AccessedTime { get; internal set; }
private LocalFileStatus _status=LocalFileStatus.Nothing;
internal void SetStatus(LocalFileStatus lfs,bool set=true)
{
if (set)
_status |= lfs;
else
_status &= ~lfs;
}
public bool GetStatus(LocalFileStatus lfs)
{
return (_status & lfs) != 0;
}
public virtual ulong? LocalHead => null;
}
[Flags]
public enum LocalFileStatus
{
Nothing = 0x00000,
Zip64 = 0x00001,
TrrntZip = 0x00002,
FilenameMisMatch = 0x00010,
DirectoryLengthError = 0x00020,
DateTimeMisMatch = 0x00040
}
}

View File

@@ -1,194 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Interop = Compress.SevenZip.Compress.ZSTD.ZstandardInterop;
namespace Compress.SevenZip.Compress.ZSTD
{
/// <summary>
/// A Zstandard dictionary improves the compression ratio and speed on small data dramatically.
/// </summary>
/// <remarks>
/// A Zstandard dictionary is calculated with a high number of small sample data.
/// Please refer to the Zstandard documentation for more details.
/// </remarks>
/// <seealso cref="System.IDisposable" />
public sealed class ZstandardDictionary : IDisposable
{
private byte[] dictionary;
private IntPtr ddict;
private Dictionary<int, IntPtr> cdicts = new Dictionary<int, IntPtr>();
private object lockObject = new object();
private bool isDisposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
/// </summary>
/// <param name="dictionary">The dictionary raw data.</param>
public ZstandardDictionary(byte[] dictionary)
{
this.dictionary = dictionary;
}
/// <summary>
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
/// </summary>
/// <param name="dictionaryPath">The dictionary path.</param>
public ZstandardDictionary(string dictionaryPath)
{
this.dictionary = System.IO.File.ReadAllBytes(dictionaryPath);
}
/// <summary>
/// Initializes a new instance of the <see cref="ZstandardDictionary"/> class.
/// </summary>
/// <param name="dictionaryStream">The dictionary stream.</param>
public ZstandardDictionary(Stream dictionaryStream)
{
using (var memoryStream = new MemoryStream())
{
dictionaryStream.CopyTo(memoryStream);
this.dictionary = memoryStream.ToArray();
}
}
/// <summary>
/// Finalizes an instance of the <see cref="ZstandardDictionary"/> class.
/// </summary>
~ZstandardDictionary()
{
this.Dispose(false);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
private void Dispose(bool dispose)
{
if (this.isDisposed == false)
{
this.isDisposed = true;
if (this.ddict != IntPtr.Zero)
{
Interop.ZSTD_freeDDict(this.ddict);
this.ddict = IntPtr.Zero;
}
foreach (var kv in this.cdicts.ToList())
{
Interop.ZSTD_freeCDict(kv.Value);
this.cdicts.Remove(kv.Key);
}
}
}
/// <summary>
/// Gets the compression dictionary for the specified compression level.
/// </summary>
/// <param name="compressionLevel">The compression level.</param>
/// <returns>
/// The IntPtr to the compression dictionary.
/// </returns>
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
internal IntPtr GetCompressionDictionary(int compressionLevel)
{
if (this.isDisposed)
{
throw new ObjectDisposedException(nameof(ZstandardDictionary));
}
lock (this.lockObject)
{
if (this.cdicts.TryGetValue(compressionLevel, out var cdict) == false)
{
this.cdicts[compressionLevel] = cdict = this.CreateCompressionDictionary(compressionLevel);
}
return cdict;
}
}
/// <summary>
/// Gets the decompression dictionary.
/// </summary>
/// <returns>
/// The IntPtr to the decompression dictionary.
/// </returns>
/// <exception cref="ObjectDisposedException">ZstandardDictionary</exception>
internal IntPtr GetDecompressionDictionary()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(nameof(ZstandardDictionary));
}
lock (this.lockObject)
{
if (this.ddict == IntPtr.Zero)
{
this.ddict = this.CreateDecompressionDictionary();
}
return this.ddict;
}
}
/// <summary>
/// Creates a new compression dictionary.
/// </summary>
/// <param name="compressionLevel">The compression level.</param>
/// <returns>
/// The IntPtr to the compression dictionary.
/// </returns>
private IntPtr CreateCompressionDictionary(int compressionLevel)
{
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
try
{
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
var dictSize = new UIntPtr((uint)this.dictionary.Length);
return Interop.ZSTD_createCDict(dictBuffer, dictSize, compressionLevel);
}
finally
{
alloc.Free();
}
}
/// <summary>
/// Creates a new decompression dictionary.
/// </summary>
/// <returns>
/// The IntPtr to the decompression dictionary.
/// </returns>
private IntPtr CreateDecompressionDictionary()
{
var alloc = GCHandle.Alloc(this.dictionary, GCHandleType.Pinned);
try
{
var dictBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(this.dictionary, 0);
var dictSize = new UIntPtr((uint)this.dictionary.Length);
return Interop.ZSTD_createDDict(dictBuffer, dictSize);
}
finally
{
alloc.Free();
}
}
}
}

View File

@@ -1,143 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Compress.SevenZip.Compress.ZSTD
{
internal static class ZstandardInterop
{
static ZstandardInterop()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
var root = Path.GetDirectoryName(typeof(ZstandardInterop).Assembly.Location);
var path = Environment.Is64BitProcess ? "x64" : "x86";
var file = Path.Combine(root, path, "libzstd.dll");
LoadLibraryEx(file, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
}
}
[StructLayout(LayoutKind.Sequential)]
public class Buffer
{
public IntPtr Data = IntPtr.Zero;
public UIntPtr Size = UIntPtr.Zero;
public UIntPtr Position = UIntPtr.Zero;
}
public static void ThrowIfError(UIntPtr code)
{
if (ZSTD_isError(code))
{
var errorPtr = ZSTD_getErrorName(code);
var errorMsg = Marshal.PtrToStringAnsi(errorPtr);
throw new IOException(errorMsg);
}
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
[Flags]
private enum LoadLibraryFlags : uint
{
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
}
[DllImport("kernel32", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern uint ZSTD_versionNumber();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern int ZSTD_maxCLevel();
//-----------------------------------------------------------------------------------------
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createCStream();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_initCStream(IntPtr zcs, int compressionLevel);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_freeCStream(IntPtr zcs);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_CStreamInSize();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_CStreamOutSize();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_compressStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createCDict(IntPtr dictBuffer, UIntPtr dictSize, int compressionLevel);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_freeCDict(IntPtr cdict);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_initCStream_usingCDict(IntPtr zcs, IntPtr cdict);
//-----------------------------------------------------------------------------------------
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createDStream();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_initDStream(IntPtr zds);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_freeDStream(IntPtr zds);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_DStreamInSize();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_DStreamOutSize();
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_decompressStream(IntPtr zds, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer, [MarshalAs(UnmanagedType.LPStruct)] Buffer inputBuffer);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createDDict(IntPtr dictBuffer, UIntPtr dictSize);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_freeDDict(IntPtr ddict);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_initDStream_usingDDict(IntPtr zds, IntPtr ddict);
//-----------------------------------------------------------------------------------------
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_flushStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
public static extern UIntPtr ZSTD_endStream(IntPtr zcs, [MarshalAs(UnmanagedType.LPStruct)] Buffer outputBuffer);
//-----------------------------------------------------------------------------------------
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool ZSTD_isError(UIntPtr code);
[DllImport("libzstd", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ZSTD_getErrorName(UIntPtr code);
}
}

View File

@@ -1,397 +0,0 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using Interop = Compress.SevenZip.Compress.ZSTD.ZstandardInterop;
namespace Compress.SevenZip.Compress.ZSTD
{
/// <summary>
/// Provides methods and properties for compressing and decompressing streams by using the Zstandard algorithm.
/// </summary>
public class ZstandardStream : Stream
{
private Stream stream;
private CompressionMode mode;
private Boolean leaveOpen;
private Boolean isClosed = false;
private Boolean isDisposed = false;
private Boolean isInitialized = false;
private IntPtr zstream;
private uint zstreamInputSize;
private uint zstreamOutputSize;
private byte[] data;
private bool dataDepleted = false;
private bool dataSkipRead = false;
private int dataPosition = 0;
private int dataSize = 0;
private long position = 0;
private Interop.Buffer outputBuffer = new Interop.Buffer();
private Interop.Buffer inputBuffer = new Interop.Buffer();
/// <summary>
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression mode, and optionally leaves the stream open.
/// </summary>
/// <param name="stream">The stream to compress.</param>
/// <param name="mode">One of the enumeration values that indicates whether to compress or decompress the stream.</param>
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
public ZstandardStream(Stream stream, CompressionMode mode, bool leaveOpen = false)
{
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
this.mode = mode;
this.leaveOpen = leaveOpen;
position = 0;
if (mode == CompressionMode.Compress)
{
this.zstreamInputSize = Interop.ZSTD_CStreamInSize().ToUInt32();
this.zstreamOutputSize = Interop.ZSTD_CStreamOutSize().ToUInt32();
this.zstream = Interop.ZSTD_createCStream();
this.data = new byte[(int)this.zstreamOutputSize];
}
if (mode == CompressionMode.Decompress)
{
this.zstreamInputSize = Interop.ZSTD_DStreamInSize().ToUInt32();
this.zstreamOutputSize = Interop.ZSTD_DStreamOutSize().ToUInt32();
this.zstream = Interop.ZSTD_createDStream();
this.data = new byte[(int)this.zstreamInputSize];
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ZstandardStream"/> class by using the specified stream and compression level, and optionally leaves the stream open.
/// </summary>
/// <param name="stream">The stream to compress.</param>
/// <param name="compressionLevel">The compression level.</param>
/// <param name="leaveOpen">true to leave the stream open after disposing the <see cref="ZstandardStream"/> object; otherwise, false.</param>
public ZstandardStream(Stream stream, int compressionLevel, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
{
this.CompressionLevel = compressionLevel;
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
/// <summary>
/// The version of the native Zstd library.
/// </summary>
public static Version Version
{
get
{
var version = (int)Interop.ZSTD_versionNumber();
return new Version((version / 10000) % 100, (version / 100) % 100, version % 100);
}
}
/// <summary>
/// The maximum compression level supported by the native Zstd library.
/// </summary>
public static int MaxCompressionLevel
{
get
{
return Interop.ZSTD_maxCLevel();
}
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the compression level to use, the default is 6.
/// </summary>
/// <remarks>
/// To get the maximum compression level see <see cref="MaxCompressionLevel"/>.
/// </remarks>
public int CompressionLevel { get; set; } = 6;
/// <summary>
/// Gets or sets the compression dictionary tp use, the default is null.
/// </summary>
/// <value>
/// The compression dictionary.
/// </value>
public ZstandardDictionary CompressionDictionary { get; set; } = null;
/// <summary>
/// Gets whether the current stream supports reading.
/// </summary>
public override bool CanRead => this.stream.CanRead && this.mode == CompressionMode.Decompress;
/// <summary>
/// Gets whether the current stream supports writing.
/// </summary>
public override bool CanWrite => this.stream.CanWrite && this.mode == CompressionMode.Compress;
/// <summary>
/// Gets whether the current stream supports seeking.
/// </summary>
public override bool CanSeek => false;
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
public override long Length => throw new NotSupportedException();
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
public override long Position
{
get => position;
set => throw new NotSupportedException();
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (this.isDisposed == false)
{
if (!this.isClosed) ReleaseResources(flushStream: false);
this.isDisposed = true;
this.data = null;
}
}
public override void Close()
{
if (this.isClosed) return;
try
{
ReleaseResources(flushStream: true);
}
finally
{
this.isClosed = true;
base.Close();
}
}
private void ReleaseResources(bool flushStream)
{
if (this.mode == CompressionMode.Compress)
{
try
{
if (flushStream)
{
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_endStream(zcs, buffer)));
this.stream.Flush();
}
}
finally
{
Interop.ZSTD_freeCStream(this.zstream);
if (!this.leaveOpen) this.stream.Close();
}
}
else if (this.mode == CompressionMode.Decompress)
{
Interop.ZSTD_freeDStream(this.zstream);
if (!this.leaveOpen) this.stream.Close();
}
}
public override void Flush()
{
if (this.mode == CompressionMode.Compress)
{
this.ProcessStream((zcs, buffer) => Interop.ThrowIfError(Interop.ZSTD_flushStream(zcs, buffer)));
this.stream.Flush();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (this.CanRead == false) throw new NotSupportedException();
// prevent the buffers from being moved around by the garbage collector
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
try
{
var length = 0;
if (this.isInitialized == false)
{
this.isInitialized = true;
var result = this.CompressionDictionary == null
? Interop.ZSTD_initDStream(this.zstream)
: Interop.ZSTD_initDStream_usingDDict(this.zstream, this.CompressionDictionary.GetDecompressionDictionary());
}
while (count > 0)
{
var inputSize = this.dataSize - this.dataPosition;
// read data from input stream
if (inputSize <= 0 && !this.dataDepleted && !this.dataSkipRead)
{
this.dataSize = this.stream.Read(this.data, 0, (int)this.zstreamInputSize);
this.dataDepleted = this.dataSize <= 0;
this.dataPosition = 0;
inputSize = this.dataDepleted ? 0 : this.dataSize;
// skip stream.Read until the internal buffer is depleted
// avoids a Read timeout for applications that know the exact number of bytes in the stream
this.dataSkipRead = true;
}
// configure the inputBuffer
this.inputBuffer.Data = inputSize <= 0 ? IntPtr.Zero : Marshal.UnsafeAddrOfPinnedArrayElement(this.data, this.dataPosition);
this.inputBuffer.Size = inputSize <= 0 ? UIntPtr.Zero : new UIntPtr((uint)inputSize);
this.inputBuffer.Position = UIntPtr.Zero;
// configure the outputBuffer
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
this.outputBuffer.Size = new UIntPtr((uint)count);
this.outputBuffer.Position = UIntPtr.Zero;
// decompress inputBuffer to outputBuffer
Interop.ThrowIfError(Interop.ZSTD_decompressStream(this.zstream, this.outputBuffer, this.inputBuffer));
// calculate progress in outputBuffer
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
if (outputBufferPosition == 0)
{
// the internal buffer is depleted, we're either done
if (this.dataDepleted) break;
// or we need more bytes
this.dataSkipRead = false;
}
length += outputBufferPosition;
offset += outputBufferPosition;
count -= outputBufferPosition;
// calculate progress in inputBuffer
var inputBufferPosition = (int)inputBuffer.Position.ToUInt32();
this.dataPosition += inputBufferPosition;
}
position += length;
return length;
}
finally
{
alloc1.Free();
alloc2.Free();
}
}
public override void Write(byte[] buffer, int offset, int count)
{
if (this.CanWrite == false) throw new NotSupportedException();
// prevent the buffers from being moved around by the garbage collector
var alloc1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var alloc2 = GCHandle.Alloc(this.data, GCHandleType.Pinned);
try
{
if (this.isInitialized == false)
{
this.isInitialized = true;
var result = this.CompressionDictionary == null
? Interop.ZSTD_initCStream(this.zstream, this.CompressionLevel)
: Interop.ZSTD_initCStream_usingCDict(this.zstream, this.CompressionDictionary.GetCompressionDictionary(this.CompressionLevel));
Interop.ThrowIfError(result);
}
while (count > 0)
{
var inputSize = Math.Min((uint)count, this.zstreamInputSize);
// configure the outputBuffer
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
this.outputBuffer.Position = UIntPtr.Zero;
// configure the inputBuffer
this.inputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);
this.inputBuffer.Size = new UIntPtr((uint)inputSize);
this.inputBuffer.Position = UIntPtr.Zero;
// compress inputBuffer to outputBuffer
Interop.ThrowIfError(Interop.ZSTD_compressStream(this.zstream, this.outputBuffer, this.inputBuffer));
// write data to output stream
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
this.stream.Write(this.data, 0, outputBufferPosition);
// calculate progress in inputBuffer
var inputBufferPosition = (int)this.inputBuffer.Position.ToUInt32();
offset += inputBufferPosition;
count -= inputBufferPosition;
}
}
finally
{
alloc1.Free();
alloc2.Free();
}
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin != SeekOrigin.Current)
throw new NotImplementedException();
byte[] tmpBuff = new byte[1024];
long sizeToGo = offset;
while (sizeToGo > 0)
{
int sizenow = sizeToGo > 1024 ? 1024 : (int)sizeToGo;
Read(tmpBuff, 0, sizenow);
sizeToGo -= sizenow;
}
return offset;
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
private void ProcessStream(Action<IntPtr, Interop.Buffer> outputAction)
{
var alloc = GCHandle.Alloc(this.data, GCHandleType.Pinned);
try
{
this.outputBuffer.Data = Marshal.UnsafeAddrOfPinnedArrayElement(this.data, 0);
this.outputBuffer.Size = new UIntPtr(this.zstreamOutputSize);
this.outputBuffer.Position = UIntPtr.Zero;
outputAction(this.zstream, this.outputBuffer);
var outputBufferPosition = (int)this.outputBuffer.Position.ToUInt32();
this.stream.Write(this.data, 0, outputBufferPosition);
}
finally
{
alloc.Free();
}
}
}
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Compress.SevenZip.Compress.ZSTD;
using Compress.SevenZip.Structure;
using FileInfo = RVIO.FileInfo;
@@ -11,47 +9,21 @@ namespace Compress.SevenZip
public partial class SevenZ : ICompress
{
public enum sevenZipCompressType
public enum SevenZipCompressType
{
uncompressed,
lzma,
zstd
}
public static bool supportZstd
private class SevenZipLocalFile : LocalFile
{
get;
private set;
}
public static void TestForZstd()
{
supportZstd = false;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
var root = Path.GetDirectoryName(typeof(ZstandardInterop).Assembly.Location);
var path = Environment.Is64BitProcess ? "x64" : "x86";
var file = Path.Combine(root, path, "libzstd.dll");
supportZstd = RVIO.File.Exists(file);
}
}
private class LocalFile
{
public string FileName;
public ulong UncompressedSize;
public bool IsDirectory;
public byte[] CRC;
public int StreamIndex;
public ulong StreamOffset;
public long LastModified;
public ZipReturn FileStatus = ZipReturn.ZipUntested;
}
private List<LocalFile> _localFiles = new List<LocalFile>();
private List<SevenZipLocalFile> _localFiles = new();
private FileInfo _zipFileInfo;
@@ -59,7 +31,6 @@ namespace Compress.SevenZip
private SignatureHeader _signatureHeader;
private sevenZipCompressType _compressed = sevenZipCompressType.lzma;
private long _baseOffset;
@@ -76,40 +47,9 @@ namespace Compress.SevenZip
return _localFiles.Count;
}
public string Filename(int i)
public LocalFile GetLocalFile(int i)
{
return _localFiles[i].FileName;
}
public ulong? LocalHeader(int i)
{
return 0;
}
public ulong UncompressedSize(int i)
{
return _localFiles[i].UncompressedSize;
}
public int StreamIndex(int i)
{
return _localFiles[i].StreamIndex;
}
public ZipReturn FileStatus(int i)
{
return _localFiles[i].FileStatus;
}
public byte[] CRC32(int i)
{
return _localFiles[i].CRC;
}
public long LastModified(int i)
{
return _localFiles[i].LastModified;
return _localFiles[i];
}
public void ZipFileCloseFailed()
@@ -139,20 +79,6 @@ namespace Compress.SevenZip
ZipOpen = ZipOpenType.Closed;
}
public bool IsDirectory(int i)
{
return _localFiles[i].IsDirectory;
}
public void ZipFileClose()
{
@@ -184,7 +110,7 @@ namespace Compress.SevenZip
public StringBuilder HeaderReport()
{
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
if (_header == null)
{

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Compress.SevenZip.Structure;
using Compress.Utils;
using Compress.Support.Utils;
using FileInfo = RVIO.FileInfo;
using FileStream = RVIO.FileStream;
@@ -73,7 +73,7 @@ namespace Compress.SevenZip
{
try
{
SignatureHeader signatureHeader = new SignatureHeader();
SignatureHeader signatureHeader = new();
if (!signatureHeader.Read(_zipFs))
{
return ZipReturn.ZipSignatureError;
@@ -115,27 +115,27 @@ namespace Compress.SevenZip
}
private void PopulateLocalFiles(out List<LocalFile> localFiles)
private void PopulateLocalFiles(out List<SevenZipLocalFile> localFiles)
{
int emptyFileIndex = 0;
int folderIndex = 0;
int unpackedStreamsIndex = 0;
ulong streamOffset = 0;
localFiles = new List<LocalFile>();
localFiles = new List<SevenZipLocalFile>();
if (_header == null)
return;
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
{
LocalFile lf = new LocalFile { FileName = _header.FileInfo.Names[i] };
SevenZipLocalFile lf = new() { Filename = _header.FileInfo.Names[i] };
if ((_header.FileInfo.EmptyStreamFlags == null) || !_header.FileInfo.EmptyStreamFlags[i])
{
lf.StreamIndex = folderIndex;
lf.StreamOffset = streamOffset;
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
lf.CRC = Util.uinttobytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
lf.CRC = Util.UIntToBytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
streamOffset += lf.UncompressedSize;
unpackedStreamsIndex++;
@@ -155,17 +155,19 @@ namespace Compress.SevenZip
if (lf.IsDirectory)
{
if (lf.FileName.Substring(lf.FileName.Length - 1, 1) != "/")
if (lf.Filename.Substring(lf.Filename.Length - 1, 1) != "/")
{
lf.FileName += "/";
lf.Filename += "/";
}
}
}
if (_header.FileInfo.TimeLastWrite != null)
{
lf.LastModified = DateTime.FromFileTimeUtc((long)_header.FileInfo.TimeLastWrite[i]).Ticks;
}
lf.ModifiedTime = DateTime.FromFileTimeUtc((long)_header.FileInfo.TimeLastWrite[i]).Ticks;
if (_header.FileInfo.TimeCreation != null)
lf.CreatedTime = DateTime.FromFileTimeUtc((long)_header.FileInfo.TimeCreation[i]).Ticks;
if (_header.FileInfo.TimeLastAccess != null)
lf.AccessedTime = DateTime.FromFileTimeUtc((long)_header.FileInfo.TimeLastAccess[i]).Ticks;
localFiles.Add(lf);
}

View File

@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using Compress.SevenZip.Compress.BZip2;
using Compress.SevenZip.Compress.LZMA;
using Compress.SevenZip.Compress.PPmd;
using Compress.SevenZip.Compress.ZSTD;
using Compress.SevenZip.Filters;
using Compress.SevenZip.Structure;
using Compress.Support.Compression.BZip2;
using Compress.Support.Compression.LZMA;
using Compress.Support.Compression.PPmd;
using Compress.Support.Compression.zStd;
using Compress.Support.Filters;
using FileStream = RVIO.FileStream;
namespace Compress.SevenZip
@@ -20,7 +20,7 @@ namespace Compress.SevenZip
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
{
Debug.WriteLine("Opening File " + _localFiles[index].FileName);
Debug.WriteLine("Opening File " + _localFiles[index].Filename);
stream = null;
unCompressedSize = 0;
@@ -31,7 +31,7 @@ namespace Compress.SevenZip
return ZipReturn.ZipErrorGettingDataStream;
}
if (IsDirectory(index))
if (GetLocalFile(index).IsDirectory)
{
return ZipReturn.ZipTryingToAccessADirectory;
}
@@ -61,7 +61,7 @@ namespace Compress.SevenZip
// first make the List of Decompressors streams
int codersNeeded = folder.Coders.Length;
List<InStreamSourceInfo> allInputStreams = new List<InStreamSourceInfo>();
List<InStreamSourceInfo> allInputStreams = new();
for (int i = 0; i < codersNeeded; i++)
{
folder.Coders[i].DecoderStream = null;
@@ -96,7 +96,7 @@ namespace Compress.SevenZip
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
}
List<Stream> inputCoders = new List<Stream>();
List<Stream> inputCoders = new();
bool allCodersComplete = false;
while (!allCodersComplete)
@@ -164,7 +164,7 @@ namespace Compress.SevenZip
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
break;
case DecompressType.ZSTD:
coder.DecoderStream = new ZstandardStream(inputCoders[0], CompressionMode.Decompress, true);
coder.DecoderStream =new zStdSharp(inputCoders[0]);
break;
default:
return ZipReturn.ZipDecodeError;
@@ -217,7 +217,7 @@ namespace Compress.SevenZip
memStream.Position = 0;
byte[] newStream = new byte[memStream.Length];
memStream.Read(newStream, 0, (int)memStream.Length);
MemoryStream ret = new MemoryStream(newStream, false);
MemoryStream ret = new(newStream, false);
memStream.Position = pos;
return ret;
}

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Text;
using Compress.Support.Utils;
namespace Compress.SevenZip
{
@@ -36,9 +37,10 @@ namespace Compress.SevenZip
const string sig = "RomVault7Z01";
byte[] rv7Zid = Util.Enc.GetBytes(sig);
byte[] header = new byte[12];
_zipFs.Read(header, 0, 12);
for (int i = 0; i < 12; i++)
{
if (header[i] != rv7Zid[i])
@@ -50,7 +52,7 @@ namespace Compress.SevenZip
uint headerCRC;
ulong headerOffset; // is location of header in file
ulong headerSize;
using (BinaryReader br = new BinaryReader(_zipFs, Encoding.UTF8, true))
using (BinaryReader br = new(_zipFs, Encoding.UTF8, true))
{
headerCRC = br.ReadUInt32();
headerOffset = br.ReadUInt64();
@@ -65,6 +67,7 @@ namespace Compress.SevenZip
return headerSize == testHeaderLength;
}
private bool Istorrent7Z()
{
const int crcsz = 128;
@@ -84,7 +87,7 @@ namespace Compress.SevenZip
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
if (ar < crcsz)
{
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
Util.MemSet(buffer, bufferPos + ar, 0, crcsz - ar);
}
bufferPos = crcsz;
@@ -105,12 +108,12 @@ namespace Compress.SevenZip
{
ar = kSignatureSize;
}
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
Util.MemSet(buffer, bufferPos + ar, 0, crcsz - ar);
Util.MemCrypt(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
}
else
{
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
Util.MemCrypt(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
}
foffs = _zipFs.Length;
@@ -121,15 +124,15 @@ namespace Compress.SevenZip
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
buffer[crcsz * 2 + 4] = 0;
buffer[crcsz * 2 + 5] = 0;
buffer[crcsz * 2 + 6] = 0;
buffer[crcsz * 2 + 7] = 0;
buffer[crcsz * 2 + 4] = (byte)((foffs >> 32) & 0xff);
buffer[crcsz * 2 + 5] = (byte)((foffs >> 40) & 0xff);
buffer[crcsz * 2 + 6] = (byte)((foffs >> 48) & 0xff);
buffer[crcsz * 2 + 7] = (byte)((foffs >> 56) & 0xff);
if (Util.memcmp(buffer, 0, kSignature, kSignatureSize))
if (Util.MemCmp(buffer, 0, kSignature, kSignatureSize))
{
t7Zid[16] = buffer[crcsz * 2 + 4 + 8 + 16];
if (Util.memcmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
if (Util.MemCmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
{
uint inCrc32 = (uint)(buffer[crcsz * 2 + 8 + 0] +
(buffer[crcsz * 2 + 8 + 1] << 8) +
@@ -141,7 +144,7 @@ namespace Compress.SevenZip
buffer[crcsz * 2 + 8 + 2] = 0xff;
buffer[crcsz * 2 + 8 + 3] = 0xff;
uint calcCrc32 = Utils.CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
uint calcCrc32 = CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
if (inCrc32 == calcCrc32)
{

View File

@@ -1,9 +1,8 @@
using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Compress.SevenZip.Compress.LZMA;
using Compress.SevenZip.Compress.ZSTD;
using Compress.SevenZip.Structure;
using Compress.Utils;
using Compress.Support.Compression.LZMA;
using FileInfo = RVIO.FileInfo;
using FileStream = RVIO.FileStream;
@@ -11,37 +10,40 @@ namespace Compress.SevenZip
{
public partial class SevenZ
{
private Stream _lzmaStream;
private ulong _packStreamStart;
private ulong _packStreamSize;
private ulong _unpackedStreamSize;
private byte[] _codeMSbytes;
private Stream _compressStream;
public class outStreams
{
public SevenZipCompressType compType;
public byte[] Method;
public byte[] Properties;
public ulong packedStart;
public ulong packedSize;
public List<UnpackedStreamInfo> unpackedStreams;
}
public List<outStreams> _packedOutStreams;
public ZipReturn ZipFileCreate(string newFilename)
{
return ZipFileCreate(newFilename, sevenZipCompressType.lzma);
return ZipFileCreate(newFilename, SevenZipCompressType.lzma);
}
public ZipReturn ZipFileCreateFromUncompressedSize(string newFilename, sevenZipCompressType ctype, ulong unCompressedSize)
public ZipReturn ZipFileCreateFromUncompressedSize(string newFilename, SevenZipCompressType ctype, ulong unCompressedSize)
{
if (ctype == sevenZipCompressType.zstd)
{
if (!supportZstd)
ctype = sevenZipCompressType.lzma;
}
return ZipFileCreate(newFilename, ctype, GetDictionarySizeFromUncompressedSize(unCompressedSize));
}
public ZipReturn ZipFileCreate(string newFilename, sevenZipCompressType compressOutput, int dictionarySize = 1 << 24, int numFastBytes = 64)
private SevenZipCompressType _compType;
public ZipReturn ZipFileCreate(string newFilename, SevenZipCompressType compressOutput, int dictionarySize = 1 << 24, int numFastBytes = 64)
{
if (ZipOpen != ZipOpenType.Closed)
{
return ZipReturn.ZipFileAlreadyOpen;
}
DirUtil.CreateDirForFile(newFilename);
CompressUtils.CreateDirForFile(newFilename);
_zipFileInfo = new FileInfo(newFilename);
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
@@ -55,31 +57,56 @@ namespace Compress.SevenZip
_signatureHeader = new SignatureHeader();
_header = new Header();
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
using (BinaryWriter bw = new(_zipFs, Encoding.UTF8, true))
{
_signatureHeader.Write(bw);
}
_baseOffset = _zipFs.Position;
_compressed = compressOutput;
_unpackedStreamSize = 0;
if (_compressed == sevenZipCompressType.lzma)
_packedOutStreams = new List<outStreams>();
_compType = compressOutput;
#if solid
outStreams newStream = new()
{
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, dictionarySize, numFastBytes);
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
_codeMSbytes = lzs.Properties;
_lzmaStream = lzs;
_packStreamStart = (ulong)_zipFs.Position;
}
else if (_compressed == sevenZipCompressType.zstd)
packedStart = (ulong)_zipFs.Position,
compType = compressOutput,
packedSize = 0,
unpackedStreams = new List<UnpackedStreamInfo>()
};
switch (compressOutput)
{
ZstandardStream zss = new ZstandardStream(_zipFs, 18, true);
_codeMSbytes = new byte[] { 1, 4, 18, 0, 0 };
_lzmaStream = zss;
_packStreamStart = (ulong)_zipFs.Position;
case SevenZipCompressType.lzma:
LzmaEncoderProperties ep = new(true, dictionarySize, numFastBytes);
LzmaStream lzs = new(ep, false, _zipFs);
newStream.Method = new byte[] { 3, 1, 1 };
newStream.Properties = lzs.Properties;
_compressStream = lzs;
break;
case SevenZipCompressType.zstd:
Stream zss = new ZstdSharp.CompressionStream(_zipFs, 18);
newStream.Method = new byte[] { 4, 247, 17, 1 };
newStream.Properties = new byte[] { 1, 5, 19, 0, 0 };
_compressStream = zss;
break;
case SevenZipCompressType.uncompressed:
newStream.Method = new byte[] { 0 };
newStream.Properties = null;
_compressStream = _zipFs;
break;
}
_packedOutStreams.Add(newStream);
#endif
return ZipReturn.ZipGood;
}
@@ -89,14 +116,14 @@ namespace Compress.SevenZip
if (fName.Substring(fName.Length - 1, 1) == @"/")
fName = fName.Substring(0, fName.Length - 1);
LocalFile lf = new LocalFile
SevenZipLocalFile lf = new()
{
FileName = fName,
Filename = fName,
UncompressedSize = 0,
IsDirectory = true,
StreamOffset = 0
IsDirectory = true
};
_localFiles.Add(lf);
unpackedStreamInfo = null;
}
public void ZipFileAddZeroLengthFile()
@@ -104,36 +131,100 @@ namespace Compress.SevenZip
// do nothing here for 7zip
}
UnpackedStreamInfo unpackedStreamInfo;
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream, TimeStamps dateTime)
{
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
}
private ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
{
LocalFile lf = new LocalFile
{
FileName = filename,
UncompressedSize = uncompressedSize,
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
};
// check if we are writing a directory
if (uncompressedSize == 0 && filename.Substring(filename.Length - 1, 1) == "/")
{
lf.FileName = filename.Substring(0, filename.Length - 1);
lf.IsDirectory = true;
ZipFileAddDirectory(filename);
stream = null;
return ZipReturn.ZipGood;
}
_unpackedStreamSize += uncompressedSize;
SevenZipLocalFile localFile = new()
{
Filename = filename,
UncompressedSize = uncompressedSize
};
_localFiles.Add(localFile);
_localFiles.Add(lf);
stream = _compressed == sevenZipCompressType.uncompressed ? _zipFs : _lzmaStream;
if (uncompressedSize == 0)
{
unpackedStreamInfo = null;
stream = null;
return ZipReturn.ZipGood;
}
#if !solid
outStreams newStream = new()
{
packedStart = (ulong)_zipFs.Position,
compType = _compType,
packedSize = 0,
unpackedStreams = new List<UnpackedStreamInfo>()
};
switch (_compType)
{
case SevenZipCompressType.lzma:
LzmaEncoderProperties ep = new(true, GetDictionarySizeFromUncompressedSize(uncompressedSize), 64);
LzmaStream lzs = new(ep, false, _zipFs);
newStream.Method = new byte[] { 3, 1, 1 };
newStream.Properties = lzs.Properties;
_compressStream = lzs;
break;
case SevenZipCompressType.zstd:
ZstdSharp.CompressionStream zss = new(_zipFs, 19);
newStream.Method = new byte[] { 4, 247, 17, 1 };
newStream.Properties = new byte[] { 1, 5, 19, 0, 0 };
_compressStream = zss;
break;
case SevenZipCompressType.uncompressed:
newStream.Method = new byte[] { 0 };
newStream.Properties = null;
_compressStream = _zipFs;
break;
}
_packedOutStreams.Add(newStream);
#endif
unpackedStreamInfo = new UnpackedStreamInfo { UnpackedSize = uncompressedSize };
_packedOutStreams[_packedOutStreams.Count - 1].unpackedStreams.Add(unpackedStreamInfo);
stream = _compressStream;
return ZipReturn.ZipGood;
}
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
{
_localFiles[_localFiles.Count - 1].CRC = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
SevenZipLocalFile localFile = _localFiles[_localFiles.Count - 1];
localFile.CRC = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
if (unpackedStreamInfo != null)
unpackedStreamInfo.Crc = Util.BytesToUint(localFile.CRC);
#if !solid
if (unpackedStreamInfo != null)
{
if (_packedOutStreams[_packedOutStreams.Count - 1].compType != SevenZipCompressType.uncompressed)
{
_compressStream.Flush();
_compressStream.Close();
}
_packedOutStreams[_packedOutStreams.Count - 1].packedSize = (ulong)_zipFs.Position - _packedOutStreams[_packedOutStreams.Count - 1].packedStart;
}
#endif
return ZipReturn.ZipGood;
}

View File

@@ -1,9 +1,8 @@
using System.IO;
using System.Text;
using Compress.SevenZip.Compress.LZMA;
using Compress.SevenZip.Compress.ZSTD;
using Compress.SevenZip.Structure;
using Compress.Utils;
using Compress.Support.Compression.LZMA;
using Compress.Support.Utils;
namespace Compress.SevenZip
{
@@ -23,7 +22,7 @@ namespace Compress.SevenZip
ulong emptyFileCount = 0;
for (int i = 0; i < fileCount; i++)
{
_header.FileInfo.Names[i] = _localFiles[i].FileName;
_header.FileInfo.Names[i] = _localFiles[i].Filename;
if (_localFiles[i].UncompressedSize != 0)
{
@@ -37,7 +36,6 @@ namespace Compress.SevenZip
emptyStreamCount += 1;
}
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
_header.FileInfo.EmptyStreamFlags = null;
_header.FileInfo.EmptyFileFlags = null;
@@ -82,158 +80,75 @@ namespace Compress.SevenZip
//StreamsInfo
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
//StreamsInfo.PackedStreamsInfo
if (_compressed!=sevenZipCompressType.uncompressed)
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[_packedOutStreams.Count];
for (int i = 0; i < _packedOutStreams.Count; i++)
{
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
_header.StreamsInfo.PackedStreams[i] = new PackedStreamInfo { PackedSize = _packedOutStreams[i].packedSize };
}
else
{
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
int fileIndex = 0;
for (int i = 0; i < fileCount; i++)
{
if (_localFiles[i].UncompressedSize == 0)
{
continue;
}
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
}
}
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
if (_compressed != sevenZipCompressType.uncompressed)
_header.StreamsInfo.Folders = new Folder[_packedOutStreams.Count];
for (int i = 0; i < _packedOutStreams.Count; i++)
{
//StreamsInfo.Folders
_header.StreamsInfo.Folders = new Folder[1];
ulong unpackedStreamSize = 0;
foreach (UnpackedStreamInfo v in _packedOutStreams[i].unpackedStreams)
unpackedStreamSize += v.UnpackedSize;
//StreamsInfo.Folders.Coder
// flags 0x23
Folder folder = new Folder
_header.StreamsInfo.Folders[i] = new Folder()
{
BindPairs = null,
Coders = new[] {
Coders = new Coder[] {
new Coder {
Method = new byte[] { 3, 1, 1 },
Method = _packedOutStreams[i].Method,
NumInStreams = 1,
NumOutStreams = 1,
Properties = _codeMSbytes
Properties = _packedOutStreams[i].Properties
}
},
PackedStreamIndices = new[] { (ulong)0 },
UnpackedStreamSizes = new[] { _unpackedStreamSize },
UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount],
PackedStreamIndices = new ulong[] { (ulong)i },
UnpackedStreamSizes = new ulong[] { unpackedStreamSize },
UnpackedStreamInfo = _packedOutStreams[i].unpackedStreams.ToArray(),
UnpackCRC = null
};
switch (_lzmaStream)
{
case LzmaStream _:
folder.Coders[0].Method = new byte[] { 3, 1, 1 };
break;
case ZstandardStream _:
folder.Coders[0].Method = new byte[] { 4, 247, 17, 1 };
break;
}
int fileIndex = 0;
for (int i = 0; i < fileCount; i++)
{
if (_localFiles[i].UncompressedSize == 0)
{
continue;
}
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
{
UnpackedSize = _localFiles[i].UncompressedSize,
Crc = Util.bytestouint(_localFiles[i].CRC)
};
folder.UnpackedStreamInfo[fileIndex++] = unpackedStreamInfo;
}
_header.StreamsInfo.Folders[0] = folder;
}
else
{
_header.StreamsInfo.Folders = new Folder[outFileCount];
int fileIndex = 0;
for (int i = 0; i < fileCount; i++)
{
if (_localFiles[i].UncompressedSize == 0)
{
continue;
}
Folder folder = new Folder
{
BindPairs = null,
Coders = new[] {
new Coder {
Method = new byte[] {0},
NumInStreams = 1,
NumOutStreams = 1,
Properties = null
}
},
PackedStreamIndices = new[] { (ulong)i },
UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize },
UnpackCRC = null,
UnpackedStreamInfo = new[] {
new UnpackedStreamInfo {
UnpackedSize = _localFiles[i].UncompressedSize,
Crc = Util.bytestouint(_localFiles[i].CRC)
}
}
};
_header.StreamsInfo.Folders[fileIndex++] = folder;
}
}
}
private void CloseWriting7Zip()
{
if (_compressed != sevenZipCompressType.uncompressed)
#if solid
if (_packedOutStreams[0].compType != SevenZipCompressType.uncompressed)
{
_lzmaStream.Flush();
_lzmaStream.Close();
_compressStream.Flush();
_compressStream.Close();
}
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
_packedOutStreams[0].packedSize = (ulong)_zipFs.Position - _packedOutStreams[0].packedStart;
#endif
Create7ZStructure();
byte[] newHeaderByte;
using (Stream headerMem = new MemoryStream())
{
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
{
using BinaryWriter headerBw = new(headerMem, Encoding.UTF8, true);
_header.WriteHeader(headerBw);
newHeaderByte = new byte[headerMem.Length];
headerMem.Position = 0;
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
}
}
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
#region Header Compression
long packedHeaderPos = _zipFs.Position;
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
LzmaEncoderProperties ep = new(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
LzmaStream lzs = new(ep, false, _zipFs);
byte[] lzmaStreamProperties = lzs.Properties;
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
lzs.Close();
StreamsInfo streamsInfo = new StreamsInfo
StreamsInfo streamsInfo = new()
{
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
Folders = new[] {
@@ -262,22 +177,19 @@ namespace Compress.SevenZip
using (Stream headerMem = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(headerMem, Encoding.UTF8, true))
{
using BinaryWriter bw = new(headerMem, Encoding.UTF8, true);
bw.Write((byte)HeaderProperty.kEncodedHeader);
streamsInfo.WriteHeader(bw);
newHeaderByte = new byte[headerMem.Length];
headerMem.Position = 0;
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
}
}
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
#endregion
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
using (BinaryWriter bw = new(_zipFs, Encoding.UTF8, true))
{
ulong headerPosition = (ulong)_zipFs.Position + 32; //tzip header is 32 bytes
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Text;
using Compress.Utils;
using Compress.Support.Utils;
namespace Compress.SevenZip.Structure
{
@@ -106,7 +106,7 @@ namespace Compress.SevenZip.Structure
{
DecoderType = DecompressType.LZMA2;
}
else if (SevenZ.supportZstd && Method.Length == 4 && Method[0] == 4 && Method[1] == 247 && Method[2] == 17 && Method[3] == 1)
else if (Method.Length == 4 && Method[0] == 4 && Method[1] == 247 && Method[2] == 17 && Method[3] == 1)
{
DecoderType = DecompressType.ZSTD;
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace Compress.SevenZip.Structure
@@ -97,10 +96,9 @@ namespace Compress.SevenZip.Structure
byte[] namebyte;
using (MemoryStream nameMem = new MemoryStream())
{
using (BinaryWriter nameBw = new BinaryWriter(nameMem, Encoding.UTF8, true))
using (MemoryStream nameMem = new())
{
using BinaryWriter nameBw = new(nameMem, Encoding.UTF8, true);
nameBw.Write((byte)0); //not external
foreach (string name in Names)
{
@@ -111,7 +109,6 @@ namespace Compress.SevenZip.Structure
nameMem.Position = 0;
nameMem.Read(namebyte, 0, namebyte.Length);
}
}
bw.Write((byte)HeaderProperty.kName);
bw.WriteEncodedUInt64((ulong)namebyte.Length);

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Text;
using Compress.Utils;
using Compress.Support.Utils;
namespace Compress.SevenZip.Structure
{
@@ -175,8 +175,7 @@ namespace Compress.SevenZip.Structure
case HeaderProperty.kCRC:
{
uint?[] crcs;
Util.UnPackCRCs(br, (ulong)Folders.Length, out crcs);
Util.UnPackCRCs(br, (ulong)Folders.Length, out uint?[] crcs);
for (int i = 0; i < Folders.Length; i++)
{
Folders[i].UnpackCRC = crcs[i];
@@ -250,8 +249,10 @@ namespace Compress.SevenZip.Structure
if (folder.UnpackedStreamInfo == null)
{
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
folder.UnpackedStreamInfo[0] = new UnpackedStreamInfo();
folder.UnpackedStreamInfo[0].UnpackedSize = folder.GetUnpackSize();
folder.UnpackedStreamInfo[0] = new UnpackedStreamInfo
{
UnpackedSize = folder.GetUnpackSize()
};
}
if ((folder.UnpackedStreamInfo.Length != 1) || !folder.UnpackCRC.HasValue)
@@ -261,8 +262,7 @@ namespace Compress.SevenZip.Structure
}
int crcIndex = 0;
uint?[] crc;
Util.UnPackCRCs(br, numCRC, out crc);
Util.UnPackCRCs(br, numCRC, out uint?[] crc);
for (uint i = 0; i < Folders.Length; i++)
{
Folder folder = Folders[i];
@@ -384,7 +384,7 @@ namespace Compress.SevenZip.Structure
Folder folder = Folders[f];
for (int i = 0; i < folder.UnpackedStreamInfo.Length; i++)
{
bw.Write(Util.uinttobytes(folder.UnpackedStreamInfo[i].Crc));
bw.Write(Util.UIntToBytes(folder.UnpackedStreamInfo[i].Crc));
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System.IO;
using System.Text;
using Compress.SevenZip.Compress.LZMA;
using Compress.Utils;
using Compress.Support.Compression.LZMA;
namespace Compress.SevenZip.Structure
{
@@ -50,14 +49,13 @@ namespace Compress.SevenZip.Structure
{
header = null;
using (BinaryReader br = new BinaryReader(stream, Encoding.UTF8, true))
{
using BinaryReader br = new(stream, Encoding.UTF8, true);
HeaderProperty hp = (HeaderProperty)br.ReadByte();
switch (hp)
{
case HeaderProperty.kEncodedHeader:
{
StreamsInfo streamsInfo = new StreamsInfo();
StreamsInfo streamsInfo = new();
streamsInfo.Read(br);
if (streamsInfo.Folders.Length > 1)
@@ -78,7 +76,7 @@ namespace Compress.SevenZip.Structure
}
stream.Seek(baseOffset + (long)streamsInfo.PackPosition, SeekOrigin.Begin);
using (LzmaStream decoder = new LzmaStream(firstFolder.Coders[0].Properties, stream))
using (LzmaStream decoder = new(firstFolder.Coders[0].Properties, stream))
{
ZipReturn zr = ReadHeaderOrPackedHeader(decoder, baseOffset, out header);
if (zr != ZipReturn.ZipGood)
@@ -100,7 +98,6 @@ namespace Compress.SevenZip.Structure
return ZipReturn.ZipCentralDirError;
}
}
public void Report(ref StringBuilder sb)
{

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Text;
using Compress.Utils;
using Compress.Support.Utils;
namespace Compress.SevenZip.Structure
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Text;
using Compress.Support.Utils;
namespace Compress.SevenZip.Structure
{
@@ -7,9 +8,6 @@ namespace Compress.SevenZip.Structure
{
private static readonly byte[] Signature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
private byte _major;
private byte _minor;
private uint _startHeaderCRC;
public ulong NextHeaderOffset;
@@ -22,23 +20,22 @@ namespace Compress.SevenZip.Structure
public bool Read(Stream stream)
{
using (BinaryReader br = new BinaryReader(stream, Encoding.UTF8, true))
{
using BinaryReader br = new(stream, Encoding.UTF8, true);
byte[] signatureBytes = br.ReadBytes(6);
if (!signatureBytes.Compare(Signature))
{
return false;
}
_major = br.ReadByte();
_minor = br.ReadByte();
br.ReadByte(); // major version
br.ReadByte(); // minor version
_startHeaderCRC = br.ReadUInt32();
long pos = br.BaseStream.Position;
byte[] mainHeader = new byte[8 + 8 + 4];
br.BaseStream.Read(mainHeader, 0, mainHeader.Length);
if (!Utils.CRC.VerifyDigest(_startHeaderCRC, mainHeader, 0, (uint) mainHeader.Length))
if (!CRC.VerifyDigest(_startHeaderCRC, mainHeader, 0, (uint)mainHeader.Length))
{
return false;
}
@@ -50,7 +47,6 @@ namespace Compress.SevenZip.Structure
NextHeaderCRC = br.ReadUInt32();
return true;
}
}
public void Write(BinaryWriter bw)
{
@@ -84,10 +80,9 @@ namespace Compress.SevenZip.Structure
byte[] sigHeaderBytes;
using (MemoryStream sigHeaderMem = new MemoryStream())
{
using (BinaryWriter sigHeaderBw = new BinaryWriter(sigHeaderMem,Encoding.UTF8,true))
using (MemoryStream sigHeaderMem = new())
{
using BinaryWriter sigHeaderBw = new(sigHeaderMem, Encoding.UTF8, true);
sigHeaderBw.Write((ulong)((long)headerpos - BaseOffset)); //NextHeaderOffset
sigHeaderBw.Write(headerLength); //NextHeaderSize
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
@@ -96,9 +91,8 @@ namespace Compress.SevenZip.Structure
sigHeaderMem.Position = 0;
sigHeaderMem.Read(sigHeaderBytes, 0, sigHeaderBytes.Length);
}
}
uint sigHeaderCRC = Utils.CRC.CalculateDigest(sigHeaderBytes, 0, (uint) sigHeaderBytes.Length);
uint sigHeaderCRC = CRC.CalculateDigest(sigHeaderBytes, 0, (uint)sigHeaderBytes.Length);
bw.BaseStream.Position = _crcOffset;
bw.Write(sigHeaderCRC); //Header CRC

View File

@@ -1,8 +1,6 @@
using System;
using System.IO;
using System.Security.Permissions;
using System.Text;
using Compress.Utils;
namespace Compress.SevenZip.Structure
{

View File

@@ -1,5 +1,5 @@
using System.Text;
using Compress.Utils;
using Compress.Support.Utils;
namespace Compress.SevenZip.Structure
{

View File

@@ -47,7 +47,7 @@ namespace Compress.SevenZip
{
public static readonly Encoding Enc = Encoding.GetEncoding(28591);
public static void memset(byte[] buffer, int start, byte val, int len)
public static void MemSet(byte[] buffer, int start, byte val, int len)
{
for (int i = 0; i < len; i++)
{
@@ -55,7 +55,7 @@ namespace Compress.SevenZip
}
}
public static void memcpyr(byte[] destBuffer, int destPoint, byte[] sourceBuffer, int sourcePoint, int len)
public static void MemCrypt(byte[] destBuffer, int destPoint, byte[] sourceBuffer, int sourcePoint, int len)
{
for (int i = len - 1; i >= 0; i--)
{
@@ -64,7 +64,7 @@ namespace Compress.SevenZip
}
public static bool memcmp(byte[] buffer1, int offset, byte[] buffer2, int len)
public static bool MemCmp(byte[] buffer1, int offset, byte[] buffer2, int len)
{
for (int i = 0; i < len; i++)
{
@@ -147,7 +147,7 @@ namespace Compress.SevenZip
public static string ReadName(this BinaryReader br)
{
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new();
for (; ; )
{
char c = (char)br.ReadUInt16();
@@ -334,7 +334,7 @@ namespace Compress.SevenZip
}
}
public static byte[] uinttobytes(uint? crc)
public static byte[] UIntToBytes(uint? crc)
{
if (crc == null)
{
@@ -350,7 +350,7 @@ namespace Compress.SevenZip
return b;
}
public static uint? bytestouint(byte[] crc)
public static uint? BytesToUint(byte[] crc)
{
if (crc == null)
{

View File

@@ -20,7 +20,7 @@
* great code.
*/
namespace Compress.SevenZip.Compress.BZip2
namespace Compress.Support.Compression.BZip2
{
/**
* Base class for both the compress and decompress classes.

View File

@@ -23,7 +23,7 @@ using System.IO;
* great code.
*/
namespace Compress.SevenZip.Compress.BZip2
namespace Compress.Support.Compression.BZip2
{
/**
* An input stream that decompresses from the BZip2 format (with the file
@@ -119,7 +119,6 @@ namespace Compress.SevenZip.Compress.BZip2
private int[] minLens = new int[BZip2Constants.N_GROUPS];
private Stream bsStream;
private bool leaveOpen;
private bool streamEnd = false;
@@ -342,19 +341,7 @@ namespace Compress.SevenZip.Compress.BZip2
private void BsFinishedWithStream()
{
try
{
if (this.bsStream != null)
{
if (!leaveOpen)
this.bsStream.Dispose();
this.bsStream = null;
}
}
catch
{
//ignore
}
bsStream = null;
}
private void BsSetStream(Stream f)

View File

@@ -22,7 +22,7 @@
* great code.
*/
namespace Compress.SevenZip.Compress.BZip2
namespace Compress.Support.Compression.BZip2
{
/**
* An output stream that compresses into the BZip2 format (with the file

View File

@@ -21,7 +21,7 @@
* great code.
*/
namespace Compress.SevenZip.Compress.BZip2
namespace Compress.Support.Compression.BZip2
{
/**
* A simple class the hold and calculate the CRC for sanity checking

View File

@@ -69,7 +69,7 @@
using System;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
internal enum BlockState
@@ -731,8 +731,8 @@ namespace Compress.ZipFile.ZLib
* *
* *************************************************************
*/
if (false) //CompSettings
{
//CompSettings
/*
if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2)
{
// Compute an upper bound for the compressed length
@@ -747,7 +747,7 @@ namespace Compress.ZipFile.ZLib
if ((matches < (last_lit / 2)) && out_length < in_length / 2)
return true;
}
}
*/
return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize);
// dinoch - wraparound?

View File

@@ -62,7 +62,7 @@
using System;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
sealed class InfTree
@@ -83,25 +83,19 @@ namespace Compress.ZipFile.ZLib
internal const int fixed_bl = 9;
internal const int fixed_bd = 5;
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] fixed_tl = new int[]{96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] fixed_td = new int[]{80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577};
// Tables for deflate from PKZIP's appnote.txt.
//UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cplens = new int[]{3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
// see note #13 above about 258
//UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cplext = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112};
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cpdist = new int[]{1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
internal static readonly int[] cpdext = new int[]{0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
// If BMAX needs to be larger than 16, then h and x[] should be uLong.

View File

@@ -64,7 +64,7 @@
using System;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
sealed class InflateBlocks
{

View File

@@ -61,7 +61,7 @@
// -----------------------------------------------------------------------
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
sealed class Tree
{

View File

@@ -89,7 +89,7 @@
using System.Runtime.InteropServices;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
/// <summary>

View File

@@ -25,9 +25,9 @@
// ------------------------------------------------------------------
using System;
using System.IO;
using Compress.Support.Utils;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
public enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE = 1951, GZIP = 1952 }
@@ -50,7 +50,7 @@ namespace Compress.ZipFile.ZLib
protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
// workitem 7159
Compress.Utils.CRC crc;
CRC crc;
protected internal string _GzipFileName;
protected internal string _GzipComment;
protected internal DateTime _GzipMtime;
@@ -75,7 +75,7 @@ namespace Compress.ZipFile.ZLib
// workitem 7159
if (flavor == ZlibStreamFlavor.GZIP)
{
this.crc = new Compress.Utils.CRC();
this.crc = new CRC();
}
}

View File

@@ -68,7 +68,7 @@ using System;
using System.Runtime.InteropServices;
using Interop=System.Runtime.InteropServices;
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
/// <summary>
/// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951).

View File

@@ -61,7 +61,7 @@
// -----------------------------------------------------------------------
namespace Compress.ZipFile.ZLib
namespace Compress.Support.Compression.Deflate
{
/// <summary>
/// A bunch of constants used in the Zlib interface.

View File

@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Compress.Support.Compression.Deflate64
{
internal enum BlockType
{
Uncompressed = 0,
Static = 1,
Dynamic = 2
}
}

View File

@@ -0,0 +1,288 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime.CompilerServices;
namespace Compress.Support.Compression.Deflate64
{
public enum ZipCompressionMethod
{
Deflate64,
Deflate
}
public sealed class Deflate64Stream : Stream
{
private const int DEFAULT_BUFFER_SIZE = 8192;
private Stream _stream;
private CompressionMode _mode;
private InflaterManaged _inflater;
private byte[] _buffer;
public Deflate64Stream(Stream stream, CompressionMode mode)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
if (mode != CompressionMode.Decompress)
{
throw new NotImplementedException("Deflate64: this implementation only supports decompression");
}
if (!stream.CanRead)
{
throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream));
}
InitializeInflater(stream, ZipCompressionMethod.Deflate64);
}
/// <summary>
/// Sets up this DeflateManagedStream to be used for Inflation/Decompression
/// </summary>
private void InitializeInflater(Stream stream, ZipCompressionMethod method = ZipCompressionMethod.Deflate)
{
Debug.Assert(stream != null);
Debug.Assert(method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64);
if (!stream.CanRead)
{
throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream));
}
_inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64);
_stream = stream;
_mode = CompressionMode.Decompress;
_buffer = new byte[DEFAULT_BUFFER_SIZE];
}
public override bool CanRead
{
get
{
if (_stream is null)
{
return false;
}
return (_mode == CompressionMode.Decompress && _stream.CanRead);
}
}
public override bool CanWrite
{
get
{
if (_stream is null)
{
return false;
}
return (_mode == CompressionMode.Compress && _stream.CanWrite);
}
}
public override bool CanSeek => false;
public override long Length
{
get { throw new NotSupportedException("Deflate64: not supported"); }
}
public override long Position
{
get { throw new NotSupportedException("Deflate64: not supported"); }
set { throw new NotSupportedException("Deflate64: not supported"); }
}
public override void Flush()
{
EnsureNotDisposed();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("Deflate64: not supported");
}
public override void SetLength(long value)
{
throw new NotSupportedException("Deflate64: not supported");
}
public override int Read(byte[] array, int offset, int count)
{
EnsureDecompressionMode();
ValidateParameters(array, offset, count);
EnsureNotDisposed();
int bytesRead;
int currentOffset = offset;
int remainingCount = count;
while (true)
{
bytesRead = _inflater.Inflate(array, currentOffset, remainingCount);
currentOffset += bytesRead;
remainingCount -= bytesRead;
if (remainingCount == 0)
{
break;
}
if (_inflater.Finished())
{
// if we finished decompressing, we can't have anything left in the outputwindow.
Debug.Assert(_inflater.AvailableOutput == 0, "We should have copied all stuff out!");
break;
}
int bytes = _stream.Read(_buffer, 0, _buffer.Length);
if (bytes <= 0)
{
break;
}
else if (bytes > _buffer.Length)
{
// The stream is either malicious or poorly implemented and returned a number of
// bytes larger than the buffer supplied to it.
throw new InvalidDataException("Deflate64: invalid data");
}
_inflater.SetInput(_buffer, 0, bytes);
}
return count - remainingCount;
}
private void ValidateParameters(byte[] array, int offset, int count)
{
if (array is null)
{
throw new ArgumentNullException(nameof(array));
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (array.Length - offset < count)
{
throw new ArgumentException("Deflate64: invalid offset/count combination");
}
}
private void EnsureNotDisposed()
{
if (_stream is null)
{
ThrowStreamClosedException();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowStreamClosedException()
{
throw new ObjectDisposedException(null, "Deflate64: stream has been disposed");
}
private void EnsureDecompressionMode()
{
if (_mode != CompressionMode.Decompress)
{
ThrowCannotReadFromDeflateManagedStreamException();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowCannotReadFromDeflateManagedStreamException()
{
throw new InvalidOperationException("Deflate64: cannot read from this stream");
}
private void EnsureCompressionMode()
{
if (_mode != CompressionMode.Compress)
{
ThrowCannotWriteToDeflateManagedStreamException();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowCannotWriteToDeflateManagedStreamException()
{
throw new InvalidOperationException("Deflate64: cannot write to this stream");
}
public override void Write(byte[] array, int offset, int count)
{
ThrowCannotWriteToDeflateManagedStreamException();
}
// This is called by Dispose:
private void PurgeBuffers(bool disposing)
{
if (!disposing)
{
return;
}
if (_stream is null)
{
return;
}
Flush();
}
protected override void Dispose(bool disposing)
{
try
{
PurgeBuffers(disposing);
}
finally
{
// Close the underlying stream even if PurgeBuffers threw.
// Stream.Close() may throw here (may or may not be due to the same error).
// In this case, we still need to clean up internal resources, hence the inner finally blocks.
try
{
if (disposing)
{
//_stream?.Dispose();
}
}
finally
{
_stream = null;
try
{
_inflater?.Dispose();
}
finally
{
_inflater = null;
base.Dispose(disposing);
}
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace Compress.Support.Compression.Deflate64
{
internal sealed class DeflateInput
{
public DeflateInput(byte[] buffer)
{
Buffer = buffer;
}
public byte[] Buffer { get; }
public int Count { get; set; }
public int StartIndex { get; set; }
internal void ConsumeBytes(int n)
{
Debug.Assert(n <= Count, "Should use more bytes than what we have in the buffer");
StartIndex += n;
Count -= n;
Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!");
}
internal InputState DumpState() => new InputState(Count, StartIndex);
internal void RestoreState(InputState state)
{
Count = state._count;
StartIndex = state._startIndex;
}
internal /*readonly */struct InputState
{
internal readonly int _count;
internal readonly int _startIndex;
internal InputState(int count, int startIndex)
{
_count = count;
_startIndex = startIndex;
}
}
}
}

View File

@@ -0,0 +1,249 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
namespace Compress.Support.Compression.Deflate64
{
internal static class FastEncoderStatics
{
// static information for encoding, DO NOT MODIFY
internal static readonly byte[] FAST_ENCODER_TREE_STRUCTURE_DATA =
{
0xec,0xbd,0x07,0x60,0x1c,0x49,0x96,0x25,0x26,0x2f,0x6d,0xca,
0x7b,0x7f,0x4a,0xf5,0x4a,0xd7,0xe0,0x74,0xa1,0x08,0x80,0x60,
0x13,0x24,0xd8,0x90,0x40,0x10,0xec,0xc1,0x88,0xcd,0xe6,0x92,
0xec,0x1d,0x69,0x47,0x23,0x29,0xab,0x2a,0x81,0xca,0x65,0x56,
0x65,0x5d,0x66,0x16,0x40,0xcc,0xed,0x9d,0xbc,0xf7,0xde,0x7b,
0xef,0xbd,0xf7,0xde,0x7b,0xef,0xbd,0xf7,0xba,0x3b,0x9d,0x4e,
0x27,0xf7,0xdf,0xff,0x3f,0x5c,0x66,0x64,0x01,0x6c,0xf6,0xce,
0x4a,0xda,0xc9,0x9e,0x21,0x80,0xaa,0xc8,0x1f,0x3f,0x7e,0x7c,
0x1f,0x3f
};
internal static readonly byte[] B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA =
{
0xed,0xbd,0x07,0x60,0x1c,0x49,0x96,0x25,0x26,0x2f,0x6d,0xca,
0x7b,0x7f,0x4a,0xf5,0x4a,0xd7,0xe0,0x74,0xa1,0x08,0x80,0x60,
0x13,0x24,0xd8,0x90,0x40,0x10,0xec,0xc1,0x88,0xcd,0xe6,0x92,
0xec,0x1d,0x69,0x47,0x23,0x29,0xab,0x2a,0x81,0xca,0x65,0x56,
0x65,0x5d,0x66,0x16,0x40,0xcc,0xed,0x9d,0xbc,0xf7,0xde,0x7b,
0xef,0xbd,0xf7,0xde,0x7b,0xef,0xbd,0xf7,0xba,0x3b,0x9d,0x4e,
0x27,0xf7,0xdf,0xff,0x3f,0x5c,0x66,0x64,0x01,0x6c,0xf6,0xce,
0x4a,0xda,0xc9,0x9e,0x21,0x80,0xaa,0xc8,0x1f,0x3f,0x7e,0x7c,
0x1f,0x3f
};
// Output a currentMatch with length matchLen (>= MIN_MATCH) and displacement matchPos
//
// Optimisation: unlike the other encoders, here we have an array of codes for each currentMatch
// length (not just each currentMatch length slot), complete with all the extra bits filled in, in
// a single array element.
//
// There are many advantages to doing this:
//
// 1. A single array lookup on g_FastEncoderLiteralCodeInfo, instead of separate array lookups
// on g_LengthLookup (to get the length slot), g_FastEncoderLiteralTreeLength,
// g_FastEncoderLiteralTreeCode, g_ExtraLengthBits, and g_BitMask
//
// 2. The array is an array of ULONGs, so no access penalty, unlike for accessing those USHORT
// code arrays in the other encoders (although they could be made into ULONGs with some
// modifications to the source).
//
// Note, if we could guarantee that codeLen <= 16 always, then we could skip an if statement here.
//
// A completely different optimisation is used for the distance codes since, obviously, a table for
// all 8192 distances combining their extra bits is not feasible. The distance codeinfo table is
// made up of code[], len[] and # extraBits for this code.
//
// The advantages are similar to the above; a ULONG array instead of a USHORT and BYTE array, better
// cache locality, fewer memory operations.
//
// Encoding information for literal and Length.
// The least 5 significant bits are the length
// and the rest is the code bits.
internal static readonly uint[] FAST_ENCODER_LITERAL_CODE_INFO =
{
0x0000d7ee,0x0004d7ee,0x0002d7ee,0x0006d7ee,0x0001d7ee,0x0005d7ee,0x0003d7ee,
0x0007d7ee,0x000037ee,0x0000c7ec,0x00000126,0x000437ee,0x000237ee,0x000637ee,
0x000137ee,0x000537ee,0x000337ee,0x000737ee,0x0000b7ee,0x0004b7ee,0x0002b7ee,
0x0006b7ee,0x0001b7ee,0x0005b7ee,0x0003b7ee,0x0007b7ee,0x000077ee,0x000477ee,
0x000277ee,0x000677ee,0x000017ed,0x000177ee,0x00000526,0x000577ee,0x000023ea,
0x0001c7ec,0x000377ee,0x000777ee,0x000217ed,0x000063ea,0x00000b68,0x00000ee9,
0x00005beb,0x000013ea,0x00000467,0x00001b68,0x00000c67,0x00002ee9,0x00000768,
0x00001768,0x00000f68,0x00001ee9,0x00001f68,0x00003ee9,0x000053ea,0x000001e9,
0x000000e8,0x000021e9,0x000011e9,0x000010e8,0x000031e9,0x000033ea,0x000008e8,
0x0000f7ee,0x0004f7ee,0x000018e8,0x000009e9,0x000004e8,0x000029e9,0x000014e8,
0x000019e9,0x000073ea,0x0000dbeb,0x00000ce8,0x00003beb,0x0002f7ee,0x000039e9,
0x00000bea,0x000005e9,0x00004bea,0x000025e9,0x000027ec,0x000015e9,0x000035e9,
0x00000de9,0x00002bea,0x000127ec,0x0000bbeb,0x0006f7ee,0x0001f7ee,0x0000a7ec,
0x00007beb,0x0005f7ee,0x0000fbeb,0x0003f7ee,0x0007f7ee,0x00000fee,0x00000326,
0x00000267,0x00000a67,0x00000667,0x00000726,0x00001ce8,0x000002e8,0x00000e67,
0x000000a6,0x0001a7ec,0x00002de9,0x000004a6,0x00000167,0x00000967,0x000002a6,
0x00000567,0x000117ed,0x000006a6,0x000001a6,0x000005a6,0x00000d67,0x000012e8,
0x00000ae8,0x00001de9,0x00001ae8,0x000007eb,0x000317ed,0x000067ec,0x000097ed,
0x000297ed,0x00040fee,0x00020fee,0x00060fee,0x00010fee,0x00050fee,0x00030fee,
0x00070fee,0x00008fee,0x00048fee,0x00028fee,0x00068fee,0x00018fee,0x00058fee,
0x00038fee,0x00078fee,0x00004fee,0x00044fee,0x00024fee,0x00064fee,0x00014fee,
0x00054fee,0x00034fee,0x00074fee,0x0000cfee,0x0004cfee,0x0002cfee,0x0006cfee,
0x0001cfee,0x0005cfee,0x0003cfee,0x0007cfee,0x00002fee,0x00042fee,0x00022fee,
0x00062fee,0x00012fee,0x00052fee,0x00032fee,0x00072fee,0x0000afee,0x0004afee,
0x0002afee,0x0006afee,0x0001afee,0x0005afee,0x0003afee,0x0007afee,0x00006fee,
0x00046fee,0x00026fee,0x00066fee,0x00016fee,0x00056fee,0x00036fee,0x00076fee,
0x0000efee,0x0004efee,0x0002efee,0x0006efee,0x0001efee,0x0005efee,0x0003efee,
0x0007efee,0x00001fee,0x00041fee,0x00021fee,0x00061fee,0x00011fee,0x00051fee,
0x00031fee,0x00071fee,0x00009fee,0x00049fee,0x00029fee,0x00069fee,0x00019fee,
0x00059fee,0x00039fee,0x00079fee,0x00005fee,0x00045fee,0x00025fee,0x00065fee,
0x00015fee,0x00055fee,0x00035fee,0x00075fee,0x0000dfee,0x0004dfee,0x0002dfee,
0x0006dfee,0x0001dfee,0x0005dfee,0x0003dfee,0x0007dfee,0x00003fee,0x00043fee,
0x00023fee,0x00063fee,0x00013fee,0x00053fee,0x00033fee,0x00073fee,0x0000bfee,
0x0004bfee,0x0002bfee,0x0006bfee,0x0001bfee,0x0005bfee,0x0003bfee,0x0007bfee,
0x00007fee,0x00047fee,0x00027fee,0x00067fee,0x00017fee,0x000197ed,0x000397ed,
0x000057ed,0x00057fee,0x000257ed,0x00037fee,0x000157ed,0x00077fee,0x000357ed,
0x0000ffee,0x0004ffee,0x0002ffee,0x0006ffee,0x0001ffee,0x00000084,0x00000003,
0x00000184,0x00000044,0x00000144,0x000000c5,0x000002c5,0x000001c5,0x000003c6,
0x000007c6,0x00000026,0x00000426,0x000003a7,0x00000ba7,0x000007a7,0x00000fa7,
0x00000227,0x00000627,0x00000a27,0x00000e27,0x00000068,0x00000868,0x00001068,
0x00001868,0x00000369,0x00001369,0x00002369,0x00003369,0x000006ea,0x000026ea,
0x000046ea,0x000066ea,0x000016eb,0x000036eb,0x000056eb,0x000076eb,0x000096eb,
0x0000b6eb,0x0000d6eb,0x0000f6eb,0x00003dec,0x00007dec,0x0000bdec,0x0000fdec,
0x00013dec,0x00017dec,0x0001bdec,0x0001fdec,0x00006bed,0x0000ebed,0x00016bed,
0x0001ebed,0x00026bed,0x0002ebed,0x00036bed,0x0003ebed,0x000003ec,0x000043ec,
0x000083ec,0x0000c3ec,0x000103ec,0x000143ec,0x000183ec,0x0001c3ec,0x00001bee,
0x00009bee,0x00011bee,0x00019bee,0x00021bee,0x00029bee,0x00031bee,0x00039bee,
0x00041bee,0x00049bee,0x00051bee,0x00059bee,0x00061bee,0x00069bee,0x00071bee,
0x00079bee,0x000167f0,0x000367f0,0x000567f0,0x000767f0,0x000967f0,0x000b67f0,
0x000d67f0,0x000f67f0,0x001167f0,0x001367f0,0x001567f0,0x001767f0,0x001967f0,
0x001b67f0,0x001d67f0,0x001f67f0,0x000087ef,0x000187ef,0x000287ef,0x000387ef,
0x000487ef,0x000587ef,0x000687ef,0x000787ef,0x000887ef,0x000987ef,0x000a87ef,
0x000b87ef,0x000c87ef,0x000d87ef,0x000e87ef,0x000f87ef,0x0000e7f0,0x0002e7f0,
0x0004e7f0,0x0006e7f0,0x0008e7f0,0x000ae7f0,0x000ce7f0,0x000ee7f0,0x0010e7f0,
0x0012e7f0,0x0014e7f0,0x0016e7f0,0x0018e7f0,0x001ae7f0,0x001ce7f0,0x001ee7f0,
0x0005fff3,0x000dfff3,0x0015fff3,0x001dfff3,0x0025fff3,0x002dfff3,0x0035fff3,
0x003dfff3,0x0045fff3,0x004dfff3,0x0055fff3,0x005dfff3,0x0065fff3,0x006dfff3,
0x0075fff3,0x007dfff3,0x0085fff3,0x008dfff3,0x0095fff3,0x009dfff3,0x00a5fff3,
0x00adfff3,0x00b5fff3,0x00bdfff3,0x00c5fff3,0x00cdfff3,0x00d5fff3,0x00ddfff3,
0x00e5fff3,0x00edfff3,0x00f5fff3,0x00fdfff3,0x0003fff3,0x000bfff3,0x0013fff3,
0x001bfff3,0x0023fff3,0x002bfff3,0x0033fff3,0x003bfff3,0x0043fff3,0x004bfff3,
0x0053fff3,0x005bfff3,0x0063fff3,0x006bfff3,0x0073fff3,0x007bfff3,0x0083fff3,
0x008bfff3,0x0093fff3,0x009bfff3,0x00a3fff3,0x00abfff3,0x00b3fff3,0x00bbfff3,
0x00c3fff3,0x00cbfff3,0x00d3fff3,0x00dbfff3,0x00e3fff3,0x00ebfff3,0x00f3fff3,
0x00fbfff3,0x0007fff3,0x000ffff3,0x0017fff3,0x001ffff3,0x0027fff3,0x002ffff3,
0x0037fff3,0x003ffff3,0x0047fff3,0x004ffff3,0x0057fff3,0x005ffff3,0x0067fff3,
0x006ffff3,0x0077fff3,0x007ffff3,0x0087fff3,0x008ffff3,0x0097fff3,0x009ffff3,
0x00a7fff3,0x00affff3,0x00b7fff3,0x00bffff3,0x00c7fff3,0x00cffff3,0x00d7fff3,
0x00dffff3,0x00e7fff3,0x00effff3,0x00f7fff3,0x00fffff3,0x0001e7f1,0x0003e7f1,
0x0005e7f1,0x0007e7f1,0x0009e7f1,0x000be7f1,0x000de7f1,0x000fe7f1,0x0011e7f1,
0x0013e7f1,0x0015e7f1,0x0017e7f1,0x0019e7f1,0x001be7f1,0x001de7f1,0x001fe7f1,
0x0021e7f1,0x0023e7f1,0x0025e7f1,0x0027e7f1,0x0029e7f1,0x002be7f1,0x002de7f1,
0x002fe7f1,0x0031e7f1,0x0033e7f1,0x0035e7f1,0x0037e7f1,0x0039e7f1,0x003be7f1,
0x003de7f1,0x000047eb
};
internal static readonly uint[] FAST_ENCODER_DISTANCE_CODE_INFO =
{
0x00000f06,0x0001ff0a,0x0003ff0b,0x0007ff0b,0x0000ff19,0x00003f18,0x0000bf28,
0x00007f28,0x00001f37,0x00005f37,0x00000d45,0x00002f46,0x00000054,0x00001d55,
0x00000864,0x00000365,0x00000474,0x00001375,0x00000c84,0x00000284,0x00000a94,
0x00000694,0x00000ea4,0x000001a4,0x000009b4,0x00000bb5,0x000005c4,0x00001bc5,
0x000007d5,0x000017d5,0x00000000,0x00000100
};
internal static readonly uint[] BIT_MASK = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767 };
internal static readonly byte[] EXTRA_LENGTH_BITS = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
internal static readonly byte[] EXTRA_DISTANCE_BITS = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 };
internal const int NUM_CHARS = 256;
internal const int NUM_LENGTH_BASE_CODES = 29;
internal const int NUM_DIST_BASE_CODES = 30;
internal const uint FAST_ENCODER_POST_TREE_BIT_BUF = 0x0022;
internal const int FAST_ENCODER_POST_TREE_BIT_COUNT = 9;
internal const uint NO_COMPRESSION_HEADER = 0x0;
internal const int NO_COMPRESSION_HEADER_BIT_COUNT = 3;
internal const uint B_FINAL_NO_COMPRESSION_HEADER = 0x1;
internal const int B_FINAL_NO_COMPRESSION_HEADER_BIT_COUNT = 3;
internal const int MAX_CODE_LEN = 16;
private static readonly byte[] S_DIST_LOOKUP = CreateDistanceLookup();
private static byte[] CreateDistanceLookup()
{
byte[] result = new byte[512];
// Generate the global slot tables which allow us to convert a distance
// (0..32K) to a distance slot (0..29)
//
// Distance table
// Extra Extra Extra
// Code Bits Dist Code Bits Dist Code Bits Distance
// ---- ---- ---- ---- ---- ------ ---- ---- --------
// 0 0 1 10 4 33-48 20 9 1025-1536
// 1 0 2 11 4 49-64 21 9 1537-2048
// 2 0 3 12 5 65-96 22 10 2049-3072
// 3 0 4 13 5 97-128 23 10 3073-4096
// 4 1 5,6 14 6 129-192 24 11 4097-6144
// 5 1 7,8 15 6 193-256 25 11 6145-8192
// 6 2 9-12 16 7 257-384 26 12 8193-12288
// 7 2 13-16 17 7 385-512 27 12 12289-16384
// 8 3 17-24 18 8 513-768 28 13 16385-24576
// 9 3 25-32 19 8 769-1024 29 13 24577-32768
// Initialize the mapping length (0..255) -> length code (0..28)
//int length = 0;
//for (code = 0; code < FastEncoderStatics.NumLengthBaseCodes-1; code++) {
// for (int n = 0; n < (1 << FastEncoderStatics.ExtraLengthBits[code]); n++)
// lengthLookup[length++] = (byte) code;
//}
//lengthLookup[length-1] = (byte) code;
// Initialize the mapping dist (0..32K) -> dist code (0..29)
int dist = 0;
int code;
for (code = 0; code < 16; code++)
{
for (int n = 0; n < (1 << EXTRA_DISTANCE_BITS[code]); n++)
{
result[dist++] = (byte)code;
}
}
dist >>= 7; // from now on, all distances are divided by 128
for (; code < NUM_DIST_BASE_CODES; code++)
{
for (int n = 0; n < (1 << (EXTRA_DISTANCE_BITS[code] - 7)); n++)
{
result[256 + dist++] = (byte)code;
}
}
return result;
}
// Return the position slot (0...29) of a match offset (0...32767)
internal static int GetSlot(int pos) =>
S_DIST_LOOKUP[((pos) < 256) ? (pos) : (256 + ((pos) >> 7))];
// Reverse 'length' of the bits in code
public static uint BitReverse(uint code, int length)
{
uint newCode = 0;
Debug.Assert(length > 0 && length <= 16, "Invalid len");
do
{
newCode |= (code & 1);
newCode <<= 1;
code >>= 1;
} while (--length > 0);
return newCode >> 1;
}
}
}

View File

@@ -0,0 +1,318 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.IO;
namespace Compress.Support.Compression.Deflate64
{
// Strictly speaking this class is not a HuffmanTree, this class is
// a lookup table combined with a HuffmanTree. The idea is to speed up
// the lookup for short symbols (they should appear more frequently ideally.)
// However we don't want to create a huge table since it might take longer to
// build the table than decoding (Deflate usually generates new tables frequently.)
//
// Jean-loup Gailly and Mark Adler gave a very good explanation about this.
// The full text (algorithm.txt) can be found inside
// ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib.zip.
//
// Following paper explains decoding in details:
// Hirschberg and Lelewer, "Efficient decoding of prefix codes,"
// Comm. ACM, 33,4, April 1990, pp. 449-459.
//
internal sealed class HuffmanTree
{
internal const int MAX_LITERAL_TREE_ELEMENTS = 288;
internal const int MAX_DIST_TREE_ELEMENTS = 32;
internal const int END_OF_BLOCK_CODE = 256;
internal const int NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS = 19;
private readonly int _tableBits;
private readonly short[] _table;
private readonly short[] _left;
private readonly short[] _right;
private readonly byte[] _codeLengthArray;
private readonly int _tableMask;
// huffman tree for static block
public static HuffmanTree StaticLiteralLengthTree { get; } = new HuffmanTree(GetStaticLiteralTreeLength());
public static HuffmanTree StaticDistanceTree { get; } = new HuffmanTree(GetStaticDistanceTreeLength());
public HuffmanTree(byte[] codeLengths)
{
Debug.Assert(
codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS ||
codeLengths.Length == MAX_DIST_TREE_ELEMENTS ||
codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS,
"we only expect three kinds of Length here");
_codeLengthArray = codeLengths;
if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS)
{
// bits for Literal/Length tree table
_tableBits = 9;
}
else
{
// bits for distance tree table and code length tree table
_tableBits = 7;
}
_tableMask = (1 << _tableBits) - 1;
_table = new short[1 << _tableBits];
// I need to find proof that left and right array will always be
// enough. I think they are.
_left = new short[2 * _codeLengthArray.Length];
_right = new short[2 * _codeLengthArray.Length];
CreateTable();
}
// Generate the array contains huffman codes lengths for static huffman tree.
// The data is in RFC 1951.
private static byte[] GetStaticLiteralTreeLength()
{
byte[] literalTreeLength = new byte[MAX_LITERAL_TREE_ELEMENTS];
for (int i = 0; i <= 143; i++)
{
literalTreeLength[i] = 8;
}
for (int i = 144; i <= 255; i++)
{
literalTreeLength[i] = 9;
}
for (int i = 256; i <= 279; i++)
{
literalTreeLength[i] = 7;
}
for (int i = 280; i <= 287; i++)
{
literalTreeLength[i] = 8;
}
return literalTreeLength;
}
private static byte[] GetStaticDistanceTreeLength()
{
byte[] staticDistanceTreeLength = new byte[MAX_DIST_TREE_ELEMENTS];
for (int i = 0; i < MAX_DIST_TREE_ELEMENTS; i++)
{
staticDistanceTreeLength[i] = 5;
}
return staticDistanceTreeLength;
}
// Calculate the huffman code for each character based on the code length for each character.
// This algorithm is described in standard RFC 1951
private uint[] CalculateHuffmanCode()
{
uint[] bitLengthCount = new uint[17];
foreach (int codeLength in _codeLengthArray)
{
bitLengthCount[codeLength]++;
}
bitLengthCount[0] = 0; // clear count for length 0
uint[] nextCode = new uint[17];
uint tempCode = 0;
for (int bits = 1; bits <= 16; bits++)
{
tempCode = (tempCode + bitLengthCount[bits - 1]) << 1;
nextCode[bits] = tempCode;
}
uint[] code = new uint[MAX_LITERAL_TREE_ELEMENTS];
for (int i = 0; i < _codeLengthArray.Length; i++)
{
int len = _codeLengthArray[i];
if (len > 0)
{
code[i] = FastEncoderStatics.BitReverse(nextCode[len], len);
nextCode[len]++;
}
}
return code;
}
private void CreateTable()
{
uint[] codeArray = CalculateHuffmanCode();
short avail = (short)_codeLengthArray.Length;
for (int ch = 0; ch < _codeLengthArray.Length; ch++)
{
// length of this code
int len = _codeLengthArray[ch];
if (len > 0)
{
// start value (bit reversed)
int start = (int)codeArray[ch];
if (len <= _tableBits)
{
// If a particular symbol is shorter than nine bits,
// then that symbol's translation is duplicated
// in all those entries that start with that symbol's bits.
// For example, if the symbol is four bits, then it's duplicated
// 32 times in a nine-bit table. If a symbol is nine bits long,
// it appears in the table once.
//
// Make sure that in the loop below, code is always
// less than table_size.
//
// On last iteration we store at array index:
// initial_start_at + (locs-1)*increment
// = initial_start_at + locs*increment - increment
// = initial_start_at + (1 << tableBits) - increment
// = initial_start_at + table_size - increment
//
// Therefore we must ensure:
// initial_start_at + table_size - increment < table_size
// or: initial_start_at < increment
//
int increment = 1 << len;
if (start >= increment)
{
throw new InvalidDataException("Deflate64: invalid Huffman data");
}
// Note the bits in the table are reverted.
int locs = 1 << (_tableBits - len);
for (int j = 0; j < locs; j++)
{
_table[start] = (short)ch;
start += increment;
}
}
else
{
// For any code which has length longer than num_elements,
// build a binary tree.
int overflowBits = len - _tableBits; // the nodes we need to respent the data.
int codeBitMask = 1 << _tableBits; // mask to get current bit (the bits can't fit in the table)
// the left, right table is used to repesent the
// the rest bits. When we got the first part (number bits.) and look at
// tbe table, we will need to follow the tree to find the real character.
// This is in place to avoid bloating the table if there are
// a few ones with long code.
int index = start & ((1 << _tableBits) - 1);
short[] array = _table;
do
{
short value = array[index];
if (value == 0)
{
// set up next pointer if this node is not used before.
array[index] = (short)-avail; // use next available slot.
value = (short)-avail;
avail++;
}
if (value > 0)
{
// prevent an IndexOutOfRangeException from array[index]
throw new InvalidDataException("Deflate64: invalid Huffman data");
}
Debug.Assert(value < 0, "CreateTable: Only negative numbers are used for tree pointers!");
if ((start & codeBitMask) == 0)
{
// if current bit is 0, go change the left array
array = _left;
}
else
{
// if current bit is 1, set value in the right array
array = _right;
}
index = -value; // go to next node
codeBitMask <<= 1;
overflowBits--;
} while (overflowBits != 0);
array[index] = (short)ch;
}
}
}
}
//
// This function will try to get enough bits from input and
// try to decode the bits.
// If there are no enought bits in the input, this function will return -1.
//
public int GetNextSymbol(InputBuffer input)
{
// Try to load 16 bits into input buffer if possible and get the bitBuffer value.
// If there aren't 16 bits available we will return all we have in the
// input buffer.
uint bitBuffer = input.TryLoad16Bits();
if (input.AvailableBits == 0)
{ // running out of input.
return -1;
}
// decode an element
int symbol = _table[bitBuffer & _tableMask];
if (symbol < 0)
{ // this will be the start of the binary tree
// navigate the tree
uint mask = (uint)1 << _tableBits;
do
{
symbol = -symbol;
if ((bitBuffer & mask) == 0)
{
symbol = _left[symbol];
}
else
{
symbol = _right[symbol];
}
mask <<= 1;
} while (symbol < 0);
}
int codeLength = _codeLengthArray[symbol];
// huffman code lengths must be at least 1 bit long
if (codeLength <= 0)
{
throw new InvalidDataException("Deflate64: invalid Huffman data");
}
//
// If this code is longer than the # bits we had in the bit buffer (i.e.
// we read only part of the code), we can hit the entry in the table or the tree
// for another symbol. However the length of another symbol will not match the
// available bits count.
if (codeLength > input.AvailableBits)
{
// We already tried to load 16 bits and maximum length is 15,
// so this means we are running out of input.
return -1;
}
input.SkipBits(codeLength);
return symbol;
}
}
}

View File

@@ -0,0 +1,740 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// zlib.h -- interface of the 'zlib' general purpose compression library
// version 1.2.1, November 17th, 2003
//
// Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
//
using System;
using System.Diagnostics;
using System.IO;
namespace Compress.Support.Compression.Deflate64
{
internal sealed class InflaterManaged
{
// const tables used in decoding:
// Extra bits for length code 257 - 285.
private static readonly byte[] S_EXTRA_LENGTH_BITS = new byte[]
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,16 };
// The base length for length code 257 - 285.
// The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits)
private static readonly int[] S_LENGTH_BASE =
{ 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,3};
// The base distance for distance code 0 - 31
// The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits)
private static readonly int[] S_DISTANCE_BASE_POSITION =
{ 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,32769,49153 };
// code lengths for code length alphabet is stored in following order
private static readonly byte[] S_CODE_ORDER = new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
private static readonly byte[] S_STATIC_DISTANCE_TREE_TABLE = new byte[]
{
0x00,0x10,0x08,0x18,0x04,0x14,0x0c,0x1c,0x02,0x12,0x0a,0x1a,
0x06,0x16,0x0e,0x1e,0x01,0x11,0x09,0x19,0x05,0x15,0x0d,0x1d,
0x03,0x13,0x0b,0x1b,0x07,0x17,0x0f,0x1f
};
private readonly OutputWindow _output;
private readonly InputBuffer _input;
private HuffmanTree _literalLengthTree;
private HuffmanTree _distanceTree;
private InflaterState _state;
//private bool _hasFormatReader;
private int _bfinal;
private BlockType _blockType;
// uncompressed block
private readonly byte[] _blockLengthBuffer = new byte[4];
private int _blockLength;
// compressed block
private int _length;
private int _distanceCode;
private int _extraBits;
private int _loopCounter;
private int _literalLengthCodeCount;
private int _distanceCodeCount;
private int _codeLengthCodeCount;
private int _codeArraySize;
private int _lengthCode;
private readonly byte[] _codeList; // temporary array to store the code length for literal/Length and distance
private readonly byte[] _codeLengthTreeCodeLength;
private readonly bool _deflate64;
private HuffmanTree _codeLengthTree;
//private IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip)
internal InflaterManaged(/*IFileFormatReader reader, */bool deflate64)
{
_output = new OutputWindow();
_input = new InputBuffer();
_codeList = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS + HuffmanTree.MAX_DIST_TREE_ELEMENTS];
_codeLengthTreeCodeLength = new byte[HuffmanTree.NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS];
_deflate64 = deflate64;
//if (reader != null)
//{
// _formatReader = reader;
// _hasFormatReader = true;
//}
Reset();
}
private void Reset()
{
_state = //_hasFormatReader ?
//InflaterState.ReadingHeader : // start by reading Header info
InflaterState.ReadingBFinal; // start by reading BFinal bit
}
public void SetInput(byte[] inputBytes, int offset, int length) =>
_input.SetInput(inputBytes, offset, length); // append the bytes
public bool Finished() => _state == InflaterState.Done || _state == InflaterState.VerifyingFooter;
public int AvailableOutput => _output.AvailableBytes;
public int Inflate(byte[] bytes, int offset, int length)
{
// copy bytes from output to outputbytes if we have available bytes
// if buffer is not filled up. keep decoding until no input are available
// if decodeBlock returns false. Throw an exception.
int count = 0;
do
{
int copied = _output.CopyTo(bytes, offset, length);
if (copied > 0)
{
//if (_hasFormatReader)
//{
// _formatReader.UpdateWithBytesRead(bytes, offset, copied);
//}
offset += copied;
count += copied;
length -= copied;
}
if (length == 0)
{ // filled in the bytes array
break;
}
// Decode will return false when more input is needed
} while (!Finished() && Decode());
if (_state == InflaterState.VerifyingFooter)
{ // finished reading CRC
// In this case finished is true and output window has all the data.
// But some data in output window might not be copied out.
if (_output.AvailableBytes == 0)
{
//_formatReader.Validate();
}
}
return count;
}
//Each block of compressed data begins with 3 header bits
// containing the following data:
// first bit BFINAL
// next 2 bits BTYPE
// Note that the header bits do not necessarily begin on a byte
// boundary, since a block does not necessarily occupy an integral
// number of bytes.
// BFINAL is set if and only if this is the last block of the data
// set.
// BTYPE specifies how the data are compressed, as follows:
// 00 - no compression
// 01 - compressed with fixed Huffman codes
// 10 - compressed with dynamic Huffman codes
// 11 - reserved (error)
// The only difference between the two compressed cases is how the
// Huffman codes for the literal/length and distance alphabets are
// defined.
//
// This function returns true for success (end of block or output window is full,)
// false if we are short of input
//
private bool Decode()
{
bool eob = false;
bool result = false;
if (Finished())
{
return true;
}
//if (_hasFormatReader)
//{
// if (_state == InflaterState.ReadingHeader)
// {
// if (!_formatReader.ReadHeader(_input))
// {
// return false;
// }
// _state = InflaterState.ReadingBFinal;
// }
// else if (_state == InflaterState.StartReadingFooter || _state == InflaterState.ReadingFooter)
// {
// if (!_formatReader.ReadFooter(_input))
// return false;
// _state = InflaterState.VerifyingFooter;
// return true;
// }
//}
if (_state == InflaterState.ReadingBFinal)
{
// reading bfinal bit
// Need 1 bit
if (!_input.EnsureBitsAvailable(1))
{
return false;
}
_bfinal = _input.GetBits(1);
_state = InflaterState.ReadingBType;
}
if (_state == InflaterState.ReadingBType)
{
// Need 2 bits
if (!_input.EnsureBitsAvailable(2))
{
_state = InflaterState.ReadingBType;
return false;
}
_blockType = (BlockType)_input.GetBits(2);
if (_blockType == BlockType.Dynamic)
{
_state = InflaterState.ReadingNumLitCodes;
}
else if (_blockType == BlockType.Static)
{
_literalLengthTree = HuffmanTree.StaticLiteralLengthTree;
_distanceTree = HuffmanTree.StaticDistanceTree;
_state = InflaterState.DecodeTop;
}
else if (_blockType == BlockType.Uncompressed)
{
_state = InflaterState.UncompressedAligning;
}
else
{
throw new InvalidDataException("Deflate64: unknown block type");
}
}
if (_blockType == BlockType.Dynamic)
{
if (_state < InflaterState.DecodeTop)
{
// we are reading the header
result = DecodeDynamicBlockHeader();
}
else
{
result = DecodeBlock(out eob); // this can returns true when output is full
}
}
else if (_blockType == BlockType.Static)
{
result = DecodeBlock(out eob);
}
else if (_blockType == BlockType.Uncompressed)
{
result = DecodeUncompressedBlock(out eob);
}
else
{
throw new InvalidDataException("Deflate64: unknown block type");
}
//
// If we reached the end of the block and the block we were decoding had
// bfinal=1 (final block)
//
if (eob && (_bfinal != 0))
{
//if (_hasFormatReader)
// _state = InflaterState.StartReadingFooter;
//else
_state = InflaterState.Done;
}
return result;
}
// Format of Non-compressed blocks (BTYPE=00):
//
// Any bits of input up to the next byte boundary are ignored.
// The rest of the block consists of the following information:
//
// 0 1 2 3 4...
// +---+---+---+---+================================+
// | LEN | NLEN |... LEN bytes of literal data...|
// +---+---+---+---+================================+
//
// LEN is the number of data bytes in the block. NLEN is the
// one's complement of LEN.
private bool DecodeUncompressedBlock(out bool endOfBlock)
{
endOfBlock = false;
while (true)
{
switch (_state)
{
case InflaterState.UncompressedAligning: // initial state when calling this function
// we must skip to a byte boundary
_input.SkipToByteBoundary();
_state = InflaterState.UncompressedByte1;
goto case InflaterState.UncompressedByte1;
case InflaterState.UncompressedByte1: // decoding block length
case InflaterState.UncompressedByte2:
case InflaterState.UncompressedByte3:
case InflaterState.UncompressedByte4:
int bits = _input.GetBits(8);
if (bits < 0)
{
return false;
}
_blockLengthBuffer[_state - InflaterState.UncompressedByte1] = (byte)bits;
if (_state == InflaterState.UncompressedByte4)
{
_blockLength = _blockLengthBuffer[0] + ((int)_blockLengthBuffer[1]) * 256;
int blockLengthComplement = _blockLengthBuffer[2] + ((int)_blockLengthBuffer[3]) * 256;
// make sure complement matches
if ((ushort)_blockLength != (ushort)(~blockLengthComplement))
{
throw new InvalidDataException("Deflate64: invalid block length");
}
}
_state += 1;
break;
case InflaterState.DecodingUncompressed: // copying block data
// Directly copy bytes from input to output.
int bytesCopied = _output.CopyFrom(_input, _blockLength);
_blockLength -= bytesCopied;
if (_blockLength == 0)
{
// Done with this block, need to re-init bit buffer for next block
_state = InflaterState.ReadingBFinal;
endOfBlock = true;
return true;
}
// We can fail to copy all bytes for two reasons:
// Running out of Input
// running out of free space in output window
if (_output.FreeBytes == 0)
{
return true;
}
return false;
default:
Debug./*Fail*/Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
}
}
}
private bool DecodeBlock(out bool endOfBlockCodeSeen)
{
endOfBlockCodeSeen = false;
int freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property
while (freeBytes > 65536)
{
// With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available
// in the OutputWindow to avoid overwriting previous unflushed output data.
int symbol;
switch (_state)
{
case InflaterState.DecodeTop:
// decode an element from the literal tree
// TODO: optimize this!!!
symbol = _literalLengthTree.GetNextSymbol(_input);
if (symbol < 0)
{
// running out of input
return false;
}
if (symbol < 256)
{
// literal
_output.Write((byte)symbol);
--freeBytes;
}
else if (symbol == 256)
{
// end of block
endOfBlockCodeSeen = true;
// Reset state
_state = InflaterState.ReadingBFinal;
return true;
}
else
{
// length/distance pair
symbol -= 257; // length code started at 257
if (symbol < 8)
{
symbol += 3; // match length = 3,4,5,6,7,8,9,10
_extraBits = 0;
}
else if (!_deflate64 && symbol == 28)
{
// extra bits for code 285 is 0
symbol = 258; // code 285 means length 258
_extraBits = 0;
}
else
{
if (symbol < 0 || symbol >= S_EXTRA_LENGTH_BITS.Length)
{
throw new InvalidDataException("Deflate64: invalid data");
}
_extraBits = S_EXTRA_LENGTH_BITS[symbol];
Debug.Assert(_extraBits != 0, "We handle other cases separately!");
}
_length = symbol;
goto case InflaterState.HaveInitialLength;
}
break;
case InflaterState.HaveInitialLength:
if (_extraBits > 0)
{
_state = InflaterState.HaveInitialLength;
int bits = _input.GetBits(_extraBits);
if (bits < 0)
{
return false;
}
if (_length < 0 || _length >= S_LENGTH_BASE.Length)
{
throw new InvalidDataException("Deflate64: invalid data");
}
_length = S_LENGTH_BASE[_length] + bits;
}
_state = InflaterState.HaveFullLength;
goto case InflaterState.HaveFullLength;
case InflaterState.HaveFullLength:
if (_blockType == BlockType.Dynamic)
{
_distanceCode = _distanceTree.GetNextSymbol(_input);
}
else
{
// get distance code directly for static block
_distanceCode = _input.GetBits(5);
if (_distanceCode >= 0)
{
_distanceCode = S_STATIC_DISTANCE_TREE_TABLE[_distanceCode];
}
}
if (_distanceCode < 0)
{
// running out input
return false;
}
_state = InflaterState.HaveDistCode;
goto case InflaterState.HaveDistCode;
case InflaterState.HaveDistCode:
// To avoid a table lookup we note that for distanceCode > 3,
// extra_bits = (distanceCode-2) >> 1
int offset;
if (_distanceCode > 3)
{
_extraBits = (_distanceCode - 2) >> 1;
int bits = _input.GetBits(_extraBits);
if (bits < 0)
{
return false;
}
offset = S_DISTANCE_BASE_POSITION[_distanceCode] + bits;
}
else
{
offset = _distanceCode + 1;
}
_output.WriteLengthDistance(_length, offset);
freeBytes -= _length;
_state = InflaterState.DecodeTop;
break;
default:
Debug./*Fail*/Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
}
}
return true;
}
// Format of the dynamic block header:
// 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
// 5 Bits: HDIST, # of Distance codes - 1 (1 - 32)
// 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19)
//
// (HCLEN + 4) x 3 bits: code lengths for the code length
// alphabet given just above, in the order: 16, 17, 18,
// 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
//
// These code lengths are interpreted as 3-bit integers
// (0-7); as above, a code length of 0 means the
// corresponding symbol (literal/length or distance code
// length) is not used.
//
// HLIT + 257 code lengths for the literal/length alphabet,
// encoded using the code length Huffman code
//
// HDIST + 1 code lengths for the distance alphabet,
// encoded using the code length Huffman code
//
// The code length repeat codes can cross from HLIT + 257 to the
// HDIST + 1 code lengths. In other words, all code lengths form
// a single sequence of HLIT + HDIST + 258 values.
private bool DecodeDynamicBlockHeader()
{
switch (_state)
{
case InflaterState.ReadingNumLitCodes:
_literalLengthCodeCount = _input.GetBits(5);
if (_literalLengthCodeCount < 0)
{
return false;
}
_literalLengthCodeCount += 257;
_state = InflaterState.ReadingNumDistCodes;
goto case InflaterState.ReadingNumDistCodes;
case InflaterState.ReadingNumDistCodes:
_distanceCodeCount = _input.GetBits(5);
if (_distanceCodeCount < 0)
{
return false;
}
_distanceCodeCount += 1;
_state = InflaterState.ReadingNumCodeLengthCodes;
goto case InflaterState.ReadingNumCodeLengthCodes;
case InflaterState.ReadingNumCodeLengthCodes:
_codeLengthCodeCount = _input.GetBits(4);
if (_codeLengthCodeCount < 0)
{
return false;
}
_codeLengthCodeCount += 4;
_loopCounter = 0;
_state = InflaterState.ReadingCodeLengthCodes;
goto case InflaterState.ReadingCodeLengthCodes;
case InflaterState.ReadingCodeLengthCodes:
while (_loopCounter < _codeLengthCodeCount)
{
int bits = _input.GetBits(3);
if (bits < 0)
{
return false;
}
_codeLengthTreeCodeLength[S_CODE_ORDER[_loopCounter]] = (byte)bits;
++_loopCounter;
}
for (int i = _codeLengthCodeCount; i < S_CODE_ORDER.Length; i++)
{
_codeLengthTreeCodeLength[S_CODE_ORDER[i]] = 0;
}
// create huffman tree for code length
_codeLengthTree = new HuffmanTree(_codeLengthTreeCodeLength);
_codeArraySize = _literalLengthCodeCount + _distanceCodeCount;
_loopCounter = 0; // reset loop count
_state = InflaterState.ReadingTreeCodesBefore;
goto case InflaterState.ReadingTreeCodesBefore;
case InflaterState.ReadingTreeCodesBefore:
case InflaterState.ReadingTreeCodesAfter:
while (_loopCounter < _codeArraySize)
{
if (_state == InflaterState.ReadingTreeCodesBefore)
{
if ((_lengthCode = _codeLengthTree.GetNextSymbol(_input)) < 0)
{
return false;
}
}
// The alphabet for code lengths is as follows:
// 0 - 15: Represent code lengths of 0 - 15
// 16: Copy the previous code length 3 - 6 times.
// The next 2 bits indicate repeat length
// (0 = 3, ... , 3 = 6)
// Example: Codes 8, 16 (+2 bits 11),
// 16 (+2 bits 10) will expand to
// 12 code lengths of 8 (1 + 6 + 5)
// 17: Repeat a code length of 0 for 3 - 10 times.
// (3 bits of length)
// 18: Repeat a code length of 0 for 11 - 138 times
// (7 bits of length)
if (_lengthCode <= 15)
{
_codeList[_loopCounter++] = (byte)_lengthCode;
}
else
{
int repeatCount;
if (_lengthCode == 16)
{
if (!_input.EnsureBitsAvailable(2))
{
_state = InflaterState.ReadingTreeCodesAfter;
return false;
}
if (_loopCounter == 0)
{
// can't have "prev code" on first code
throw new InvalidDataException();
}
byte previousCode = _codeList[_loopCounter - 1];
repeatCount = _input.GetBits(2) + 3;
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
}
for (int j = 0; j < repeatCount; j++)
{
_codeList[_loopCounter++] = previousCode;
}
}
else if (_lengthCode == 17)
{
if (!_input.EnsureBitsAvailable(3))
{
_state = InflaterState.ReadingTreeCodesAfter;
return false;
}
repeatCount = _input.GetBits(3) + 3;
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
}
for (int j = 0; j < repeatCount; j++)
{
_codeList[_loopCounter++] = 0;
}
}
else
{
// code == 18
if (!_input.EnsureBitsAvailable(7))
{
_state = InflaterState.ReadingTreeCodesAfter;
return false;
}
repeatCount = _input.GetBits(7) + 11;
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
}
for (int j = 0; j < repeatCount; j++)
{
_codeList[_loopCounter++] = 0;
}
}
}
_state = InflaterState.ReadingTreeCodesBefore; // we want to read the next code.
}
break;
default:
Debug./*Fail*/Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
}
byte[] literalTreeCodeLength = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS];
byte[] distanceTreeCodeLength = new byte[HuffmanTree.MAX_DIST_TREE_ELEMENTS];
// Create literal and distance tables
Array.Copy(_codeList, literalTreeCodeLength, _literalLengthCodeCount);
Array.Copy(_codeList, _literalLengthCodeCount, distanceTreeCodeLength, 0, _distanceCodeCount);
// Make sure there is an end-of-block code, otherwise how could we ever end?
if (literalTreeCodeLength[HuffmanTree.END_OF_BLOCK_CODE] == 0)
{
throw new InvalidDataException();
}
_literalLengthTree = new HuffmanTree(literalTreeCodeLength);
_distanceTree = new HuffmanTree(distanceTreeCodeLength);
_state = InflaterState.DecodeTop;
return true;
}
public void Dispose() { }
}
}

View File

@@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Compress.Support.Compression.Deflate64
{
// Do not rearrange the enum values.
internal enum InflaterState
{
ReadingHeader = 0, // Only applies to GZIP
ReadingBFinal = 2, // About to read bfinal bit
ReadingBType = 3, // About to read blockType bits
ReadingNumLitCodes = 4, // About to read # literal codes
ReadingNumDistCodes = 5, // About to read # dist codes
ReadingNumCodeLengthCodes = 6, // About to read # code length codes
ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes
ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top)
ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15)
DecodeTop = 10, // About to decode a literal (char/match) in a compressed block
HaveInitialLength = 11, // Decoding a match, have the literal code (base length)
HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits)
HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits
/* uncompressed blocks */
UncompressedAligning = 15,
UncompressedByte1 = 16,
UncompressedByte2 = 17,
UncompressedByte3 = 18,
UncompressedByte4 = 19,
DecodingUncompressed = 20,
// These three apply only to GZIP
StartReadingFooter = 21, // (Initialisation for reading footer)
ReadingFooter = 22,
VerifyingFooter = 23,
Done = 24 // Finished
}
}

View File

@@ -0,0 +1,202 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
namespace Compress.Support.Compression.Deflate64
{
// This class can be used to read bits from an byte array quickly.
// Normally we get bits from 'bitBuffer' field and bitsInBuffer stores
// the number of bits available in 'BitBuffer'.
// When we used up the bits in bitBuffer, we will try to get byte from
// the byte array and copy the byte to appropiate position in bitBuffer.
//
// The byte array is not reused. We will go from 'start' to 'end'.
// When we reach the end, most read operations will return -1,
// which means we are running out of input.
internal sealed class InputBuffer
{
private byte[] _buffer; // byte array to store input
private int _start; // start poisition of the buffer
private int _end; // end position of the buffer
private uint _bitBuffer = 0; // store the bits here, we can quickly shift in this buffer
private int _bitsInBuffer = 0; // number of bits available in bitBuffer
/// <summary>Total bits available in the input buffer.</summary>
public int AvailableBits => _bitsInBuffer;
/// <summary>Total bytes available in the input buffer.</summary>
public int AvailableBytes => (_end - _start) + (_bitsInBuffer / 8);
/// <summary>Ensure that count bits are in the bit buffer.</summary>
/// <param name="count">Can be up to 16.</param>
/// <returns>Returns false if input is not sufficient to make this true.</returns>
public bool EnsureBitsAvailable(int count)
{
Debug.Assert(0 < count && count <= 16, "count is invalid.");
// manual inlining to improve perf
if (_bitsInBuffer < count)
{
if (NeedsInput())
{
return false;
}
// insert a byte to bitbuffer
_bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
_bitsInBuffer += 8;
if (_bitsInBuffer < count)
{
if (NeedsInput())
{
return false;
}
// insert a byte to bitbuffer
_bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
_bitsInBuffer += 8;
}
}
return true;
}
/// <summary>
/// This function will try to load 16 or more bits into bitBuffer.
/// It returns whatever is contained in bitBuffer after loading.
/// The main difference between this and GetBits is that this will
/// never return -1. So the caller needs to check AvailableBits to
/// see how many bits are available.
/// </summary>
public uint TryLoad16Bits()
{
if (_bitsInBuffer < 8)
{
if (_start < _end)
{
_bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
_bitsInBuffer += 8;
}
if (_start < _end)
{
_bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
_bitsInBuffer += 8;
}
}
else if (_bitsInBuffer < 16)
{
if (_start < _end)
{
_bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer;
_bitsInBuffer += 8;
}
}
return _bitBuffer;
}
private uint GetBitMask(int count) => ((uint)1 << count) - 1;
/// <summary>Gets count bits from the input buffer. Returns -1 if not enough bits available.</summary>
public int GetBits(int count)
{
Debug.Assert(0 < count && count <= 16, "count is invalid.");
if (!EnsureBitsAvailable(count))
{
return -1;
}
int result = (int)(_bitBuffer & GetBitMask(count));
_bitBuffer >>= count;
_bitsInBuffer -= count;
return result;
}
/// <summary>
/// Copies length bytes from input buffer to output buffer starting at output[offset].
/// You have to make sure, that the buffer is byte aligned. If not enough bytes are
/// available, copies fewer bytes.
/// </summary>
/// <returns>Returns the number of bytes copied, 0 if no byte is available.</returns>
public int CopyTo(byte[] output, int offset, int length)
{
Debug.Assert(output != null);
Debug.Assert(offset >= 0);
Debug.Assert(length >= 0);
Debug.Assert(offset <= output.Length - length);
Debug.Assert((_bitsInBuffer % 8) == 0);
// Copy the bytes in bitBuffer first.
int bytesFromBitBuffer = 0;
while (_bitsInBuffer > 0 && length > 0)
{
output[offset++] = (byte)_bitBuffer;
_bitBuffer >>= 8;
_bitsInBuffer -= 8;
length--;
bytesFromBitBuffer++;
}
if (length == 0)
{
return bytesFromBitBuffer;
}
int avail = _end - _start;
if (length > avail)
{
length = avail;
}
Array.Copy(_buffer, _start, output, offset, length);
_start += length;
return bytesFromBitBuffer + length;
}
/// <summary>
/// Return true is all input bytes are used.
/// This means the caller can call SetInput to add more input.
/// </summary>
public bool NeedsInput() => _start == _end;
/// <summary>
/// Set the byte array to be processed.
/// All the bits remained in bitBuffer will be processed before the new bytes.
/// We don't clone the byte array here since it is expensive.
/// The caller should make sure after a buffer is passed in.
/// It will not be changed before calling this function again.
/// </summary>
public void SetInput(byte[] buffer, int offset, int length)
{
Debug.Assert(buffer != null);
Debug.Assert(offset >= 0);
Debug.Assert(length >= 0);
Debug.Assert(offset <= buffer.Length - length);
Debug.Assert(_start == _end);
_buffer = buffer;
_start = offset;
_end = offset + length;
}
/// <summary>Skip n bits in the buffer.</summary>
public void SkipBits(int n)
{
Debug.Assert(_bitsInBuffer >= n, "No enough bits in the buffer, Did you call EnsureBitsAvailable?");
_bitBuffer >>= n;
_bitsInBuffer -= n;
}
/// <summary>Skips to the next byte boundary.</summary>
public void SkipToByteBoundary()
{
_bitBuffer >>= (_bitsInBuffer % 8);
_bitsInBuffer = _bitsInBuffer - (_bitsInBuffer % 8);
}
}
}

View File

@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Compress.Support.Compression.Deflate64
{
/// <summary>
/// This class represents a match in the history window.
/// </summary>
internal sealed class Match
{
internal MatchState State { get; set; }
internal int Position { get; set; }
internal int Length { get; set; }
internal byte Symbol { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Compress.Support.Compression.Deflate64
{
internal enum MatchState
{
HasSymbol = 1,
HasMatch = 2,
HasSymbolAndMatch = 3
}
}

View File

@@ -0,0 +1,151 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
namespace Compress.Support.Compression.Deflate64
{
/// <summary>
/// This class maintains a window for decompressed output.
/// We need to keep this because the decompressed information can be
/// a literal or a length/distance pair. For length/distance pair,
/// we need to look back in the output window and copy bytes from there.
/// We use a byte array of WindowSize circularly.
/// </summary>
internal sealed class OutputWindow
{
// With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at
// least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without
// overwriting existing data. OutputWindow requires that the WindowSize be an exponent of 2, so we round up to 2^18.
private const int WINDOW_SIZE = 262144;
private const int WINDOW_MASK = 262143;
private readonly byte[] _window = new byte[WINDOW_SIZE]; // The window is 2^18 bytes
private int _end; // this is the position to where we should write next byte
private int _bytesUsed; // The number of bytes in the output window which is not consumed.
/// <summary>Add a byte to output window.</summary>
public void Write(byte b)
{
Debug.Assert(_bytesUsed < WINDOW_SIZE, "Can't add byte when window is full!");
_window[_end++] = b;
_end &= WINDOW_MASK;
++_bytesUsed;
}
public void WriteLengthDistance(int length, int distance)
{
Debug.Assert((_bytesUsed + length) <= WINDOW_SIZE, "No Enough space");
// move backwards distance bytes in the output stream,
// and copy length bytes from this position to the output stream.
_bytesUsed += length;
int copyStart = (_end - distance) & WINDOW_MASK; // start position for coping.
int border = WINDOW_SIZE - length;
if (copyStart <= border && _end < border)
{
if (length <= distance)
{
Array.Copy(_window, copyStart, _window, _end, length);
_end += length;
}
else
{
// The referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream.
while (length-- > 0)
{
_window[_end++] = _window[copyStart++];
}
}
}
else
{
// copy byte by byte
while (length-- > 0)
{
_window[_end++] = _window[copyStart++];
_end &= WINDOW_MASK;
copyStart &= WINDOW_MASK;
}
}
}
/// <summary>
/// Copy up to length of bytes from input directly.
/// This is used for uncompressed block.
/// </summary>
public int CopyFrom(InputBuffer input, int length)
{
length = Math.Min(Math.Min(length, WINDOW_SIZE - _bytesUsed), input.AvailableBytes);
int copied;
// We might need wrap around to copy all bytes.
int tailLen = WINDOW_SIZE - _end;
if (length > tailLen)
{
// copy the first part
copied = input.CopyTo(_window, _end, tailLen);
if (copied == tailLen)
{
// only try to copy the second part if we have enough bytes in input
copied += input.CopyTo(_window, 0, length - tailLen);
}
}
else
{
// only one copy is needed if there is no wrap around.
copied = input.CopyTo(_window, _end, length);
}
_end = (_end + copied) & WINDOW_MASK;
_bytesUsed += copied;
return copied;
}
/// <summary>Free space in output window.</summary>
public int FreeBytes => WINDOW_SIZE - _bytesUsed;
/// <summary>Bytes not consumed in output window.</summary>
public int AvailableBytes => _bytesUsed;
/// <summary>Copy the decompressed bytes to output array.</summary>
public int CopyTo(byte[] output, int offset, int length)
{
int copyEnd;
if (length > _bytesUsed)
{
// we can copy all the decompressed bytes out
copyEnd = _end;
length = _bytesUsed;
}
else
{
copyEnd = (_end - _bytesUsed + length) & WINDOW_MASK; // copy length of bytes
}
int copied = length;
int tailLen = length - copyEnd;
if (tailLen > 0)
{
// this means we need to copy two parts separately
// copy tailLen bytes from the end of output window
Array.Copy(_window, WINDOW_SIZE - tailLen,
output, offset, tailLen);
offset += tailLen;
length = copyEnd;
}
Array.Copy(_window, copyEnd - length, output, offset, length);
_bytesUsed -= copied;
Debug.Assert(_bytesUsed >= 0, "check this function and find why we copied more bytes than we have");
return copied;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using Compress.SevenZip.Common;
namespace Compress.SevenZip.Compress.LZ
namespace Compress.Support.Compression.LZ
{
internal class BinTree : InWindow
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Compress.LZ
namespace Compress.Support.Compression.LZ
{
internal class InWindow
{

View File

@@ -1,6 +1,6 @@
using Compress.SevenZip.Common;
using Compress.Support.Compression.LZMA;
namespace Compress.SevenZip.Compress.LZ
namespace Compress.Support.Compression.LZ
{
internal class OutWindow
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Common
namespace Compress.Support.Compression.LZMA
{
/// <summary>
/// The exception that is thrown when an error in input stream occurs during decoding.
@@ -32,40 +32,6 @@ namespace Compress.SevenZip.Common
void SetProgress(Int64 inSize, Int64 outSize);
};
internal 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>
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.
@@ -134,19 +100,4 @@ namespace Compress.SevenZip.Common
EndMarker
};
internal interface ISetCoderProperties
{
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
};
internal interface IWriteCoderProperties
{
void WriteCoderProperties(System.IO.Stream outStream);
}
internal interface ISetDecoderProperties
{
void SetDecoderProperties(byte[] properties);
}
}

View File

@@ -1,4 +1,4 @@
namespace Compress.SevenZip.Compress.LZMA
namespace Compress.Support.Compression.LZMA
{
internal abstract class Base
{

View File

@@ -1,10 +1,9 @@
using System;
using Compress.SevenZip.Common;
using Compress.SevenZip.Compress.RangeCoder;
using Compress.Support.Compression.RangeCoder;
namespace Compress.SevenZip.Compress.LZMA
namespace Compress.Support.Compression.LZMA
{
internal class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
internal class Decoder
{
class LenDecoder
{

View File

@@ -1,11 +1,10 @@
using System;
using Compress.SevenZip.Common;
using Compress.SevenZip.Compress.RangeCoder;
using Compress.Support.Compression.RangeCoder;
namespace Compress.SevenZip.Compress.LZMA
namespace Compress.Support.Compression.LZMA
{
internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
internal class Encoder
{
enum EMatchFinderType
{

View File

@@ -1,6 +1,4 @@
using Compress.SevenZip.Common;
namespace Compress.SevenZip.Compress.LZMA
namespace Compress.Support.Compression.LZMA
{
public class LzmaEncoderProperties
{

View File

@@ -1,9 +1,8 @@
using System;
using System.IO;
using Compress.SevenZip.Common;
using Compress.SevenZip.Compress.LZ;
using Compress.Support.Compression.LZ;
namespace Compress.SevenZip.Compress.LZMA
namespace Compress.Support.Compression.LZMA
{
public class LzmaStream : Stream
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class FreqData : Pointer
{

View File

@@ -1,8 +1,8 @@
using System.IO;
using System.Text;
using Decoder = Compress.SevenZip.Compress.RangeCoder.Decoder;
using Decoder = Compress.Support.Compression.RangeCoder.Decoder;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class ModelPPM
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class PPMContext : Pointer
{

View File

@@ -1,5 +1,5 @@
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal abstract class Pointer
{

View File

@@ -1,7 +1,7 @@
using System.IO;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class RangeCoder
{

View File

@@ -1,5 +1,5 @@
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class RarMemBlock : Pointer
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class RarNode : Pointer
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class SEE2Context
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class State : Pointer
{

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class StateRef
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Text;
namespace Compress.SevenZip.Compress.PPmd.H
namespace Compress.Support.Compression.PPmd.H
{
internal class SubAllocator
{

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with

View File

@@ -4,7 +4,7 @@ using System.IO;
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// A simple range coder.

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// A structure containing a single address. The address represents a location in the <see cref="Memory"/>

View File

@@ -7,7 +7,7 @@ using System.IO;
// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1.
// Ported by Michael Bone (mjbone03@yahoo.com.au).
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// The model.

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// The method used to adjust the model when the memory limit is reached.

View File

@@ -4,7 +4,7 @@ using System;
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// A structure containing a single address representing a position in the <see cref="Memory"/> array. This

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// The PPM context structure. This is tightly coupled with <see cref="Model"/>.

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// PPM state.

View File

@@ -4,7 +4,7 @@
#endregion
namespace Compress.SevenZip.Compress.PPmd.I1
namespace Compress.Support.Compression.PPmd.I1
{
/// <summary>
/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols.

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Compress.PPmd
namespace Compress.Support.Compression.PPmd
{
public enum PpmdVersion
{

View File

@@ -1,8 +1,8 @@
using System;
using System.IO;
using Compress.SevenZip.Compress.RangeCoder;
using Compress.Support.Compression.RangeCoder;
namespace Compress.SevenZip.Compress.PPmd
namespace Compress.Support.Compression.PPmd
{
public class PpmdStream : Stream
{

View File

@@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
namespace Compress.SevenZip.Compress.PPmd
namespace Compress.Support.Compression.PPmd
{
internal static class Utility
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Compress.RangeCoder
namespace Compress.Support.Compression.RangeCoder
{
internal class Encoder
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Compress.RangeCoder
namespace Compress.Support.Compression.RangeCoder
{
internal struct BitEncoder
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.SevenZip.Compress.RangeCoder
namespace Compress.Support.Compression.RangeCoder
{
internal struct BitTreeEncoder
{

View File

@@ -0,0 +1,279 @@
namespace Compress.Support.Compression.SimpleInflate
{
public class Tree
{
public int[] Codes = new int[288];
public int[] num = new int[288];
public int[] bitLen = new int[288];
public int max;
public void Build(byte[] lens, int lensOffset, int symcount)
{
unchecked
{
int[] codes = new int[16];
int[] first = new int[16];
int[] counts = new int[16];
int endcount = lensOffset + symcount;
// Frequency count.
for (int n = lensOffset; n < endcount; n++)
counts[lens[n]]++;
// Distribute codes.
counts[0] = codes[0] = first[0] = 0;
for (int n = 1; n <= 15; n++)
{
codes[n] = (codes[n - 1] + counts[n - 1]) << 1;
first[n] = first[n - 1] + counts[n - 1];
}
// Insert keys into the tree for each symbol.
int lensOffsetLocal = lensOffset;
for (int n = 0; n < symcount; n++)
{
int len = lens[lensOffsetLocal++];
if (len == 0) continue;
int code = codes[len]++;
int slot = first[len]++;
Codes[slot] = code << (16 - len);
num[slot] = n;
bitLen[slot] = len;
}
max = first[15];
}
}
}
public class Inflate
{
private int _bits, _count;
private byte[] _bIn;
private int _indexIn; //public int endIn;
private byte[] _bOut;
private int _indexOut; //public int endOut;
private readonly Tree _dLitCodes = new Tree();
private readonly Tree _dDistCodes = new Tree();
private readonly Tree _lenCodes = new Tree();
private Tree _litCodes;
private Tree _distCodes;
private static readonly byte[] Order = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
private static readonly byte[] LenBits = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 };
private static readonly int[] LenBase = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };
private static readonly byte[] DistBits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 };
private static readonly int[] DistBase = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 };
// Table to bit-reverse a byte.
private static readonly byte[] ReverseTable = new byte[256];
// Static tables
private static readonly Tree SLitCodes = new Tree();
private static readonly Tree SDistCodes = new Tree();
static Inflate()
{
for (int i = 0; i < 256; i++)
{
ReverseTable[i] = (byte)(
((i & 0x80) >> 7) | ((i & 0x40) >> 5) | ((i & 0x20) >> 3) | ((i & 0x10) >> 1) |
((i & 0x08) << 1) | ((i & 0x04) << 3) | ((i & 0x02) << 5) | ((i & 0x01) << 7)
);
}
// Fixed set of Huffman codes.
byte[] lens = new byte[288 + 32];
int n;
for (n = 0; n <= 143; n++) lens[n] = 8;
for (n = 144; n <= 255; n++) lens[n] = 9;
for (n = 256; n <= 279; n++) lens[n] = 7;
for (n = 280; n <= 287; n++) lens[n] = 8;
for (n = 0; n < 32; n++) lens[288 + n] = 5;
SLitCodes.Build(lens, 0, 288);
SDistCodes.Build(lens, 288, 32);
}
public static int Rev16(int n)
{
return (ReverseTable[n & 0xff] << 8) | ReverseTable[(n >> 8) & 0xff];
}
private int Bits(int n)
{
int v = _bits & ((1 << n) - 1);
_bits >>= n;
_count -= n;
while (_count < 16)
{
_bits |= _bIn[_indexIn++] << _count;
_count += 8;
}
return v;
}
private void Copy(byte[] src, int index, int len)
{
while (len-- > 0)
{
_bOut[_indexOut++] = src[index++];
}
}
private int Decode(Tree tree)
{
unchecked
{
// Find the next prefix code.
int lo = 0;
int hi = tree.max;
int search = Rev16(_bits);
while (lo < hi)
{
int guess = (lo + hi) >> 1;
if (search < tree.Codes[guess]) hi = guess;
else lo = guess + 1;
}
Bits(tree.bitLen[lo - 1]);
return tree.num[lo - 1];
}
}
private void Run(int sym)
{
int length = Bits(LenBits[sym]) + LenBase[sym];
int dsym = Decode(_distCodes);
int offs = Bits(DistBits[dsym]) + DistBase[dsym];
Copy(_bOut, _indexOut - offs, length);
}
private void Block()
{
for (; ; )
{
int sym = Decode(_litCodes);
if (sym < 256)
{
_bOut[_indexOut++] = (byte)sym;
}
else if (sym > 256)
{
Run(sym - 257);
}
else // == 256
break;
}
}
private void Stored()
{
// Uncompressed data block.
// skip any remaining unused bits to get back byte aligned.
Bits(_count & 7);
// read the numbers of bytes to directly copy
int len = Bits(16);
// copy the input stream to the output stream for len bytes
Copy(_bIn, _indexIn, len);
_indexIn += len;
// reload the
Bits(16);
}
private void Fixed()
{
_litCodes = SLitCodes;
_distCodes = SDistCodes;
}
private void Dynamic()
{
unchecked
{
byte[] lenlens = new byte[19];
byte[] lens = new byte[288 + 32];
int nlit = 257 + Bits(5);
int ndist = 1 + Bits(5);
int nlen = 4 + Bits(4);
for (int n = 0; n < nlen; n++)
lenlens[Order[n]] = (byte)Bits(3);
// Build the tree for decoding code lengths.
_lenCodes.Build(lenlens, 0, 19);
// Decode code lengths.
for (int n = 0; n < nlit + ndist;)
{
int sym = Decode(_lenCodes);
switch (sym)
{
case 16:
for (int i = 3 + Bits(2); i > 0; i--, n++)
lens[n] = lens[n - 1];
break;
case 17:
for (int i = 3 + Bits(3); i > 0; i--, n++)
lens[n] = 0;
break;
case 18:
for (int i = 11 + Bits(7); i > 0; i--, n++)
lens[n] = 0;
break;
default:
lens[n++] = (byte)sym;
break;
}
}
// Build lit/dist trees.
_dLitCodes.Build(lens, 0, nlit);
_dDistCodes.Build(lens, nlit, ndist);
_litCodes = _dLitCodes;
_distCodes = _dDistCodes;
}
}
public int InflateBuffer(byte[] outbuffer, byte[] inbuffer)
{
int last;
// We assume we can buffer 2 extra bytes from off the end of 'in'.
_bIn = inbuffer;
_bOut = outbuffer;
_bits = 0;
_count = 0;
Bits(0);
do
{
last = Bits(1);
switch (Bits(2))
{
case 0: Stored(); break;
case 1: Fixed(); Block(); break;
case 2: Dynamic(); Block(); break; // 87% block()
//case 3:
default: throw new System.InvalidOperationException("Invalid Initial bits");
}
} while (last == 0);
return 1;
}
}
}

View File

@@ -0,0 +1,219 @@
/*
#include "tigr_internal.h"
#include <stdlib.h>
#include <setjmp.h>
typedef struct {
unsigned bits, count;
const unsigned char *in, *inend;
unsigned char *out, *outend;
jmp_buf jmp;
unsigned litcodes[288], distcodes[32], LenCodes[19];
int tlit, tdist, tlen;
} State;
#define FAIL() longjmp(s->jmp, 1)
#define CHECK(X) if (!(X)) FAIL()
// Built-in DEFLATE standard tables.
static char order[] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
static char lenBits[29+2] = { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0, 0,0 };
static int lenBase[29+2] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 0,0 };
static char distBits[30+2] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13, 0,0 };
static int distBase[30+2] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577 };
// Table to bit-reverse a byte.
static const unsigned char reverseTable[256] = {
#define R2(n) n, n + 128, n + 64, n + 192
#define R4(n) R2(n), R2(n + 32), R2(n + 16), R2(n + 48)
#define R6(n) R4(n), R4(n + 8), R4(n + 4), R4(n + 12)
R6(0), R6(2), R6(1), R6(3)
};
static unsigned rev16(unsigned n) { return (reverseTable[n&0xff] << 8) | reverseTable[(n>>8)&0xff]; }
static int bits(State *s, int n)
{
int v = s->bits & ((1 << n)-1);
s->bits >>= n;
s->count -= n;
while (s->count < 16)
{
CHECK(s->in != s->inend);
s->bits |= (*s->in++) << s->count;
s->count += 8;
}
return v;
}
static unsigned char *emit(State *s, int len)
{
s->out += len;
CHECK(s->out <= s->outend);
return s->out-len;
}
static void copy(State *s, const unsigned char *src, int len)
{
unsigned char *dest = emit(s, len);
while (len--) *dest++ = *src++;
}
static int build(State *s, unsigned *tree, unsigned char *lens, int symcount)
{
int n, codes[16], first[16], counts[16]={0};
// Frequency count.
for (n=0;n<symcount;n++) counts[lens[n]]++;
// Distribute codes.
counts[0] = codes[0] = first[0] = 0;
for (n=1;n<=15;n++) {
codes[n] = (codes[n-1] + counts[n-1]) << 1;
first[n] = first[n-1] + counts[n-1];
}
CHECK(first[15]+counts[15] <= symcount);
// Insert keys into the tree for each symbol.
for (n=0;n<symcount;n++)
{
int len = lens[n];
if (len != 0) {
int code = codes[len]++, slot = first[len]++;
tree[slot] = (code << (32-len)) | (n << 4) | len;
}
}
return first[15];
}
static int decode(State *s, unsigned tree[], int max)
{
// Find the next prefix code.
unsigned lo = 0, hi = max, key;
unsigned search = (rev16(s->bits) << 16) | 0xffff;
while (lo < hi) {
unsigned guess = (lo + hi) / 2;
if (search < tree[guess]) hi = guess;
else lo = guess + 1;
}
// Pull out the key and check it.
key = tree[lo-1];
CHECK(((search^key) >> (32-(key&0xf))) == 0);
bits(s, key & 0xf);
return (key >> 4) & 0xfff;
}
static void run(State *s, int sym)
{
int length = bits(s, lenBits[sym]) + lenBase[sym];
int dsym = decode(s, s->distcodes, s->tdist);
int offs = bits(s, distBits[dsym]) + distBase[dsym];
copy(s, s->out - offs, length);
}
static void block(State *s)
{
for (;;) {
int sym = decode(s, s->litcodes, s->tlit);
if (sym < 256) *emit(s, 1) = (unsigned char)sym;
else if (sym > 256) run(s, sym-257);
else break;
}
}
static void stored(State *s)
{
// Uncompressed data block.
int len;
bits(s, s->count & 7);
len = bits(s, 16);
CHECK(((len^s->bits)&0xffff) == 0xffff);
CHECK(s->in + len <= s->inend);
copy(s, s->in, len);
s->in += len;
bits(s, 16);
}
static void fixed(State *s)
{
// Fixed set of Huffman codes.
int n;
unsigned char lens[288+32];
for (n= 0;n<=143;n++) lens[n] = 8;
for (n=144;n<=255;n++) lens[n] = 9;
for (n=256;n<=279;n++) lens[n] = 7;
for (n=280;n<=287;n++) lens[n] = 8;
for (n=0;n<32;n++) lens[288+n] = 5;
// Build lit/dist trees.
s->tlit = build(s, s->litcodes, lens, 288);
s->tdist = build(s, s->distcodes, lens+288, 32);
}
static void dynamic(State *s)
{
int n, i, nlit, ndist, nlen;
unsigned char lenlens[19] = {0}, lens[288+32];
nlit = 257 + bits(s, 5);
ndist = 1 + bits(s, 5);
nlen = 4 + bits(s, 4);
for (n=0;n<nlen;n++)
lenlens[order[n]] = (unsigned char)bits(s, 3);
// Build the tree for decoding code lengths.
s->tlen = build(s, s->LenCodes, lenlens, 19);
// Decode code lengths.
for (n=0;n<nlit+ndist;)
{
int sym = decode(s, s->LenCodes, s->tlen);
switch (sym) {
case 16: for (i = 3+bits(s,2); i; i--,n++) lens[n] = lens[n-1]; break;
case 17: for (i = 3+bits(s,3); i; i--,n++) lens[n] = 0; break;
case 18: for (i = 11+bits(s,7); i; i--,n++) lens[n] = 0; break;
default: lens[n++] = (unsigned char)sym; break;
}
}
// Build lit/dist trees.
s->tlit = build(s, s->litcodes, lens, nlit);
s->tdist = build(s, s->distcodes, lens+nlit, ndist);
}
int tigrInflate(void *out, unsigned outlen, const void *in, unsigned inlen)
{
int last;
State *s = (State *)calloc(1, sizeof(State));
// We assume we can buffer 2 extra bytes from off the end of 'in'.
s->in = (unsigned char *)in; s->inend = s->in + inlen + 2;
s->out = (unsigned char *)out; s->outend = s->out + outlen;
s->bits = 0; s->count = 0; bits(s, 0);
if (setjmp(s->jmp) == 1) {
free(s);
return 0;
}
do {
last = bits(s, 1);
switch (bits(s, 2)) {
case 0: stored(s); break;
case 1: fixed(s); block(s); break;
case 2: dynamic(s); block(s); break;
case 3: FAIL();
}
} while(!last);
free(s);
return 1;
}
#undef CHECK
#undef FAIL
*/

View File

@@ -0,0 +1,64 @@
using System.IO;
namespace Compress.Support.Compression.zStd
{
// C# version of zstd
internal class zStdSharp : ZstdSharp.DecompressionStream
{
long pos = 0;
public zStdSharp(Stream stream, int bufferSize = 0) : base(stream, bufferSize)
{
pos = 0;
}
public override int Read(byte[] buffer, int offset, int count)
{
int read = base.Read(buffer, offset, count);
pos += read;
return read;
}
public override bool CanSeek => true;
public override long Position { get => pos; set => base.Position = value; }
public override long Seek(long offset, SeekOrigin origin)
{
long readLen;
switch (origin)
{
case SeekOrigin.Begin:
{
if (offset < pos)
{
// error connot go backwards
return -1;
}
readLen = offset - pos;
break;
}
case SeekOrigin.Current:
{
readLen = offset;
break;
}
default:
{
// unknown origin
return -1;
}
}
byte[] buffer = new byte[4096];
while(readLen>0)
{
int count = readLen > 4096 ? 4096 : (int)readLen;
int read = Read(buffer, 0, count);
readLen -= read;
}
return pos;
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
namespace Compress.SevenZip.Filters
namespace Compress.Support.Filters
{
public class BCJ2Filter : Stream
{

View File

@@ -1,6 +1,6 @@
using System.IO;
namespace Compress.SevenZip.Filters
namespace Compress.Support.Filters
{
public class BCJFilter : Filter
{

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
namespace Compress.SevenZip.Filters
namespace Compress.Support.Filters
{
public class Delta : Stream
{

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
namespace Compress.SevenZip.Filters
namespace Compress.Support.Filters
{
public abstract class Filter : Stream
{

View File

@@ -0,0 +1,115 @@
using Compress.SevenZip;
using Compress.ZipFile;
using System.IO;
using Directory = RVIO.Directory;
using FileStream = RVIO.FileStream;
using Path = RVIO.Path;
namespace Compress.Support.Utils
{
public delegate void MessageBack(string message);
public class ArchiveExtract
{
public MessageBack MessageCallBack = null;
public ArchiveExtract()
{ }
public ArchiveExtract(MessageBack messageCallBack)
{
MessageCallBack=messageCallBack;
}
public bool FullExtract(string filename, string outDir)
{
MessageCallBack?.Invoke($"Processing file: {filename}");
if (!string.IsNullOrEmpty(outDir))
MessageCallBack?.Invoke($"Output dir: {outDir}");
string ext = Path.GetExtension(filename);
ICompress z = null;
switch (ext.ToLower())
{
case ".zip":
z = new Zip();
break;
case ".7z":
z = new SevenZ();
break;
}
if (z == null)
{
MessageCallBack?.Invoke($"Unknown file type {ext}");
return false;
}
ZipReturn zRet = z.ZipFileOpen(filename);
if (zRet != ZipReturn.ZipGood)
{
MessageCallBack?.Invoke($"Error opening archive {zRet}");
return false;
}
ulong buflen = 409600;
byte[] buffer = new byte[buflen];
for (int i = 0; i < z.LocalFilesCount(); i++)
{
LocalFile lf = z.GetLocalFile(i);
byte[] cread = null;
string filenameOut = lf.Filename;
if (lf.IsDirectory)
{
string outFullDir = Path.Combine(outDir, filenameOut.Substring(0, filenameOut.Length - 1).Replace('/', '\\'));
Directory.CreateDirectory(outFullDir);
continue;
}
else
{
MessageCallBack?.Invoke($"Extracting {filenameOut}");
string fOut = Path.Combine(outDir, filenameOut.Replace('/', '\\'));
string dOut = Path.GetDirectoryName(fOut);
if (!string.IsNullOrWhiteSpace(dOut) && !Directory.Exists(dOut))
Directory.CreateDirectory(dOut);
int errorCode = FileStream.OpenFileWrite(fOut, out Stream sWrite);
if (errorCode != 0)
{
MessageCallBack?.Invoke($"Error opening outputfile {fOut}");
}
z.ZipFileOpenReadStream(i, out Stream sRead, out _);
CRC crc = new();
ulong sizeToGo = lf.UncompressedSize;
while (sizeToGo > 0)
{
ulong sizeNow = sizeToGo > buflen ? buflen : sizeToGo;
int sizeRead = sRead.Read(buffer, 0, (int)sizeNow);
crc.SlurpBlock(buffer, 0, sizeRead);
sWrite.Write(buffer, 0, sizeRead);
sizeToGo -= (ulong)sizeRead;
}
sWrite.Close();
sWrite.Dispose();
cread = crc.Crc32ResultB;
}
byte[] fread = lf.CRC;
if (cread[0] != fread[0] || cread[1] != fread[1] || cread[2] != fread[2] || cread[3] != fread[3])
{
MessageCallBack?.Invoke($"CRC error. Expected {fread.ToHex()} found {cread.ToHex()}");
return false;
}
}
return true;
}
}
}

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.Utils
namespace Compress.Support.Utils
{
public class CRC
{

View File

@@ -1,6 +1,6 @@
using System;
namespace Compress.Utils
namespace Compress.Support.Utils
{
class CRCStream
{

View File

@@ -1,5 +1,5 @@

namespace Compress.Utils
namespace Compress.Support.Utils
{
public static class Reporter
{
@@ -30,6 +30,20 @@ namespace Compress.Utils
return ret;
}
public static string ToHex(this byte[] arr)
{
if (arr == null)
return "NULL";
string ret = "";
for (int i = 0; i < arr.Length; i++)
{
ret += arr[i].ToString("X2");
}
return ret;
}
public static string ToHex(this uint? v)
{

View File

@@ -1,11 +1,12 @@
using System;
using System.Threading;
using Compress.Support.Utils;
namespace Compress.ThreadReaders
{
public class ThreadCRC : IDisposable
{
private Utils.CRC crc;
private CRC crc;
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
@@ -17,7 +18,7 @@ namespace Compress.ThreadReaders
public ThreadCRC()
{
crc=new Utils.CRC();
crc=new CRC();
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);
_finished = false;
@@ -56,6 +57,13 @@ namespace Compress.ThreadReaders
_size = size;
_waitEvent.Set();
}
public void TriggerOnce(byte[] buffer, int size)
{
crc.Reset();
_buffer = buffer;
_size = size;
_waitEvent.Set();
}
public void Wait()
{

View File

@@ -4,7 +4,7 @@ using System.Threading;
namespace Compress.ThreadReaders
{
public class ThreadLoadBuffer : IDisposable
public class ThreadReadBuffer : IDisposable
{
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
@@ -18,7 +18,7 @@ namespace Compress.ThreadReaders
public int SizeRead;
public ThreadLoadBuffer(Stream ds)
public ThreadReadBuffer(Stream ds)
{
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);

View File

@@ -0,0 +1,79 @@
using System;
using System.IO;
using System.Threading;
namespace Compress.ThreadReaders
{
public class ThreadWriteBuffer : IDisposable
{
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
private byte[] _buffer;
private int _size;
private readonly Stream _ds;
private bool _finished;
public bool errorState;
public int SizeRead;
public ThreadWriteBuffer(Stream ds)
{
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);
_finished = false;
_ds = ds;
errorState = false;
_tWorker = new Thread(MainLoop);
_tWorker.Start();
}
public void Dispose()
{
_waitEvent.Close();
_outEvent.Close();
}
private void MainLoop()
{
while (true)
{
_waitEvent.WaitOne();
if (_finished)
{
break;
}
try
{
_ds.Write(_buffer, 0, _size);
}
catch (Exception)
{
errorState = true;
}
_outEvent.Set();
}
}
public void Trigger(byte[] buffer, int size)
{
_buffer = buffer;
_size = size;
_waitEvent.Set();
}
public void Wait()
{
_outEvent.WaitOne();
}
public void Finish()
{
_finished = true;
_waitEvent.Set();
_tWorker.Join();
}
}
}

View File

@@ -1,4 +1,4 @@
namespace Compress.Utils
namespace Compress
{
public class TimeStamps
{

View File

@@ -1,24 +0,0 @@
using RVIO;
namespace Compress.Utils
{
public static class DirUtil
{
public static void CreateDirForFile(string sFilename)
{
string strTemp = Path.GetDirectoryName(sFilename);
if (string.IsNullOrEmpty(strTemp))
{
return;
}
if (Directory.Exists(strTemp))
{
return;
}
Directory.CreateDirectory(strTemp);
}
}
}

Some files were not shown because too many files have changed in this diff Show More