Sync Compress and RVIO with latest from RVWorld

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

View File

@@ -9,7 +9,7 @@ using SabreTools.Core.Tools;
using SabreTools.IO; using 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();

View File

@@ -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);
} }
} }
} }

View File

@@ -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)

View File

@@ -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);
} }
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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)

View File

@@ -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; }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,6 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.IO; using System.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)
{ {

View File

@@ -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);
} }

View File

@@ -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;
} }

View File

@@ -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)
{ {

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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));
} }
} }

View File

@@ -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)

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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)
{ {

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View 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

View File

@@ -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?

View File

@@ -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.

View File

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

View File

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

View File

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

View File

@@ -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();
} }
} }

View File

@@ -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).

View File

@@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
}
} }

View File

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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

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

View File

@@ -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
{ {

View File

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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -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.

View File

@@ -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"/>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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"/>.

View File

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

View File

@@ -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.

View File

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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

@@ -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
{ {

View File

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

View File

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

View File

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

View File

@@ -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)
{ {

View File

@@ -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()
{ {

View File

@@ -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);

View File

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

View File

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

View File

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

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