From c69dddbc2620987bd634f2d628998a3a6c60799a Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 16 Sep 2016 11:37:55 -0700 Subject: [PATCH] [FileTools, SimpleSort, ZipFile/Entry] TorrentZip works! Mostly! Writing to torrentzip works but for some reason the compressed streams are not being generated at the correct size. This is odd and seems to only affect newly added files and not ones copied from other archives. Also, found some glaring flaws in the headered output that explains why I was having issues previously. Typos D= --- SabreTools.Helper/Objects/SimpleSort.cs | 7 +- SabreTools.Helper/Objects/ZipFIle.cs | 7 +- SabreTools.Helper/Objects/ZipFileEntry.cs | 530 +++++++++++----------- SabreTools.Helper/Tools/FileTools.cs | 55 ++- 4 files changed, 313 insertions(+), 286 deletions(-) diff --git a/SabreTools.Helper/Objects/SimpleSort.cs b/SabreTools.Helper/Objects/SimpleSort.cs index 1f4699b8..d1040e04 100644 --- a/SabreTools.Helper/Objects/SimpleSort.cs +++ b/SabreTools.Helper/Objects/SimpleSort.cs @@ -337,6 +337,7 @@ namespace SabreTools.Helper else { FileTools.WriteToArchive(input, _outdir, found); + //FileTools.WriteTorrentZip(input, _outdir, found, _logger); } } } @@ -404,12 +405,14 @@ namespace SabreTools.Helper else { FileTools.WriteToArchive(newinput, _outdir, found); + //FileTools.WriteTorrentZip(newinput, _outdir, found, _logger); } } // Then output the headered rom (renamed) Rom newfound = found; newfound.Name = Path.GetFileNameWithoutExtension(newfound.Name) + " (" + rom.HashData.CRC + ")" + Path.GetExtension(newfound.Name); + newfound.HashData = rom.HashData; // Add rom to the matched list key = newfound.HashData.Size + "-" + newfound.HashData.CRC; @@ -450,6 +453,7 @@ namespace SabreTools.Helper else { FileTools.WriteToArchive(input, _outdir, newfound); + //FileTools.WriteTorrentZip(input, _outdir, newfound, _logger); } } } @@ -535,7 +539,8 @@ namespace SabreTools.Helper } else { - FileTools.WriteToArchive(outfile, _outdir, found); + FileTools.WriteToArchive(input, _outdir, found); + //FileTools.WriteTorrentZip(input, _outdir, found, _logger); } try diff --git a/SabreTools.Helper/Objects/ZipFIle.cs b/SabreTools.Helper/Objects/ZipFIle.cs index 92eb0979..eb655691 100644 --- a/SabreTools.Helper/Objects/ZipFIle.cs +++ b/SabreTools.Helper/Objects/ZipFIle.cs @@ -86,6 +86,10 @@ namespace SabreTools.Helper { return _entries[i].SHA1; } + public bool Contains(string n) + { + return _entries.Contains(new ZipFileEntry(new MemoryStream(), n, true)); + } #endregion @@ -658,6 +662,8 @@ namespace SabreTools.Helper torrentZip &= zfe.TorrentZip; } + _centerDirSize = (ulong)_zipstream.Position - _centerDirStart; + // Then get the central directory hash OptimizedCRC ocrc = new OptimizedCRC(); byte[] buffer = new byte[_centerDirSize]; @@ -674,7 +680,6 @@ namespace SabreTools.Helper _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); diff --git a/SabreTools.Helper/Objects/ZipFileEntry.cs b/SabreTools.Helper/Objects/ZipFileEntry.cs index cf20dcd9..73cabb9c 100644 --- a/SabreTools.Helper/Objects/ZipFileEntry.cs +++ b/SabreTools.Helper/Objects/ZipFileEntry.cs @@ -399,190 +399,189 @@ namespace SabreTools.Helper _torrentZip = true; // Open the stream for reading - using (BinaryReader br = new BinaryReader(_zipstream)) + BinaryReader br = new BinaryReader(_zipstream); + + // Set the position of the writer based on the entry information + br.BaseStream.Seek((long)_relativeOffset, SeekOrigin.Begin); + + // If the first bytes aren't a local file header, log and return + if (br.ReadUInt32() != Constants.LocalFileHeaderSignature) { - // Set the position of the writer based on the entry information - br.BaseStream.Seek((long)_relativeOffset, SeekOrigin.Begin); + return ZipReturn.ZipLocalFileHeaderError; + } - // If the first bytes aren't a local file header, log and return - if (br.ReadUInt32() != Constants.LocalFileHeaderSignature) - { - return ZipReturn.ZipLocalFileHeaderError; - } + // Now read in available information, comparing to the known data + if (br.ReadUInt16() != (ushort)_versionNeeded) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if (br.ReadUInt16() != (ushort)_generalPurposeBitFlag) + { + _torrentZip = false; + } + if (br.ReadUInt16() != (ushort)_compressionMethod) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if (br.ReadUInt16() != _lastModFileTime) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if (br.ReadUInt16() != _lastModFileDate) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && br.ReadUInt32() != _crc) + { + return ZipReturn.ZipLocalFileHeaderError; + } - // Now read in available information, comparing to the known data - if (br.ReadUInt16() != (ushort)_versionNeeded) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if (br.ReadUInt16() != (ushort)_generalPurposeBitFlag) - { - _torrentZip = false; - } - if (br.ReadUInt16() != (ushort)_compressionMethod) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if (br.ReadUInt16() != _lastModFileTime) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if (br.ReadUInt16() != _lastModFileDate) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && br.ReadUInt32() != _crc) - { - return ZipReturn.ZipLocalFileHeaderError; - } + uint readCompressedSize = br.ReadUInt32(); + // If we have Zip64, the compressed size should be 0xffffffff + if (_zip64 && readCompressedSize != 0xffffffff && readCompressedSize != _compressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } + // If we have the zeroed flag set, then no size should be included + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize && readCompressedSize != 0) + { + return ZipReturn.ZipLocalFileHeaderError; + } + // If we don't have the zeroed flag set, then the size should match + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && readCompressedSize != _compressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } - uint readCompressedSize = br.ReadUInt32(); - // If we have Zip64, the compressed size should be 0xffffffff - if (_zip64 && readCompressedSize != 0xffffffff && readCompressedSize != _compressedSize) + uint readUncompressedSize = br.ReadUInt32(); + // If we have Zip64, the uncompressed size should be 0xffffffff + if (_zip64 && readUncompressedSize != 0xffffffff && readUncompressedSize != _compressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } + // If we have the zeroed flag set, then no size should be included + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize && readUncompressedSize != 0) + { + return ZipReturn.ZipLocalFileHeaderError; + } + // If we don't have the zeroed flag set, then the size should match + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && readUncompressedSize != _uncompressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } + + ushort fileNameLength = br.ReadUInt16(); + ushort extraFieldLength = br.ReadUInt16(); + + byte[] fileNameBytes = br.ReadBytes(fileNameLength); + string tempFileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0 + ? Encoding.ASCII.GetString(fileNameBytes) + : Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength)); + + byte[] extraField = br.ReadBytes(extraFieldLength); + + /* + Full disclosure: this next section is in GordonJ's work but I honestly + have no idea everything that it does. It seems to do something to figure + out if it's Zip64, or possibly check for random things but it uses the + extra field for this, which I do not fully understand. It's copied in + its entirety below in the hope that it makes things better... + */ + + _zip64 = false; + int pos = 0; + while (extraFieldLength > pos) + { + ushort type = BitConverter.ToUInt16(extraField, pos); + pos += 2; + ushort blockLength = BitConverter.ToUInt16(extraField, pos); + pos += 2; + switch (type) { - return ZipReturn.ZipLocalFileHeaderError; - } - // If we have the zeroed flag set, then no size should be included - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize && readCompressedSize != 0) - { - return ZipReturn.ZipLocalFileHeaderError; - } - // If we don't have the zeroed flag set, then the size should match - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && readCompressedSize != _compressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - - uint readUncompressedSize = br.ReadUInt32(); - // If we have Zip64, the uncompressed size should be 0xffffffff - if (_zip64 && readUncompressedSize != 0xffffffff && readUncompressedSize != _compressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - // If we have the zeroed flag set, then no size should be included - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize && readUncompressedSize != 0) - { - return ZipReturn.ZipLocalFileHeaderError; - } - // If we don't have the zeroed flag set, then the size should match - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0 && readUncompressedSize != _uncompressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - - ushort fileNameLength = br.ReadUInt16(); - ushort extraFieldLength = br.ReadUInt16(); - - byte[] fileNameBytes = br.ReadBytes(fileNameLength); - string tempFileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0 - ? Encoding.ASCII.GetString(fileNameBytes) - : Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength)); - - byte[] extraField = br.ReadBytes(extraFieldLength); - - /* - Full disclosure: this next section is in GordonJ's work but I honestly - have no idea everything that it does. It seems to do something to figure - out if it's Zip64, or possibly check for random things but it uses the - extra field for this, which I do not fully understand. It's copied in - its entirety below in the hope that it makes things better... - */ - - _zip64 = false; - int pos = 0; - while (extraFieldLength > pos) - { - ushort type = BitConverter.ToUInt16(extraField, pos); - pos += 2; - ushort blockLength = BitConverter.ToUInt16(extraField, pos); - pos += 2; - switch (type) - { - case 0x0001: - Zip64 = true; - if (readUncompressedSize == 0xffffffff) - { - ulong tLong = BitConverter.ToUInt64(extraField, pos); - if (tLong != UncompressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - pos += 8; - } - if (readCompressedSize == 0xffffffff) - { - ulong tLong = BitConverter.ToUInt64(extraField, pos); - if (tLong != _compressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - pos += 8; - } - break; - case 0x7075: - //byte version = extraField[pos]; - pos += 1; - uint nameCRC32 = BitConverter.ToUInt32(extraField, pos); - pos += 4; - - CRC32 crcTest = new CRC32(); - crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength); - uint fCRC = (uint)crcTest.Crc32Result; - - if (nameCRC32 != fCRC) + case 0x0001: + Zip64 = true; + if (readUncompressedSize == 0xffffffff) + { + ulong tLong = BitConverter.ToUInt64(extraField, pos); + if (tLong != UncompressedSize) { return ZipReturn.ZipLocalFileHeaderError; } + pos += 8; + } + if (readCompressedSize == 0xffffffff) + { + ulong tLong = BitConverter.ToUInt64(extraField, pos); + if (tLong != _compressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } + pos += 8; + } + break; + case 0x7075: + //byte version = extraField[pos]; + pos += 1; + uint nameCRC32 = BitConverter.ToUInt32(extraField, pos); + pos += 4; - int charLen = blockLength - 5; + CRC32 crcTest = new CRC32(); + crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength); + uint fCRC = (uint)crcTest.Crc32Result; - tempFileName = Encoding.UTF8.GetString(extraField, pos, charLen); - pos += charLen; + if (nameCRC32 != fCRC) + { + return ZipReturn.ZipLocalFileHeaderError; + } - break; - default: - pos += blockLength; - break; - } + int charLen = blockLength - 5; + + tempFileName = Encoding.UTF8.GetString(extraField, pos, charLen); + pos += charLen; + + break; + default: + pos += blockLength; + break; } + } - // Back to code I understand - if (String.Equals(_fileName, tempFileName, StringComparison.InvariantCulture)) - { - return ZipReturn.ZipLocalFileHeaderError; - } + // Back to code I understand + if (!String.Equals(_fileName, tempFileName, StringComparison.InvariantCulture)) + { + return ZipReturn.ZipLocalFileHeaderError; + } - // Set the position of the data - _dataLocation = (ulong)_zipstream.Position; + // Set the position of the data + _dataLocation = (ulong)_zipstream.Position; - // Now if no other data should be after the data, return - if((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize) - { - return ZipReturn.ZipGood; - } + // Now if no other data should be after the data, return + if((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == 0) + { + return ZipReturn.ZipGood; + } - // Otherwise, compare the data after the file too - _zipstream.Seek((long)_compressedSize, SeekOrigin.Current); + // Otherwise, compare the data after the file too + _zipstream.Position += (long)_compressedSize; - // If there's no subheader, read the next thing as crc - uint tempCrc = br.ReadUInt32(); - if (tempCrc != Constants.EndOfLocalFileHeaderSignature) - { - tempCrc = br.ReadUInt32(); - } + // If there's no subheader, read the next thing as crc + uint tempCrc = br.ReadUInt32(); + if (tempCrc != Constants.EndOfLocalFileHeaderSignature) + { + tempCrc = br.ReadUInt32(); + } - if (tempCrc != _crc) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if (br.ReadUInt32() != _compressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } - if (br.ReadUInt32() != _uncompressedSize) - { - return ZipReturn.ZipLocalFileHeaderError; - } + if (tempCrc != _crc) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if (br.ReadUInt32() != _compressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; + } + if (br.ReadUInt32() != _uncompressedSize) + { + return ZipReturn.ZipLocalFileHeaderError; } } catch @@ -605,105 +604,104 @@ namespace SabreTools.Helper _torrentZip = true; // Open the stream for reading - using (BinaryReader br = new BinaryReader(_zipstream)) + BinaryReader br = new BinaryReader(_zipstream); + + // Set the position of the writer based on the entry information + br.BaseStream.Seek((long)_relativeOffset, SeekOrigin.Begin); + + // If the first bytes aren't a local file header, log and return + if (br.ReadUInt32() != Constants.LocalFileHeaderSignature) { - // Set the position of the writer based on the entry information - br.BaseStream.Seek((long)_relativeOffset, SeekOrigin.Begin); - - // If the first bytes aren't a local file header, log and return - if (br.ReadUInt32() != Constants.LocalFileHeaderSignature) - { - return ZipReturn.ZipLocalFileHeaderError; - } - - // Now read in available information, ignoring unneeded - _versionNeeded = (ArchiveVersion)br.ReadUInt16(); - _generalPurposeBitFlag = (GeneralPurposeBitFlag)br.ReadUInt16(); - - // If the flag says there's no hash data, then we can't use quick mode - if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize) - { - return ZipReturn.ZipCannotFastOpen; - } - - _compressionMethod = (CompressionMethod)br.ReadUInt16(); - _lastModFileTime = br.ReadUInt16(); - _lastModFileDate = br.ReadUInt16(); - _crc = br.ReadUInt32(); - _compressedSize = br.ReadUInt32(); - _uncompressedSize = br.ReadUInt32(); - - ushort fileNameLength = br.ReadUInt16(); - ushort extraFieldLength = br.ReadUInt16(); - - byte[] fileNameBytes = br.ReadBytes(fileNameLength); - _fileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0 - ? Encoding.ASCII.GetString(fileNameBytes) - : Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength)); - - byte[] extraField = br.ReadBytes(extraFieldLength); - - /* - Full disclosure: this next section is in GordonJ's work but I honestly - have no idea everything that it does. It seems to do something to figure - out if it's Zip64, or possibly check for random things but it uses the - extra field for this, which I do not fully understand. It's copied in - its entirety below in the hope that it makes things better... - */ - - _zip64 = false; - int pos = 0; - while (extraFieldLength > pos) - { - ushort type = BitConverter.ToUInt16(extraField, pos); - pos += 2; - ushort blockLength = BitConverter.ToUInt16(extraField, pos); - pos += 2; - switch (type) - { - case 0x0001: - Zip64 = true; - if (_uncompressedSize == 0xffffffff) - { - _uncompressedSize = BitConverter.ToUInt64(extraField, pos); - pos += 8; - } - if (_compressedSize == 0xffffffff) - { - _compressedSize = BitConverter.ToUInt64(extraField, pos); - pos += 8; - } - break; - case 0x7075: - pos += 1; - uint nameCRC32 = BitConverter.ToUInt32(extraField, pos); - pos += 4; - - CRC32 crcTest = new CRC32(); - crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength); - uint fCRC = (uint)crcTest.Crc32Result; - - if (nameCRC32 != fCRC) - { - return ZipReturn.ZipLocalFileHeaderError; - } - - int charLen = blockLength - 5; - - FileName = Encoding.UTF8.GetString(extraField, pos, charLen); - - pos += charLen; - - break; - default: - pos += blockLength; - break; - } - } - - // Set the position of the data - _dataLocation = (ulong)_zipstream.Position; + return ZipReturn.ZipLocalFileHeaderError; } + + // Now read in available information, ignoring unneeded + _versionNeeded = (ArchiveVersion)br.ReadUInt16(); + _generalPurposeBitFlag = (GeneralPurposeBitFlag)br.ReadUInt16(); + + // If the flag says there's no hash data, then we can't use quick mode + if ((_generalPurposeBitFlag & GeneralPurposeBitFlag.ZeroedCRCAndSize) == GeneralPurposeBitFlag.ZeroedCRCAndSize) + { + return ZipReturn.ZipCannotFastOpen; + } + + _compressionMethod = (CompressionMethod)br.ReadUInt16(); + _lastModFileTime = br.ReadUInt16(); + _lastModFileDate = br.ReadUInt16(); + _crc = br.ReadUInt32(); + _compressedSize = br.ReadUInt32(); + _uncompressedSize = br.ReadUInt32(); + + ushort fileNameLength = br.ReadUInt16(); + ushort extraFieldLength = br.ReadUInt16(); + + byte[] fileNameBytes = br.ReadBytes(fileNameLength); + _fileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0 + ? Encoding.ASCII.GetString(fileNameBytes) + : Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength)); + + byte[] extraField = br.ReadBytes(extraFieldLength); + + /* + Full disclosure: this next section is in GordonJ's work but I honestly + have no idea everything that it does. It seems to do something to figure + out if it's Zip64, or possibly check for random things but it uses the + extra field for this, which I do not fully understand. It's copied in + its entirety below in the hope that it makes things better... + */ + + _zip64 = false; + int pos = 0; + while (extraFieldLength > pos) + { + ushort type = BitConverter.ToUInt16(extraField, pos); + pos += 2; + ushort blockLength = BitConverter.ToUInt16(extraField, pos); + pos += 2; + switch (type) + { + case 0x0001: + Zip64 = true; + if (_uncompressedSize == 0xffffffff) + { + _uncompressedSize = BitConverter.ToUInt64(extraField, pos); + pos += 8; + } + if (_compressedSize == 0xffffffff) + { + _compressedSize = BitConverter.ToUInt64(extraField, pos); + pos += 8; + } + break; + case 0x7075: + pos += 1; + uint nameCRC32 = BitConverter.ToUInt32(extraField, pos); + pos += 4; + + CRC32 crcTest = new CRC32(); + crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength); + uint fCRC = (uint)crcTest.Crc32Result; + + if (nameCRC32 != fCRC) + { + return ZipReturn.ZipLocalFileHeaderError; + } + + int charLen = blockLength - 5; + + FileName = Encoding.UTF8.GetString(extraField, pos, charLen); + + pos += charLen; + + break; + default: + pos += blockLength; + break; + } + } + + // Set the position of the data + _dataLocation = (ulong)_zipstream.Position; } catch { @@ -750,6 +748,7 @@ namespace SabreTools.Helper bw.Write((ushort)_compressionMethod); bw.Write(_lastModFileTime); bw.Write(_lastModFileDate); + _crc32Location = (ulong)_zipstream.Position; // Now, write dummy bytes for crc, compressed size, and uncompressed size @@ -984,8 +983,9 @@ namespace SabreTools.Helper using (OptimizedCRC crc = new OptimizedCRC()) using (MD5 md5 = System.Security.Cryptography.MD5.Create()) using (SHA1 sha1 = System.Security.Cryptography.SHA1.Create()) - using (BinaryReader fs = new BinaryReader(stream)) { + BinaryReader fs = new BinaryReader(stream); + byte[] buffer = new byte[1024]; int read; while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) @@ -999,7 +999,7 @@ namespace SabreTools.Helper md5.TransformFinalBlock(buffer, 0, 0); sha1.TransformFinalBlock(buffer, 0, 0); - tempCrc = (uint)crc.Value; + tempCrc = crc.UnsignedValue; _md5 = md5.Hash; _sha1 = sha1.Hash; } diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 2f46771d..ac15738d 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -129,10 +129,6 @@ namespace SabreTools.Helper Directory.CreateDirectory(Path.GetDirectoryName(archiveFileName)); } - // Open the input file for reading - readStream = File.OpenRead(inputFile); - ulong streamSize = (ulong)(new FileInfo(inputFile).Length); - // Open or create the archive if (!File.Exists(archiveFileName)) { @@ -141,29 +137,50 @@ namespace SabreTools.Helper else { // Open the old archive for reading - oldZipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, false); - zipFile.Create(archiveFileName + ".new"); + oldZipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, true); - // Copy over all files to the new archive - for (int i = 0; i < oldZipFile.EntriesCount; i++) + // If the old one contains the new file, then just skip out + if (oldZipFile.Contains(rom.Name)) { - // Instantiate the streams - CompressionMethod icompressionMethod = CompressionMethod.Stored; - ulong istreamSize = 0; - oldZipFile.OpenReadStream(i, true, out readStream, out istreamSize, out icompressionMethod); - zipFile.OpenWriteStream(true, true, oldZipFile.Filename(i), streamSize, CompressionMethod.Deflated, out writeStream); + success = true; + } + // Otherwise, process the old zipfile + else + { + zipFile.Create(archiveFileName + ".new"); - // Copy the input stream to the output - byte[] ibuffer = new byte[8 * 1024]; - int ilen; - while ((ilen = readStream.Read(ibuffer, 0, ibuffer.Length)) > 0) + // Copy over all files to the new archive + for (int i = 0; i < oldZipFile.EntriesCount; i++) { - writeStream.Write(ibuffer, 0, ilen); + // Instantiate the streams + CompressionMethod icompressionMethod = CompressionMethod.Stored; + ulong istreamSize = 0; + oldZipFile.OpenReadStream(i, false, out readStream, out istreamSize, out icompressionMethod); + zipFile.OpenWriteStream(false, true, oldZipFile.Filename(i), istreamSize, CompressionMethod.Deflated, out writeStream); + + // Copy the input stream to the output + byte[] ibuffer = new byte[8 * 1024]; + int ilen; + while ((ilen = readStream.Read(ibuffer, 0, ibuffer.Length)) > 0) + { + writeStream.Write(ibuffer, 0, ilen); + } + writeStream.Flush(); + + zipFile.CloseWriteStream(BitConverter.ToUInt32(oldZipFile.CRC32(i), 0)); } } } - // Now open the write stream for the new rom + // If the file has already been found, return it + if (success) + { + return success; + } + + // Open the input file for reading + readStream = File.OpenRead(inputFile); + ulong streamSize = (ulong)(new FileInfo(inputFile).Length); zipReturn = zipFile.OpenWriteStream(false, true, rom.Name, streamSize, CompressionMethod.Deflated, out writeStream); // Copy the input stream to the output