783 lines
29 KiB
C#
783 lines
29 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Security.Cryptography;
|
|||
|
|
using ROMVault2.SupportedFiles.SevenZip.Common;
|
|||
|
|
using ROMVault2.SupportedFiles.SevenZip.Compress.LZMA;
|
|||
|
|
using ROMVault2.SupportedFiles.SevenZip.Filters;
|
|||
|
|
using ROMVault2.SupportedFiles.SevenZip.Structure;
|
|||
|
|
|
|||
|
|
namespace ROMVault2.SupportedFiles.SevenZip
|
|||
|
|
{
|
|||
|
|
public class SevenZ : ICompress
|
|||
|
|
{
|
|||
|
|
public class LocalFile
|
|||
|
|
{
|
|||
|
|
public string FileName;
|
|||
|
|
public ulong UncompressedSize;
|
|||
|
|
public bool isDirectory;
|
|||
|
|
public byte[] crc;
|
|||
|
|
public byte[] sha1;
|
|||
|
|
public byte[] md5;
|
|||
|
|
public int StreamIndex;
|
|||
|
|
public ulong StreamOffset;
|
|||
|
|
public ZipReturn FileStatus = ZipReturn.ZipUntested;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<LocalFile> _localFiles = new List<LocalFile>();
|
|||
|
|
|
|||
|
|
private IO.FileInfo _zipFileInfo;
|
|||
|
|
|
|||
|
|
private Stream _zipFs;
|
|||
|
|
|
|||
|
|
private ZipOpenType _zipOpen;
|
|||
|
|
private ZipStatus _pZipStatus;
|
|||
|
|
|
|||
|
|
SignatureHeader _signatureHeader;
|
|||
|
|
|
|||
|
|
private bool _compressed = true;
|
|||
|
|
private Stream _tmpOutStream;
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
private Stream _streamNow;
|
|||
|
|
private int _streamIndex = -1;
|
|||
|
|
|
|||
|
|
|
|||
|
|
public string ZipFilename
|
|||
|
|
{
|
|||
|
|
get { return _zipFileInfo != null ? _zipFileInfo.FullName : ""; }
|
|||
|
|
}
|
|||
|
|
public long TimeStamp
|
|||
|
|
{
|
|||
|
|
get { return _zipFileInfo != null ? _zipFileInfo.LastWriteTime : 0; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ZipOpenType ZipOpen { get { return _zipOpen; } }
|
|||
|
|
public ZipStatus ZipStatus { get { return _pZipStatus; } }
|
|||
|
|
public int LocalFilesCount() { return _localFiles.Count; }
|
|||
|
|
public string Filename(int i) { return _localFiles[i].FileName; }
|
|||
|
|
public ulong? LocalHeader(int i) { return 0; }
|
|||
|
|
public ulong UncompressedSize(int i) { return _localFiles[i].UncompressedSize; }
|
|||
|
|
public ZipReturn FileStatus(int i) { return _localFiles[i].FileStatus; }
|
|||
|
|
public byte[] CRC32(int i) { return _localFiles[i].crc; }
|
|||
|
|
public byte[] MD5(int i) { return _localFiles[i].md5; }
|
|||
|
|
public byte[] SHA1(int i) { return _localFiles[i].sha1; }
|
|||
|
|
public bool IsDirectory(int i) { return _localFiles[i].isDirectory; }
|
|||
|
|
|
|||
|
|
|
|||
|
|
private long _baseOffset;
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region open 7z files
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileOpen(string filename, long timestamp,bool readHeaders)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine(filename);
|
|||
|
|
#region open file stream
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (!IO.File.Exists(filename))
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipErrorFileNotFound;
|
|||
|
|
}
|
|||
|
|
_zipFileInfo = new IO.FileInfo(filename);
|
|||
|
|
if (timestamp != -1 && _zipFileInfo.LastWriteTime != timestamp)
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipErrorTimeStamp;
|
|||
|
|
}
|
|||
|
|
int errorCode = IO.FileStream.OpenFileRead(filename, out _zipFs);
|
|||
|
|
if (errorCode != 0)
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipErrorOpeningFile;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (PathTooLongException)
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipFileNameToLong;
|
|||
|
|
}
|
|||
|
|
catch (IOException)
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipErrorOpeningFile;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
_zipOpen = ZipOpenType.OpenRead;
|
|||
|
|
_pZipStatus = ZipStatus.None;
|
|||
|
|
|
|||
|
|
SignatureHeader signatureHeader = new SignatureHeader();
|
|||
|
|
if (!signatureHeader.Read(new BinaryReader(_zipFs)))
|
|||
|
|
return ZipReturn.ZipSignatureError;
|
|||
|
|
|
|||
|
|
_baseOffset = _zipFs.Position; Util.log("BaseOffset : " + _baseOffset);
|
|||
|
|
|
|||
|
|
Util.log("Loading Stream : " + (_baseOffset + (long)signatureHeader.NextHeaderOffset) + " , Size : " + signatureHeader.NextHeaderSize);
|
|||
|
|
|
|||
|
|
//_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
|||
|
|
//byte[] mainHeader = new byte[signatureHeader.NextHeaderSize];
|
|||
|
|
//_zipFs.Read(mainHeader, 0, (int)signatureHeader.NextHeaderSize);
|
|||
|
|
//if (!CRC.VerifyDigest(signatureHeader.NextHeaderCRC, mainHeader, 0, (uint)signatureHeader.NextHeaderSize))
|
|||
|
|
// return ZipReturn.Zip64EndOfCentralDirError;
|
|||
|
|
|
|||
|
|
_zipFs.Seek(_baseOffset + (long)signatureHeader.NextHeaderOffset, SeekOrigin.Begin);
|
|||
|
|
ZipReturn zr = Header.ReadHeaderOrPackedHeader(_zipFs, _baseOffset, out _header);
|
|||
|
|
if (zr != ZipReturn.ZipGood)
|
|||
|
|
return zr;
|
|||
|
|
|
|||
|
|
_zipFs.Seek(_baseOffset + (long)(signatureHeader.NextHeaderOffset + signatureHeader.NextHeaderSize), SeekOrigin.Begin);
|
|||
|
|
_pZipStatus = Istorrent7Z() ? ZipStatus.TrrntZip : ZipStatus.None;
|
|||
|
|
PopulateLocalFiles(out _localFiles);
|
|||
|
|
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private void PopulateLocalFiles(out List<LocalFile> localFiles)
|
|||
|
|
{
|
|||
|
|
int emptyFileIndex = 0;
|
|||
|
|
int folderIndex = 0;
|
|||
|
|
int unpackedStreamsIndex = 0;
|
|||
|
|
ulong streamOffset = 0;
|
|||
|
|
localFiles = new List<LocalFile>();
|
|||
|
|
|
|||
|
|
for (int i = 0; i < _header.FileInfo.Names.Length; i++)
|
|||
|
|
{
|
|||
|
|
LocalFile lf = new LocalFile { FileName = _header.FileInfo.Names[i] };
|
|||
|
|
|
|||
|
|
if (_header.FileInfo.EmptyStreamFlags == null || !_header.FileInfo.EmptyStreamFlags[i])
|
|||
|
|
{
|
|||
|
|
lf.StreamIndex = folderIndex;
|
|||
|
|
lf.StreamOffset = streamOffset;
|
|||
|
|
lf.UncompressedSize = _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].UnpackedSize;
|
|||
|
|
lf.crc = Util.uinttobytes(_header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo[unpackedStreamsIndex].Crc);
|
|||
|
|
|
|||
|
|
streamOffset += lf.UncompressedSize;
|
|||
|
|
unpackedStreamsIndex++;
|
|||
|
|
|
|||
|
|
if (unpackedStreamsIndex >= _header.StreamsInfo.Folders[folderIndex].UnpackedStreamInfo.Length)
|
|||
|
|
{
|
|||
|
|
folderIndex++;
|
|||
|
|
unpackedStreamsIndex = 0;
|
|||
|
|
streamOffset = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
lf.UncompressedSize = 0;
|
|||
|
|
lf.crc = new byte[] { 0, 0, 0, 0 };
|
|||
|
|
lf.isDirectory = _header.FileInfo.EmptyFileFlags == null || !_header.FileInfo.EmptyFileFlags[emptyFileIndex++];
|
|||
|
|
|
|||
|
|
if (lf.isDirectory)
|
|||
|
|
if (lf.FileName.Substring(lf.FileName.Length - 1, 1) != "/")
|
|||
|
|
lf.FileName += "/";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
localFiles.Add(lf);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ZipFileClose()
|
|||
|
|
{
|
|||
|
|
ZipFileClose(null);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ZipFileClose(ICodeProgress p)
|
|||
|
|
{
|
|||
|
|
if (_zipOpen == ZipOpenType.Closed)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (_zipOpen == ZipOpenType.OpenRead)
|
|||
|
|
{
|
|||
|
|
ZipFileCloseReadStream();
|
|||
|
|
if (_zipFs != null)
|
|||
|
|
{
|
|||
|
|
_zipFs.Close();
|
|||
|
|
_zipFs.Dispose();
|
|||
|
|
}
|
|||
|
|
_zipOpen = ZipOpenType.Closed;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CloseWriting7Zip(p);
|
|||
|
|
|
|||
|
|
_zipFileInfo = new IO.FileInfo(_zipFileInfo.FullName);
|
|||
|
|
_zipOpen = ZipOpenType.Closed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private Header _header;
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
private bool Istorrent7Z()
|
|||
|
|
{
|
|||
|
|
const int crcsz = 128;
|
|||
|
|
const int t7ZsigSize = 16 + 1 + 9 + 4 + 4;
|
|||
|
|
byte[] kSignature = { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
|||
|
|
int kSignatureSize = kSignature.Length;
|
|||
|
|
const string sig = "\xa9\x9f\xd1\x57\x08\xa9\xd7\xea\x29\x64\xb2\x36\x1b\x83\x52\x33\x01torrent7z_0.9beta";
|
|||
|
|
byte[] t7Zid = Util.Enc.GetBytes(sig);
|
|||
|
|
int t7ZidSize = t7Zid.Length;
|
|||
|
|
|
|||
|
|
const int tmpbufsize = 256 + t7ZsigSize + 8 + 4;
|
|||
|
|
byte[] buffer = new byte[tmpbufsize];
|
|||
|
|
|
|||
|
|
// read fist 128 bytes, pad with zeros if less bytes
|
|||
|
|
int offs = 0;
|
|||
|
|
_zipFs.Seek(0, SeekOrigin.Begin);
|
|||
|
|
int ar = _zipFs.Read(buffer, offs, crcsz);
|
|||
|
|
if (ar < crcsz)
|
|||
|
|
Util.memset(buffer, offs + ar, 0, crcsz - ar);
|
|||
|
|
|
|||
|
|
|
|||
|
|
offs = crcsz;
|
|||
|
|
long foffs = _zipFs.Length;
|
|||
|
|
foffs = foffs < (crcsz + t7ZsigSize + 4) ? 0 : foffs - (crcsz + t7ZsigSize + 4);
|
|||
|
|
_zipFs.Seek(foffs, SeekOrigin.Begin);
|
|||
|
|
|
|||
|
|
ar = _zipFs.Read(buffer, offs, (crcsz + t7ZsigSize + 4));
|
|||
|
|
if (ar < (crcsz + t7ZsigSize + 4))
|
|||
|
|
{
|
|||
|
|
if (ar >= t7ZsigSize + 4)
|
|||
|
|
{
|
|||
|
|
ar -= t7ZsigSize + 4;
|
|||
|
|
}
|
|||
|
|
if (ar < kSignatureSize)
|
|||
|
|
{
|
|||
|
|
ar = kSignatureSize;
|
|||
|
|
}
|
|||
|
|
Util.memset(buffer, offs + ar, 0, crcsz - ar);
|
|||
|
|
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, offs + ar, t7ZsigSize + 4);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
Util.memcpyr(buffer, crcsz * 2 + 8, buffer, crcsz * 2, t7ZsigSize + 4);
|
|||
|
|
|
|||
|
|
foffs = _zipFs.Length;
|
|||
|
|
foffs -= t7ZsigSize + 4;
|
|||
|
|
|
|||
|
|
//memcpy(buffer, crcsz * 2, &foffs, 8);
|
|||
|
|
buffer[crcsz * 2 + 0] = (byte)((foffs >> 0) & 0xff);
|
|||
|
|
buffer[crcsz * 2 + 1] = (byte)((foffs >> 8) & 0xff);
|
|||
|
|
buffer[crcsz * 2 + 2] = (byte)((foffs >> 16) & 0xff);
|
|||
|
|
buffer[crcsz * 2 + 3] = (byte)((foffs >> 24) & 0xff);
|
|||
|
|
buffer[crcsz * 2 + 4] = 0;
|
|||
|
|
buffer[crcsz * 2 + 5] = 0;
|
|||
|
|
buffer[crcsz * 2 + 6] = 0;
|
|||
|
|
buffer[crcsz * 2 + 7] = 0;
|
|||
|
|
|
|||
|
|
if (Util.memcmp(buffer, 0, kSignature, kSignatureSize))
|
|||
|
|
{
|
|||
|
|
t7Zid[16] = buffer[crcsz * 2 + 4 + 8 + 16];
|
|||
|
|
if (Util.memcmp(buffer, crcsz * 2 + 4 + 8, t7Zid, t7ZidSize))
|
|||
|
|
{
|
|||
|
|
UInt32 inCrc32 = (UInt32)((buffer[crcsz * 2 + 8 + 0]) +
|
|||
|
|
(buffer[crcsz * 2 + 8 + 1] << 8) +
|
|||
|
|
(buffer[crcsz * 2 + 8 + 2] << 16) +
|
|||
|
|
(buffer[crcsz * 2 + 8 + 3] << 24));
|
|||
|
|
|
|||
|
|
buffer[crcsz * 2 + 8 + 0] = 0xff;
|
|||
|
|
buffer[crcsz * 2 + 8 + 1] = 0xff;
|
|||
|
|
buffer[crcsz * 2 + 8 + 2] = 0xff;
|
|||
|
|
buffer[crcsz * 2 + 8 + 3] = 0xff;
|
|||
|
|
|
|||
|
|
uint calcCrc32 = CRC.CalculateDigest(buffer, 0, crcsz * 2 + 8 + t7ZsigSize + 4);
|
|||
|
|
|
|||
|
|
if (inCrc32 == calcCrc32) return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void DeepScan()
|
|||
|
|
{
|
|||
|
|
const int bufferSize = 4096 * 128;
|
|||
|
|
byte[] buffer = new byte[bufferSize];
|
|||
|
|
|
|||
|
|
for (int index = 0; index < _localFiles.Count; index++)
|
|||
|
|
{
|
|||
|
|
if (_localFiles[index].isDirectory || _localFiles[index].UncompressedSize == 0)
|
|||
|
|
{
|
|||
|
|
_localFiles[index].md5 = new byte[] { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e };
|
|||
|
|
_localFiles[index].sha1 = new byte[] { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 };
|
|||
|
|
_localFiles[index].FileStatus = ZipReturn.ZipGood;
|
|||
|
|
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ulong sizetogo;
|
|||
|
|
Stream inStream;
|
|||
|
|
ZipReturn zr = ZipFileOpenReadStream(index, out inStream, out sizetogo);
|
|||
|
|
if (zr != ZipReturn.ZipGood)
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
if (inStream == null)
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
CRC crc32 = new CRC();
|
|||
|
|
MD5 lmd5 = System.Security.Cryptography.MD5.Create();
|
|||
|
|
SHA1 lsha1 = System.Security.Cryptography.SHA1.Create();
|
|||
|
|
|
|||
|
|
while (sizetogo > 0)
|
|||
|
|
{
|
|||
|
|
int sizenow = sizetogo > (ulong)bufferSize ? bufferSize : (int)sizetogo;
|
|||
|
|
inStream.Read(buffer, 0, sizenow);
|
|||
|
|
|
|||
|
|
crc32.Update(buffer, 0, (uint)sizenow);
|
|||
|
|
lmd5.TransformBlock(buffer, 0, sizenow, null, 0);
|
|||
|
|
lsha1.TransformBlock(buffer, 0, sizenow, null, 0);
|
|||
|
|
|
|||
|
|
sizetogo = sizetogo - (ulong)sizenow;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lmd5.TransformFinalBlock(buffer, 0, 0);
|
|||
|
|
lsha1.TransformFinalBlock(buffer, 0, 0);
|
|||
|
|
|
|||
|
|
byte[] testcrc = Util.uinttobytes(crc32.GetDigest());
|
|||
|
|
_localFiles[index].md5 = lmd5.Hash;
|
|||
|
|
_localFiles[index].sha1 = lsha1.Hash;
|
|||
|
|
|
|||
|
|
_localFiles[index].FileStatus = Util.ByteArrCompare(_localFiles[index].crc, testcrc) ? ZipReturn.ZipGood : ZipReturn.ZipCRCDecodeError;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region read 7z file
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileOpenReadStream(int index, out Stream stream, out ulong unCompressedSize)
|
|||
|
|
{
|
|||
|
|
Debug.WriteLine("Opening File " + _localFiles[index].FileName);
|
|||
|
|
stream = null;
|
|||
|
|
unCompressedSize = 0;
|
|||
|
|
|
|||
|
|
if (_zipOpen != ZipOpenType.OpenRead)
|
|||
|
|
return ZipReturn.ZipErrorGettingDataStream;
|
|||
|
|
|
|||
|
|
if (IsDirectory(index))
|
|||
|
|
return ZipReturn.ZipTryingToAccessADirectory;
|
|||
|
|
|
|||
|
|
unCompressedSize = _localFiles[index].UncompressedSize;
|
|||
|
|
|
|||
|
|
int thisStreamIndex = _localFiles[index].StreamIndex;
|
|||
|
|
|
|||
|
|
// first see if we can re-use the current open stream
|
|||
|
|
if (_streamIndex == thisStreamIndex)
|
|||
|
|
{
|
|||
|
|
stream = _streamNow;
|
|||
|
|
if (_streamNow is BCJFilter) // it is a BCJ + Decoder stream but need to check the position in the stream can be used.
|
|||
|
|
{
|
|||
|
|
if ((long)_localFiles[index].StreamOffset >= _streamNow.Position)
|
|||
|
|
{
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset - _streamNow.Position, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (_streamNow is Decoder) // it is a Decoder stream but need to check the position in the stream can be used.
|
|||
|
|
{
|
|||
|
|
if ((long)_localFiles[index].StreamOffset >= _streamNow.Position)
|
|||
|
|
{
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset - _streamNow.Position, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else // it is an uncompressed stream
|
|||
|
|
{
|
|||
|
|
if (stream != null)
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset - _streamNow.Position, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// need to open a new stream
|
|||
|
|
|
|||
|
|
// first close the old streams
|
|||
|
|
ZipFileCloseReadStream();
|
|||
|
|
|
|||
|
|
|
|||
|
|
// open new stream
|
|||
|
|
_streamIndex = thisStreamIndex;
|
|||
|
|
_zipFs.Seek(_baseOffset + (long)_header.StreamsInfo.PackedStreams[thisStreamIndex].StreamPosition, SeekOrigin.Begin);
|
|||
|
|
|
|||
|
|
byte[] method = _header.StreamsInfo.Folders[_localFiles[index].StreamIndex].Coders[0].Method;
|
|||
|
|
if (method.Length == 3 && method[0] == 3 && method[1] == 1 && method[2] == 1) // LZMA
|
|||
|
|
{
|
|||
|
|
Decoder decoder = new Decoder();
|
|||
|
|
decoder.SetDecoderProperties(_header.StreamsInfo.Folders[_localFiles[index].StreamIndex].Coders[0].Properties);
|
|||
|
|
decoder.SetUpStream(_zipFs);
|
|||
|
|
stream = decoder;
|
|||
|
|
_streamNow = stream;
|
|||
|
|
|
|||
|
|
if (_header.StreamsInfo.Folders[_localFiles[index].StreamIndex].Coders.Length > 1) // BCJ
|
|||
|
|
{
|
|||
|
|
method = _header.StreamsInfo.Folders[_localFiles[index].StreamIndex].Coders[1].Method;
|
|||
|
|
if (method.Length == 4 && method[0] == 3 && method[1] == 3 && method[2] == 1 && method[3] == 3)
|
|||
|
|
{
|
|||
|
|
BCJFilter filter = new BCJFilter(false, stream);
|
|||
|
|
stream = filter;
|
|||
|
|
_streamNow = stream;
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
return ZipReturn.ZipUnsupportedCompression;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
if (method.Length == 1 && method[0] == 33) // lzma2
|
|||
|
|
{
|
|||
|
|
return ZipReturn.ZipUnsupportedCompression;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (method.Length == 1 && method[0] == 0) // uncompressed
|
|||
|
|
{
|
|||
|
|
stream = _zipFs;
|
|||
|
|
_streamNow = stream;
|
|||
|
|
stream.Seek((long)_localFiles[index].StreamOffset, SeekOrigin.Current);
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (method.Length == 3 && method[0] == 4 && method[1] == 2 && method[2] == 2) // BZip2
|
|||
|
|
{
|
|||
|
|
return ZipReturn.ZipUnsupportedCompression;
|
|||
|
|
}
|
|||
|
|
if (method.Length == 1 && method[0] == 33) // LZMA2
|
|||
|
|
{
|
|||
|
|
return ZipReturn.ZipUnsupportedCompression;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ZipReturn.ZipUnsupportedCompression;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileCloseReadStream()
|
|||
|
|
{
|
|||
|
|
if (_streamNow is BCJFilter)
|
|||
|
|
{
|
|||
|
|
Stream baseStream = ((BCJFilter)_streamNow).BaseStream;
|
|||
|
|
_streamNow.Dispose();
|
|||
|
|
_streamNow = baseStream;
|
|||
|
|
}
|
|||
|
|
if (_streamNow is Decoder)
|
|||
|
|
{
|
|||
|
|
_streamNow.Close();
|
|||
|
|
_streamNow.Dispose();
|
|||
|
|
}
|
|||
|
|
_streamNow = null;
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region write 7z File
|
|||
|
|
|
|||
|
|
public void ZipFileAddDirectory()
|
|||
|
|
{
|
|||
|
|
// do nothing here for 7zip
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileCreate(string newFilename)
|
|||
|
|
{
|
|||
|
|
return ZipFileCreate(newFilename, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileCreate(string newFilename, bool compressOutput)
|
|||
|
|
{
|
|||
|
|
if (_zipOpen != ZipOpenType.Closed)
|
|||
|
|
return ZipReturn.ZipFileAlreadyOpen;
|
|||
|
|
|
|||
|
|
DirUtil.CreateDirForFile(newFilename);
|
|||
|
|
_zipFileInfo = new IO.FileInfo(newFilename);
|
|||
|
|
|
|||
|
|
int errorCode = IO.FileStream.OpenFileWrite(newFilename, out _zipFs);
|
|||
|
|
if (errorCode != 0)
|
|||
|
|
{
|
|||
|
|
ZipFileClose();
|
|||
|
|
return ZipReturn.ZipErrorOpeningFile;
|
|||
|
|
}
|
|||
|
|
_zipOpen = ZipOpenType.OpenWrite;
|
|||
|
|
|
|||
|
|
_signatureHeader = new SignatureHeader();
|
|||
|
|
_header = new Header();
|
|||
|
|
|
|||
|
|
BinaryWriter bw = new BinaryWriter(_zipFs);
|
|||
|
|
_signatureHeader.Write(bw);
|
|||
|
|
|
|||
|
|
_compressed = compressOutput;
|
|||
|
|
_tmpOutStream = compressOutput ? new FileStream(_zipFileInfo.FullName + ".tmp", FileMode.Create, FileAccess.Write) : null;
|
|||
|
|
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileOpenWriteStream(bool raw, bool trrntzip, string filename, ulong uncompressedSize, ushort compressionMethod, out Stream stream)
|
|||
|
|
{
|
|||
|
|
return ZipFileOpenWriteStream(filename, uncompressedSize, out stream);
|
|||
|
|
}
|
|||
|
|
public ZipReturn ZipFileOpenWriteStream(string filename, ulong uncompressedSize, out Stream stream)
|
|||
|
|
{
|
|||
|
|
LocalFile lf = new LocalFile
|
|||
|
|
{
|
|||
|
|
FileName = filename,
|
|||
|
|
UncompressedSize = uncompressedSize,
|
|||
|
|
StreamOffset = (ulong)(_zipFs.Position - _signatureHeader.BaseOffset)
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
_localFiles.Add(lf);
|
|||
|
|
stream = _tmpOutStream ?? _zipFs;
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileCloseWriteStream(byte[] crc32)
|
|||
|
|
{
|
|||
|
|
_localFiles[_localFiles.Count - 1].crc = new[] { crc32[3], crc32[2], crc32[1], crc32[0] };
|
|||
|
|
return ZipReturn.ZipGood;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Create7ZStructure()
|
|||
|
|
{
|
|||
|
|
int fileCount = _localFiles.Count;
|
|||
|
|
|
|||
|
|
//FileInfo
|
|||
|
|
_header.FileInfo = new Structure.FileInfo
|
|||
|
|
{
|
|||
|
|
Names = new string[fileCount]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
ulong emptyStreamCount = 0;
|
|||
|
|
ulong emptyFileCount = 0;
|
|||
|
|
for (int i = 0; i < fileCount; i++)
|
|||
|
|
{
|
|||
|
|
_header.FileInfo.Names[i] = _localFiles[i].FileName;
|
|||
|
|
|
|||
|
|
if (_localFiles[i].UncompressedSize != 0)
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
if (!_localFiles[i].isDirectory)
|
|||
|
|
emptyFileCount += 1;
|
|||
|
|
|
|||
|
|
emptyStreamCount += 1;
|
|||
|
|
}
|
|||
|
|
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
|||
|
|
|
|||
|
|
_header.FileInfo.EmptyStreamFlags = null;
|
|||
|
|
_header.FileInfo.EmptyFileFlags = null;
|
|||
|
|
_header.FileInfo.Attributes = null;
|
|||
|
|
|
|||
|
|
if (emptyStreamCount > 0)
|
|||
|
|
{
|
|||
|
|
if (emptyStreamCount != emptyFileCount) //then we found directories and need to set the attributes
|
|||
|
|
_header.FileInfo.Attributes = new uint[fileCount];
|
|||
|
|
|
|||
|
|
if (emptyFileCount > 0)
|
|||
|
|
_header.FileInfo.EmptyFileFlags = new bool[emptyStreamCount];
|
|||
|
|
|
|||
|
|
emptyStreamCount = 0;
|
|||
|
|
_header.FileInfo.EmptyStreamFlags = new bool[fileCount];
|
|||
|
|
for (int i = 0; i < fileCount; i++)
|
|||
|
|
{
|
|||
|
|
if (_localFiles[i].UncompressedSize != 0)
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
if (_localFiles[i].isDirectory)
|
|||
|
|
_header.FileInfo.Attributes[i] = 0x10; // set attributes to directory
|
|||
|
|
else
|
|||
|
|
_header.FileInfo.EmptyFileFlags[emptyStreamCount] = true; // set empty file flag
|
|||
|
|
|
|||
|
|
_header.FileInfo.EmptyStreamFlags[i] = true;
|
|||
|
|
emptyStreamCount += 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
//StreamsInfo
|
|||
|
|
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
|||
|
|
|
|||
|
|
//StreamsInfo.PackedStreamsInfo
|
|||
|
|
if (_compressed)
|
|||
|
|
{
|
|||
|
|
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
|||
|
|
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
|||
|
|
int fileIndex = 0;
|
|||
|
|
for (int i = 0; i < fileCount; i++)
|
|||
|
|
{
|
|||
|
|
if (_localFiles[i].UncompressedSize == 0)
|
|||
|
|
continue;
|
|||
|
|
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
|||
|
|
|
|||
|
|
if (_compressed)
|
|||
|
|
{
|
|||
|
|
//StreamsInfo.Folders
|
|||
|
|
_header.StreamsInfo.Folders = new Folder[1];
|
|||
|
|
|
|||
|
|
Folder folder = new Folder { Coders = new Coder[1] };
|
|||
|
|
|
|||
|
|
//StreamsInfo.Folders.Coder
|
|||
|
|
// flags 0x23
|
|||
|
|
folder.Coders[0] = new Coder
|
|||
|
|
{
|
|||
|
|
Method = new byte[] { 3, 1, 1 },
|
|||
|
|
NumInStreams = 1,
|
|||
|
|
NumOutStreams = 1,
|
|||
|
|
Properties = _codeMSbytes
|
|||
|
|
};
|
|||
|
|
folder.BindPairs = null;
|
|||
|
|
folder.PackedStreamIndices = new[] { (ulong)0 };
|
|||
|
|
folder.UnpackedStreamSizes = new[] { _unpackedStreamSize };
|
|||
|
|
folder.UnpackCRC = null;
|
|||
|
|
|
|||
|
|
folder.UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount];
|
|||
|
|
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 { Coders = new Coder[1] };
|
|||
|
|
|
|||
|
|
//StreamsInfo.Folders.Coder
|
|||
|
|
// flags 0x01
|
|||
|
|
folder.Coders[0] = new Coder
|
|||
|
|
{
|
|||
|
|
Method = new byte[] { 0 },
|
|||
|
|
NumInStreams = 1,
|
|||
|
|
NumOutStreams = 1,
|
|||
|
|
Properties = null
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
folder.BindPairs = null;
|
|||
|
|
folder.PackedStreamIndices = new[] { (ulong)i };
|
|||
|
|
folder.UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize };
|
|||
|
|
folder.UnpackCRC = null;
|
|||
|
|
|
|||
|
|
folder.UnpackedStreamInfo = new UnpackedStreamInfo[1];
|
|||
|
|
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
|||
|
|
{
|
|||
|
|
UnpackedSize = _localFiles[i].UncompressedSize,
|
|||
|
|
Crc = Util.bytestouint(_localFiles[i].crc)
|
|||
|
|
};
|
|||
|
|
folder.UnpackedStreamInfo[0] = unpackedStreamInfo;
|
|||
|
|
|
|||
|
|
_header.StreamsInfo.Folders[fileIndex++] = folder;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ulong _packStreamSize;
|
|||
|
|
ulong _unpackedStreamSize;
|
|||
|
|
byte[] _codeMSbytes;
|
|||
|
|
|
|||
|
|
private void CloseWriting7Zip(ICodeProgress p = null)
|
|||
|
|
{
|
|||
|
|
if (_compressed)
|
|||
|
|
{
|
|||
|
|
_unpackedStreamSize = (ulong)_tmpOutStream.Length;
|
|||
|
|
_tmpOutStream.Close();
|
|||
|
|
_tmpOutStream.Dispose();
|
|||
|
|
|
|||
|
|
UInt64 packStreamStart = (UInt64)_zipFs.Position;
|
|||
|
|
using (Stream inStream = new FileStream(_zipFileInfo.FullName + ".tmp", FileMode.Open, FileAccess.Read))
|
|||
|
|
{
|
|||
|
|
LZMACompressFile.CompressFile(inStream, _zipFs, out _codeMSbytes, p);
|
|||
|
|
}
|
|||
|
|
_packStreamSize = (UInt64)_zipFs.Position - packStreamStart;
|
|||
|
|
|
|||
|
|
File.Delete(_zipFileInfo.FullName + ".tmp");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Create7ZStructure();
|
|||
|
|
|
|||
|
|
byte[] newHeaderByte;
|
|||
|
|
using (Stream headerMem = new MemoryStream())
|
|||
|
|
{
|
|||
|
|
using (BinaryWriter headerBw = new BinaryWriter(headerMem))
|
|||
|
|
{
|
|||
|
|
_header.WriteHeader(headerBw);
|
|||
|
|
newHeaderByte = new byte[headerMem.Length];
|
|||
|
|
headerMem.Position = 0;
|
|||
|
|
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CRC mainHeadercrc = new CRC();
|
|||
|
|
mainHeadercrc.Update(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
|||
|
|
UInt32 mainHeaderCRC = mainHeadercrc.GetDigest();
|
|||
|
|
|
|||
|
|
UInt64 headerpos = (UInt64)_zipFs.Position;
|
|||
|
|
BinaryWriter bw = new BinaryWriter(_zipFs);
|
|||
|
|
bw.Write(newHeaderByte);
|
|||
|
|
|
|||
|
|
_signatureHeader.WriteFinal(bw, headerpos, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
|||
|
|
|
|||
|
|
_zipFs.Flush();
|
|||
|
|
_zipFs.Close();
|
|||
|
|
_zipFs.Dispose();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void ZipFileAddDirectory(string filename)
|
|||
|
|
{
|
|||
|
|
LocalFile lf = new LocalFile
|
|||
|
|
{
|
|||
|
|
FileName = filename,
|
|||
|
|
UncompressedSize = 0,
|
|||
|
|
isDirectory = true,
|
|||
|
|
StreamOffset = 0
|
|||
|
|
};
|
|||
|
|
_localFiles.Add(lf);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ZipReturn ZipFileRollBack()
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ZipFileCloseFailed()
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|