public static TrrntZipStatus CheckZipFiles(ref List <ZippedFile> zippedFiles, int ThreadID, LogCallback StatusLogCallBack) { TrrntZipStatus tzStatus = TrrntZipStatus.Unknown; // ***************************** RULE 1 ************************************* // Directory separator should be a '/' a '\' is invalid and should be replaced with '/' // // check if any '\' = 92 need converted to '/' = 47 // this needs done before the sort, so that the sort is correct. // return BadDirectorySeparator if errors found. bool error1 = false; foreach (ZippedFile t in zippedFiles) { char[] bytes = t.Name.ToCharArray(); bool fixDir = false; for (int j = 0; j < bytes.Length; j++) { if (bytes[j] != 92) { continue; } fixDir = true; bytes[j] = (char)47; tzStatus |= TrrntZipStatus.BadDirectorySeparator; if (!error1 && Program.VerboseLogging) { error1 = true; StatusLogCallBack?.Invoke(ThreadID, "Incorrect directory separator found"); } } if (fixDir) { t.Name = new string(bytes); } } // ***************************** RULE 2 ************************************* // All Files in a torrentzip should be sorted with a lower case file compare. // // if needed sort the files correctly, and return Unsorted if errors found. bool error2 = false; bool thisSortFound = true; while (thisSortFound) { thisSortFound = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { int c = TrrntZipStringCompare(zippedFiles[i].Name, zippedFiles[i + 1].Name); if (c > 0) { ZippedFile T = zippedFiles[i]; zippedFiles[i] = zippedFiles[i + 1]; zippedFiles[i + 1] = T; tzStatus |= TrrntZipStatus.Unsorted; thisSortFound = true; if (!error2 && Program.VerboseLogging) { error2 = true; StatusLogCallBack?.Invoke(ThreadID, "Incorrect file order found"); } } } } // ***************************** RULE 3 ************************************* // Directory marker files are only needed if they are empty directories. // // now that the files are sorted correctly, we can see if there are unneeded // directory files, by first finding directory files (these end in a '\' character ascii 92) // and then checking if the next file is a file in that found directory. // If we find this 2 entry pattern (directory followed by file in that directory) // then the directory entry should not be present and the torrentzip is incorrect. // return ExtraDirectoryEnteries if error is found. bool error3 = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { // check if this is a directory entry if (zippedFiles[i].Name[zippedFiles[i].Name.Length - 1] != 47) { continue; } // check if the next filename is shorter or equal to this filename. // if it is shorter or equal it cannot be a file in the directory. if (zippedFiles[i + 1].Name.Length <= zippedFiles[i].Name.Length) { continue; } // check if the directory part of the two file enteries match // if they do we found an incorrect directory entry. bool delete = true; for (int j = 0; j < zippedFiles[i].Name.Length; j++) { if (zippedFiles[i].Name[j] != zippedFiles[i + 1].Name[j]) { delete = false; break; } } // we found an incorrect directory so remove it. if (delete) { zippedFiles.RemoveAt(i); tzStatus |= TrrntZipStatus.ExtraDirectoryEnteries; if (!error3 && Program.VerboseLogging) { error3 = true; StatusLogCallBack?.Invoke(ThreadID, "Un-needed directory records found"); } i--; } } // check for repeat files bool error4 = false; for (int i = 0; i < zippedFiles.Count - 1; i++) { if (zippedFiles[i].Name == zippedFiles[i + 1].Name) { tzStatus |= TrrntZipStatus.RepeatFilesFound; if (!error4 && Program.VerboseLogging) { error4 = true; StatusLogCallBack?.Invoke(ThreadID, "Duplcate file enteries found"); } } } return(tzStatus); }
public static TrrntZipStatus ReZipFiles(List <ZippedFile> zippedFiles, ICompress originalZipFile, byte[] buffer, StatusCallback StatusCallBack, LogCallback LogCallback, int ThreadID) { zipType inputType; if (originalZipFile is ZipFile) { inputType = zipType.zip; } else if (originalZipFile is SevenZ) { inputType = zipType.sevenzip; } else { return(TrrntZipStatus.Unknown); } zipType outputType = Program.OutZip == zipType.both ? inputType : Program.OutZip; int bufferSize = buffer.Length; string filename = originalZipFile.ZipFilename; string tmpFilename = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + ".tmp"); string outExt = outputType == zipType.zip ? ".zip" : ".7z"; string outfilename = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + outExt); if (inputType != outputType) { if (File.Exists(outfilename)) { LogCallback?.Invoke(ThreadID, "Error output " + outExt + " file already exists"); return(TrrntZipStatus.RepeatFilesFound); } } if (File.Exists(tmpFilename)) { File.Delete(tmpFilename); } ICompress zipFileOut = outputType == zipType.zip ? new ZipFile() : (ICompress) new SevenZ(); try { zipFileOut.ZipFileCreate(tmpFilename); ulong fileSizeTotal = 0; ulong fileSizeProgress = 0; int filePercentReported = 20; foreach (ZippedFile f in zippedFiles) { fileSizeTotal += f.Size; } // by now the zippedFiles have been sorted so just loop over them for (int i = 0; i < zippedFiles.Count; i++) { ZippedFile t = zippedFiles[i]; if (Program.VerboseLogging) { LogCallback?.Invoke(ThreadID, $"{t.Size,15} {t.StringCRC} {t.Name}"); } Stream readStream = null; ulong streamSize = 0; ushort compMethod; ZipFile z = originalZipFile as ZipFile; ZipReturn zrInput = ZipReturn.ZipUntested; if (z != null) { zrInput = z.ZipFileOpenReadStream(t.Index, false, out readStream, out streamSize, out compMethod); } SevenZ z7 = originalZipFile as SevenZ; if (z7 != null) { zrInput = z7.ZipFileOpenReadStream(t.Index, out readStream, out streamSize); } Stream writeStream; ZipReturn zrOutput = zipFileOut.ZipFileOpenWriteStream(false, true, t.Name, streamSize, 8, out writeStream); if ((zrInput != ZipReturn.ZipGood) || (zrOutput != ZipReturn.ZipGood)) { //Error writing local File. zipFileOut.ZipFileClose(); originalZipFile.ZipFileClose(); File.Delete(tmpFilename); return(TrrntZipStatus.CorruptZip); } Stream crcCs = new CrcCalculatorStream(readStream, true); ulong sizetogo = streamSize; while (sizetogo > 0) { int sizenow = sizetogo > (ulong)bufferSize ? bufferSize : (int)sizetogo; fileSizeProgress += (ulong)sizenow; int filePercent = (int)((double)fileSizeProgress / fileSizeTotal * 20); if (filePercent != filePercentReported) { StatusCallBack?.Invoke(ThreadID, filePercent * 5); filePercentReported = filePercent; } crcCs.Read(buffer, 0, sizenow); writeStream.Write(buffer, 0, sizenow); sizetogo = sizetogo - (ulong)sizenow; } writeStream.Flush(); crcCs.Close(); if (z != null) { originalZipFile.ZipFileCloseReadStream(); } uint crc = (uint)((CrcCalculatorStream)crcCs).Crc; if (crc != t.CRC) { return(TrrntZipStatus.CorruptZip); } zipFileOut.ZipFileCloseWriteStream(t.ByteCRC); } StatusCallBack?.Invoke(ThreadID, 100); zipFileOut.ZipFileClose(); originalZipFile.ZipFileClose(); File.Delete(filename); File.Move(tmpFilename, outfilename); return(TrrntZipStatus.ValidTrrntzip); } catch (Exception) { zipFileOut?.ZipFileCloseFailed(); originalZipFile?.ZipFileClose(); return(TrrntZipStatus.CorruptZip); } }