Skip to content

Commit

Permalink
Merge pull request #24 from goaaats/old_streams
Browse files Browse the repository at this point in the history
Use old SqPackStream
  • Loading branch information
NotAdam authored Apr 15, 2021
2 parents 6edcdcb + 33f6304 commit 5cea061
Show file tree
Hide file tree
Showing 5 changed files with 588 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using System.IO;
using Lumina.Data;
using Penumbra.Util;

namespace Penumbra.Importer
{
public class MagicTempFileStreamManagerAndDeleterFuckery : SqPackStream, IDisposable
public class MagicTempFileStreamManagerAndDeleterFuckery : PenumbraSqPackStream, IDisposable
{
private readonly FileStream _fileStream;

Expand Down
35 changes: 28 additions & 7 deletions Penumbra/Importer/TexToolsImport.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -9,6 +10,7 @@
using Newtonsoft.Json;
using Penumbra.Importer.Models;
using Penumbra.Models;
using Penumbra.Util;

namespace Penumbra.Importer
{
Expand Down Expand Up @@ -62,12 +64,28 @@ private void WriteZipEntryToTempFile( Stream s )
fs.Close();
}

private SqPackStream GetMagicSqPackDeleterStream( ZipFile file, string entryName )
// You can in no way rely on any file paths in TTMPs so we need to just do this, sorry
private ZipEntry FindZipEntry( ZipFile file, string fileName )
{
for( var i = 0; i < file.Count; i++ )
{
var entry = file[ i ];

if( entry.Name.Contains( fileName ) )
return entry;
}

return null;
}

private PenumbraSqPackStream GetMagicSqPackDeleterStream( ZipFile file, string entryName )
{
State = ImporterState.WritingPackToDisk;

// write shitty zip garbage to disk
var entry = file.GetEntry( entryName );
var entry = FindZipEntry( file, entryName );
Debug.Assert( entry != null, $"Could not find in mod zip: {entryName}" );

using var s = file.GetInputStream( entry );

WriteZipEntryToTempFile( s );
Expand All @@ -80,8 +98,11 @@ private void VerifyVersionAndImport( FileInfo modPackFile )
{
using var zfs = modPackFile.OpenRead();
using var extractedModPack = new ZipFile( zfs );
var mpl = extractedModPack.GetEntry( "TTMPL.mpl" );
var modRaw = GetStringFromZipEntry( extractedModPack, mpl, Encoding.UTF8 );

var mpl = FindZipEntry( extractedModPack, "TTMPL.mpl" );
Debug.Assert( mpl != null, "Could not find mod meta in ZIP." );

var modRaw = GetStringFromZipEntry( extractedModPack, mpl, Encoding.UTF8 );

// At least a better validation than going by the extension.
if( modRaw.Contains( "\"TTMPVersion\":" ) )
Expand Down Expand Up @@ -277,7 +298,7 @@ private void ImportMetaModPack( FileInfo file )
throw new NotImplementedException();
}

private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< SimpleMod > mods, SqPackStream dataStream )
private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< SimpleMod > mods, PenumbraSqPackStream dataStream )
{
State = ImporterState.ExtractingModFiles;

Expand All @@ -294,13 +315,13 @@ private void ExtractSimpleModList( DirectoryInfo outDirectory, IEnumerable< Simp
}
}

private void ExtractMod( DirectoryInfo outDirectory, SimpleMod mod, SqPackStream dataStream )
private void ExtractMod( DirectoryInfo outDirectory, SimpleMod mod, PenumbraSqPackStream dataStream )
{
PluginLog.Log( " -> Extracting {0} at {1}", mod.FullPath, mod.ModOffset.ToString( "X" ) );

try
{
var data = dataStream.ReadFile< FileResource >( mod.ModOffset );
var data = dataStream.ReadFile< PenumbraSqPackStream.PenumbraFileResource >( mod.ModOffset );

var extractedFile = new FileInfo( Path.Combine( outDirectory.FullName, mod.FullPath ) );
extractedFile.Directory?.Create();
Expand Down
140 changes: 140 additions & 0 deletions Penumbra/Util/BinaryReaderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Penumbra.Util
{
public static class BinaryReaderExtensions
{
/// <summary>
/// Reads a structure from the current stream position.
/// </summary>
/// <param name="br"></param>
/// <typeparam name="T">The structure to read in to</typeparam>
/// <returns>The file data as a structure</returns>
public static T ReadStructure< T >( this BinaryReader br ) where T : struct
{
ReadOnlySpan< byte > data = br.ReadBytes( Unsafe.SizeOf< T >() );

return MemoryMarshal.Read< T >( data );
}

/// <summary>
/// Reads many structures from the current stream position.
/// </summary>
/// <param name="br"></param>
/// <param name="count">The number of T to read from the stream</param>
/// <typeparam name="T">The structure to read in to</typeparam>
/// <returns>A list containing the structures read from the stream</returns>
public static List< T > ReadStructures< T >( this BinaryReader br, int count ) where T : struct
{
var size = Marshal.SizeOf< T >();
var data = br.ReadBytes( size * count );

var list = new List< T >( count );

for( int i = 0; i < count; i++ )
{
var offset = size * i;
var span = new ReadOnlySpan< byte >( data, offset, size );

list.Add( MemoryMarshal.Read< T >( span ) );
}

return list;
}

public static T[] ReadStructuresAsArray< T >( this BinaryReader br, int count ) where T : struct
{
var size = Marshal.SizeOf< T >();
var data = br.ReadBytes( size * count );

// im a pirate arr
var arr = new T[ count ];

for( int i = 0; i < count; i++ )
{
var offset = size * i;
var span = new ReadOnlySpan< byte >( data, offset, size );

arr[ i ] = MemoryMarshal.Read< T >( span );
}

return arr;
}

/// <summary>
/// Moves the BinaryReader position to offset, reads a string, then
/// sets the reader position back to where it was when it started
/// </summary>
/// <param name="br"></param>
/// <param name="offset">The offset to read a string starting from.</param>
/// <returns></returns>
public static string ReadStringOffsetData( this BinaryReader br, long offset )
{
return Encoding.UTF8.GetString( ReadRawOffsetData( br, offset ) );
}

/// <summary>
/// Moves the BinaryReader position to offset, reads raw bytes until a null byte, then
/// sets the reader position back to where it was when it started
/// </summary>
/// <param name="br"></param>
/// <param name="offset">The offset to read data starting from.</param>
/// <returns></returns>
public static byte[] ReadRawOffsetData( this BinaryReader br, long offset )
{
var originalPosition = br.BaseStream.Position;
br.BaseStream.Position = offset;

var chars = new List< byte >();

byte current;
while( ( current = br.ReadByte() ) != 0 )
{
chars.Add( current );
}

br.BaseStream.Position = originalPosition;

return chars.ToArray();
}

/// <summary>
/// Seeks this BinaryReader's position to the given offset. Syntactic sugar.
/// </summary>
public static void Seek( this BinaryReader br, long offset ) {
br.BaseStream.Position = offset;
}

/// <summary>
/// Reads a byte and moves the stream position back to where it started before the operation
/// </summary>
/// <param name="br">The reader to use to read the byte</param>
/// <returns>The byte that was read</returns>
public static byte PeekByte( this BinaryReader br )
{
var data = br.ReadByte();
br.BaseStream.Position--;
return data;
}

/// <summary>
/// Reads bytes and moves the stream position back to where it started before the operation
/// </summary>
/// <param name="br">The reader to use to read the bytes</param>
/// <param name="count">The number of bytes to read</param>
/// <returns>The read bytes</returns>
public static byte[] PeekBytes( this BinaryReader br, int count )
{
var data = br.ReadBytes( count );
br.BaseStream.Position -= count;
return data;
}
}
}
17 changes: 17 additions & 0 deletions Penumbra/Util/MemoryStreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Penumbra.Util
{
public static class MemoryStreamExtensions
{
public static void Write( this MemoryStream stream, byte[] data )
{
stream.Write( data, 0, data.Length );
}
}
}
Loading

0 comments on commit 5cea061

Please sign in to comment.