[ArchiveTools] Fix file extraction (out of memory errors)

This commit is contained in:
Matt Nadareski
2017-01-30 22:08:33 -08:00
parent 80d09f1b30
commit 70393e4c15

View File

@@ -222,61 +222,17 @@ namespace SabreTools.Helper.Tools
public static string ExtractItem(string input, string entryName, string tempDir, Logger logger) public static string ExtractItem(string input, string entryName, string tempDir, Logger logger)
{ {
string realEntry = ""; string realEntry = "";
Stream ms = ExtractStream(input, entryName, out realEntry, logger);
// If we got out a null or empty entry, then we don't have a stream
if (String.IsNullOrEmpty(realEntry) || ms == null)
{
ms?.Dispose();
return null;
}
realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
}
FileStream fs = File.Open(realEntry, FileMode.Create, FileAccess.Write);
byte[] ibuffer = new byte[_bufferSize];
int ilen;
while ((ilen = ms.Read(ibuffer, 0, _bufferSize)) > 0)
{
fs.Write(ibuffer, 0, ilen);
fs.Flush();
}
// Dispose of the streams
ms.Dispose();
fs.Dispose();
return realEntry;
}
/// <summary>
/// Attempt to extract a stream from an archive
/// </summary>
/// <param name="input">Name of the archive to be extracted</param>
/// <param name="entryName">Name of the entry to be extracted</param>
/// <param name="logger">Logger object for file and console output</param>
/// <returns>Name of the extracted file, null on error</returns>
public static Stream ExtractStream(string input, string entryName, out string realEntry, Logger logger)
{
// Set the real entry name // Set the real entry name
realEntry = ""; realEntry = "";
// Get a writable stream to return
Stream st = new MemoryStream();
// First get the archive type // First get the archive type
ArchiveType? at = GetCurrentArchiveType(input, logger); ArchiveType? at = GetCurrentArchiveType(input, logger);
// If we got back null, then it's not an archive, so we we return // If we got back null, then it's not an archive, so we we return
if (at == null) if (at == null)
{ {
return st; return realEntry;
} }
try try
@@ -291,7 +247,16 @@ namespace SabreTools.Helper.Tools
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName)) if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
{ {
realEntry = entry.Key; realEntry = entry.Key;
entry.WriteTo(st);
// Get the output path
realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
}
// Write the file out
entry.WriteToFile(realEntry);
break; break;
} }
} }
@@ -302,10 +267,28 @@ namespace SabreTools.Helper.Tools
// Decompress the input stream // Decompress the input stream
realEntry = Path.GetFileNameWithoutExtension(input); realEntry = Path.GetFileNameWithoutExtension(input);
GZipStream gzstream = new GZipStream(File.OpenRead(input), CompressionMode.Decompress); GZipStream gzstream = new GZipStream(File.OpenRead(input), CompressionMode.Decompress);
gzstream.CopyTo(st);
// Dispose of the stream // Get the output path
realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
}
// Write the file out
FileStream gzfileout = File.Open(realEntry, FileMode.Create, FileAccess.Write);
byte[] gbuffer = new byte[_bufferSize];
int glen;
while ((glen = gzstream.Read(gbuffer, 0, _bufferSize)) > 0)
{
gzfileout.Write(gbuffer, 0, glen);
gzfileout.Flush();
}
// Dispose of the streams
gzstream.Dispose(); gzstream.Dispose();
gzfileout.Dispose();
break; break;
case ArchiveType.Rar: case ArchiveType.Rar:
@@ -316,7 +299,16 @@ namespace SabreTools.Helper.Tools
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName)) if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
{ {
realEntry = entry.Key; realEntry = entry.Key;
entry.WriteTo(st);
// Get the output path
realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
}
// Write the file out
entry.WriteToFile(realEntry);
break; break;
} }
} }
@@ -331,7 +323,16 @@ namespace SabreTools.Helper.Tools
if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName)) if (entry != null && !entry.IsDirectory && entry.Key.Contains(entryName))
{ {
realEntry = entry.Key; realEntry = entry.Key;
entry.WriteTo(st);
// Get the output path
realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{
Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
}
// Write the file out
entry.WriteToFile(realEntry);
break; break;
} }
} }
@@ -361,15 +362,25 @@ namespace SabreTools.Helper.Tools
zr = zf.OpenReadStream(i, false, out readStream, out streamsize, out cm, out lastMod); zr = zf.OpenReadStream(i, false, out readStream, out streamsize, out cm, out lastMod);
byte[] ibuffer = new byte[_bufferSize]; // Get the output path
int ilen; realEntry = Path.Combine(Path.GetFullPath(tempDir), realEntry);
while ((ilen = readStream.Read(ibuffer, 0, _bufferSize)) > 0) if (!Directory.Exists(Path.GetDirectoryName(realEntry)))
{ {
st.Write(ibuffer, 0, ilen); Directory.CreateDirectory(Path.GetDirectoryName(realEntry));
st.Flush(); }
// Write the file out
FileStream zipfileout = File.Open(realEntry, FileMode.Create, FileAccess.Write);
byte[] zbuffer = new byte[_bufferSize];
int zlen;
while ((zlen = readStream.Read(zbuffer, 0, _bufferSize)) > 0)
{
zipfileout.Write(zbuffer, 0, zlen);
zipfileout.Flush();
} }
zr = zf.CloseReadStream(); zr = zf.CloseReadStream();
zipfileout.Dispose();
} }
} }
break; break;
@@ -378,16 +389,10 @@ namespace SabreTools.Helper.Tools
catch (Exception ex) catch (Exception ex)
{ {
logger.Error(ex.ToString()); logger.Error(ex.ToString());
st = null; realEntry = "";
} }
// If we have a non-null stream, we seek to the beginning return realEntry;
if (st != null)
{
st.Position = 0;
}
return st;
} }
#endregion #endregion