/// <summary> /// Write a set of input files to a torrentzip archive (assuming the same output archive name) /// </summary> /// <param name="inputFile">Input filenames to be moved</param> /// <param name="outDir">Output directory to build to</param> /// <param name="rom">List of Rom representing the new information</param> /// <param name="date">True if the date from the DAT should be used if available, false otherwise (default)</param> /// <param name="romba">True if files should be output in Romba depot folders, false otherwise</param> /// <returns>True if the archive was written properly, false otherwise</returns> public override bool Write(List <string> inputFiles, string outDir, List <Rom> roms, bool date = false, bool romba = false) { bool success = false; string tempFile = Path.Combine(outDir, "tmp" + Guid.NewGuid().ToString()); // If either list of roms is null or empty, return if (inputFiles == null || roms == null || inputFiles.Count == 0 || roms.Count == 0) { return(success); } // If the number of inputs is less than the number of available roms, return if (inputFiles.Count < roms.Count) { return(success); } // If one of the files doesn't exist, return foreach (string file in inputFiles) { if (!File.Exists(file)) { return(success); } } // Get the output archive name from the first rebuild rom string archiveFileName = Path.Combine(outDir, Utilities.RemovePathUnsafeCharacters(roms[0].MachineName) + (roms[0].MachineName.EndsWith(".zip") ? "" : ".zip")); // Set internal variables Stream writeStream = null; ZipFile oldZipFile = new ZipFile(); ZipFile zipFile = new ZipFile(); ZipReturn zipReturn = ZipReturn.ZipGood; try { // If the full output path doesn't exist, create it if (!Directory.Exists(Path.GetDirectoryName(archiveFileName))) { Directory.CreateDirectory(Path.GetDirectoryName(archiveFileName)); } // If the archive doesn't exist, create it and put the single file if (!File.Exists(archiveFileName)) { zipReturn = zipFile.Create(tempFile); // Map all inputs to index Dictionary <string, int> inputIndexMap = new Dictionary <string, int>(); for (int i = 0; i < inputFiles.Count; i++) { inputIndexMap.Add(roms[i].Name.Replace('\\', '/'), i); } // Sort the keys in TZIP order List <string> keys = inputIndexMap.Keys.ToList(); keys.Sort(ZipFile.TorrentZipStringCompare); // Now add all of the files in order foreach (string key in keys) { // Get the index mapped to the key int index = inputIndexMap[key]; // Open the input file for reading Stream freadStream = Utilities.TryOpenRead(inputFiles[index]); ulong istreamSize = (ulong)(new FileInfo(inputFiles[index]).Length); DateTime dt = DateTime.Now; if (date && !String.IsNullOrWhiteSpace(roms[index].Date) && DateTime.TryParse(roms[index].Date.Replace('\\', '/'), out dt)) { uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt); zipFile.OpenWriteStream(false, false, roms[index].Name.Replace('\\', '/'), istreamSize, SabreTools.Library.Data.CompressionMethod.Deflated, out writeStream, lastMod: msDosDateTime); } else { zipFile.OpenWriteStream(false, true, roms[index].Name.Replace('\\', '/'), istreamSize, SabreTools.Library.Data.CompressionMethod.Deflated, out writeStream); } // Copy the input stream to the output byte[] ibuffer = new byte[_bufferSize]; int ilen; while ((ilen = freadStream.Read(ibuffer, 0, _bufferSize)) > 0) { writeStream.Write(ibuffer, 0, ilen); writeStream.Flush(); } freadStream.Dispose(); zipFile.CloseWriteStream(Convert.ToUInt32(roms[index].CRC, 16)); } } // Otherwise, sort the input files and write out in the correct order else { // Open the old archive for reading oldZipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, true); // Map all inputs to index Dictionary <string, int> inputIndexMap = new Dictionary <string, int>(); for (int i = 0; i < inputFiles.Count; i++) { // If the old one contains the new file, then just skip out if (oldZipFile.Contains(roms[i].Name.Replace('\\', '/'))) { continue; } inputIndexMap.Add(roms[i].Name.Replace('\\', '/'), -(i + 1)); } // Then add all of the old entries to it too for (int i = 0; i < oldZipFile.EntriesCount; i++) { inputIndexMap.Add(oldZipFile.Filename(i), i); } // If the number of entries is the same as the old archive, skip out if (inputIndexMap.Keys.Count <= oldZipFile.EntriesCount) { success = true; return(success); } // Otherwise, process the old zipfile zipFile.Create(tempFile); // Get the order for the entries with the new file List <string> keys = inputIndexMap.Keys.ToList(); keys.Sort(ZipFile.TorrentZipStringCompare); // Copy over all files to the new archive foreach (string key in keys) { // Get the index mapped to the key int index = inputIndexMap[key]; // If we have the input file, add it now if (index < 0) { // Open the input file for reading Stream freadStream = Utilities.TryOpenRead(inputFiles[-index - 1]); ulong istreamSize = (ulong)(new FileInfo(inputFiles[-index - 1]).Length); DateTime dt = DateTime.Now; if (date && !String.IsNullOrWhiteSpace(roms[-index - 1].Date) && DateTime.TryParse(roms[-index - 1].Date.Replace('\\', '/'), out dt)) { uint msDosDateTime = Utilities.ConvertDateTimeToMsDosTimeFormat(dt); zipFile.OpenWriteStream(false, false, roms[-index - 1].Name.Replace('\\', '/'), istreamSize, SabreTools.Library.Data.CompressionMethod.Deflated, out writeStream, lastMod: msDosDateTime); } else { zipFile.OpenWriteStream(false, true, roms[-index - 1].Name.Replace('\\', '/'), istreamSize, SabreTools.Library.Data.CompressionMethod.Deflated, out writeStream); } // Copy the input stream to the output byte[] ibuffer = new byte[_bufferSize]; int ilen; while ((ilen = freadStream.Read(ibuffer, 0, _bufferSize)) > 0) { writeStream.Write(ibuffer, 0, ilen); writeStream.Flush(); } freadStream.Dispose(); zipFile.CloseWriteStream(Convert.ToUInt32(roms[-index - 1].CRC, 16)); } // Otherwise, copy the file from the old archive else { // Instantiate the streams oldZipFile.OpenReadStream(index, false, out Stream zreadStream, out ulong istreamSize, out SabreTools.Library.Data.CompressionMethod icompressionMethod, out uint lastMod); zipFile.OpenWriteStream(false, lastMod == Constants.TorrentZipFileDateTime, oldZipFile.Filename(index), istreamSize, SabreTools.Library.Data.CompressionMethod.Deflated, out writeStream, lastMod: lastMod); // Copy the input stream to the output byte[] ibuffer = new byte[_bufferSize]; int ilen; while ((ilen = zreadStream.Read(ibuffer, 0, _bufferSize)) > 0) { writeStream.Write(ibuffer, 0, ilen); writeStream.Flush(); } zipFile.CloseWriteStream(BitConverter.ToUInt32(oldZipFile.CRC32(index), 0)); } } } // Close the output zip file zipFile.Close(); success = true; } catch (Exception ex) { Console.WriteLine(ex); success = false; } finally { zipFile.Dispose(); oldZipFile.Dispose(); } // If the old file exists, delete it and replace if (File.Exists(archiveFileName)) { Utilities.TryDeleteFile(archiveFileName); } File.Move(tempFile, archiveFileName); return(true); }