mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
[ZIpFile, ZipFileEntry] Finish porting over code from RV
This commit is contained in:
@@ -178,7 +178,7 @@ namespace SabreTools.Helper
|
||||
public const uint EndOfLocalFileHeaderSignature = 0x08074b50;
|
||||
public const uint CentralDirectoryHeaderSignature = 0x02014b50;
|
||||
public const uint EndOfCentralDirSignature = 0x06054b50;
|
||||
public const uint Zip64EndOfCentralDirSignatue = 0x06064b50;
|
||||
public const uint Zip64EndOfCentralDirSignature = 0x06064b50;
|
||||
public const uint Zip64EndOfCentralDirectoryLocator = 0x07064b50;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -260,5 +260,16 @@
|
||||
ZipUntested
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zip open type
|
||||
/// </summary>
|
||||
/// <remarks>https://raw.githubusercontent.com/gjefferyes/RomVault/5a93500001f0d068f32cf77a048950717507f733/ROMVault2/SupportedFiles/ZipEnums.cs</remarks>
|
||||
public enum ZipOpenType
|
||||
{
|
||||
Closed,
|
||||
OpenRead,
|
||||
OpenWrite
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -80,4 +80,16 @@ namespace SabreTools.Helper
|
||||
Bit1 = 0x0002,
|
||||
Bit2 = 0x0004,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zipfile special status
|
||||
/// </summary>
|
||||
/// <remarks>https://github.com/gjefferyes/RomVault/blob/5a93500001f0d068f32cf77a048950717507f733/ROMVault2/SupportedFiles/ZipEnums.cs</remarks>
|
||||
[Flags]
|
||||
public enum ZipStatus
|
||||
{
|
||||
None = 0x0,
|
||||
TorrentZip = 0x1,
|
||||
ExtraData = 0x2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using Ionic.Zlib;
|
||||
using Ionic.Crc;
|
||||
using Ionic.Zlib;
|
||||
using OCRC;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -11,7 +14,890 @@ namespace SabreTools.Helper
|
||||
/// Based on work by GordonJ for RomVault
|
||||
/// https://github.com/gjefferyes/RomVault/blob/master/ROMVault2/SupportedFiles/Zip/zipFile.cs
|
||||
/// </remarks>
|
||||
public class ZipFIle
|
||||
public class ZipFile : IDisposable
|
||||
{
|
||||
#region Private instance variables
|
||||
|
||||
private FileInfo _zipFileInfo;
|
||||
private ulong _centerDirStart;
|
||||
private ulong _centerDirSize;
|
||||
private ulong _endOfCenterDir64;
|
||||
private byte[] _fileComment;
|
||||
private Stream _zipstream;
|
||||
private uint _entriesCount;
|
||||
private readonly List<ZipFileEntry> _entries = new List<ZipFileEntry>();
|
||||
private ZipStatus _zipStatus;
|
||||
private bool _zip64;
|
||||
private ZipOpenType _zipOpen;
|
||||
private int _readIndex;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public facing variables
|
||||
|
||||
public string ZipFilename
|
||||
{
|
||||
get { return (_zipFileInfo != null ? _zipFileInfo.FullName : ""); }
|
||||
}
|
||||
public long TimeStamp
|
||||
{
|
||||
get { return (_zipFileInfo != null ? _zipFileInfo.LastWriteTime.Ticks : 0); }
|
||||
}
|
||||
public ZipOpenType ZipOpen
|
||||
{
|
||||
get { return _zipOpen; }
|
||||
set { _zipOpen = value; }
|
||||
}
|
||||
public ZipStatus ZipStatus
|
||||
{
|
||||
get { return _zipStatus; }
|
||||
}
|
||||
public int EntriesCount
|
||||
{
|
||||
get { return _entries.Count; }
|
||||
}
|
||||
public string Filename(int i)
|
||||
{
|
||||
return _entries[i].FileName;
|
||||
}
|
||||
public ulong UncompressedSize(int i)
|
||||
{
|
||||
return _entries[i].UncompressedSize;
|
||||
}
|
||||
public ulong? LocalHeader(int i)
|
||||
{
|
||||
return ((_entries[i].GeneralPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0
|
||||
? (ulong?)_entries[i].RelativeOffset
|
||||
: null);
|
||||
}
|
||||
public ZipReturn FileStatus(int i)
|
||||
{
|
||||
return _entries[i].FileStatus;
|
||||
}
|
||||
public byte[] CRC32(int i)
|
||||
{
|
||||
return _entries[i].CRC;
|
||||
}
|
||||
public byte[] MD5(int i)
|
||||
{
|
||||
return _entries[i].MD5;
|
||||
}
|
||||
public byte[] SHA1(int i)
|
||||
{
|
||||
return _entries[i].SHA1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Destructors
|
||||
|
||||
~ZipFile()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_zipstream != null)
|
||||
{
|
||||
_zipstream.Close();
|
||||
_zipstream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Find the end of the central directory signature
|
||||
/// </summary>
|
||||
/// <returns>Status of the given stream</returns>
|
||||
private ZipReturn FindEndOfCentralDirSignature()
|
||||
{
|
||||
long fileSize = _zipstream.Length;
|
||||
long maxBackSearch = 0xffff;
|
||||
|
||||
if (_zipstream.Length < maxBackSearch)
|
||||
{
|
||||
maxBackSearch = _zipstream.Length;
|
||||
}
|
||||
|
||||
const long buffsize = 0x400;
|
||||
byte[] buffer = new byte[buffsize + 4];
|
||||
|
||||
long backPosition = 4;
|
||||
while (backPosition < maxBackSearch)
|
||||
{
|
||||
backPosition += buffsize;
|
||||
if (backPosition > maxBackSearch) backPosition = maxBackSearch;
|
||||
|
||||
long readSize = backPosition > (buffsize + 4) ? (buffsize + 4) : backPosition;
|
||||
|
||||
_zipstream.Position = fileSize - backPosition;
|
||||
|
||||
_zipstream.Read(buffer, 0, (int)readSize);
|
||||
|
||||
|
||||
for (long i = readSize - 4; i >= 0; i--)
|
||||
{
|
||||
if ((buffer[i] != 0x50) || (buffer[i + 1] != 0x4b) || (buffer[i + 2] != 0x05) || (buffer[i + 3] != 0x06))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_zipstream.Position = (fileSize - backPosition) + i;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
}
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the end of the central directory
|
||||
/// </summary>
|
||||
/// <returns>Status of the given stream</returns>
|
||||
private ZipReturn ReadEndOfCentralDir()
|
||||
{
|
||||
// Open the stream for reading
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
|
||||
// If the stream doesn't start with the correct signature, return
|
||||
uint thisSignature = br.ReadUInt32();
|
||||
if (thisSignature != Constants.EndOfCentralDirSignature)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
|
||||
// If this is part of a spanned archive, return
|
||||
ushort tushort = br.ReadUInt16(); // NumberOfThisDisk
|
||||
if (tushort != 0)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
tushort = br.ReadUInt16(); // NumberOfThisDiskCenterDir
|
||||
if (tushort != 0)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
|
||||
// If the number of entries in the current disk doesn't match up with the total entries, return
|
||||
_entriesCount = br.ReadUInt16(); // TotalNumberOfEntriesDisk
|
||||
tushort = br.ReadUInt16(); // TotalNumber of entries in the central directory
|
||||
if (tushort != _entriesCount)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
|
||||
_centerDirSize = br.ReadUInt32(); // SizeOfCenteralDir
|
||||
_centerDirStart = br.ReadUInt32(); // Offset
|
||||
|
||||
// Get the file comment
|
||||
ushort zipFileCommentLength = br.ReadUInt16();
|
||||
_fileComment = br.ReadBytes(zipFileCommentLength);
|
||||
|
||||
// If there's extra data past the comment, flag that we have extra data
|
||||
if (_zipstream.Position != _zipstream.Length)
|
||||
{
|
||||
_zipStatus |= ZipStatus.ExtraData;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the end of the central directory
|
||||
/// </summary>
|
||||
private void WriteEndOfCentralDir()
|
||||
{
|
||||
// Open the stream for writing
|
||||
BinaryWriter bw = new BinaryWriter(_zipstream);
|
||||
|
||||
// Now write out all of the data
|
||||
bw.Write(Constants.EndOfCentralDirSignature);
|
||||
bw.Write((ushort)0); // NumberOfThisDisk
|
||||
bw.Write((ushort)0); // NumberOfThisDiskCenterDir
|
||||
bw.Write((ushort)(_entries.Count >= 0xffff ? 0xffff : _entries.Count)); // TotalNumberOfEnteriesDisk
|
||||
bw.Write((ushort)(_entries.Count >= 0xffff ? 0xffff : _entries.Count)); // TotalNumber of enteries in the central directory
|
||||
bw.Write((uint)(_centerDirSize >= 0xffffffff ? 0xffffffff : _centerDirSize));
|
||||
bw.Write((uint)(_centerDirStart >= 0xffffffff ? 0xffffffff : _centerDirStart));
|
||||
bw.Write((ushort)_fileComment.Length);
|
||||
bw.Write(_fileComment, 0, _fileComment.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the end of the Zip64 central directory
|
||||
/// </summary>
|
||||
/// <returns>Status of the given stream</returns>
|
||||
private ZipReturn ReadZip64EndOfCentralDir()
|
||||
{
|
||||
// Set the type of the archive to Zip64
|
||||
_zip64 = true;
|
||||
|
||||
// Open the stream for reading
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
|
||||
// If the signature doesn't match, then return
|
||||
uint thisSignature = br.ReadUInt32();
|
||||
if (thisSignature != Constants.Zip64EndOfCentralDirSignature)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
|
||||
// If the size of the central dir record isn't right, return
|
||||
ulong tulong = br.ReadUInt64(); // Size of zip64 end of central directory record
|
||||
if (tulong != 44)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
}
|
||||
|
||||
br.ReadUInt16(); // version made by
|
||||
|
||||
// If the version needed to extract isn't correct, return
|
||||
ushort tushort = br.ReadUInt16(); // version needed to extract
|
||||
if (tushort != (ushort)ArchiveVersion.TorrentZip64)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
}
|
||||
|
||||
// If this is part of a spanned archive, return
|
||||
uint tuint = br.ReadUInt32(); // number of this disk
|
||||
if (tuint != 0)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
}
|
||||
tuint = br.ReadUInt32(); // number of the disk with the start of the central directory
|
||||
if (tuint != 0)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
}
|
||||
|
||||
// If the number of entries in the current disk doesn't match up with the total entries, return
|
||||
_entriesCount = (uint)br.ReadUInt64(); // total number of entries in the central directory on this disk
|
||||
tulong = br.ReadUInt64(); // total number of entries in the central directory
|
||||
if (tulong != _entriesCount)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirError;
|
||||
}
|
||||
|
||||
_centerDirSize = br.ReadUInt64(); // size of central directory
|
||||
_centerDirStart = br.ReadUInt64(); // offset of start of central directory with respect to the starting disk number
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the end of the Zip64 central directory
|
||||
/// </summary>
|
||||
private void WriteZip64EndOfCentralDir()
|
||||
{
|
||||
// Open the stream for writing
|
||||
BinaryWriter bw = new BinaryWriter(_zipstream);
|
||||
|
||||
// Now write out all of the data
|
||||
bw.Write(Constants.Zip64EndOfCentralDirSignature);
|
||||
bw.Write((ulong)44); // Size of zip64 end of central directory record
|
||||
bw.Write((ushort)ArchiveVersion.TorrentZip64); // version made by
|
||||
bw.Write((ushort)ArchiveVersion.TorrentZip64); // version needed to extract
|
||||
bw.Write((uint)0); // number of this disk
|
||||
bw.Write((uint)0); // number of the disk with the start of the central directroy
|
||||
bw.Write((ulong)_entries.Count); // total number of entries in the central directory on this disk
|
||||
bw.Write((ulong)_entries.Count); // total number of entries in the central directory
|
||||
bw.Write(_centerDirSize); // size of central directory
|
||||
bw.Write(_centerDirStart); // offset of start of central directory with respect to the starting disk number
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the end of the Zip64 central directory locator
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private ZipReturn ReadZip64EndOfCentralDirectoryLocator()
|
||||
{
|
||||
// Set the current archive type to Zip64
|
||||
_zip64 = true;
|
||||
|
||||
// Open the stream for reading
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
|
||||
// If the signature doesn't match, return
|
||||
uint thisSignature = br.ReadUInt32();
|
||||
if (thisSignature != Constants.Zip64EndOfCentralDirectoryLocator)
|
||||
{
|
||||
return ZipReturn.ZipEndOfCentralDirectoryError;
|
||||
}
|
||||
|
||||
// If the disk isn't the first and only, then return
|
||||
uint tuint = br.ReadUInt32(); // number of the disk with the start of the zip64 end of centeral directory
|
||||
if (tuint != 0)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirectoryLocatorError;
|
||||
}
|
||||
|
||||
_endOfCenterDir64 = br.ReadUInt64(); // relative offset of the zip64 end of central directory record
|
||||
|
||||
tuint = br.ReadUInt32(); // total number of disks
|
||||
if (tuint != 1)
|
||||
{
|
||||
return ZipReturn.Zip64EndOfCentralDirectoryLocatorError;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the end of the Zip64 central directory locator
|
||||
/// </summary>
|
||||
private void WriteZip64EndOfCentralDirectoryLocator()
|
||||
{
|
||||
// Open the stream for writing
|
||||
BinaryWriter bw = new BinaryWriter(_zipstream);
|
||||
|
||||
// Now write the data
|
||||
bw.Write(Constants.Zip64EndOfCentralDirectoryLocator);
|
||||
bw.Write((uint)0); // number of the disk with the start of the zip64 end of centeral directory
|
||||
bw.Write(_endOfCenterDir64); // relative offset of the zip64 end of central directroy record
|
||||
bw.Write((uint)1); // total number of disks
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open a new file as an archive
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the new file to open</param>
|
||||
/// <param name="timestamp">Timestamp the file should have</param>
|
||||
/// <param name="readHeaders">True if file headers should be read, false otherwise</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn Open(string filename, long timestamp, bool readHeaders)
|
||||
{
|
||||
// If a stream already exists, close it
|
||||
Close();
|
||||
|
||||
// Now, reset the archive information
|
||||
_zipStatus = ZipStatus.None;
|
||||
_zip64 = false;
|
||||
_centerDirStart = 0;
|
||||
_centerDirSize = 0;
|
||||
_zipFileInfo = null;
|
||||
|
||||
// Then, attempt to open the file and get information from it
|
||||
try
|
||||
{
|
||||
// If the input file doesn't exist, close the stream and return
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipErrorFileNotFound;
|
||||
}
|
||||
|
||||
// Get the fileinfo object
|
||||
_zipFileInfo = new FileInfo(filename);
|
||||
|
||||
// If the timestamps don't match, close the stream and return
|
||||
if (_zipFileInfo.LastWriteTime.Ticks != timestamp)
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipErrorTimeStamp;
|
||||
}
|
||||
|
||||
// Now try to open the file for reading
|
||||
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
|
||||
int errorcode = fs.Read(new byte[1], 0, 1);
|
||||
if (errorcode != 0)
|
||||
{
|
||||
Close();
|
||||
if (errorcode == 32)
|
||||
{
|
||||
return ZipReturn.ZipFileLocked;
|
||||
}
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
}
|
||||
catch (PathTooLongException)
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipFileNameToLong;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
|
||||
// If we succedded, set the flag for read
|
||||
_zipOpen = ZipOpenType.OpenRead;
|
||||
|
||||
// If we're not reading the headers, return
|
||||
if (!readHeaders)
|
||||
{
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
//Otherwise, we want to get all of the archive information
|
||||
try
|
||||
{
|
||||
// First, try to get the end of the central directory
|
||||
ZipReturn zr = FindEndOfCentralDirSignature();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// Now read the end of the central directory
|
||||
long eocd = _zipstream.Position;
|
||||
zr = ReadEndOfCentralDir();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// If we have any indicators of Zip64, check for the Zip64 EOCD
|
||||
if (_centerDirStart == 0xffffffff || _centerDirSize == 0xffffffff || _entriesCount == 0xffff)
|
||||
{
|
||||
_zip64 = true;
|
||||
|
||||
// Check for the Zip64 EOCD locator
|
||||
_zipstream.Position = eocd - 20;
|
||||
zr = ReadZip64EndOfCentralDirectoryLocator();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// If it was found, read the Zip64 EOCD
|
||||
_zipstream.Position = (long)_endOfCenterDir64;
|
||||
zr = ReadZip64EndOfCentralDir();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have the rest of the information, check for TorrentZip
|
||||
bool torrentZip = false;
|
||||
if (_fileComment.Length == 22)
|
||||
{
|
||||
if (Encoding.ASCII.GetString(_fileComment).Substring(0, 14) == "TORRENTZIPPED-")
|
||||
{
|
||||
// First get to the right part of the stream
|
||||
OptimizedCRC ocrc = new OptimizedCRC();
|
||||
byte[] buffer = new byte[_centerDirSize];
|
||||
_zipstream.Position = (long)_centerDirStart;
|
||||
|
||||
// Then read in the central directory and hash
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
buffer = br.ReadBytes((int)_centerDirSize);
|
||||
ocrc.Update(buffer, 0, (int)_centerDirSize);
|
||||
string calculatedCrc = ocrc.Value.ToString("X8");
|
||||
|
||||
// If the hashes match, then we have a torrentzip file
|
||||
string extractedCrc = Encoding.ASCII.GetString(_fileComment).Substring(14, 8);
|
||||
if (String.Equals(calculatedCrc, extractedCrc, StringComparison.Ordinal))
|
||||
{
|
||||
torrentZip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// With potential torrentzip out of the way, read the central directory
|
||||
_zipstream.Position = (long)_centerDirStart;
|
||||
|
||||
// Remove any entries already listed in the archive
|
||||
_entries.Clear();
|
||||
_entries.Capacity = (int)_entriesCount;
|
||||
|
||||
// Now populate the entries from the central directory
|
||||
for (int i = 0; i < _entriesCount; i++)
|
||||
{
|
||||
ZipFileEntry zfe = new ZipFileEntry(_zipstream);
|
||||
zr = zfe.ReadCentralDirectory();
|
||||
|
||||
// If we get any errors, close and return
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// If we have a Zip64 entry, make sure the archive is
|
||||
_zip64 |= zfe.Zip64;
|
||||
|
||||
// Now add the entry to the archive
|
||||
_entries.Add(zfe);
|
||||
}
|
||||
|
||||
// Now that the entries are populated, verify against the actual headers
|
||||
for (int i = 0; i < _entriesCount; i++)
|
||||
{
|
||||
zr = _entries[i].ReadHeader();
|
||||
|
||||
// If we get any errors, close and return
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// If we have a torrentzipped entry, make sure the archive is
|
||||
torrentZip &= _entries[i].TorrentZip;
|
||||
}
|
||||
|
||||
// If we have a torrentzipped file, check the file order
|
||||
if (torrentZip)
|
||||
{
|
||||
for (int i = 0; i < _entriesCount - 1; i++)
|
||||
{
|
||||
if (TorrentZipStringCompare(_entries[i].FileName, _entries[i + 1].FileName) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
torrentZip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check for torrentzipped directories if we still have a torrentZip file
|
||||
if (torrentZip)
|
||||
{
|
||||
for (int i = 0; i < _entriesCount - 1; i++)
|
||||
{
|
||||
// See if we found a directory
|
||||
string filename0 = _entries[i].FileName;
|
||||
if (filename0.Substring(filename0.Length - 1, 1) != "/")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if the next file is in that directory
|
||||
string filename1 = _entries[i + 1].FileName;
|
||||
if (filename1.Length <= filename0.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (TorrentZipStringCompare(filename0, filename1.Substring(0, filename0.Length)) = 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we found a file in the directory, then we don't need the directory entry
|
||||
torrentZip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we still have torrentzip, say the archive is too
|
||||
if (torrentZip)
|
||||
{
|
||||
_zipStatus |= ZipStatus.TorrentZip;
|
||||
}
|
||||
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipErrorReadingFile;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new file as an archive
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the new file to create</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn Create(string filename)
|
||||
{
|
||||
// If the file is already open, return
|
||||
if (_zipOpen != ZipOpenType.Closed)
|
||||
{
|
||||
return ZipReturn.ZipFileAlreadyOpen;
|
||||
}
|
||||
|
||||
// Otherwise, create the directory for the file
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
_zipFileInfo = new FileInfo(filename);
|
||||
|
||||
// Now try to open the file
|
||||
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||
int errorcode = fs.Read(new byte[1], 0, 1);
|
||||
if (errorcode != 0)
|
||||
{
|
||||
Close();
|
||||
return ZipReturn.ZipErrorOpeningFile;
|
||||
}
|
||||
ZipOpen = ZipOpenType.OpenWrite;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the file that the stream refers to
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
// If the stream is already closed, then just return
|
||||
if (_zipOpen == ZipOpenType.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the stream is opened for read, close it
|
||||
if (_zipOpen == ZipOpenType.OpenRead)
|
||||
{
|
||||
Dispose();
|
||||
_zipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, the only other choice is open for writing so we check everything is correct
|
||||
_zip64 = false;
|
||||
bool torrentZip = true;
|
||||
|
||||
// Check the central directory
|
||||
_centerDirStart = (ulong)_zipstream.Position;
|
||||
if (_centerDirStart >= 0xffffffff)
|
||||
{
|
||||
_zip64 = true;
|
||||
}
|
||||
|
||||
// Now loop through and add all of the central directory entries
|
||||
foreach (ZipFileEntry zfe in _entries)
|
||||
{
|
||||
zfe.WriteCentralDirectory(_zipstream);
|
||||
_zip64 |= zfe.Zip64;
|
||||
torrentZip &= zfe.TorrentZip;
|
||||
}
|
||||
|
||||
// Then get the central directory hash
|
||||
OptimizedCRC ocrc = new OptimizedCRC();
|
||||
byte[] buffer = new byte[_centerDirSize];
|
||||
long currentPosition = _zipstream.Position;
|
||||
_zipstream.Position = (long)_centerDirStart;
|
||||
|
||||
// Then read in the central directory and hash
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
buffer = br.ReadBytes((int)_centerDirSize);
|
||||
ocrc.Update(buffer, 0, (int)_centerDirSize);
|
||||
string calculatedCrc = ocrc.Value.ToString("X8");
|
||||
|
||||
// Finally get back to the original position
|
||||
_zipstream.Position = currentPosition;
|
||||
|
||||
// Now set more of the information
|
||||
_centerDirSize = (ulong)_zipstream.Position - _centerDirStart;
|
||||
_fileComment = (torrentZip ? Encoding.ASCII.GetBytes(("TORRENTZIPPED-" + calculatedCrc).ToCharArray()) : new byte[0]);
|
||||
_zipStatus = (torrentZip ? ZipStatus.TorrentZip : ZipStatus.None);
|
||||
|
||||
// If we have a Zip64 archive, write the correct information
|
||||
if (_zip64)
|
||||
{
|
||||
_endOfCenterDir64 = (ulong)_zipstream.Position;
|
||||
WriteZip64EndOfCentralDir();
|
||||
WriteZip64EndOfCentralDirectoryLocator();
|
||||
}
|
||||
|
||||
// Now write out the end of the central directory
|
||||
WriteEndOfCentralDir();
|
||||
|
||||
// Finally, close and dispose of the stream
|
||||
_zipstream.SetLength(_zipstream.Position);
|
||||
_zipstream.Flush();
|
||||
_zipstream.Close();
|
||||
_zipstream.Dispose();
|
||||
|
||||
// Get the new file information
|
||||
_zipFileInfo = new FileInfo(_zipFileInfo.FullName);
|
||||
|
||||
// And set the stream to closed
|
||||
_zipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close a failed stream
|
||||
/// </summary>
|
||||
public void CloseFailed()
|
||||
{
|
||||
// If the stream is already closed, return
|
||||
if (_zipOpen == ZipOpenType.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're open for read, close the underlying stream
|
||||
if (_zipOpen == ZipOpenType.OpenRead)
|
||||
{
|
||||
Dispose();
|
||||
_zipOpen = ZipOpenType.Closed;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we only have an open for write left
|
||||
_zipstream.Flush();
|
||||
_zipstream.Close();
|
||||
_zipstream.Dispose();
|
||||
|
||||
// Delete the failed file
|
||||
File.Delete(_zipFileInfo.FullName);
|
||||
_zipFileInfo = null;
|
||||
_zipOpen = ZipOpenType.Closed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the read file stream
|
||||
/// </summary>
|
||||
/// <param name="index">Index of entry to read</param>
|
||||
/// <param name="raw">If compression mode is deflate, use the zipstream as is, otherwise decompress</param>
|
||||
/// <param name="stream">Output stream representing the correctly compressed stream</param>
|
||||
/// <param name="streamSize">Size of the stream regardless of compression</param>
|
||||
/// <param name="compressionMethod">Compression method to compare against</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn OpenReadStream(int index, bool raw, out Stream stream, out ulong streamSize, out CompressionMethod compressionMethod)
|
||||
{
|
||||
// Set all of the defaults
|
||||
streamSize = 0;
|
||||
compressionMethod = CompressionMethod.Stored;
|
||||
_readIndex = index;
|
||||
stream = null;
|
||||
|
||||
// If the file isn't open for read, return
|
||||
if (_zipOpen != ZipOpenType.OpenRead)
|
||||
{
|
||||
return ZipReturn.ZipReadingFromOutputFile;
|
||||
}
|
||||
|
||||
// Now try to read the local file header
|
||||
ZipReturn zr = _entries[index].ReadHeader();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
Close();
|
||||
return zr;
|
||||
}
|
||||
|
||||
// Now return the results of opening the local file
|
||||
return _entries[index].OpenReadStream(raw, out stream, out streamSize, out compressionMethod);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the read file stream wihtout verification, if possible
|
||||
/// </summary>
|
||||
/// <param name="index">Index of entry to read</param>
|
||||
/// <param name="raw">If compression mode is deflate, use the zipstream as is, otherwise decompress</param>
|
||||
/// <param name="stream">Output stream representing the correctly compressed stream</param>
|
||||
/// <param name="streamSize">Size of the stream regardless of compression</param>
|
||||
/// <param name="compressionMethod">Compression method to compare against</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn OpenReadStreamQuick(ulong pos, bool raw, out Stream stream, out ulong streamSize, out CompressionMethod compressionMethod)
|
||||
{
|
||||
// Get the temporary entry based on the defined position
|
||||
ZipFileEntry tempEntry = new ZipFileEntry(_zipstream);
|
||||
tempEntry.RelativeOffset = pos;
|
||||
|
||||
// Clear the local files and add this file instead
|
||||
_entries.Clear();
|
||||
_entries.Add(tempEntry);
|
||||
|
||||
// Now try to read the header quickly
|
||||
ZipReturn zr = tempEntry.ReadHeaderQuick();
|
||||
if (zr != ZipReturn.ZipGood)
|
||||
{
|
||||
stream = null;
|
||||
streamSize = 0;
|
||||
compressionMethod = CompressionMethod.Stored;
|
||||
return zr;
|
||||
}
|
||||
_readIndex = 0;
|
||||
|
||||
// Return the file stream if it worked
|
||||
return tempEntry.OpenReadStream(raw, out stream, out streamSize, out compressionMethod);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the read file stream
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ZipReturn CloseReadStream()
|
||||
{
|
||||
return _entries[_readIndex].CloseReadStream();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the write file stream
|
||||
/// </summary>
|
||||
/// <param name="raw">If compression mode is deflate, use the zipstream as is, otherwise decompress</param>
|
||||
/// <param name="torrentZip">True if outputted stream should be torrentzipped, false otherwise</param>
|
||||
/// <param name="uncompressedSize">Uncompressed size of the stream</param>
|
||||
/// <param name="compressionMethod">Compression method to compare against</param>
|
||||
/// <param name="stream">Output stream representing the correctly compressed stream</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn OpenWriteStream(bool raw, bool torrentZip, string filename, ulong uncompressedSize, CompressionMethod compressionMethod, out Stream stream)
|
||||
{
|
||||
// Check to see if the stream is writable
|
||||
stream = null;
|
||||
if (_zipOpen != ZipOpenType.OpenWrite)
|
||||
{
|
||||
return ZipReturn.ZipWritingToInputFile;
|
||||
}
|
||||
|
||||
// Open the entry stream based on the current position
|
||||
ZipFileEntry zfe = new ZipFileEntry(_zipstream, filename);
|
||||
ZipReturn zr = zfe.OpenWriteStream(raw, torrentZip, uncompressedSize, compressionMethod, out stream);
|
||||
_entries.Add(zfe);
|
||||
|
||||
return zr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the write file stream
|
||||
/// </summary>
|
||||
/// <param name="crc32">CRC to assign to the current stream</param>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn CloseWriteStream(uint crc32)
|
||||
{
|
||||
return _entries[_entries.Count - 1].CloseWriteStream(crc32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the last added entry, if possible
|
||||
/// </summary>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn RollBack()
|
||||
{
|
||||
// If the stream isn't writable, return
|
||||
if (_zipOpen != ZipOpenType.OpenWrite)
|
||||
{
|
||||
return ZipReturn.ZipWritingToInputFile;
|
||||
}
|
||||
|
||||
// Otherwise, make sure there are entries to roll back
|
||||
int fileCount = _entries.Count;
|
||||
if (fileCount == 0)
|
||||
{
|
||||
return ZipReturn.ZipErrorRollBackFile;
|
||||
}
|
||||
|
||||
// Get the last added entry and remove
|
||||
ZipFileEntry zfe = _entries[fileCount - 1];
|
||||
_entries.RemoveAt(fileCount - 1);
|
||||
_zipstream.Position = (long)zfe.RelativeOffset;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a directory marking to a local file
|
||||
/// </summary>
|
||||
public void AddDirectory()
|
||||
{
|
||||
_entries[_entries.Count - 1].AddDirectory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan every individual entry for validity
|
||||
/// </summary>
|
||||
public void DeepScan()
|
||||
{
|
||||
foreach (ZipFileEntry zfe in _entries)
|
||||
{
|
||||
zfe.Check();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Read the central directory entry from the input stream
|
||||
/// </summary>
|
||||
/// <returns>True if the central directory was read correctly, false otherwise</returns>
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn ReadCentralDirectory()
|
||||
{
|
||||
try
|
||||
@@ -381,8 +381,8 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Read the local file header from the input stream
|
||||
/// </summary>
|
||||
/// <returns>True if the local file header was read correctly, false otherwise</returns>
|
||||
public ZipReturn ReadLocalFileHeader()
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn ReadHeader()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -587,8 +587,8 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Read the local file header from the input stream, assuming correctness
|
||||
/// </summary>
|
||||
/// <returns>True if the local file header was read correctly, false otherwise</returns>
|
||||
public ZipReturn ReadLocalFileHeaderQuick()
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn ReadHeaderQuick()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -707,7 +707,7 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Write the local file header entry to the included stream
|
||||
/// </summary>
|
||||
public void WriteLocalFileHeader()
|
||||
public void WriteHeader()
|
||||
{
|
||||
// Open the stream for writing
|
||||
BinaryWriter bw = new BinaryWriter(_zipstream);
|
||||
@@ -777,8 +777,8 @@ namespace SabreTools.Helper
|
||||
/// <param name="stream">Output stream representing the correctly compressed stream</param>
|
||||
/// <param name="streamSize">Size of the stream regardless of compression</param>
|
||||
/// <param name="compressionMethod">Compression method to compare against</param>
|
||||
/// <returns>True if the output stream was read, false otherwise</returns>
|
||||
public bool LocalFileOpenReadStream(bool raw, out Stream stream, out ulong streamSize, out CompressionMethod compressionMethod)
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn OpenReadStream(bool raw, out Stream stream, out ulong streamSize, out CompressionMethod compressionMethod)
|
||||
{
|
||||
streamSize = 0;
|
||||
compressionMethod = _compressionMethod;
|
||||
@@ -806,14 +806,14 @@ namespace SabreTools.Helper
|
||||
break;
|
||||
}
|
||||
stream = _readStream;
|
||||
return (stream != null);
|
||||
return (stream == null ? ZipReturn.ZipErrorGettingDataStream : ZipReturn.ZipGood);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the read file stream
|
||||
/// </summary>
|
||||
/// <returns>True if the stream could be closed, false otherwise</returns>
|
||||
public bool LocalFileCloseReadStream()
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn CloseReadStream()
|
||||
{
|
||||
DeflateStream dfStream = _readStream as DeflateStream;
|
||||
if (dfStream != null)
|
||||
@@ -821,7 +821,7 @@ namespace SabreTools.Helper
|
||||
dfStream.Close();
|
||||
dfStream.Dispose();
|
||||
}
|
||||
return true;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -832,13 +832,13 @@ namespace SabreTools.Helper
|
||||
/// <param name="uncompressedSize">Uncompressed size of the stream</param>
|
||||
/// <param name="compressionMethod">Compression method to compare against</param>
|
||||
/// <param name="stream">Output stream representing the correctly compressed stream</param>
|
||||
/// <returns>True if the output stream was written, false otherwise</returns>
|
||||
public bool LocalFileOpenWriteStream(bool raw, bool torrentZip, ulong uncompressedSize, CompressionMethod compressionMethod, out Stream stream)
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn OpenWriteStream(bool raw, bool torrentZip, ulong uncompressedSize, CompressionMethod compressionMethod, out Stream stream)
|
||||
{
|
||||
_uncompressedSize = uncompressedSize;
|
||||
_compressionMethod = compressionMethod;
|
||||
|
||||
WriteLocalFileHeader();
|
||||
WriteHeader();
|
||||
_dataLocation = (ulong)_zipstream.Position;
|
||||
|
||||
if (raw)
|
||||
@@ -861,15 +861,15 @@ namespace SabreTools.Helper
|
||||
}
|
||||
|
||||
stream = _writeStream;
|
||||
return (stream != null);
|
||||
return (stream == null ? ZipReturn.ZipErrorGettingDataStream : ZipReturn.ZipGood);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the write file stream
|
||||
/// </summary>
|
||||
/// <param name="crc32">CRC to assign to the current stream</param>
|
||||
/// <returns>True if the stream could be closed, false otherwise</returns>
|
||||
public bool LocalFileCloseWriteStream(uint crc32)
|
||||
/// <returns>Status of the underlying stream</returns>
|
||||
public ZipReturn CloseWriteStream(uint crc32)
|
||||
{
|
||||
DeflateStream dfStream = _writeStream as DeflateStream;
|
||||
if (dfStream != null)
|
||||
@@ -883,14 +883,14 @@ namespace SabreTools.Helper
|
||||
|
||||
if (_compressedSize == 0 && _uncompressedSize == 0)
|
||||
{
|
||||
LocalFileAddDirectory();
|
||||
AddDirectory();
|
||||
_compressedSize = (ulong)_zipstream.Position - _dataLocation;
|
||||
}
|
||||
|
||||
_crc = crc32;
|
||||
WriteCompressedSize();
|
||||
|
||||
return true;
|
||||
return ZipReturn.ZipGood;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -941,7 +941,7 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Get the data from the current file, if not already checked
|
||||
/// </summary>
|
||||
public void LocalFileCheck()
|
||||
public void Check()
|
||||
{
|
||||
// If the file has been tested or has an error, return
|
||||
if (_fileStatus != ZipReturn.ZipUntested)
|
||||
@@ -1012,11 +1012,110 @@ namespace SabreTools.Helper
|
||||
/// <summary>
|
||||
/// Add a directory marking to a local file
|
||||
/// </summary>
|
||||
public void LocalFileAddDirectory()
|
||||
public void AddDirectory()
|
||||
{
|
||||
Stream ds = _zipstream;
|
||||
ds.WriteByte(03);
|
||||
ds.WriteByte(00);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the text associated with a return status
|
||||
/// </summary>
|
||||
/// <param name="zr">ZipReturn status to parse</param>
|
||||
/// <returns>String associated with the ZipReturn</returns>
|
||||
public static string ZipErrorMessageText(ZipReturn zr)
|
||||
{
|
||||
string ret = "Unknown";
|
||||
switch (zr)
|
||||
{
|
||||
case ZipReturn.ZipGood:
|
||||
ret = "";
|
||||
break;
|
||||
case ZipReturn.ZipFileCountError:
|
||||
ret = "The number of file in the Zip does not mach the number of files in the Zips Centeral Directory";
|
||||
break;
|
||||
case ZipReturn.ZipSignatureError:
|
||||
ret = "An unknown Signature Block was found in the Zip";
|
||||
break;
|
||||
case ZipReturn.ZipExtraDataOnEndOfZip:
|
||||
ret = "Extra Data was found on the end of the Zip";
|
||||
break;
|
||||
case ZipReturn.ZipUnsupportedCompression:
|
||||
ret = "An unsupported Compression method was found in the Zip, if you recompress this zip it will be usable";
|
||||
break;
|
||||
case ZipReturn.ZipLocalFileHeaderError:
|
||||
ret = "Error reading a zipped file header information";
|
||||
break;
|
||||
case ZipReturn.ZipCentralDirError:
|
||||
ret = "There is an error in the Zip Centeral Directory";
|
||||
break;
|
||||
case ZipReturn.ZipReadingFromOutputFile:
|
||||
ret = "Trying to write to a Zip file open for output only";
|
||||
break;
|
||||
case ZipReturn.ZipWritingToInputFile:
|
||||
ret = "Tring to read from a Zip file open for input only";
|
||||
break;
|
||||
case ZipReturn.ZipErrorGettingDataStream:
|
||||
ret = "Error creating Data Stream";
|
||||
break;
|
||||
case ZipReturn.ZipCRCDecodeError:
|
||||
ret = "CRC error";
|
||||
break;
|
||||
case ZipReturn.ZipDecodeError:
|
||||
ret = "Error unzipping a file";
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two strings in TorrentZip format
|
||||
/// </summary>
|
||||
/// <param name="string1"></param>
|
||||
/// <param name="string2"></param>
|
||||
/// <returns></returns>
|
||||
private static int TorrentZipStringCompare(string string1, string string2)
|
||||
{
|
||||
char[] bytes1 = string1.ToCharArray();
|
||||
char[] bytes2 = string2.ToCharArray();
|
||||
|
||||
int pos1 = 0;
|
||||
int pos2 = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (pos1 == bytes1.Length)
|
||||
{
|
||||
return ((pos2 == bytes2.Length) ? 0 : -1);
|
||||
}
|
||||
if (pos2 == bytes2.Length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int byte1 = bytes1[pos1++];
|
||||
int byte2 = bytes2[pos2++];
|
||||
|
||||
if (byte1 >= 65 && byte1 <= 90)
|
||||
{
|
||||
byte1 += 0x20;
|
||||
}
|
||||
if (byte2 >= 65 && byte2 <= 90)
|
||||
{
|
||||
byte2 += 0x20;
|
||||
}
|
||||
|
||||
if (byte1 < byte2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (byte1 > byte2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<Compile Include="Objects\ImportTwo.cs" />
|
||||
<Compile Include="Objects\SimpleSort.cs" />
|
||||
<Compile Include="Objects\ZipFileEntry.cs" />
|
||||
<Compile Include="Objects\ZipFIle.cs" />
|
||||
<Compile Include="Objects\ZipFile.cs" />
|
||||
<Compile Include="Resources\Resources.de-DE.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
|
||||
@@ -49,12 +49,12 @@ namespace SabreTools.Helper
|
||||
// If the archive doesn't exist, create it
|
||||
if (!File.Exists(archiveFileName))
|
||||
{
|
||||
outarchive = ZipFile.Open(archiveFileName, ZipArchiveMode.Create);
|
||||
outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Create);
|
||||
outarchive.Dispose();
|
||||
}
|
||||
|
||||
// Open the archive for writing
|
||||
using (outarchive = ZipFile.Open(archiveFileName, ZipArchiveMode.Update))
|
||||
using (outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Update))
|
||||
{
|
||||
// If the archive doesn't already contain the entry, add it
|
||||
if (outarchive.GetEntry(rom.Name) == null)
|
||||
@@ -63,7 +63,7 @@ namespace SabreTools.Helper
|
||||
}
|
||||
|
||||
// If there's a Date attached to the rom, change the entry to that Date
|
||||
if (!String.IsNullOrEmpty(rom.Date))
|
||||
if (!string.IsNullOrEmpty(rom.Date))
|
||||
{
|
||||
DateTimeOffset dto = DateTimeOffset.Now;
|
||||
if (DateTimeOffset.TryParse(rom.Date, out dto))
|
||||
|
||||
@@ -32,11 +32,11 @@ namespace SabreTools.Helper
|
||||
{
|
||||
if (!File.Exists(archiveFileName))
|
||||
{
|
||||
outarchive = ZipFile.Open(archiveFileName, ZipArchiveMode.Create);
|
||||
outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Create);
|
||||
}
|
||||
else
|
||||
{
|
||||
outarchive = ZipFile.Open(archiveFileName, ZipArchiveMode.Update);
|
||||
outarchive = System.IO.Compression.ZipFile.Open(archiveFileName, ZipArchiveMode.Update);
|
||||
}
|
||||
|
||||
if (File.Exists(input))
|
||||
|
||||
Reference in New Issue
Block a user