mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Sync Compress and RVIO with latest from RVWorld
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
52
SabreTools.FileTypes/Compress/LocalFile.cs
Normal file
52
SabreTools.FileTypes/Compress/LocalFile.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace Compress.SevenZip
|
||||
ZipFileCloseReadStream();
|
||||
_streamIndex = thisStreamIndex;
|
||||
|
||||
if (_header.StreamsInfo==null)
|
||||
if (_header.StreamsInfo == null)
|
||||
{
|
||||
stream = null;
|
||||
return ZipReturn.ZipGood;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.Folders = new Folder[_packedOutStreams.Count];
|
||||
for (int i = 0; i < _packedOutStreams.Count; i++)
|
||||
{
|
||||
_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
|
||||
ulong unpackedStreamSize = 0;
|
||||
foreach (UnpackedStreamInfo v in _packedOutStreams[i].unpackedStreams)
|
||||
unpackedStreamSize += v.UnpackedSize;
|
||||
|
||||
if (_compressed != sevenZipCompressType.uncompressed)
|
||||
{
|
||||
//StreamsInfo.Folders
|
||||
_header.StreamsInfo.Folders = new Folder[1];
|
||||
|
||||
//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))
|
||||
{
|
||||
_header.WriteHeader(headerBw);
|
||||
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);
|
||||
}
|
||||
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
|
||||
#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))
|
||||
{
|
||||
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
||||
streamsInfo.WriteHeader(bw);
|
||||
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);
|
||||
|
||||
}
|
||||
newHeaderByte = new byte[headerMem.Length];
|
||||
headerMem.Position = 0;
|
||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||
}
|
||||
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||
#endregion
|
||||
#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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
@@ -97,20 +96,18 @@ namespace Compress.SevenZip.Structure
|
||||
|
||||
|
||||
byte[] namebyte;
|
||||
using (MemoryStream nameMem = new MemoryStream())
|
||||
using (MemoryStream nameMem = new())
|
||||
{
|
||||
using (BinaryWriter nameBw = new BinaryWriter(nameMem, Encoding.UTF8, true))
|
||||
using BinaryWriter nameBw = new(nameMem, Encoding.UTF8, true);
|
||||
nameBw.Write((byte)0); //not external
|
||||
foreach (string name in Names)
|
||||
{
|
||||
nameBw.Write((byte)0); //not external
|
||||
foreach (string name in Names)
|
||||
{
|
||||
nameBw.WriteName(name);
|
||||
}
|
||||
|
||||
namebyte = new byte[nameMem.Length];
|
||||
nameMem.Position = 0;
|
||||
nameMem.Read(namebyte, 0, namebyte.Length);
|
||||
nameBw.WriteName(name);
|
||||
}
|
||||
|
||||
namebyte = new byte[nameMem.Length];
|
||||
nameMem.Position = 0;
|
||||
nameMem.Read(namebyte, 0, namebyte.Length);
|
||||
}
|
||||
|
||||
bw.Write((byte)HeaderProperty.kName);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,56 +49,54 @@ 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)
|
||||
{
|
||||
HeaderProperty hp = (HeaderProperty)br.ReadByte();
|
||||
switch (hp)
|
||||
{
|
||||
case HeaderProperty.kEncodedHeader:
|
||||
case HeaderProperty.kEncodedHeader:
|
||||
{
|
||||
StreamsInfo streamsInfo = new();
|
||||
streamsInfo.Read(br);
|
||||
|
||||
if (streamsInfo.Folders.Length > 1)
|
||||
{
|
||||
StreamsInfo streamsInfo = new StreamsInfo();
|
||||
streamsInfo.Read(br);
|
||||
|
||||
if (streamsInfo.Folders.Length > 1)
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
Folder firstFolder = streamsInfo.Folders[0];
|
||||
if (firstFolder.Coders.Length > 1)
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
byte[] method = firstFolder.Coders[0].Method;
|
||||
if (!((method.Length == 3) && (method[0] == 3) && (method[1] == 1) && (method[2] == 1))) // LZMA
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
stream.Seek(baseOffset + (long)streamsInfo.PackPosition, SeekOrigin.Begin);
|
||||
using (LzmaStream decoder = new LzmaStream(firstFolder.Coders[0].Properties, stream))
|
||||
{
|
||||
ZipReturn zr = ReadHeaderOrPackedHeader(decoder, baseOffset, out header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
case HeaderProperty.kHeader:
|
||||
Folder firstFolder = streamsInfo.Folders[0];
|
||||
if (firstFolder.Coders.Length > 1)
|
||||
{
|
||||
header = new Header();
|
||||
header.Read(br);
|
||||
return ZipReturn.ZipGood;
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
byte[] method = firstFolder.Coders[0].Method;
|
||||
if (!((method.Length == 3) && (method[0] == 3) && (method[1] == 1) && (method[2] == 1))) // LZMA
|
||||
{
|
||||
return ZipReturn.ZipUnsupportedCompression;
|
||||
}
|
||||
|
||||
stream.Seek(baseOffset + (long)streamsInfo.PackPosition, SeekOrigin.Begin);
|
||||
using (LzmaStream decoder = new(firstFolder.Coders[0].Properties, stream))
|
||||
{
|
||||
ZipReturn zr = ReadHeaderOrPackedHeader(decoder, baseOffset, out header);
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
case HeaderProperty.kHeader:
|
||||
{
|
||||
header = new Header();
|
||||
header.Read(br);
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
}
|
||||
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
public void Report(ref StringBuilder sb)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
using Compress.Support.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Compress.Support.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
internal class SignatureHeader
|
||||
{
|
||||
private static readonly byte[] Signature = {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
||||
private byte _major;
|
||||
private byte _minor;
|
||||
private static readonly byte[] Signature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
|
||||
private uint _startHeaderCRC;
|
||||
|
||||
@@ -22,34 +20,32 @@ 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))
|
||||
{
|
||||
byte[] signatureBytes = br.ReadBytes(6);
|
||||
if (!signatureBytes.Compare(Signature))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_major = br.ReadByte();
|
||||
_minor = br.ReadByte();
|
||||
|
||||
_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))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
br.BaseStream.Seek(pos, SeekOrigin.Begin);
|
||||
|
||||
NextHeaderOffset = br.ReadUInt64();
|
||||
NextHeaderSize = br.ReadUInt64();
|
||||
NextHeaderCRC = br.ReadUInt32();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
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 (!CRC.VerifyDigest(_startHeaderCRC, mainHeader, 0, (uint)mainHeader.Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
br.BaseStream.Seek(pos, SeekOrigin.Begin);
|
||||
|
||||
NextHeaderOffset = br.ReadUInt64();
|
||||
NextHeaderSize = br.ReadUInt64();
|
||||
NextHeaderCRC = br.ReadUInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter bw)
|
||||
@@ -61,18 +57,18 @@ namespace Compress.SevenZip.Structure
|
||||
|
||||
//ArchiveVersion
|
||||
//{
|
||||
bw.Write((byte) 0); // BYTE Major
|
||||
bw.Write((byte) 3); // BYTE Minor
|
||||
bw.Write((byte)0); // BYTE Major
|
||||
bw.Write((byte)3); // BYTE Minor
|
||||
//};
|
||||
|
||||
_crcOffset = bw.BaseStream.Position;
|
||||
bw.Write((uint) 0); //HeaderCRC
|
||||
bw.Write((uint)0); //HeaderCRC
|
||||
|
||||
//StartHeader
|
||||
//{
|
||||
bw.Write((ulong) 0); //NextHeaderOffset
|
||||
bw.Write((ulong) 0); //NextHeaderSize
|
||||
bw.Write((uint) 0); //NextHeaderCRC
|
||||
bw.Write((ulong)0); //NextHeaderOffset
|
||||
bw.Write((ulong)0); //NextHeaderSize
|
||||
bw.Write((uint)0); //NextHeaderCRC
|
||||
//}
|
||||
|
||||
BaseOffset = bw.BaseStream.Position;
|
||||
@@ -84,21 +80,19 @@ namespace Compress.SevenZip.Structure
|
||||
|
||||
|
||||
byte[] sigHeaderBytes;
|
||||
using (MemoryStream sigHeaderMem = new MemoryStream())
|
||||
using (MemoryStream sigHeaderMem = new())
|
||||
{
|
||||
using (BinaryWriter sigHeaderBw = new BinaryWriter(sigHeaderMem,Encoding.UTF8,true))
|
||||
{
|
||||
sigHeaderBw.Write((ulong) ((long) headerpos - BaseOffset)); //NextHeaderOffset
|
||||
sigHeaderBw.Write(headerLength); //NextHeaderSize
|
||||
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
|
||||
using BinaryWriter sigHeaderBw = new(sigHeaderMem, Encoding.UTF8, true);
|
||||
sigHeaderBw.Write((ulong)((long)headerpos - BaseOffset)); //NextHeaderOffset
|
||||
sigHeaderBw.Write(headerLength); //NextHeaderSize
|
||||
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
|
||||
|
||||
sigHeaderBytes = new byte[sigHeaderMem.Length];
|
||||
sigHeaderMem.Position = 0;
|
||||
sigHeaderMem.Read(sigHeaderBytes, 0, sigHeaderBytes.Length);
|
||||
}
|
||||
sigHeaderBytes = new byte[sigHeaderMem.Length];
|
||||
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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Text;
|
||||
using Compress.Utils;
|
||||
using Compress.Support.Utils;
|
||||
|
||||
namespace Compress.SevenZip.Structure
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
namespace Compress.Support.Compression.Deflate
|
||||
{
|
||||
|
||||
internal enum BlockState
|
||||
@@ -545,10 +545,10 @@ namespace Compress.ZipFile.ZLib
|
||||
internal void send_tree(short[] tree, int max_code)
|
||||
{
|
||||
int n; // iterates over all tree elements
|
||||
int prevlen = -1; // last emitted length
|
||||
int prevlen = -1; // last emitted length
|
||||
int curlen; // length of current code
|
||||
int nextlen = tree[0 * 2 + 1]; // length of next code
|
||||
int count = 0; // repeat count of the current code
|
||||
int nextlen = tree[0 * 2 + 1]; // length of next code
|
||||
int count = 0; // repeat count of the current code
|
||||
int max_count = 7; // max repeat count
|
||||
int min_count = 4; // min repeat count
|
||||
|
||||
@@ -731,23 +731,23 @@ namespace Compress.ZipFile.ZLib
|
||||
* *
|
||||
* *************************************************************
|
||||
*/
|
||||
if (false) //CompSettings
|
||||
//CompSettings
|
||||
/*
|
||||
if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2)
|
||||
{
|
||||
if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2)
|
||||
// Compute an upper bound for the compressed length
|
||||
int out_length = last_lit << 3;
|
||||
int in_length = strstart - block_start;
|
||||
int dcode;
|
||||
for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++)
|
||||
{
|
||||
// Compute an upper bound for the compressed length
|
||||
int out_length = last_lit << 3;
|
||||
int in_length = strstart - block_start;
|
||||
int dcode;
|
||||
for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++)
|
||||
{
|
||||
out_length = (int)(out_length + (int)dyn_dtree[dcode * 2] * (5L + Tree.ExtraDistanceBits[dcode]));
|
||||
}
|
||||
out_length >>= 3;
|
||||
if ((matches < (last_lit / 2)) && out_length < in_length / 2)
|
||||
return true;
|
||||
out_length = (int)(out_length + (int)dyn_dtree[dcode * 2] * (5L + Tree.ExtraDistanceBits[dcode]));
|
||||
}
|
||||
out_length >>= 3;
|
||||
if ((matches < (last_lit / 2)) && out_length < in_length / 2)
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize);
|
||||
// dinoch - wraparound?
|
||||
@@ -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.
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
namespace Compress.Support.Compression.Deflate
|
||||
{
|
||||
sealed class InflateBlocks
|
||||
{
|
||||
@@ -61,7 +61,7 @@
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
namespace Compress.Support.Compression.Deflate
|
||||
{
|
||||
sealed class Tree
|
||||
{
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
namespace Compress.Support.Compression.Deflate
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
@@ -61,7 +61,7 @@
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace Compress.ZipFile.ZLib
|
||||
namespace Compress.Support.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// A bunch of constants used in the Zlib interface.
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() { }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Compress.SevenZip.Common;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZ
|
||||
namespace Compress.Support.Compression.LZ
|
||||
{
|
||||
internal class BinTree : InWindow
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZ
|
||||
namespace Compress.Support.Compression.LZ
|
||||
{
|
||||
internal class InWindow
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
namespace Compress.Support.Compression.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,6 +1,4 @@
|
||||
using Compress.SevenZip.Common;
|
||||
|
||||
namespace Compress.SevenZip.Compress.LZMA
|
||||
namespace Compress.Support.Compression.LZMA
|
||||
{
|
||||
public class LzmaEncoderProperties
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class FreqData : Pointer
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class PPMContext : Pointer
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal abstract class Pointer
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class RarMemBlock : Pointer
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class RarNode : Pointer
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class SEE2Context
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class StateRef
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.H
|
||||
namespace Compress.Support.Compression.PPmd.H
|
||||
{
|
||||
internal class SubAllocator
|
||||
{
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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"/>
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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"/>.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
||||
namespace Compress.Support.Compression.PPmd.I1
|
||||
{
|
||||
/// <summary>
|
||||
/// PPM state.
|
||||
@@ -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.
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.PPmd
|
||||
namespace Compress.Support.Compression.PPmd
|
||||
{
|
||||
public enum PpmdVersion
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
namespace Compress.Support.Compression.RangeCoder
|
||||
{
|
||||
internal class Encoder
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
namespace Compress.Support.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitEncoder
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.SevenZip.Compress.RangeCoder
|
||||
namespace Compress.Support.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitTreeEncoder
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
namespace Compress.Support.Filters
|
||||
{
|
||||
public class BCJ2Filter : Stream
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
namespace Compress.Support.Filters
|
||||
{
|
||||
public class BCJFilter : Filter
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
namespace Compress.Support.Filters
|
||||
{
|
||||
public class Delta : Stream
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Compress.SevenZip.Filters
|
||||
namespace Compress.Support.Filters
|
||||
{
|
||||
public abstract class Filter : Stream
|
||||
{
|
||||
115
SabreTools.FileTypes/Compress/Support/Utils/ArchiveExtract.cs
Normal file
115
SabreTools.FileTypes/Compress/Support/Utils/ArchiveExtract.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.Utils
|
||||
namespace Compress.Support.Utils
|
||||
{
|
||||
public class CRC
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Compress.Utils
|
||||
namespace Compress.Support.Utils
|
||||
{
|
||||
class CRCStream
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Compress.Utils
|
||||
namespace Compress
|
||||
{
|
||||
public class TimeStamps
|
||||
{
|
||||
@@ -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
Reference in New Issue
Block a user