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 SabreTools.IO;
|
||||||
using Compress;
|
using Compress;
|
||||||
using Compress.gZip;
|
using Compress.gZip;
|
||||||
using Compress.ZipFile.ZLib;
|
using Compress.Support.Compression.Deflate;
|
||||||
|
|
||||||
namespace SabreTools.FileTypes.Archives
|
namespace SabreTools.FileTypes.Archives
|
||||||
{
|
{
|
||||||
@@ -240,7 +240,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn ret = gz.ZipFileOpen(this.Filename);
|
ZipReturn ret = gz.ZipFileOpen(this.Filename);
|
||||||
ret = gz.ZipFileOpenReadStream(0, out Stream gzstream, out ulong streamSize);
|
ret = gz.ZipFileOpenReadStream(0, out Stream gzstream, out ulong streamSize);
|
||||||
gzipEntryRom = GetInfo(gzstream, hashes: this.AvailableHashes);
|
gzipEntryRom = GetInfo(gzstream, hashes: this.AvailableHashes);
|
||||||
gzipEntryRom.Filename = gz.Filename(0);
|
gzipEntryRom.Filename = gz.GetLocalFile(0).Filename;
|
||||||
gzipEntryRom.Parent = gamename;
|
gzipEntryRom.Parent = gamename;
|
||||||
gzipEntryRom.Date = (gz.TimeStamp > 0 ? gz.TimeStamp.ToString() : null);
|
gzipEntryRom.Date = (gz.TimeStamp > 0 ? gz.TimeStamp.ToString() : null);
|
||||||
gzstream.Dispose();
|
gzstream.Dispose();
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ using SabreTools.Core;
|
|||||||
using SabreTools.Core.Tools;
|
using SabreTools.Core.Tools;
|
||||||
using Compress;
|
using Compress;
|
||||||
using Compress.SevenZip;
|
using Compress.SevenZip;
|
||||||
using Compress.Utils;
|
|
||||||
using Compress.ZipFile;
|
|
||||||
using NaturalSort;
|
using NaturalSort;
|
||||||
|
|
||||||
namespace SabreTools.FileTypes.Archives
|
namespace SabreTools.FileTypes.Archives
|
||||||
@@ -75,7 +73,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
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++)
|
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);
|
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
|
||||||
|
|
||||||
// Create the rest of the path, if needed
|
// 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 the entry ends with a directory separator, continue to the next item, if any
|
||||||
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
if (zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
|
||||||
{
|
{
|
||||||
zf.ZipFileCloseReadStream();
|
zf.ZipFileCloseReadStream();
|
||||||
continue;
|
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 the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||||
if (streamsize < _bufferSize)
|
if (streamsize < _bufferSize)
|
||||||
@@ -198,15 +196,15 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
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++)
|
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
|
// Open the read stream
|
||||||
realEntry = zf.Filename(i);
|
realEntry = zf.GetLocalFile(i).Filename;
|
||||||
zr = zf.ZipFileOpenReadStream(i, out Stream readStream, out ulong streamsize);
|
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
|
// 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);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
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 the entry is a directory (or looks like a directory), we don't want to open it
|
||||||
if (zf.IsDirectory(i)
|
if (zf.GetLocalFile(i).IsDirectory
|
||||||
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -298,17 +296,17 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
// Perform a quickscan, if flagged to
|
// Perform a quickscan, if flagged to
|
||||||
if (this.AvailableHashes == Hash.CRC)
|
if (this.AvailableHashes == Hash.CRC)
|
||||||
{
|
{
|
||||||
zipEntryRom.Size = (long)zf.UncompressedSize(i);
|
zipEntryRom.Size = (long)zf.GetLocalFile(i).UncompressedSize;
|
||||||
zipEntryRom.CRC = zf.CRC32(i);
|
zipEntryRom.CRC = zf.GetLocalFile(i).CRC;
|
||||||
}
|
}
|
||||||
// Otherwise, use the stream directly
|
// Otherwise, use the stream directly
|
||||||
else
|
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
|
// Fill in comon details and add to the list
|
||||||
zipEntryRom.Filename = zf.Filename(i);
|
zipEntryRom.Filename = zf.GetLocalFile(i).Filename;
|
||||||
zipEntryRom.Parent = gamename;
|
zipEntryRom.Parent = gamename;
|
||||||
found.Add(zipEntryRom);
|
found.Add(zipEntryRom);
|
||||||
}
|
}
|
||||||
@@ -337,13 +335,13 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(string, bool)> zipEntries = new();
|
List<(string, bool)> zipEntries = new();
|
||||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
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();
|
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);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return zf.ZipStatus == ZipStatus.Trrnt7Zip;
|
return zf.ZipStatus == ZipStatus.Trrnt7Zip;
|
||||||
@@ -474,7 +472,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
var oldZipFileContents = new List<string>();
|
var oldZipFileContents = new List<string>();
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Then add all of the old entries to it too
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -544,7 +542,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
{
|
{
|
||||||
// Instantiate the streams
|
// Instantiate the streams
|
||||||
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
|
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
|
// Copy the input stream to the output
|
||||||
byte[] ibuffer = new byte[_bufferSize];
|
byte[] ibuffer = new byte[_bufferSize];
|
||||||
@@ -556,7 +554,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldZipFile.ZipFileCloseReadStream();
|
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
|
// Sort the keys in TZIP order
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Now add all of the files in order
|
// Now add all of the files in order
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -694,7 +692,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
var oldZipFileContents = new List<string>();
|
var oldZipFileContents = new List<string>();
|
||||||
for (int j = 0; j < oldZipFile.LocalFilesCount(); j++)
|
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
|
// 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
|
// Then add all of the old entries to it too
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -768,7 +766,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
{
|
{
|
||||||
// Instantiate the streams
|
// Instantiate the streams
|
||||||
oldZipFile.ZipFileOpenReadStream(index, out Stream zreadStream, out ulong istreamSize);
|
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
|
// Copy the input stream to the output
|
||||||
byte[] ibuffer = new byte[_bufferSize];
|
byte[] ibuffer = new byte[_bufferSize];
|
||||||
@@ -779,7 +777,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
writeStream.Flush();
|
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;
|
||||||
using SabreTools.Core.Tools;
|
using SabreTools.Core.Tools;
|
||||||
using Compress.ZipFile;
|
using Compress;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Tar;
|
using SharpCompress.Archives.Tar;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
@@ -330,7 +330,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
|
|
||||||
// Get the order for the entries with the new file
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -444,7 +444,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
|
|
||||||
// Sort the keys in TZIP order
|
// Sort the keys in TZIP order
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Now add all of the files in order
|
// Now add all of the files in order
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -499,7 +499,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
|
|
||||||
// Get the order for the entries with the new file
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using SabreTools.Core;
|
using SabreTools.Core;
|
||||||
using SabreTools.Core.Tools;
|
using SabreTools.Core.Tools;
|
||||||
using Compress;
|
using Compress;
|
||||||
using Compress.Utils;
|
|
||||||
using Compress.ZipFile;
|
using Compress.ZipFile;
|
||||||
using NaturalSort;
|
using NaturalSort;
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
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++)
|
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);
|
zr = zf.ZipFileOpenReadStream(i, false, out Stream readStream, out ulong streamsize, out ushort cm);
|
||||||
|
|
||||||
// Create the rest of the path, if needed
|
// 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 the entry ends with a directory separator, continue to the next item, if any
|
||||||
if (zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
if (zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
|
||||||
{
|
{
|
||||||
zf.ZipFileCloseReadStream();
|
zf.ZipFileCloseReadStream();
|
||||||
continue;
|
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 the stream is smaller than the buffer, just run one loop through to avoid issues
|
||||||
if (streamsize < _bufferSize)
|
if (streamsize < _bufferSize)
|
||||||
@@ -209,15 +208,15 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
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++)
|
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
|
// 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);
|
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
|
// 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);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
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 the entry is a directory (or looks like a directory), we don't want to open it
|
||||||
if (zf.IsDirectory(i)
|
if (zf.GetLocalFile(i).IsDirectory
|
||||||
|| zf.Filename(i).EndsWith(Path.DirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.AltDirectorySeparatorChar.ToString())
|
||||||
|| zf.Filename(i).EndsWith(Path.PathSeparator.ToString()))
|
|| zf.GetLocalFile(i).Filename.EndsWith(Path.PathSeparator.ToString()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -309,19 +308,19 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
// Perform a quickscan, if flagged to
|
// Perform a quickscan, if flagged to
|
||||||
if (this.AvailableHashes == Hash.CRC)
|
if (this.AvailableHashes == Hash.CRC)
|
||||||
{
|
{
|
||||||
zipEntryRom.Size = (long)zf.UncompressedSize(i);
|
zipEntryRom.Size = (long)zf.GetLocalFile(i).UncompressedSize;
|
||||||
zipEntryRom.CRC = zf.CRC32(i);
|
zipEntryRom.CRC = zf.GetLocalFile(i).CRC;
|
||||||
}
|
}
|
||||||
// Otherwise, use the stream directly
|
// Otherwise, use the stream directly
|
||||||
else
|
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
|
// Fill in comon details and add to the list
|
||||||
zipEntryRom.Filename = zf.Filename(i);
|
zipEntryRom.Filename = zf.GetLocalFile(i).Filename;
|
||||||
zipEntryRom.Parent = gamename;
|
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);
|
found.Add(zipEntryRom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,13 +348,13 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(string, bool)> zipEntries = new();
|
List<(string, bool)> zipEntries = new();
|
||||||
for (int i = 0; i < zf.LocalFilesCount(); i++)
|
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();
|
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);
|
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
|
||||||
if (zr != ZipReturn.ZipGood)
|
if (zr != ZipReturn.ZipGood)
|
||||||
{
|
{
|
||||||
throw new Exception(ZipUtils.ZipErrorMessageText(zr));
|
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return zf.ZipStatus == ZipStatus.TrrntZip;
|
return zf.ZipStatus == ZipStatus.TrrntZip;
|
||||||
@@ -486,7 +485,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
var oldZipFileContents = new List<string>();
|
var oldZipFileContents = new List<string>();
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Then add all of the old entries to it too
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -554,9 +553,9 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
{
|
{
|
||||||
// Instantiate the streams
|
// Instantiate the streams
|
||||||
oldZipFile.ZipFileOpenReadStream(index, false, out Stream zreadStream, out ulong istreamSize, out ushort icompressionMethod);
|
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 };
|
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
|
// Copy the input stream to the output
|
||||||
byte[] ibuffer = new byte[_bufferSize];
|
byte[] ibuffer = new byte[_bufferSize];
|
||||||
@@ -568,7 +567,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldZipFile.ZipFileCloseReadStream();
|
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
|
// Sort the keys in TZIP order
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Now add all of the files in order
|
// Now add all of the files in order
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -706,7 +705,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
var oldZipFileContents = new List<string>();
|
var oldZipFileContents = new List<string>();
|
||||||
for (int j = 0; j < oldZipFile.LocalFilesCount(); j++)
|
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
|
// 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
|
// Then add all of the old entries to it too
|
||||||
for (int i = 0; i < oldZipFile.LocalFilesCount(); i++)
|
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
|
// 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
|
// Get the order for the entries with the new file
|
||||||
List<string> keys = inputIndexMap.Keys.ToList();
|
List<string> keys = inputIndexMap.Keys.ToList();
|
||||||
keys.Sort(ZipUtils.TrrntZipStringCompare);
|
keys.Sort(CompressUtils.TrrntZipStringCompare);
|
||||||
|
|
||||||
// Copy over all files to the new archive
|
// Copy over all files to the new archive
|
||||||
foreach (string key in keys)
|
foreach (string key in keys)
|
||||||
@@ -780,9 +779,9 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
{
|
{
|
||||||
// Instantiate the streams
|
// Instantiate the streams
|
||||||
oldZipFile.ZipFileOpenReadStream(index, false, out Stream zreadStream, out ulong istreamSize, out ushort icompressionMethod);
|
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 };
|
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
|
// Copy the input stream to the output
|
||||||
byte[] ibuffer = new byte[_bufferSize];
|
byte[] ibuffer = new byte[_bufferSize];
|
||||||
@@ -793,7 +792,7 @@ namespace SabreTools.FileTypes.Archives
|
|||||||
writeStream.Flush();
|
writeStream.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
zipFile.ZipFileCloseWriteStream(oldZipFile.CRC32(index));
|
zipFile.ZipFileCloseWriteStream(oldZipFile.GetLocalFile(index).CRC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,31 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
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;
|
private static Encoding enc = null;
|
||||||
|
|
||||||
public static void EncodeSetup()
|
public static void EncodeSetup()
|
||||||
@@ -154,7 +173,7 @@ namespace Compress.ZipFile
|
|||||||
ret = "";
|
ret = "";
|
||||||
break;
|
break;
|
||||||
case ZipReturn.ZipFileCountError:
|
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;
|
break;
|
||||||
case ZipReturn.ZipSignatureError:
|
case ZipReturn.ZipSignatureError:
|
||||||
ret = "An unknown Signature Block was found in the Zip";
|
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";
|
ret = "Extra Data was found on the end of the Zip";
|
||||||
break;
|
break;
|
||||||
case ZipReturn.ZipUnsupportedCompression:
|
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;
|
break;
|
||||||
case ZipReturn.ZipLocalFileHeaderError:
|
case ZipReturn.ZipLocalFileHeaderError:
|
||||||
ret = "Error reading a zipped file header information";
|
ret = "Error reading a zipped file header information";
|
||||||
break;
|
break;
|
||||||
case ZipReturn.ZipCentralDirError:
|
case ZipReturn.ZipCentralDirError:
|
||||||
ret = "There is an error in the Zip Centeral Directory";
|
ret = "There is an error in the Zip Central Directory";
|
||||||
break;
|
break;
|
||||||
case ZipReturn.ZipReadingFromOutputFile:
|
case ZipReturn.ZipReadingFromOutputFile:
|
||||||
ret = "Trying to write to a Zip file open for output only";
|
ret = "Trying to write to a Zip file open for output only";
|
||||||
break;
|
break;
|
||||||
case ZipReturn.ZipWritingToInputFile:
|
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;
|
break;
|
||||||
case ZipReturn.ZipErrorGettingDataStream:
|
case ZipReturn.ZipErrorGettingDataStream:
|
||||||
ret = "Error creating Data Stream";
|
ret = "Error creating Data Stream";
|
||||||
@@ -190,32 +209,34 @@ namespace Compress.ZipFile
|
|||||||
|
|
||||||
return ret;
|
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 TicksPerMillisecond = 10000;
|
||||||
private const long TicksPerSecond = TicksPerMillisecond * 1000;
|
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);
|
DateTime dateTime = new(ticks, DateTimeKind.Unspecified);
|
||||||
DosFileDate = (ushort)((DateTime.Day & 0x1f) | ((DateTime.Month & 0x0f) << 5) | (((DateTime.Year - 1980) & 0x7f) << 9));
|
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));
|
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;
|
return 0;
|
||||||
|
|
||||||
int second = (DosFileTime & 0x1f) << 1;
|
int second = (dosFileTime & 0x1f) << 1;
|
||||||
int minute = (DosFileTime >> 5) & 0x3f;
|
int minute = (dosFileTime >> 5) & 0x3f;
|
||||||
int hour = (DosFileTime >> 11) & 0x1f;
|
int hour = (dosFileTime >> 11) & 0x1f;
|
||||||
|
|
||||||
int day = DosFileDate & 0x1f;
|
int day = dosFileDate & 0x1f;
|
||||||
int month = (DosFileDate >> 5) & 0x0f;
|
int month = (dosFileDate >> 5) & 0x0f;
|
||||||
int year = ((DosFileDate >> 9) & 0x7f) + 1980;
|
int year = ((dosFileDate >> 9) & 0x7f) + 1980;
|
||||||
|
|
||||||
// valid hours 0 to 23
|
// valid hours 0 to 23
|
||||||
// valid minutes 0 to 59
|
// valid minutes 0 to 59
|
||||||
@@ -235,15 +256,24 @@ namespace Compress.ZipFile
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static long UtcTicksToNtfsDateTime(long ticks)
|
||||||
public static long FileTimeToUTCTime(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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
using Path = RVIO.Path;
|
using Path = RVIO.Path;
|
||||||
using FileInfo = RVIO.FileInfo;
|
using FileInfo = RVIO.FileInfo;
|
||||||
using FileStream = RVIO.FileStream;
|
using FileStream = RVIO.FileStream;
|
||||||
@@ -27,39 +27,20 @@ namespace Compress.File
|
|||||||
return 1;
|
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 lf;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZipReturn ZipFileCreate(string newFilename)
|
public ZipReturn ZipFileCreate(string newFilename)
|
||||||
@@ -69,7 +50,7 @@ namespace Compress.File
|
|||||||
return ZipReturn.ZipFileAlreadyOpen;
|
return ZipReturn.ZipFileAlreadyOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirUtil.CreateDirForFile(newFilename);
|
CompressUtils.CreateDirForFile(newFilename);
|
||||||
_fileInfo = new FileInfo(newFilename);
|
_fileInfo = new FileInfo(newFilename);
|
||||||
|
|
||||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _inStream);
|
int errorCode = FileStream.OpenFileWrite(newFilename, out _inStream);
|
||||||
@@ -139,7 +120,7 @@ namespace Compress.File
|
|||||||
if (errorCode != 0)
|
if (errorCode != 0)
|
||||||
{
|
{
|
||||||
ZipFileClose();
|
ZipFileClose();
|
||||||
if (errorCode == 32)
|
if (errorCode == 32 || errorCode==5)
|
||||||
{
|
{
|
||||||
return ZipReturn.ZipFileLocked;
|
return ZipReturn.ZipFileLocked;
|
||||||
}
|
}
|
||||||
@@ -158,12 +139,6 @@ namespace Compress.File
|
|||||||
}
|
}
|
||||||
ZipOpen = ZipOpenType.OpenRead;
|
ZipOpen = ZipOpenType.OpenRead;
|
||||||
|
|
||||||
if (!readHeaders)
|
|
||||||
{
|
|
||||||
return ZipReturn.ZipGood;
|
|
||||||
}
|
|
||||||
|
|
||||||
//return ZipFileReadHeaders();
|
|
||||||
return ZipReturn.ZipGood;
|
return ZipReturn.ZipGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +170,7 @@ namespace Compress.File
|
|||||||
|
|
||||||
public void ZipFileCloseFailed()
|
public void ZipFileCloseFailed()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize)
|
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong streamSize)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress
|
namespace Compress
|
||||||
{
|
{
|
||||||
@@ -8,14 +8,7 @@ namespace Compress
|
|||||||
{
|
{
|
||||||
int LocalFilesCount();
|
int LocalFilesCount();
|
||||||
|
|
||||||
string Filename(int i);
|
LocalFile GetLocalFile(int i);
|
||||||
ulong? LocalHeader(int i);
|
|
||||||
ulong UncompressedSize(int i);
|
|
||||||
byte[] CRC32(int i);
|
|
||||||
|
|
||||||
long LastModified(int i);
|
|
||||||
|
|
||||||
bool IsDirectory(int i);
|
|
||||||
|
|
||||||
ZipOpenType ZipOpen { get; }
|
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.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.SevenZip.Compress.ZSTD;
|
|
||||||
using Compress.SevenZip.Structure;
|
using Compress.SevenZip.Structure;
|
||||||
using FileInfo = RVIO.FileInfo;
|
using FileInfo = RVIO.FileInfo;
|
||||||
|
|
||||||
@@ -11,47 +9,21 @@ namespace Compress.SevenZip
|
|||||||
public partial class SevenZ : ICompress
|
public partial class SevenZ : ICompress
|
||||||
{
|
{
|
||||||
|
|
||||||
public enum sevenZipCompressType
|
public enum SevenZipCompressType
|
||||||
{
|
{
|
||||||
uncompressed,
|
uncompressed,
|
||||||
lzma,
|
lzma,
|
||||||
zstd
|
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 int StreamIndex;
|
||||||
public ulong StreamOffset;
|
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;
|
private FileInfo _zipFileInfo;
|
||||||
|
|
||||||
@@ -59,7 +31,6 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
private SignatureHeader _signatureHeader;
|
private SignatureHeader _signatureHeader;
|
||||||
|
|
||||||
private sevenZipCompressType _compressed = sevenZipCompressType.lzma;
|
|
||||||
|
|
||||||
|
|
||||||
private long _baseOffset;
|
private long _baseOffset;
|
||||||
@@ -76,40 +47,9 @@ namespace Compress.SevenZip
|
|||||||
return _localFiles.Count;
|
return _localFiles.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Filename(int i)
|
public LocalFile GetLocalFile(int i)
|
||||||
{
|
{
|
||||||
return _localFiles[i].FileName;
|
return _localFiles[i];
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ZipFileCloseFailed()
|
public void ZipFileCloseFailed()
|
||||||
@@ -139,20 +79,6 @@ namespace Compress.SevenZip
|
|||||||
ZipOpen = ZipOpenType.Closed;
|
ZipOpen = ZipOpenType.Closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsDirectory(int i)
|
|
||||||
{
|
|
||||||
return _localFiles[i].IsDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void ZipFileClose()
|
public void ZipFileClose()
|
||||||
{
|
{
|
||||||
@@ -184,7 +110,7 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
public StringBuilder HeaderReport()
|
public StringBuilder HeaderReport()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
if (_header == null)
|
if (_header == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Compress.SevenZip.Structure;
|
using Compress.SevenZip.Structure;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
using FileInfo = RVIO.FileInfo;
|
using FileInfo = RVIO.FileInfo;
|
||||||
using FileStream = RVIO.FileStream;
|
using FileStream = RVIO.FileStream;
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ namespace Compress.SevenZip
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SignatureHeader signatureHeader = new SignatureHeader();
|
SignatureHeader signatureHeader = new();
|
||||||
if (!signatureHeader.Read(_zipFs))
|
if (!signatureHeader.Read(_zipFs))
|
||||||
{
|
{
|
||||||
return ZipReturn.ZipSignatureError;
|
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 emptyFileIndex = 0;
|
||||||
int folderIndex = 0;
|
int folderIndex = 0;
|
||||||
int unpackedStreamsIndex = 0;
|
int unpackedStreamsIndex = 0;
|
||||||
ulong streamOffset = 0;
|
ulong streamOffset = 0;
|
||||||
localFiles = new List<LocalFile>();
|
localFiles = new List<SevenZipLocalFile>();
|
||||||
|
|
||||||
if (_header == null)
|
if (_header == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
|
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])
|
if ((_header.FileInfo.EmptyStreamFlags == null) || !_header.FileInfo.EmptyStreamFlags[i])
|
||||||
{
|
{
|
||||||
lf.StreamIndex = folderIndex;
|
lf.StreamIndex = folderIndex;
|
||||||
lf.StreamOffset = streamOffset;
|
lf.StreamOffset = streamOffset;
|
||||||
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
|
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;
|
streamOffset += lf.UncompressedSize;
|
||||||
unpackedStreamsIndex++;
|
unpackedStreamsIndex++;
|
||||||
@@ -155,17 +155,19 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
if (lf.IsDirectory)
|
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)
|
if (_header.FileInfo.TimeLastWrite != null)
|
||||||
{
|
lf.ModifiedTime = DateTime.FromFileTimeUtc((long)_header.FileInfo.TimeLastWrite[i]).Ticks;
|
||||||
lf.LastModified = 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);
|
localFiles.Add(lf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
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.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;
|
using FileStream = RVIO.FileStream;
|
||||||
|
|
||||||
namespace Compress.SevenZip
|
namespace Compress.SevenZip
|
||||||
@@ -20,7 +20,7 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
|
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;
|
stream = null;
|
||||||
unCompressedSize = 0;
|
unCompressedSize = 0;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ namespace Compress.SevenZip
|
|||||||
return ZipReturn.ZipErrorGettingDataStream;
|
return ZipReturn.ZipErrorGettingDataStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsDirectory(index))
|
if (GetLocalFile(index).IsDirectory)
|
||||||
{
|
{
|
||||||
return ZipReturn.ZipTryingToAccessADirectory;
|
return ZipReturn.ZipTryingToAccessADirectory;
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ namespace Compress.SevenZip
|
|||||||
ZipFileCloseReadStream();
|
ZipFileCloseReadStream();
|
||||||
_streamIndex = thisStreamIndex;
|
_streamIndex = thisStreamIndex;
|
||||||
|
|
||||||
if (_header.StreamsInfo==null)
|
if (_header.StreamsInfo == null)
|
||||||
{
|
{
|
||||||
stream = null;
|
stream = null;
|
||||||
return ZipReturn.ZipGood;
|
return ZipReturn.ZipGood;
|
||||||
@@ -61,7 +61,7 @@ namespace Compress.SevenZip
|
|||||||
// first make the List of Decompressors streams
|
// first make the List of Decompressors streams
|
||||||
int codersNeeded = folder.Coders.Length;
|
int codersNeeded = folder.Coders.Length;
|
||||||
|
|
||||||
List<InStreamSourceInfo> allInputStreams = new List<InStreamSourceInfo>();
|
List<InStreamSourceInfo> allInputStreams = new();
|
||||||
for (int i = 0; i < codersNeeded; i++)
|
for (int i = 0; i < codersNeeded; i++)
|
||||||
{
|
{
|
||||||
folder.Coders[i].DecoderStream = null;
|
folder.Coders[i].DecoderStream = null;
|
||||||
@@ -96,7 +96,7 @@ namespace Compress.SevenZip
|
|||||||
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
|
allInputStreams[(int)folder.PackedStreamIndices[i]].InStreamIndex = packedStreamIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Stream> inputCoders = new List<Stream>();
|
List<Stream> inputCoders = new();
|
||||||
|
|
||||||
bool allCodersComplete = false;
|
bool allCodersComplete = false;
|
||||||
while (!allCodersComplete)
|
while (!allCodersComplete)
|
||||||
@@ -164,7 +164,7 @@ namespace Compress.SevenZip
|
|||||||
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
|
coder.DecoderStream = new BCJ2Filter(inputCoders[0], inputCoders[1], inputCoders[2], inputCoders[3]);
|
||||||
break;
|
break;
|
||||||
case DecompressType.ZSTD:
|
case DecompressType.ZSTD:
|
||||||
coder.DecoderStream = new ZstandardStream(inputCoders[0], CompressionMode.Decompress, true);
|
coder.DecoderStream =new zStdSharp(inputCoders[0]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ZipReturn.ZipDecodeError;
|
return ZipReturn.ZipDecodeError;
|
||||||
@@ -217,7 +217,7 @@ namespace Compress.SevenZip
|
|||||||
memStream.Position = 0;
|
memStream.Position = 0;
|
||||||
byte[] newStream = new byte[memStream.Length];
|
byte[] newStream = new byte[memStream.Length];
|
||||||
memStream.Read(newStream, 0, (int)memStream.Length);
|
memStream.Read(newStream, 0, (int)memStream.Length);
|
||||||
MemoryStream ret = new MemoryStream(newStream, false);
|
MemoryStream ret = new(newStream, false);
|
||||||
memStream.Position = pos;
|
memStream.Position = pos;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip
|
namespace Compress.SevenZip
|
||||||
{
|
{
|
||||||
@@ -36,9 +37,10 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
const string sig = "RomVault7Z01";
|
const string sig = "RomVault7Z01";
|
||||||
byte[] rv7Zid = Util.Enc.GetBytes(sig);
|
byte[] rv7Zid = Util.Enc.GetBytes(sig);
|
||||||
|
|
||||||
byte[] header = new byte[12];
|
byte[] header = new byte[12];
|
||||||
_zipFs.Read(header, 0, 12);
|
_zipFs.Read(header, 0, 12);
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < 12; i++)
|
for (int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
if (header[i] != rv7Zid[i])
|
if (header[i] != rv7Zid[i])
|
||||||
@@ -50,7 +52,7 @@ namespace Compress.SevenZip
|
|||||||
uint headerCRC;
|
uint headerCRC;
|
||||||
ulong headerOffset; // is location of header in file
|
ulong headerOffset; // is location of header in file
|
||||||
ulong headerSize;
|
ulong headerSize;
|
||||||
using (BinaryReader br = new BinaryReader(_zipFs, Encoding.UTF8, true))
|
using (BinaryReader br = new(_zipFs, Encoding.UTF8, true))
|
||||||
{
|
{
|
||||||
headerCRC = br.ReadUInt32();
|
headerCRC = br.ReadUInt32();
|
||||||
headerOffset = br.ReadUInt64();
|
headerOffset = br.ReadUInt64();
|
||||||
@@ -65,6 +67,7 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
return headerSize == testHeaderLength;
|
return headerSize == testHeaderLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Istorrent7Z()
|
private bool Istorrent7Z()
|
||||||
{
|
{
|
||||||
const int crcsz = 128;
|
const int crcsz = 128;
|
||||||
@@ -84,7 +87,7 @@ namespace Compress.SevenZip
|
|||||||
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
|
int ar = _zipFs.Read(buffer, bufferPos, crcsz);
|
||||||
if (ar < crcsz)
|
if (ar < crcsz)
|
||||||
{
|
{
|
||||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
Util.MemSet(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||||
}
|
}
|
||||||
bufferPos = crcsz;
|
bufferPos = crcsz;
|
||||||
|
|
||||||
@@ -105,12 +108,12 @@ namespace Compress.SevenZip
|
|||||||
{
|
{
|
||||||
ar = kSignatureSize;
|
ar = kSignatureSize;
|
||||||
}
|
}
|
||||||
Util.memset(buffer, bufferPos + ar, 0, crcsz - ar);
|
Util.MemSet(buffer, bufferPos + ar, 0, crcsz - ar);
|
||||||
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
|
Util.MemCrypt(buffer, crcsz * 2 + 8, buffer, bufferPos + ar, t7ZsigSize + 4);
|
||||||
}
|
}
|
||||||
else
|
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;
|
foffs = _zipFs.Length;
|
||||||
@@ -121,15 +124,15 @@ namespace Compress.SevenZip
|
|||||||
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
||||||
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
||||||
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
||||||
buffer[crcsz * 2 + 4] = 0;
|
buffer[crcsz * 2 + 4] = (byte)((foffs >> 32) & 0xff);
|
||||||
buffer[crcsz * 2 + 5] = 0;
|
buffer[crcsz * 2 + 5] = (byte)((foffs >> 40) & 0xff);
|
||||||
buffer[crcsz * 2 + 6] = 0;
|
buffer[crcsz * 2 + 6] = (byte)((foffs >> 48) & 0xff);
|
||||||
buffer[crcsz * 2 + 7] = 0;
|
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];
|
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] +
|
uint inCrc32 = (uint)(buffer[crcsz * 2 + 8 + 0] +
|
||||||
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
||||||
@@ -141,7 +144,7 @@ namespace Compress.SevenZip
|
|||||||
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
||||||
buffer[crcsz * 2 + 8 + 3] = 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)
|
if (inCrc32 == calcCrc32)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.SevenZip.Compress.LZMA;
|
|
||||||
using Compress.SevenZip.Compress.ZSTD;
|
|
||||||
using Compress.SevenZip.Structure;
|
using Compress.SevenZip.Structure;
|
||||||
using Compress.Utils;
|
using Compress.Support.Compression.LZMA;
|
||||||
using FileInfo = RVIO.FileInfo;
|
using FileInfo = RVIO.FileInfo;
|
||||||
using FileStream = RVIO.FileStream;
|
using FileStream = RVIO.FileStream;
|
||||||
|
|
||||||
@@ -11,37 +10,40 @@ namespace Compress.SevenZip
|
|||||||
{
|
{
|
||||||
public partial class SevenZ
|
public partial class SevenZ
|
||||||
{
|
{
|
||||||
private Stream _lzmaStream;
|
private Stream _compressStream;
|
||||||
private ulong _packStreamStart;
|
|
||||||
private ulong _packStreamSize;
|
|
||||||
private ulong _unpackedStreamSize;
|
|
||||||
private byte[] _codeMSbytes;
|
|
||||||
|
|
||||||
|
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)
|
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));
|
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)
|
if (ZipOpen != ZipOpenType.Closed)
|
||||||
{
|
{
|
||||||
return ZipReturn.ZipFileAlreadyOpen;
|
return ZipReturn.ZipFileAlreadyOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirUtil.CreateDirForFile(newFilename);
|
CompressUtils.CreateDirForFile(newFilename);
|
||||||
_zipFileInfo = new FileInfo(newFilename);
|
_zipFileInfo = new FileInfo(newFilename);
|
||||||
|
|
||||||
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
int errorCode = FileStream.OpenFileWrite(newFilename, out _zipFs);
|
||||||
@@ -55,31 +57,56 @@ namespace Compress.SevenZip
|
|||||||
_signatureHeader = new SignatureHeader();
|
_signatureHeader = new SignatureHeader();
|
||||||
_header = new Header();
|
_header = new Header();
|
||||||
|
|
||||||
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
using (BinaryWriter bw = new(_zipFs, Encoding.UTF8, true))
|
||||||
{
|
{
|
||||||
_signatureHeader.Write(bw);
|
_signatureHeader.Write(bw);
|
||||||
}
|
}
|
||||||
|
|
||||||
_baseOffset = _zipFs.Position;
|
_baseOffset = _zipFs.Position;
|
||||||
|
|
||||||
_compressed = compressOutput;
|
|
||||||
|
|
||||||
_unpackedStreamSize = 0;
|
_packedOutStreams = new List<outStreams>();
|
||||||
if (_compressed == sevenZipCompressType.lzma)
|
|
||||||
|
_compType = compressOutput;
|
||||||
|
|
||||||
|
#if solid
|
||||||
|
outStreams newStream = new()
|
||||||
{
|
{
|
||||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, dictionarySize, numFastBytes);
|
packedStart = (ulong)_zipFs.Position,
|
||||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
compType = compressOutput,
|
||||||
_codeMSbytes = lzs.Properties;
|
packedSize = 0,
|
||||||
_lzmaStream = lzs;
|
unpackedStreams = new List<UnpackedStreamInfo>()
|
||||||
_packStreamStart = (ulong)_zipFs.Position;
|
};
|
||||||
}
|
switch (compressOutput)
|
||||||
else if (_compressed == sevenZipCompressType.zstd)
|
|
||||||
{
|
{
|
||||||
ZstandardStream zss = new ZstandardStream(_zipFs, 18, true);
|
case SevenZipCompressType.lzma:
|
||||||
_codeMSbytes = new byte[] { 1, 4, 18, 0, 0 };
|
LzmaEncoderProperties ep = new(true, dictionarySize, numFastBytes);
|
||||||
_lzmaStream = zss;
|
LzmaStream lzs = new(ep, false, _zipFs);
|
||||||
_packStreamStart = (ulong)_zipFs.Position;
|
|
||||||
|
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;
|
return ZipReturn.ZipGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,14 +116,14 @@ namespace Compress.SevenZip
|
|||||||
if (fName.Substring(fName.Length - 1, 1) == @"/")
|
if (fName.Substring(fName.Length - 1, 1) == @"/")
|
||||||
fName = fName.Substring(0, fName.Length - 1);
|
fName = fName.Substring(0, fName.Length - 1);
|
||||||
|
|
||||||
LocalFile lf = new LocalFile
|
SevenZipLocalFile lf = new()
|
||||||
{
|
{
|
||||||
FileName = fName,
|
Filename = fName,
|
||||||
UncompressedSize = 0,
|
UncompressedSize = 0,
|
||||||
IsDirectory = true,
|
IsDirectory = true
|
||||||
StreamOffset = 0
|
|
||||||
};
|
};
|
||||||
_localFiles.Add(lf);
|
_localFiles.Add(lf);
|
||||||
|
unpackedStreamInfo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ZipFileAddZeroLengthFile()
|
public void ZipFileAddZeroLengthFile()
|
||||||
@@ -104,36 +131,100 @@ namespace Compress.SevenZip
|
|||||||
// do nothing here for 7zip
|
// 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)
|
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream, TimeStamps dateTime)
|
||||||
{
|
{
|
||||||
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
|
// check if we are writing a directory
|
||||||
}
|
|
||||||
|
|
||||||
private ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
|
|
||||||
{
|
|
||||||
LocalFile lf = new LocalFile
|
|
||||||
{
|
|
||||||
FileName = filename,
|
|
||||||
UncompressedSize = uncompressedSize,
|
|
||||||
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
|
|
||||||
};
|
|
||||||
if (uncompressedSize == 0 && filename.Substring(filename.Length - 1, 1) == "/")
|
if (uncompressedSize == 0 && filename.Substring(filename.Length - 1, 1) == "/")
|
||||||
{
|
{
|
||||||
lf.FileName = filename.Substring(0, filename.Length - 1);
|
ZipFileAddDirectory(filename);
|
||||||
lf.IsDirectory = true;
|
stream = null;
|
||||||
|
return ZipReturn.ZipGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
_unpackedStreamSize += uncompressedSize;
|
SevenZipLocalFile localFile = new()
|
||||||
|
{
|
||||||
|
Filename = filename,
|
||||||
|
UncompressedSize = uncompressedSize
|
||||||
|
};
|
||||||
|
_localFiles.Add(localFile);
|
||||||
|
|
||||||
_localFiles.Add(lf);
|
if (uncompressedSize == 0)
|
||||||
stream = _compressed == sevenZipCompressType.uncompressed ? _zipFs : _lzmaStream;
|
{
|
||||||
|
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;
|
return ZipReturn.ZipGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
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;
|
return ZipReturn.ZipGood;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.SevenZip.Compress.LZMA;
|
|
||||||
using Compress.SevenZip.Compress.ZSTD;
|
|
||||||
using Compress.SevenZip.Structure;
|
using Compress.SevenZip.Structure;
|
||||||
using Compress.Utils;
|
using Compress.Support.Compression.LZMA;
|
||||||
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip
|
namespace Compress.SevenZip
|
||||||
{
|
{
|
||||||
@@ -23,7 +22,7 @@ namespace Compress.SevenZip
|
|||||||
ulong emptyFileCount = 0;
|
ulong emptyFileCount = 0;
|
||||||
for (int i = 0; i < fileCount; i++)
|
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)
|
if (_localFiles[i].UncompressedSize != 0)
|
||||||
{
|
{
|
||||||
@@ -37,7 +36,6 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
emptyStreamCount += 1;
|
emptyStreamCount += 1;
|
||||||
}
|
}
|
||||||
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
|
||||||
|
|
||||||
_header.FileInfo.EmptyStreamFlags = null;
|
_header.FileInfo.EmptyStreamFlags = null;
|
||||||
_header.FileInfo.EmptyFileFlags = null;
|
_header.FileInfo.EmptyFileFlags = null;
|
||||||
@@ -82,158 +80,75 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
|
|
||||||
//StreamsInfo
|
//StreamsInfo
|
||||||
|
|
||||||
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
||||||
|
|
||||||
//StreamsInfo.PackedStreamsInfo
|
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[_packedOutStreams.Count];
|
||||||
if (_compressed!=sevenZipCompressType.uncompressed)
|
for (int i = 0; i < _packedOutStreams.Count; i++)
|
||||||
{
|
{
|
||||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
_header.StreamsInfo.PackedStreams[i] = new PackedStreamInfo { PackedSize = _packedOutStreams[i].packedSize };
|
||||||
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
_header.StreamsInfo.Folders = new Folder[_packedOutStreams.Count];
|
||||||
|
for (int i = 0; i < _packedOutStreams.Count; i++)
|
||||||
{
|
{
|
||||||
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
ulong unpackedStreamSize = 0;
|
||||||
int fileIndex = 0;
|
foreach (UnpackedStreamInfo v in _packedOutStreams[i].unpackedStreams)
|
||||||
for (int i = 0; i < fileCount; i++)
|
unpackedStreamSize += v.UnpackedSize;
|
||||||
{
|
|
||||||
if (_localFiles[i].UncompressedSize == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
|
||||||
|
|
||||||
if (_compressed != sevenZipCompressType.uncompressed)
|
_header.StreamsInfo.Folders[i] = new Folder()
|
||||||
{
|
|
||||||
//StreamsInfo.Folders
|
|
||||||
_header.StreamsInfo.Folders = new Folder[1];
|
|
||||||
|
|
||||||
//StreamsInfo.Folders.Coder
|
|
||||||
// flags 0x23
|
|
||||||
|
|
||||||
Folder folder = new Folder
|
|
||||||
{
|
{
|
||||||
BindPairs = null,
|
BindPairs = null,
|
||||||
Coders = new[] {
|
Coders = new Coder[] {
|
||||||
new Coder {
|
new Coder {
|
||||||
Method = new byte[] { 3, 1, 1 },
|
Method = _packedOutStreams[i].Method,
|
||||||
NumInStreams = 1,
|
NumInStreams = 1,
|
||||||
NumOutStreams = 1,
|
NumOutStreams = 1,
|
||||||
Properties = _codeMSbytes
|
Properties = _packedOutStreams[i].Properties
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PackedStreamIndices = new[] { (ulong)0 },
|
PackedStreamIndices = new ulong[] { (ulong)i },
|
||||||
UnpackedStreamSizes = new[] { _unpackedStreamSize },
|
UnpackedStreamSizes = new ulong[] { unpackedStreamSize },
|
||||||
UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount],
|
UnpackedStreamInfo = _packedOutStreams[i].unpackedStreams.ToArray(),
|
||||||
UnpackCRC = null
|
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()
|
private void CloseWriting7Zip()
|
||||||
{
|
{
|
||||||
if (_compressed != sevenZipCompressType.uncompressed)
|
#if solid
|
||||||
|
if (_packedOutStreams[0].compType != SevenZipCompressType.uncompressed)
|
||||||
{
|
{
|
||||||
_lzmaStream.Flush();
|
_compressStream.Flush();
|
||||||
_lzmaStream.Close();
|
_compressStream.Close();
|
||||||
}
|
}
|
||||||
|
_packedOutStreams[0].packedSize = (ulong)_zipFs.Position - _packedOutStreams[0].packedStart;
|
||||||
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
|
#endif
|
||||||
|
|
||||||
Create7ZStructure();
|
Create7ZStructure();
|
||||||
|
|
||||||
byte[] newHeaderByte;
|
byte[] newHeaderByte;
|
||||||
using (Stream headerMem = new MemoryStream())
|
using (Stream headerMem = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
using BinaryWriter headerBw = new(headerMem, Encoding.UTF8, true);
|
||||||
{
|
_header.WriteHeader(headerBw);
|
||||||
_header.WriteHeader(headerBw);
|
|
||||||
|
|
||||||
newHeaderByte = new byte[headerMem.Length];
|
newHeaderByte = new byte[headerMem.Length];
|
||||||
headerMem.Position = 0;
|
headerMem.Position = 0;
|
||||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
||||||
|
|
||||||
#region Header Compression
|
#region Header Compression
|
||||||
long packedHeaderPos = _zipFs.Position;
|
long packedHeaderPos = _zipFs.Position;
|
||||||
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
|
LzmaEncoderProperties ep = new(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
|
||||||
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
LzmaStream lzs = new(ep, false, _zipFs);
|
||||||
byte[] lzmaStreamProperties = lzs.Properties;
|
byte[] lzmaStreamProperties = lzs.Properties;
|
||||||
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
||||||
lzs.Close();
|
lzs.Close();
|
||||||
|
|
||||||
StreamsInfo streamsInfo = new StreamsInfo
|
StreamsInfo streamsInfo = new()
|
||||||
{
|
{
|
||||||
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
|
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
|
||||||
Folders = new[] {
|
Folders = new[] {
|
||||||
@@ -262,22 +177,19 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
using (Stream headerMem = new MemoryStream())
|
using (Stream headerMem = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (BinaryWriter bw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
using BinaryWriter bw = new(headerMem, Encoding.UTF8, true);
|
||||||
{
|
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
||||||
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
streamsInfo.WriteHeader(bw);
|
||||||
streamsInfo.WriteHeader(bw);
|
|
||||||
|
|
||||||
newHeaderByte = new byte[headerMem.Length];
|
newHeaderByte = new byte[headerMem.Length];
|
||||||
headerMem.Position = 0;
|
headerMem.Position = 0;
|
||||||
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)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
|
ulong headerPosition = (ulong)_zipFs.Position + 32; //tzip header is 32 bytes
|
||||||
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ namespace Compress.SevenZip.Structure
|
|||||||
{
|
{
|
||||||
DecoderType = DecompressType.LZMA2;
|
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;
|
DecoderType = DecompressType.ZSTD;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
@@ -97,20 +96,18 @@ namespace Compress.SevenZip.Structure
|
|||||||
|
|
||||||
|
|
||||||
byte[] namebyte;
|
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
|
nameBw.WriteName(name);
|
||||||
foreach (string name in Names)
|
|
||||||
{
|
|
||||||
nameBw.WriteName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
namebyte = new byte[nameMem.Length];
|
|
||||||
nameMem.Position = 0;
|
|
||||||
nameMem.Read(namebyte, 0, namebyte.Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namebyte = new byte[nameMem.Length];
|
||||||
|
nameMem.Position = 0;
|
||||||
|
nameMem.Read(namebyte, 0, namebyte.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bw.Write((byte)HeaderProperty.kName);
|
bw.Write((byte)HeaderProperty.kName);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
@@ -175,8 +175,7 @@ namespace Compress.SevenZip.Structure
|
|||||||
|
|
||||||
case HeaderProperty.kCRC:
|
case HeaderProperty.kCRC:
|
||||||
{
|
{
|
||||||
uint?[] crcs;
|
Util.UnPackCRCs(br, (ulong)Folders.Length, out uint?[] crcs);
|
||||||
Util.UnPackCRCs(br, (ulong)Folders.Length, out crcs);
|
|
||||||
for (int i = 0; i < Folders.Length; i++)
|
for (int i = 0; i < Folders.Length; i++)
|
||||||
{
|
{
|
||||||
Folders[i].UnpackCRC = crcs[i];
|
Folders[i].UnpackCRC = crcs[i];
|
||||||
@@ -250,8 +249,10 @@ namespace Compress.SevenZip.Structure
|
|||||||
if (folder.UnpackedStreamInfo == null)
|
if (folder.UnpackedStreamInfo == null)
|
||||||
{
|
{
|
||||||
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
|
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
|
||||||
folder.UnpackedStreamInfo[0] = new UnpackedStreamInfo();
|
folder.UnpackedStreamInfo[0] = new UnpackedStreamInfo
|
||||||
folder.UnpackedStreamInfo[0].UnpackedSize = folder.GetUnpackSize();
|
{
|
||||||
|
UnpackedSize = folder.GetUnpackSize()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((folder.UnpackedStreamInfo.Length != 1) || !folder.UnpackCRC.HasValue)
|
if ((folder.UnpackedStreamInfo.Length != 1) || !folder.UnpackCRC.HasValue)
|
||||||
@@ -261,8 +262,7 @@ namespace Compress.SevenZip.Structure
|
|||||||
}
|
}
|
||||||
|
|
||||||
int crcIndex = 0;
|
int crcIndex = 0;
|
||||||
uint?[] crc;
|
Util.UnPackCRCs(br, numCRC, out uint?[] crc);
|
||||||
Util.UnPackCRCs(br, numCRC, out crc);
|
|
||||||
for (uint i = 0; i < Folders.Length; i++)
|
for (uint i = 0; i < Folders.Length; i++)
|
||||||
{
|
{
|
||||||
Folder folder = Folders[i];
|
Folder folder = Folders[i];
|
||||||
@@ -384,7 +384,7 @@ namespace Compress.SevenZip.Structure
|
|||||||
Folder folder = Folders[f];
|
Folder folder = Folders[f];
|
||||||
for (int i = 0; i < folder.UnpackedStreamInfo.Length; i++)
|
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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.SevenZip.Compress.LZMA;
|
using Compress.Support.Compression.LZMA;
|
||||||
using Compress.Utils;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
@@ -50,56 +49,54 @@ namespace Compress.SevenZip.Structure
|
|||||||
{
|
{
|
||||||
header = null;
|
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();
|
case HeaderProperty.kEncodedHeader:
|
||||||
switch (hp)
|
{
|
||||||
{
|
StreamsInfo streamsInfo = new();
|
||||||
case HeaderProperty.kEncodedHeader:
|
streamsInfo.Read(br);
|
||||||
|
|
||||||
|
if (streamsInfo.Folders.Length > 1)
|
||||||
{
|
{
|
||||||
StreamsInfo streamsInfo = new StreamsInfo();
|
return ZipReturn.ZipUnsupportedCompression;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case HeaderProperty.kHeader:
|
Folder firstFolder = streamsInfo.Folders[0];
|
||||||
|
if (firstFolder.Coders.Length > 1)
|
||||||
{
|
{
|
||||||
header = new Header();
|
return ZipReturn.ZipUnsupportedCompression;
|
||||||
header.Read(br);
|
|
||||||
return ZipReturn.ZipGood;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
public void Report(ref StringBuilder sb)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
internal class SignatureHeader
|
internal class SignatureHeader
|
||||||
{
|
{
|
||||||
private static readonly byte[] Signature = {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
private static readonly byte[] Signature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||||
|
|
||||||
private byte _major;
|
|
||||||
private byte _minor;
|
|
||||||
|
|
||||||
private uint _startHeaderCRC;
|
private uint _startHeaderCRC;
|
||||||
|
|
||||||
@@ -22,34 +20,32 @@ namespace Compress.SevenZip.Structure
|
|||||||
|
|
||||||
public bool Read(Stream stream)
|
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);
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
public void Write(BinaryWriter bw)
|
||||||
@@ -61,18 +57,18 @@ namespace Compress.SevenZip.Structure
|
|||||||
|
|
||||||
//ArchiveVersion
|
//ArchiveVersion
|
||||||
//{
|
//{
|
||||||
bw.Write((byte) 0); // BYTE Major
|
bw.Write((byte)0); // BYTE Major
|
||||||
bw.Write((byte) 3); // BYTE Minor
|
bw.Write((byte)3); // BYTE Minor
|
||||||
//};
|
//};
|
||||||
|
|
||||||
_crcOffset = bw.BaseStream.Position;
|
_crcOffset = bw.BaseStream.Position;
|
||||||
bw.Write((uint) 0); //HeaderCRC
|
bw.Write((uint)0); //HeaderCRC
|
||||||
|
|
||||||
//StartHeader
|
//StartHeader
|
||||||
//{
|
//{
|
||||||
bw.Write((ulong) 0); //NextHeaderOffset
|
bw.Write((ulong)0); //NextHeaderOffset
|
||||||
bw.Write((ulong) 0); //NextHeaderSize
|
bw.Write((ulong)0); //NextHeaderSize
|
||||||
bw.Write((uint) 0); //NextHeaderCRC
|
bw.Write((uint)0); //NextHeaderCRC
|
||||||
//}
|
//}
|
||||||
|
|
||||||
BaseOffset = bw.BaseStream.Position;
|
BaseOffset = bw.BaseStream.Position;
|
||||||
@@ -84,21 +80,19 @@ namespace Compress.SevenZip.Structure
|
|||||||
|
|
||||||
|
|
||||||
byte[] sigHeaderBytes;
|
byte[] sigHeaderBytes;
|
||||||
using (MemoryStream sigHeaderMem = new MemoryStream())
|
using (MemoryStream sigHeaderMem = new())
|
||||||
{
|
{
|
||||||
using (BinaryWriter sigHeaderBw = new BinaryWriter(sigHeaderMem,Encoding.UTF8,true))
|
using BinaryWriter sigHeaderBw = new(sigHeaderMem, Encoding.UTF8, true);
|
||||||
{
|
sigHeaderBw.Write((ulong)((long)headerpos - BaseOffset)); //NextHeaderOffset
|
||||||
sigHeaderBw.Write((ulong) ((long) headerpos - BaseOffset)); //NextHeaderOffset
|
sigHeaderBw.Write(headerLength); //NextHeaderSize
|
||||||
sigHeaderBw.Write(headerLength); //NextHeaderSize
|
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
|
||||||
sigHeaderBw.Write(headerCRC); //NextHeaderCRC
|
|
||||||
|
|
||||||
sigHeaderBytes = new byte[sigHeaderMem.Length];
|
sigHeaderBytes = new byte[sigHeaderMem.Length];
|
||||||
sigHeaderMem.Position = 0;
|
sigHeaderMem.Position = 0;
|
||||||
sigHeaderMem.Read(sigHeaderBytes, 0, sigHeaderBytes.Length);
|
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.BaseStream.Position = _crcOffset;
|
||||||
bw.Write(sigHeaderCRC); //Header CRC
|
bw.Write(sigHeaderCRC); //Header CRC
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Permissions;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.Utils;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Compress.Utils;
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Structure
|
namespace Compress.SevenZip.Structure
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Compress.SevenZip
|
|||||||
{
|
{
|
||||||
public static readonly Encoding Enc = Encoding.GetEncoding(28591);
|
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++)
|
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--)
|
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++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
@@ -147,7 +147,7 @@ namespace Compress.SevenZip
|
|||||||
|
|
||||||
public static string ReadName(this BinaryReader br)
|
public static string ReadName(this BinaryReader br)
|
||||||
{
|
{
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new();
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
char c = (char)br.ReadUInt16();
|
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)
|
if (crc == null)
|
||||||
{
|
{
|
||||||
@@ -350,7 +350,7 @@ namespace Compress.SevenZip
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint? bytestouint(byte[] crc)
|
public static uint? BytesToUint(byte[] crc)
|
||||||
{
|
{
|
||||||
if (crc == null)
|
if (crc == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
* great code.
|
* great code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.BZip2
|
namespace Compress.Support.Compression.BZip2
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Base class for both the compress and decompress classes.
|
* Base class for both the compress and decompress classes.
|
||||||
@@ -23,7 +23,7 @@ using System.IO;
|
|||||||
* great code.
|
* great code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.BZip2
|
namespace Compress.Support.Compression.BZip2
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* An input stream that decompresses from the BZip2 format (with the file
|
* 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 int[] minLens = new int[BZip2Constants.N_GROUPS];
|
||||||
|
|
||||||
private Stream bsStream;
|
private Stream bsStream;
|
||||||
private bool leaveOpen;
|
|
||||||
|
|
||||||
private bool streamEnd = false;
|
private bool streamEnd = false;
|
||||||
|
|
||||||
@@ -342,19 +341,7 @@ namespace Compress.SevenZip.Compress.BZip2
|
|||||||
|
|
||||||
private void BsFinishedWithStream()
|
private void BsFinishedWithStream()
|
||||||
{
|
{
|
||||||
try
|
bsStream = null;
|
||||||
{
|
|
||||||
if (this.bsStream != null)
|
|
||||||
{
|
|
||||||
if (!leaveOpen)
|
|
||||||
this.bsStream.Dispose();
|
|
||||||
this.bsStream = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BsSetStream(Stream f)
|
private void BsSetStream(Stream f)
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
* great code.
|
* great code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.BZip2
|
namespace Compress.Support.Compression.BZip2
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* An output stream that compresses into the BZip2 format (with the file
|
* An output stream that compresses into the BZip2 format (with the file
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* great code.
|
* great code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.BZip2
|
namespace Compress.Support.Compression.BZip2
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* A simple class the hold and calculate the CRC for sanity checking
|
* A simple class the hold and calculate the CRC for sanity checking
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
|
|
||||||
internal enum BlockState
|
internal enum BlockState
|
||||||
@@ -545,10 +545,10 @@ namespace Compress.ZipFile.ZLib
|
|||||||
internal void send_tree(short[] tree, int max_code)
|
internal void send_tree(short[] tree, int max_code)
|
||||||
{
|
{
|
||||||
int n; // iterates over all tree elements
|
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 curlen; // length of current code
|
||||||
int nextlen = tree[0 * 2 + 1]; // length of next code
|
int nextlen = tree[0 * 2 + 1]; // length of next code
|
||||||
int count = 0; // repeat count of the current code
|
int count = 0; // repeat count of the current code
|
||||||
int max_count = 7; // max repeat count
|
int max_count = 7; // max repeat count
|
||||||
int min_count = 4; // min 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
|
out_length = (int)(out_length + (int)dyn_dtree[dcode * 2] * (5L + Tree.ExtraDistanceBits[dcode]));
|
||||||
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 >>= 3;
|
||||||
|
if ((matches < (last_lit / 2)) && out_length < in_length / 2)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize);
|
return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize);
|
||||||
// dinoch - wraparound?
|
// dinoch - wraparound?
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
|
|
||||||
sealed class InfTree
|
sealed class InfTree
|
||||||
@@ -83,25 +83,19 @@ namespace Compress.ZipFile.ZLib
|
|||||||
internal const int fixed_bl = 9;
|
internal const int fixed_bl = 9;
|
||||||
internal const int fixed_bd = 5;
|
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,
|
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,
|
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};
|
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};
|
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.
|
// 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};
|
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
|
// 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};
|
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};
|
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};
|
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.
|
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
sealed class InflateBlocks
|
sealed class InflateBlocks
|
||||||
{
|
{
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
sealed class Tree
|
sealed class Tree
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
using System;
|
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 }
|
public enum ZlibStreamFlavor { ZLIB = 1950, DEFLATE = 1951, GZIP = 1952 }
|
||||||
@@ -50,7 +50,7 @@ namespace Compress.ZipFile.ZLib
|
|||||||
protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
|
protected internal CompressionStrategy Strategy = CompressionStrategy.Default;
|
||||||
|
|
||||||
// workitem 7159
|
// workitem 7159
|
||||||
Compress.Utils.CRC crc;
|
CRC crc;
|
||||||
protected internal string _GzipFileName;
|
protected internal string _GzipFileName;
|
||||||
protected internal string _GzipComment;
|
protected internal string _GzipComment;
|
||||||
protected internal DateTime _GzipMtime;
|
protected internal DateTime _GzipMtime;
|
||||||
@@ -75,7 +75,7 @@ namespace Compress.ZipFile.ZLib
|
|||||||
// workitem 7159
|
// workitem 7159
|
||||||
if (flavor == ZlibStreamFlavor.GZIP)
|
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 System.Runtime.InteropServices;
|
||||||
using Interop=System.Runtime.InteropServices;
|
using Interop=System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Compress.ZipFile.ZLib
|
namespace Compress.Support.Compression.Deflate
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951).
|
/// 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>
|
/// <summary>
|
||||||
/// A bunch of constants used in the Zlib interface.
|
/// 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 System;
|
||||||
using Compress.SevenZip.Common;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZ
|
namespace Compress.Support.Compression.LZ
|
||||||
{
|
{
|
||||||
internal class BinTree : InWindow
|
internal class BinTree : InWindow
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZ
|
namespace Compress.Support.Compression.LZ
|
||||||
{
|
{
|
||||||
internal class InWindow
|
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
|
internal class OutWindow
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Common
|
namespace Compress.Support.Compression.LZMA
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
/// 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);
|
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>
|
/// <summary>
|
||||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||||
@@ -134,19 +100,4 @@ namespace Compress.SevenZip.Common
|
|||||||
EndMarker
|
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
|
internal abstract class Base
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using Compress.SevenZip.Common;
|
using Compress.Support.Compression.RangeCoder;
|
||||||
using Compress.SevenZip.Compress.RangeCoder;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZMA
|
namespace Compress.Support.Compression.LZMA
|
||||||
{
|
{
|
||||||
internal class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
internal class Decoder
|
||||||
{
|
{
|
||||||
class LenDecoder
|
class LenDecoder
|
||||||
{
|
{
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using Compress.SevenZip.Common;
|
using Compress.Support.Compression.RangeCoder;
|
||||||
using Compress.SevenZip.Compress.RangeCoder;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZMA
|
namespace Compress.Support.Compression.LZMA
|
||||||
{
|
{
|
||||||
|
|
||||||
internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
|
internal class Encoder
|
||||||
{
|
{
|
||||||
enum EMatchFinderType
|
enum EMatchFinderType
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using Compress.SevenZip.Common;
|
namespace Compress.Support.Compression.LZMA
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZMA
|
|
||||||
{
|
{
|
||||||
public class LzmaEncoderProperties
|
public class LzmaEncoderProperties
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Compress.SevenZip.Common;
|
using Compress.Support.Compression.LZ;
|
||||||
using Compress.SevenZip.Compress.LZ;
|
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.LZMA
|
namespace Compress.Support.Compression.LZMA
|
||||||
{
|
{
|
||||||
public class LzmaStream : Stream
|
public class LzmaStream : Stream
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class FreqData : Pointer
|
internal class FreqData : Pointer
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
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
|
internal class ModelPPM
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class PPMContext : Pointer
|
internal class PPMContext : Pointer
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal abstract class Pointer
|
internal abstract class Pointer
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class RangeCoder
|
internal class RangeCoder
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class RarMemBlock : Pointer
|
internal class RarMemBlock : Pointer
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class RarNode : Pointer
|
internal class RarNode : Pointer
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class SEE2Context
|
internal class SEE2Context
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class State : Pointer
|
internal class State : Pointer
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class StateRef
|
internal class StateRef
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.H
|
namespace Compress.Support.Compression.PPmd.H
|
||||||
{
|
{
|
||||||
internal class SubAllocator
|
internal class SubAllocator
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#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
|
/// 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
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple range coder.
|
/// A simple range coder.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure containing a single address. The address represents a location in the <see cref="Memory"/>
|
/// 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.
|
// This is a port of Dmitry Shkarin's PPMd Variant I Revision 1.
|
||||||
// Ported by Michael Bone (mjbone03@yahoo.com.au).
|
// Ported by Michael Bone (mjbone03@yahoo.com.au).
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model.
|
/// The model.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The method used to adjust the model when the memory limit is reached.
|
/// The method used to adjust the model when the memory limit is reached.
|
||||||
@@ -4,7 +4,7 @@ using System;
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure containing a single address representing a position in the <see cref="Memory"/> array. This
|
/// A structure containing a single address representing a position in the <see cref="Memory"/> array. This
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The PPM context structure. This is tightly coupled with <see cref="Model"/>.
|
/// The PPM context structure. This is tightly coupled with <see cref="Model"/>.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PPM state.
|
/// PPM state.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd.I1
|
namespace Compress.Support.Compression.PPmd.I1
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols.
|
/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd
|
namespace Compress.Support.Compression.PPmd
|
||||||
{
|
{
|
||||||
public enum PpmdVersion
|
public enum PpmdVersion
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
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
|
public class PpmdStream : Stream
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.PPmd
|
namespace Compress.Support.Compression.PPmd
|
||||||
{
|
{
|
||||||
internal static class Utility
|
internal static class Utility
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.RangeCoder
|
namespace Compress.Support.Compression.RangeCoder
|
||||||
{
|
{
|
||||||
internal class Encoder
|
internal class Encoder
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.RangeCoder
|
namespace Compress.Support.Compression.RangeCoder
|
||||||
{
|
{
|
||||||
internal struct BitEncoder
|
internal struct BitEncoder
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Compress.RangeCoder
|
namespace Compress.Support.Compression.RangeCoder
|
||||||
{
|
{
|
||||||
internal struct BitTreeEncoder
|
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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Filters
|
namespace Compress.Support.Filters
|
||||||
{
|
{
|
||||||
public class BCJ2Filter : Stream
|
public class BCJ2Filter : Stream
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Filters
|
namespace Compress.Support.Filters
|
||||||
{
|
{
|
||||||
public class BCJFilter : Filter
|
public class BCJFilter : Filter
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Filters
|
namespace Compress.Support.Filters
|
||||||
{
|
{
|
||||||
public class Delta : Stream
|
public class Delta : Stream
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Compress.SevenZip.Filters
|
namespace Compress.Support.Filters
|
||||||
{
|
{
|
||||||
public abstract class Filter : Stream
|
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;
|
using System;
|
||||||
|
|
||||||
namespace Compress.Utils
|
namespace Compress.Support.Utils
|
||||||
{
|
{
|
||||||
public class CRC
|
public class CRC
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Compress.Utils
|
namespace Compress.Support.Utils
|
||||||
{
|
{
|
||||||
class CRCStream
|
class CRCStream
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
namespace Compress.Utils
|
namespace Compress.Support.Utils
|
||||||
{
|
{
|
||||||
public static class Reporter
|
public static class Reporter
|
||||||
{
|
{
|
||||||
@@ -30,6 +30,20 @@ namespace Compress.Utils
|
|||||||
return ret;
|
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)
|
public static string ToHex(this uint? v)
|
||||||
{
|
{
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Compress.Support.Utils;
|
||||||
|
|
||||||
namespace Compress.ThreadReaders
|
namespace Compress.ThreadReaders
|
||||||
{
|
{
|
||||||
public class ThreadCRC : IDisposable
|
public class ThreadCRC : IDisposable
|
||||||
{
|
{
|
||||||
private Utils.CRC crc;
|
private CRC crc;
|
||||||
private readonly AutoResetEvent _waitEvent;
|
private readonly AutoResetEvent _waitEvent;
|
||||||
private readonly AutoResetEvent _outEvent;
|
private readonly AutoResetEvent _outEvent;
|
||||||
private readonly Thread _tWorker;
|
private readonly Thread _tWorker;
|
||||||
@@ -17,7 +18,7 @@ namespace Compress.ThreadReaders
|
|||||||
|
|
||||||
public ThreadCRC()
|
public ThreadCRC()
|
||||||
{
|
{
|
||||||
crc=new Utils.CRC();
|
crc=new CRC();
|
||||||
_waitEvent = new AutoResetEvent(false);
|
_waitEvent = new AutoResetEvent(false);
|
||||||
_outEvent = new AutoResetEvent(false);
|
_outEvent = new AutoResetEvent(false);
|
||||||
_finished = false;
|
_finished = false;
|
||||||
@@ -56,6 +57,13 @@ namespace Compress.ThreadReaders
|
|||||||
_size = size;
|
_size = size;
|
||||||
_waitEvent.Set();
|
_waitEvent.Set();
|
||||||
}
|
}
|
||||||
|
public void TriggerOnce(byte[] buffer, int size)
|
||||||
|
{
|
||||||
|
crc.Reset();
|
||||||
|
_buffer = buffer;
|
||||||
|
_size = size;
|
||||||
|
_waitEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
public void Wait()
|
public void Wait()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace Compress.ThreadReaders
|
namespace Compress.ThreadReaders
|
||||||
{
|
{
|
||||||
public class ThreadLoadBuffer : IDisposable
|
public class ThreadReadBuffer : IDisposable
|
||||||
{
|
{
|
||||||
private readonly AutoResetEvent _waitEvent;
|
private readonly AutoResetEvent _waitEvent;
|
||||||
private readonly AutoResetEvent _outEvent;
|
private readonly AutoResetEvent _outEvent;
|
||||||
@@ -18,7 +18,7 @@ namespace Compress.ThreadReaders
|
|||||||
|
|
||||||
public int SizeRead;
|
public int SizeRead;
|
||||||
|
|
||||||
public ThreadLoadBuffer(Stream ds)
|
public ThreadReadBuffer(Stream ds)
|
||||||
{
|
{
|
||||||
_waitEvent = new AutoResetEvent(false);
|
_waitEvent = new AutoResetEvent(false);
|
||||||
_outEvent = 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
|
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