Return direct stream from archives

This commit is contained in:
Matt Nadareski
2024-07-16 14:58:04 -04:00
parent 203d6ce3df
commit 0fc4e2192d
8 changed files with 115 additions and 173 deletions

View File

@@ -749,7 +749,6 @@ namespace SabreTools.DatTools
try
{
// TODO: Write entry to a temporary file to avoid over-large in-memory streams
// TODO: Once entry is written, replace GetEntryStream implementations
// TODO: Only write to file if there are multiple dupes
ItemType itemType = datItem.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue<ItemType>();
(stream, _) = archive.GetEntryStream(datItem.GetName() ?? itemType.AsStringValue() ?? string.Empty);

View File

@@ -172,42 +172,26 @@ namespace SabreTools.FileTypes.Archives
/// <inheritdoc/>
public override (Stream?, string?) GetEntryStream(string entryName)
{
var ms = new MemoryStream();
string? realEntry;
// If we have an invalid file
if (this.Filename == null)
return (null, null);
try
{
// Decompress the _filename stream
realEntry = Path.GetFileNameWithoutExtension(this.Filename);
// Open the entry stream
string realEntry = Path.GetFileNameWithoutExtension(this.Filename);
var gz = new gZip();
ZipReturn ret = gz.ZipFileOpen(this.Filename);
ret = gz.ZipFileOpenReadStream(0, out Stream? gzstream, out ulong streamSize);
ret = gz.ZipFileOpenReadStream(0, out Stream? stream, out ulong streamSize);
// Write the file out
byte[] gbuffer = new byte[_bufferSize];
int glen;
while ((glen = gzstream!.Read(gbuffer, 0, _bufferSize)) > 0)
{
ms.Write(gbuffer, 0, glen);
ms.Flush();
}
// Dispose of the streams
gzstream.Dispose();
// Return the stream
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
}
#endregion

View File

@@ -137,35 +137,44 @@ namespace SabreTools.FileTypes.Archives
public override (Stream?, string?) GetEntryStream(string entryName)
{
#if NET462_OR_GREATER || NETCOREAPP
var ms = new MemoryStream();
string? realEntry = null;
// If we have an invalid file
if (this.Filename == null)
return (null, null);
try
{
SharpCompress.Archives.Rar.RarArchive ra = SharpCompress.Archives.Rar.RarArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false, });
Stream? stream = null;
string? realEntry = null;
var ra = SharpCompress.Archives.Rar.RarArchive.Open(this.Filename, new ReaderOptions { LeaveStreamOpen = false, });
foreach (RarArchiveEntry entry in ra.Entries)
{
if (entry?.Key != null && !entry.IsDirectory && entry.Key.Contains(entryName))
{
// Write the file out
realEntry = entry.Key;
entry.WriteTo(ms);
}
// Skip invalid entries
if (entry?.Key == null || !entry.IsComplete)
continue;
// Skip directory entries
if (entry.IsDirectory)
continue;
// Skip non-matching keys
if (!entry.Key.Contains(entryName))
continue;
// Open the entry stream
realEntry = entry.Key;
stream = entry.OpenEntryStream();
break;
}
ra.Dispose();
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
#else
// TODO: Support RAR archives in old .NET
return (null, null);

View File

@@ -223,70 +223,51 @@ namespace SabreTools.FileTypes.Archives
/// <inheritdoc/>
public override (Stream?, string?) GetEntryStream(string entryName)
{
var ms = new MemoryStream();
string? realEntry = null;
// If we have an invalid file
if (this.Filename == null)
return (null, null);
try
{
SevenZ zf = new();
Stream? stream = null;
string? realEntry = null;
var zf = new SevenZ();
ZipReturn zr = zf.ZipFileOpen(this.Filename, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
{
if (zf.GetLocalFile(i).Filename!.Contains(entryName))
{
// Open the read stream
realEntry = zf.GetLocalFile(i).Filename;
zr = zf.ZipFileOpenReadStream(i, out Stream? readStream, out ulong streamsize);
// Get the entry
var entry = zf.GetLocalFile(i);
// If the stream is smaller than the buffer, just run one loop through to avoid issues
if (streamsize < _bufferSize)
{
byte[] ibuffer = new byte[streamsize];
int ilen = readStream!.Read(ibuffer, 0, (int)streamsize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
}
// Otherwise, we do the normal loop
else
{
byte[] ibuffer = new byte[_bufferSize];
int ilen;
while (streamsize > _bufferSize)
{
ilen = readStream!.Read(ibuffer, 0, _bufferSize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
streamsize -= _bufferSize;
}
// Skip invalid entries
if (entry.Filename == null)
continue;
ilen = readStream!.Read(ibuffer, 0, (int)streamsize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
}
// Skip directory entries
if (entry.IsDirectory)
continue;
zr = zf.ZipFileCloseReadStream();
}
// Skip non-matching keys
if (!entry.Filename.Contains(entryName))
continue;
// Open the entry stream
realEntry = entry.Filename;
zr = zf.ZipFileOpenReadStream(i, out stream, out ulong streamsize);
break;
}
zf.ZipFileClose();
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
}
#endregion

View File

@@ -138,31 +138,40 @@ namespace SabreTools.FileTypes.Archives
public override (Stream?, string?) GetEntryStream(string entryName)
{
#if NET462_OR_GREATER || NETCOREAPP
var ms = new MemoryStream();
string? realEntry = null;
try
{
TarArchive ta = TarArchive.Open(this.Filename!, new ReaderOptions { LeaveStreamOpen = false, });
Stream? stream = null;
string? realEntry = null;
var ta = TarArchive.Open(this.Filename!, new ReaderOptions { LeaveStreamOpen = false, });
foreach (TarArchiveEntry entry in ta.Entries)
{
if (entry?.Key != null && !entry.IsDirectory && entry.Key.Contains(entryName))
{
// Write the file out
realEntry = entry.Key;
entry.WriteTo(ms);
}
// Skip invalid entries
if (entry?.Key == null || !entry.IsComplete)
continue;
// Skip directory entries
if (entry.IsDirectory)
continue;
// Skip non-matching keys
if (!entry.Key.Contains(entryName))
continue;
// Open the entry stream
realEntry = entry.Key;
stream = entry.OpenEntryStream();
break;
}
ta.Dispose();
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
#else
// TODO: Support tape archives in old .NET
return (null, null);

View File

@@ -155,36 +155,24 @@ namespace SabreTools.FileTypes.Archives
public override (Stream?, string?) GetEntryStream(string entryName)
{
#if NET462_OR_GREATER || NETCOREAPP
var ms = new MemoryStream();
string? realEntry;
// If we have an invalid file
if (this.Filename == null)
return (null, null);
try
{
// Decompress the _filename stream
realEntry = Path.GetFileNameWithoutExtension(this.Filename);
var xz = new XZStream(File.OpenRead(this.Filename!));
// Open the entry stream
string realEntry = Path.GetFileNameWithoutExtension(this.Filename);
var stream = new XZStream(File.OpenRead(this.Filename));
// Write the file out
byte[] xbuffer = new byte[_bufferSize];
int xlen;
while ((xlen = xz.Read(xbuffer, 0, _bufferSize)) > 0)
{
ms.Write(xbuffer, 0, xlen);
ms.Flush();
}
// Dispose of the streams
xz.Dispose();
// Return the stream
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
#else
// TODO: Support XZ archives in old .NET
return (null, null);

View File

@@ -198,66 +198,51 @@ namespace SabreTools.FileTypes.Archives
/// <inheritdoc/>
public override (Stream?, string?) GetEntryStream(string entryName)
{
var ms = new MemoryStream();
string? realEntry = null;
// If we have an invalid file
if (this.Filename == null)
return (null, null);
try
{
Zip zf = new();
Stream? stream = null;
string? realEntry = null;
var zf = new Zip();
ZipReturn zr = zf.ZipFileOpen(this.Filename!, -1, true);
if (zr != ZipReturn.ZipGood)
{
throw new Exception(CompressUtils.ZipErrorMessageText(zr));
}
for (int i = 0; i < zf.LocalFilesCount() && zr == ZipReturn.ZipGood; i++)
{
if (zf.GetLocalFile(i).Filename!.Contains(entryName))
{
// Open the read stream
realEntry = zf.GetLocalFile(i).Filename;
zr = zf.ZipFileOpenReadStream(i, false, out Stream? readStream, out ulong streamsize, out ushort cm);
// Get the entry
var entry = zf.GetLocalFile(i);
// If the stream is smaller than the buffer, just run one loop through to avoid issues
if (streamsize < _bufferSize)
{
byte[] ibuffer = new byte[streamsize];
int ilen = readStream!.Read(ibuffer, 0, (int)streamsize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
}
// Otherwise, we do the normal loop
else
{
byte[] ibuffer = new byte[_bufferSize];
int ilen;
while (streamsize > _bufferSize)
{
ilen = readStream!.Read(ibuffer, 0, _bufferSize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
streamsize -= _bufferSize;
}
// Skip invalid entries
if (entry.Filename == null)
continue;
ilen = readStream!.Read(ibuffer, 0, (int)streamsize);
ms.Write(ibuffer, 0, ilen);
ms.Flush();
}
// Skip directory entries
if (entry.IsDirectory)
continue;
zr = zf.ZipFileCloseReadStream();
}
// Skip non-matching keys
if (!entry.Filename.Contains(entryName))
continue;
// Open the entry stream
realEntry = entry.Filename;
zr = zf.ZipFileOpenReadStream(i, out stream, out ulong streamsize);
break;
}
zf.ZipFileClose();
return (stream, realEntry);
}
catch (Exception ex)
{
logger.Error(ex);
ms = null;
realEntry = null;
return (null, null);
}
return (ms, realEntry);
}
#endregion

View File

@@ -212,9 +212,6 @@ namespace SabreTools.FileTypes
/// <returns>Stream representing the entry, null on error</returns>
public virtual (Stream?, string?) GetEntryStream(string entryName)
{
var ms = new MemoryStream();
string? realentry = null;
// If we have an invalid filename
if (this.Filename == null)
return (null, null);
@@ -231,30 +228,20 @@ namespace SabreTools.FileTypes
// Now sort through to find the first file that matches
string? match = files.Where(s => s.EndsWith(entryName)).FirstOrDefault();
// If we had a file, copy that over to the new name
// If we had a file, open and return the stream
if (!string.IsNullOrEmpty(match))
{
#if NET20 || NET35
var tempStream = File.OpenRead(match);
byte[] buffer = new byte[32768];
int read;
while ((read = tempStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
#else
File.OpenRead(match).CopyTo(ms);
#endif
realentry = match;
var stream = File.OpenRead(match);
return (stream, match);
}
return (null, null);
}
catch (Exception ex)
{
logger.Error(ex);
return (ms, realentry);
return (null, null);
}
return (ms, realentry);
}
#endregion