using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
namespace FastReport.Utils
{
///
///
///
public class ZipArchive
{
string rootFolder;
string errors;
List fileList;
List fileObjects;
string comment;
private uint CopyStream(Stream source, Stream target)
{
source.Position = 0;
int bufflength = 8192;
uint crc = Crc32.Begin();
byte[] buff = new byte[bufflength];
int i;
while ((i = source.Read(buff, 0, bufflength)) > 0)
{
target.Write(buff, 0, i);
crc = Crc32.Update(crc, buff, 0, i);
}
return Crc32.End(crc);
}
///
/// Clear all files in archive.
///
public void Clear()
{
foreach (ZipFileItem item in fileList)
item.Clear();
foreach (ZipLocalFile item in fileObjects)
item.Clear();
fileList.Clear();
fileObjects.Clear();
errors = "";
rootFolder = "";
comment = "";
}
///
/// Check for exisiting file in archive.
///
///
///
public bool FileExists(string FileName)
{
foreach (ZipFileItem item in fileList)
{
if (item.Name == FileName)
return true;
}
return false;
}
///
/// Adds the file form disk to the archive.
///
///
public void AddFile(string FileName)
{
if (!FileExists(FileName)) // check for exisiting file in archive
{
if (File.Exists(FileName))
{
fileList.Add(new ZipFileItem(FileName));
if (rootFolder == String.Empty)
rootFolder = Path.GetDirectoryName(FileName);
}
else
errors += "File " + FileName + " not found\r";
}
}
///
/// Adds all files from directory (recursive) on the disk to the archive.
///
///
public void AddDir(string DirName)
{
List files = new List();
files.AddRange(Directory.GetFiles(DirName));
foreach (string file in files)
{
if ((File.GetAttributes(file) & FileAttributes.Hidden) != 0)
continue;
AddFile(file);
}
List folders = new List();
folders.AddRange(Directory.GetDirectories(DirName));
foreach (string folder in folders)
{
if ((File.GetAttributes(folder) & FileAttributes.Hidden) != 0)
continue;
AddDir(folder);
}
}
///
/// Adds the stream to the archive.
///
///
///
public void AddStream(string fileName, Stream stream)
{
if (!FileExists(fileName)) // check for exisiting file in archive
fileList.Add(new ZipFileItem(fileName, stream));
}
private void AddStreamToZip(Stream stream, ZipLocalFile ZipFile)
{
if (stream.Length > 128)
{
using (DeflateStream deflate = new DeflateStream(ZipFile.FileData, CompressionMode.Compress, true))
ZipFile.LocalFileHeader.Crc32 = CopyStream(stream, deflate);
ZipFile.LocalFileHeader.CompressionMethod = 8;
}
else
{
ZipFile.LocalFileHeader.Crc32 = CopyStream(stream, ZipFile.FileData);
ZipFile.LocalFileHeader.CompressionMethod = 0;
}
ZipFile.LocalFileHeader.CompressedSize = (uint)ZipFile.FileData.Length;
ZipFile.LocalFileHeader.UnCompressedSize = (uint)stream.Length;
}
///
/// Creates the zip and writes it to rhe Stream
///
///
public void SaveToStream(Stream Stream)
{
ZipLocalFile ZipFile;
ZipCentralDirectory ZipDir;
ZipFileHeader ZipFileHeader;
long CentralStartPos, CentralEndPos;
for (int i = 0; i < fileList.Count; i++)
{
ZipFile = new ZipLocalFile();
using (ZipFile.FileData = new MemoryStream())
{
if (fileList[i].Disk)
{
ZipFile.LocalFileHeader.FileName = fileList[i].Name.Replace(rootFolder + Path.DirectorySeparatorChar, "");
using (FileStream file = new FileStream(fileList[i].Name, FileMode.Open))
AddStreamToZip(file, ZipFile);
}
else
{
ZipFile.LocalFileHeader.FileName = fileList[i].Name;
fileList[i].Stream.Position = 0;
AddStreamToZip(fileList[i].Stream, ZipFile);
}
ZipFile.Offset = (uint)Stream.Position;
ZipFile.LocalFileHeader.LastModFileDate = fileList[i].FileDateTime;
ZipFile.SaveToStream(Stream);
}
ZipFile.FileData = null;
fileObjects.Add(ZipFile);
}
CentralStartPos = Stream.Position;
for (int i = 0; i < fileObjects.Count; i++)
{
ZipFile = fileObjects[i];
ZipFileHeader = new ZipFileHeader();
ZipFileHeader.CompressionMethod = ZipFile.LocalFileHeader.CompressionMethod;
ZipFileHeader.LastModFileDate = ZipFile.LocalFileHeader.LastModFileDate;
ZipFileHeader.GeneralPurpose = ZipFile.LocalFileHeader.GeneralPurpose;
ZipFileHeader.Crc32 = ZipFile.LocalFileHeader.Crc32;
ZipFileHeader.CompressedSize = ZipFile.LocalFileHeader.CompressedSize;
ZipFileHeader.UnCompressedSize = ZipFile.LocalFileHeader.UnCompressedSize;
ZipFileHeader.RelativeOffsetLocalHeader = ZipFile.Offset;
ZipFileHeader.FileName = ZipFile.LocalFileHeader.FileName;
ZipFileHeader.SaveToStream(Stream);
}
CentralEndPos = Stream.Position;
ZipDir = new ZipCentralDirectory();
ZipDir.TotalOfEntriesCentralDirOnDisk = (ushort)fileList.Count;
ZipDir.TotalOfEntriesCentralDir = (ushort)fileList.Count;
ZipDir.SizeOfCentralDir = (uint)(CentralEndPos - CentralStartPos);
ZipDir.OffsetStartingDiskDir = (uint)CentralStartPos;
ZipDir.SaveToStream(Stream);
}
///
/// Creates the ZIP archive and writes it to the file.
///
///
public void SaveToFile(string FileName)
{
using (FileStream file = new FileStream(FileName, FileMode.Create))
SaveToStream(file);
}
///
/// Gets or sets the Root Folder.
///
public string RootFolder
{
get { return rootFolder; }
set { rootFolder = value; }
}
///
/// Gets or sets the errors.
///
public string Errors
{
get { return errors; }
set { errors = value; }
}
///
/// Gets or sets the commentary to the archive.
///
public string Comment
{
get { return comment; }
set { comment = value; }
}
///
/// Gets count of files in archive.
///
public int FileCount
{
get { return fileList.Count; }
}
///
/// Creates the new zip archive.
///
public ZipArchive()
{
fileList = new List();
fileObjects = new List();
Clear();
}
}
internal class ZipFileItem
{
private string name;
private Stream stream;
private bool disk;
private uint fileDateTime;
private uint GetDosDateTime(DateTime date)
{
return (uint)(
((date.Year - 1980 & 0x7f) << 25) |
((date.Month & 0xF) << 21) |
((date.Day & 0x1F) << 16) |
((date.Hour & 0x1F) << 11) |
((date.Minute & 0x3F) << 5) |
(date.Second >> 1));
}
public string Name
{
get { return name; }
set { name = value; }
}
public Stream Stream
{
get { return stream; }
}
public bool Disk
{
get { return disk; }
set { disk = value; }
}
public uint FileDateTime
{
get { return fileDateTime; }
set { fileDateTime = value; }
}
public void Clear()
{
if (stream != null)
{
stream.Dispose();
stream = null;
}
}
public ZipFileItem()
{
stream = new MemoryStream();
fileDateTime = GetDosDateTime(SystemFake.DateTime.Now);
disk = false;
}
public ZipFileItem(string fileName, Stream stream)
{
this.stream = stream;
name = fileName;
fileDateTime = GetDosDateTime(SystemFake.DateTime.Now);
disk = false;
}
public ZipFileItem(string fileName)
{
name = fileName;
fileDateTime = GetDosDateTime(File.GetLastWriteTime(fileName));
disk = true;
}
}
internal class ZipLocalFileHeader
{
private uint localFileHeaderSignature;
private ushort version;
private ushort generalPurpose;
private ushort compressionMethod;
private uint crc32;
private uint lastModFileDate;
private uint compressedSize;
private uint unCompressedSize;
private string extraField;
private string fileName;
private ushort fileNameLength;
private ushort extraFieldLength;
public void SaveToStream(Stream Stream)
{
Stream.Write(BitConverter.GetBytes(localFileHeaderSignature), 0, 4);
Stream.Write(BitConverter.GetBytes(version), 0, 2);
Stream.Write(BitConverter.GetBytes(generalPurpose), 0, 2);
Stream.Write(BitConverter.GetBytes(compressionMethod), 0, 2);
Stream.Write(BitConverter.GetBytes(lastModFileDate), 0, 4);
Stream.Write(BitConverter.GetBytes(crc32), 0, 4);
Stream.Write(BitConverter.GetBytes(compressedSize), 0, 4);
Stream.Write(BitConverter.GetBytes(unCompressedSize), 0, 4);
Stream.Write(BitConverter.GetBytes(fileNameLength), 0, 2);
Stream.Write(BitConverter.GetBytes(extraFieldLength), 0, 2);
if (fileNameLength > 0)
Stream.Write(System.Text.Encoding.UTF8.GetBytes(fileName), 0, fileNameLength);
if (extraFieldLength > 0)
Stream.Write(Converter.StringToByteArray(extraField), 0, extraFieldLength);
}
public uint LocalFileHeaderSignature
{
get { return localFileHeaderSignature; }
}
public ushort Version
{
get { return version; }
set { version = value; }
}
public ushort GeneralPurpose
{
get { return generalPurpose; }
set { generalPurpose = value; }
}
public ushort CompressionMethod
{
get { return compressionMethod; }
set { compressionMethod = value; }
}
public uint LastModFileDate
{
get { return lastModFileDate; }
set { lastModFileDate = value; }
}
public uint Crc32
{
get { return crc32; }
set { crc32 = value; }
}
public uint CompressedSize
{
get { return compressedSize; }
set { compressedSize = value; }
}
public uint UnCompressedSize
{
get { return unCompressedSize; }
set { unCompressedSize = value; }
}
public ushort FileNameLength
{
get { return fileNameLength; }
set { fileNameLength = value; }
}
public ushort ExtraFieldLength
{
get { return extraFieldLength; }
set { extraFieldLength = value; }
}
public string FileName
{
get { return fileName; }
set
{
fileName = value.Replace('\\', '/');
fileNameLength = (ushort)System.Text.Encoding.UTF8.GetBytes(value).Length;
}
}
public string ExtraField
{
get { return extraField; }
set
{
extraField = value;
extraFieldLength = (ushort)value.Length;
}
}
// constructor
public ZipLocalFileHeader()
{
localFileHeaderSignature = 0x04034b50;
version = 20;
generalPurpose = 0x800;
compressionMethod = 0;
crc32 = 0;
lastModFileDate = 0;
compressedSize = 0;
unCompressedSize = 0;
extraField = "";
fileName = "";
fileNameLength = 0;
extraFieldLength = 0;
}
}
internal class ZipCentralDirectory
{
private uint endOfChentralDirSignature;
private ushort numberOfTheDisk;
private ushort totalOfEntriesCentralDirOnDisk;
private ushort numberOfTheDiskStartCentralDir;
private ushort totalOfEntriesCentralDir;
private uint sizeOfCentralDir;
private uint offsetStartingDiskDir;
private string comment;
private ushort commentLength;
public void SaveToStream(Stream Stream)
{
Stream.Write(BitConverter.GetBytes(endOfChentralDirSignature), 0, 4);
Stream.Write(BitConverter.GetBytes(numberOfTheDisk), 0, 2);
Stream.Write(BitConverter.GetBytes(numberOfTheDiskStartCentralDir), 0, 2);
Stream.Write(BitConverter.GetBytes(totalOfEntriesCentralDirOnDisk), 0, 2);
Stream.Write(BitConverter.GetBytes(totalOfEntriesCentralDir), 0, 2);
Stream.Write(BitConverter.GetBytes(sizeOfCentralDir), 0, 4);
Stream.Write(BitConverter.GetBytes(offsetStartingDiskDir), 0, 4);
Stream.Write(BitConverter.GetBytes(commentLength), 0, 2);
if (commentLength > 0)
Stream.Write(Converter.StringToByteArray(comment), 0, commentLength);
}
public uint EndOfChentralDirSignature
{
get { return endOfChentralDirSignature; }
}
public ushort NumberOfTheDisk
{
get { return numberOfTheDisk; }
set { numberOfTheDisk = value; }
}
public ushort NumberOfTheDiskStartCentralDir
{
get { return numberOfTheDiskStartCentralDir; }
set { numberOfTheDiskStartCentralDir = value; }
}
public ushort TotalOfEntriesCentralDirOnDisk
{
get { return totalOfEntriesCentralDirOnDisk; }
set { totalOfEntriesCentralDirOnDisk = value; }
}
public ushort TotalOfEntriesCentralDir
{
get { return totalOfEntriesCentralDir; }
set { totalOfEntriesCentralDir = value; }
}
public uint SizeOfCentralDir
{
get { return sizeOfCentralDir; }
set { sizeOfCentralDir = value; }
}
public uint OffsetStartingDiskDir
{
get { return offsetStartingDiskDir; }
set { offsetStartingDiskDir = value; }
}
public ushort CommentLength
{
get { return commentLength; }
set { commentLength = value; }
}
public string Comment
{
get { return comment; }
set
{
comment = value;
commentLength = (ushort)value.Length;
}
}
// constructor
public ZipCentralDirectory()
{
endOfChentralDirSignature = 0x06054b50;
numberOfTheDisk = 0;
numberOfTheDiskStartCentralDir = 0;
totalOfEntriesCentralDirOnDisk = 0;
totalOfEntriesCentralDir = 0;
sizeOfCentralDir = 0;
offsetStartingDiskDir = 0;
commentLength = 0;
comment = "";
}
}
internal class ZipFileHeader
{
private uint centralFileHeaderSignature;
private uint relativeOffsetLocalHeader;
private uint unCompressedSize;
private uint compressedSize;
private uint crc32;
private uint externalFileAttribute;
private string extraField;
private string fileComment;
private string fileName;
private ushort compressionMethod;
private ushort diskNumberStart;
private uint lastModFileDate;
private ushort versionMadeBy;
private ushort generalPurpose;
private ushort fileNameLength;
private ushort internalFileAttribute;
private ushort extraFieldLength;
private ushort versionNeeded;
private ushort fileCommentLength;
public void SaveToStream(Stream Stream)
{
Stream.Write(BitConverter.GetBytes(centralFileHeaderSignature), 0, 4);
Stream.Write(BitConverter.GetBytes(versionMadeBy), 0, 2);
Stream.Write(BitConverter.GetBytes(versionNeeded), 0, 2);
Stream.Write(BitConverter.GetBytes(generalPurpose), 0, 2);
Stream.Write(BitConverter.GetBytes(compressionMethod), 0, 2);
Stream.Write(BitConverter.GetBytes(lastModFileDate), 0, 4);
Stream.Write(BitConverter.GetBytes(crc32), 0, 4);
Stream.Write(BitConverter.GetBytes(compressedSize), 0, 4);
Stream.Write(BitConverter.GetBytes(unCompressedSize), 0, 4);
Stream.Write(BitConverter.GetBytes(fileNameLength), 0, 2);
Stream.Write(BitConverter.GetBytes(extraFieldLength), 0, 2);
Stream.Write(BitConverter.GetBytes(fileCommentLength), 0, 2);
Stream.Write(BitConverter.GetBytes(diskNumberStart), 0, 2);
Stream.Write(BitConverter.GetBytes(internalFileAttribute), 0, 2);
Stream.Write(BitConverter.GetBytes(externalFileAttribute), 0, 4);
Stream.Write(BitConverter.GetBytes(relativeOffsetLocalHeader), 0, 4);
Stream.Write(System.Text.Encoding.UTF8.GetBytes(fileName), 0, fileNameLength);
Stream.Write(Converter.StringToByteArray(extraField), 0, extraFieldLength);
Stream.Write(Converter.StringToByteArray(fileComment), 0, fileCommentLength);
}
public uint CentralFileHeaderSignature
{
get { return centralFileHeaderSignature; }
}
public ushort VersionMadeBy
{
get { return versionMadeBy; }
}
public ushort VersionNeeded
{
get { return versionNeeded; }
}
public ushort GeneralPurpose
{
get { return generalPurpose; }
set { generalPurpose = value; }
}
public ushort CompressionMethod
{
get { return compressionMethod; }
set { compressionMethod = value; }
}
public uint LastModFileDate
{
get { return lastModFileDate; }
set { lastModFileDate = value; }
}
public uint Crc32
{
get { return crc32; }
set { crc32 = value; }
}
public uint CompressedSize
{
get { return compressedSize; }
set { compressedSize = value; }
}
public uint UnCompressedSize
{
get { return unCompressedSize; }
set { unCompressedSize = value; }
}
public ushort FileNameLength
{
get { return fileNameLength; }
set { fileNameLength = value; }
}
public ushort ExtraFieldLength
{
get { return extraFieldLength; }
set { extraFieldLength = value; }
}
public ushort FileCommentLength
{
get { return fileCommentLength; }
set { fileCommentLength = value; }
}
public ushort DiskNumberStart
{
get { return diskNumberStart; }
set { diskNumberStart = value; }
}
public ushort InternalFileAttribute
{
get { return internalFileAttribute; }
set { internalFileAttribute = value; }
}
public uint ExternalFileAttribute
{
get { return externalFileAttribute; }
set { externalFileAttribute = value; }
}
public uint RelativeOffsetLocalHeader
{
get { return relativeOffsetLocalHeader; }
set { relativeOffsetLocalHeader = value; }
}
public string FileName
{
get { return fileName; }
set
{
fileName = value.Replace('\\', '/');
fileNameLength = (ushort)System.Text.Encoding.UTF8.GetBytes(value).Length;
}
}
public string ExtraField
{
get { return extraField; }
set
{
extraField = value;
extraFieldLength = (ushort)value.Length;
}
}
public string FileComment
{
get { return fileComment; }
set
{
fileComment = value;
fileCommentLength = (ushort)value.Length;
}
}
// constructor
public ZipFileHeader()
{
centralFileHeaderSignature = 0x02014b50;
relativeOffsetLocalHeader = 0;
unCompressedSize = 0;
compressedSize = 0;
crc32 = 0;
externalFileAttribute = 0;
extraField = "";
fileComment = "";
fileName = "";
compressionMethod = 0;
diskNumberStart = 0;
lastModFileDate = 0;
versionMadeBy = 20;
generalPurpose = 0x800;
fileNameLength = 0;
internalFileAttribute = 0;
extraFieldLength = 0;
versionNeeded = 20;
fileCommentLength = 0;
}
}
internal class ZipLocalFile
{
ZipLocalFileHeader localFileHeader;
MemoryStream fileData;
uint offset;
public void SaveToStream(Stream Stream)
{
localFileHeader.SaveToStream(Stream);
fileData.Position = 0;
fileData.WriteTo(Stream);
fileData.Dispose();
fileData = null;
}
public ZipLocalFileHeader LocalFileHeader
{
get { return localFileHeader; }
}
public MemoryStream FileData
{
get { return fileData; }
set { fileData = value; }
}
public uint Offset
{
get { return offset; }
set { offset = value; }
}
public void Clear()
{
if (fileData != null)
{
fileData.Dispose();
fileData = null;
}
}
// constructor
public ZipLocalFile()
{
localFileHeader = new ZipLocalFileHeader();
offset = 0;
}
}
}