From 8e043aa8755d25253bf6a139f62a67f90b4a1c85 Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Sun, 27 Sep 2020 15:05:27 +0200 Subject: [PATCH] Added support for loading PK3s in read-only mode (#477) --- Source/Core/Data/PK3Reader.cs | 84 ++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs index 93e655bd..8b2dd27c 100755 --- a/Source/Core/Data/PK3Reader.cs +++ b/Source/Core/Data/PK3Reader.cs @@ -40,6 +40,7 @@ namespace CodeImp.DoomBuilder.Data private /*readonly*/ ArchiveType archivetype; //mxd private /*readonly*/ Dictionary sevenzipentries; //mxd private bool batchmode = true; //mxd + private FileStream filestream; #endregion @@ -74,7 +75,26 @@ namespace CodeImp.DoomBuilder.Data private void LoadFrom(DataLocation dl, bool asreadonly) { - General.WriteLogLine("Opening " + Path.GetExtension(location.location).ToUpper().Replace(".", "") + " resource \"" + location.location + "\""); + FileAccess access; + FileShare share; + + isreadonly = asreadonly; + + // Determine if opening for read only + if (isreadonly) + { + // Read only + access = FileAccess.Read; + share = FileShare.ReadWrite; + } + else + { + // Private access + access = FileAccess.ReadWrite; + share = FileShare.Read; + } + + General.WriteLogLine("Opening " + Path.GetExtension(location.location).ToUpper().Replace(".", "") + " resource \"" + location.location + "\""); if (!File.Exists(location.location)) throw new FileNotFoundException("Could not find the file \"" + location.location + "\"", location.location); @@ -82,8 +102,11 @@ namespace CodeImp.DoomBuilder.Data // Make list of all files List fileentries = new List(); - // Create archive - archive = ArchiveFactory.Open(location.location); + // Take the detour with a FileStream because SharpCompress doesn't directly support opening files as read-only + filestream = File.Open(location.location, FileMode.OpenOrCreate, access, share); + + // Create archive + archive = ArchiveFactory.Open(filestream); archivetype = archive.Type; // Random access of 7z archives works TERRIBLY slow in SharpCompress @@ -116,6 +139,9 @@ namespace CodeImp.DoomBuilder.Data archive.Dispose(); archive = null; + filestream.Dispose(); + filestream = null; + // Make files list files = new DirectoryFilesList(dl.GetDisplayName(), fileentries); @@ -148,6 +174,12 @@ namespace CodeImp.DoomBuilder.Data archive = null; } + if(filestream != null) + { + filestream.Dispose(); + filestream = null; + } + // Done base.Dispose(); } @@ -162,12 +194,39 @@ namespace CodeImp.DoomBuilder.Data if (enable && archive == null) { - archive = ArchiveFactory.Open(location.location); + FileAccess access; + FileShare share; + + // Determine if opening for read only + if (isreadonly) + { + // Read only + access = FileAccess.Read; + share = FileShare.ReadWrite; + } + else + { + // Private access + access = FileAccess.ReadWrite; + share = FileShare.Read; + } + + // The file might have vanished in the meantime + if (!File.Exists(location.location)) + throw new FileNotFoundException("Could not find the file \"" + location.location + "\"", location.location); + + // Take the detour with a FileStream because SharpCompress doesn't directly support opening files as read-only + filestream = File.Open(location.location, FileMode.OpenOrCreate, access, share); + + archive = ArchiveFactory.Open(filestream); } else if (!enable && !batchmode && archive != null) { archive.Dispose(); archive = null; + + filestream.Dispose(); + filestream = null; } } } @@ -522,7 +581,22 @@ namespace CodeImp.DoomBuilder.Data if (string.Compare(entry.Key, fn, true) == 0) { filedata = new MemoryStream(); - entry.WriteTo(filedata); + + try + { + entry.WriteTo(filedata); + } + catch(SharpCompress.Compressors.Deflate.ZlibException e) + { + // This happens when the PK3 was modified externally and the resources were not reloaded + General.ErrorLogger.Add(ErrorType.Error, "Cannot load the file \"" + filename + "\" from archive \"" + location.GetDisplayName() + "\". Did you modify the archive without reloading the resouces?"); + + filedata.Dispose(); + filedata = null; + + return null; + } + break; } }