diff --git a/SabreTools.Helper/Tools/ArchiveTools.cs b/SabreTools.Helper/Tools/ArchiveTools.cs index 2448d54a..b5fff4b5 100644 --- a/SabreTools.Helper/Tools/ArchiveTools.cs +++ b/SabreTools.Helper/Tools/ArchiveTools.cs @@ -571,6 +571,187 @@ namespace SabreTools.Helper.Tools return roms; } + /// + /// Generate a list of RomData objects from the header values in an archive + /// + /// Input file to get data from + /// List of RomData objects representing the found data + /// TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually + public static List GetExtendedArchiveFileInfo(string input, Hash omitFromScan = Hash.DeepHashes) + { + List found = new List(); + + // First get the archive type + ArchiveType? at = GetCurrentArchiveType(input); + + // If we got back null, then it's not an archive, so we we return + if (at == null) + { + return null; + } + + try + { + Globals.Logger.Verbose("Found archive of type: " + at); + + switch (at) + { + // 7-zip + case ArchiveType.SevenZip: + SevenZipArchive sza = SevenZipArchive.Open(FileTools.TryOpenRead(input)); + foreach (SevenZipArchiveEntry entry in sza.Entries) + { + // Create and populate the entry stream + MemoryStream entryStream = new MemoryStream(); + entry.WriteTo(entryStream); + + // Get and add the extended Rom information + Rom sevenZipEntryRom = FileTools.GetStreamInfo(entryStream, entryStream.Length, omitFromScan: omitFromScan); + sevenZipEntryRom.Name = entry.Key; + sevenZipEntryRom.Machine = new Machine() + { + Name = Path.GetFileNameWithoutExtension(input), + Description = Path.GetFileNameWithoutExtension(input), + }; + sevenZipEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); + found.Add(sevenZipEntryRom); + } + + // Dispose of the archive + sza.Dispose(); + break; + + // GZip + case ArchiveType.GZip: + // Create and populate the entry stream + MemoryStream outstream = new MemoryStream(); + GZipStream gzstream = new GZipStream(FileTools.TryOpenRead(input), Ionic.Zlib.CompressionMode.Decompress); + gzstream.CopyTo(outstream); + + // Get and add the extended Rom information + Rom gzipEntryRom = FileTools.GetStreamInfo(outstream, outstream.Length, omitFromScan: omitFromScan); + gzipEntryRom.Name = gzstream.FileName; + gzipEntryRom.Machine = new Machine() + { + Name = Path.GetFileNameWithoutExtension(input), + Description = Path.GetFileNameWithoutExtension(input), + }; + gzipEntryRom.Date = gzstream.LastModified?.ToString("yyyy/MM/dd hh:mm:ss"); + found.Add(gzipEntryRom); + + // Dispose of the archive + gzstream.Dispose(); + break; + + // RAR + case ArchiveType.Rar: + RarArchive ra = RarArchive.Open(input); + foreach (RarArchiveEntry entry in ra.Entries) + { + // Create and populate the entry stream + MemoryStream entryStream = new MemoryStream(); + entry.WriteTo(entryStream); + + // Get and add the extended Rom information + Rom rarEntryRom = FileTools.GetStreamInfo(entryStream, entryStream.Length, omitFromScan: omitFromScan); + rarEntryRom.Name = entry.Key; + rarEntryRom.Machine = new Machine() + { + Name = Path.GetFileNameWithoutExtension(input), + Description = Path.GetFileNameWithoutExtension(input), + }; + rarEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); + found.Add(rarEntryRom); + } + + // Dispose of the archive + ra.Dispose(); + break; + + // TAR + case ArchiveType.Tar: + // Extract all files to the temp directory + TarArchive ta = TarArchive.Open(input); + foreach (TarArchiveEntry entry in ta.Entries) + { + // Create and populate the entry stream + MemoryStream entryStream = new MemoryStream(); + entry.WriteTo(entryStream); + + // Get and add the extended Rom information + Rom tarEntryName = FileTools.GetStreamInfo(entryStream, entryStream.Length, omitFromScan: omitFromScan); + tarEntryName.Name = entry.Key; + tarEntryName.Machine = new Machine() + { + Name = Path.GetFileNameWithoutExtension(input), + Description = Path.GetFileNameWithoutExtension(input), + }; + tarEntryName.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); + found.Add(tarEntryName); + } + + // Dispose of the archive + ta.Dispose(); + break; + + // Zip + case ArchiveType.Zip: + ZipFile zf = new ZipFile(); + ZipReturn zr = zf.Open(input, new FileInfo(input).LastWriteTime.Ticks, true); + if (zr != ZipReturn.ZipGood) + { + throw new Exception(ZipFile.ZipErrorMessageText(zr)); + } + + for (int i = 0; i < zf.EntriesCount && zr == ZipReturn.ZipGood; i++) + { + // Open the read stream + zr = zf.OpenReadStream(i, false, out Stream readStream, out ulong streamsize, out SabreTools.Helper.Data.CompressionMethod cm, out uint lastMod); + + // If the entry ends with a directory separator, continue to the next item, if any + if (zf.Entries[i].FileName.EndsWith(Path.DirectorySeparatorChar.ToString()) + || zf.Entries[i].FileName.EndsWith(Path.AltDirectorySeparatorChar.ToString()) + || zf.Entries[i].FileName.EndsWith(Path.PathSeparator.ToString())) + { + continue; + } + + MemoryStream entryStream = new MemoryStream(); + + byte[] ibuffer = new byte[_bufferSize]; + int ilen; + while ((ilen = readStream.Read(ibuffer, 0, _bufferSize)) > 0) + { + entryStream.Write(ibuffer, 0, ilen); + entryStream.Flush(); + } + zr = zf.CloseReadStream(); + + // Get and add the extended Rom information + Rom rarEntryRom = FileTools.GetStreamInfo(entryStream, entryStream.Length, omitFromScan: omitFromScan); + rarEntryRom.Name = zf.Entries[i].FileName; + rarEntryRom.Machine = new Machine() + { + Name = Path.GetFileNameWithoutExtension(input), + Description = Path.GetFileNameWithoutExtension(input), + }; + rarEntryRom.Date = zf.Entries[i].LastMod.ToString("yyyy/MM/dd hh:mm:ss"); // TODO: Fix this from ticks + found.Add(rarEntryRom); + } + + // Dispose of the archive + zf.Close(); + break; + } + } + catch (Exception) + { + // Don't log file open errors + } + + return found; + } + /// /// Retrieve file information for a single torrent GZ file ///