1
0
mirror of synced 2024-12-12 15:51:16 +01:00
Switch-Toolbox/Switch_Toolbox_Library/IO/Extensions/IOExtensions.cs
KillzXGaming 9e3556a5f9 More additions that seem ready for use,
Basic NCCH support, only romfs previewing for easy ripping and testing for file formats. Writing back and more improvements planned soon.
Save BTI files back.
Add structure based parsing from Kuriimu's IO extension. This will be expanded upon later to parse offsets and other things easier.
2019-08-09 18:21:16 -04:00

148 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using Toolbox.Library.Security.Cryptography;
using System.Runtime.InteropServices;
using Syroot.BinaryData;
using System.Linq;
namespace Toolbox.Library.IO
{
public static class IOExtensions
{
//From https://github.com/IcySon55/Kuriimu/blob/master/src/Kontract/IO/Extensions.cs
//Read
public static unsafe T BytesToStruct<T>(this byte[] buffer, bool isBigEndian = false, int offset = 0)
{
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
AdjustBigEndianByteOrder(typeof(T), buffer, isBigEndian);
fixed (byte* pBuffer = buffer)
return Marshal.PtrToStructure<T>((IntPtr)pBuffer + offset);
}
// Write
public static unsafe byte[] StructToBytes<T>(this T item, bool isBigEndian)
{
var buffer = new byte[Marshal.SizeOf(typeof(T))];
fixed (byte* pBuffer = buffer)
Marshal.StructureToPtr(item, (IntPtr)pBuffer, false);
AdjustBigEndianByteOrder(typeof(T), buffer, isBigEndian);
return buffer;
}
//Adjust byte order for big endian
private static void AdjustBigEndianByteOrder(Type type, byte[] buffer, bool isBigEndian, int startOffset = 0)
{
if (!isBigEndian)
return;
if (type.IsPrimitive)
{
if (type == typeof(short) || type == typeof(ushort) ||
type == typeof(int) || type == typeof(uint) ||
type == typeof(long) || type == typeof(ulong))
{
Array.Reverse(buffer);
return;
}
}
foreach (var field in type.GetFields())
{
var fieldType = field.FieldType;
// Ignore static fields
if (field.IsStatic) continue;
if (fieldType.BaseType == typeof(Enum) && fieldType != typeof(ByteOrder))
fieldType = fieldType.GetFields()[0].FieldType;
// Swap bytes only for the following types (incomplete just like BinaryReaderX is)
if (fieldType == typeof(short) || fieldType == typeof(ushort) ||
fieldType == typeof(int) || fieldType == typeof(uint) ||
fieldType == typeof(long) || fieldType == typeof(ulong))
{
var offset = Marshal.OffsetOf(type, field.Name).ToInt32();
// Enums
if (fieldType.IsEnum)
fieldType = Enum.GetUnderlyingType(fieldType);
// Check for sub-fields to recurse if necessary
var subFields = fieldType.GetFields().Where(subField => subField.IsStatic == false).ToArray();
var effectiveOffset = startOffset + offset;
if (subFields.Length == 0)
Array.Reverse(buffer, effectiveOffset, Marshal.SizeOf(fieldType));
else
AdjustBigEndianByteOrder(fieldType, buffer, isBigEndian, effectiveOffset);
}
}
}
//https://github.com/exelix11/EditorCore/blob/872d210f85ec0409f8a6ac3a12fc162aaf4cd90c/EditorCoreCommon/CustomClasses.cs#L367
public static bool Matches(this byte[] arr, string magic) =>
arr.Matches(0, magic.ToCharArray());
public static bool Matches(this byte[] arr, uint magic) =>
arr.Matches(0, BitConverter.GetBytes(magic));
public static bool Matches(this byte[] arr, uint startIndex, params byte[] magic)
{
if (arr.Length < magic.Length + startIndex) return false;
for (uint i = 0; i < magic.Length; i++)
{
if (arr[i + startIndex] != magic[i]) return false;
}
return true;
}
public static byte[] ToByteArray(this string str, int length)
{
return Encoding.ASCII.GetBytes(str.PadRight(length, ' '));
}
public static uint EncodeCrc32(this string str)
{
return Crc32.Compute(str);
}
public static bool Matches(this byte[] arr, uint startIndex, params char[] magic)
{
if (arr.Length < magic.Length + startIndex) return false;
for (uint i = 0; i < magic.Length; i++)
{
if (arr[i + startIndex] != magic[i]) return false;
}
return true;
}
public static uint Reverse(this uint x)
{
// swap adjacent 16-bit blocks
x = (x >> 16) | (x << 16);
// swap adjacent 8-bit blocks
return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
}
//https://stackoverflow.com/questions/2230826/remove-invalid-disallowed-bad-characters-from-filename-or-directory-folder/12800424#12800424
public static string RemoveIllegaleFileNameCharacters(this string str)
{
return string.Join("_", str.Split(Path.GetInvalidFileNameChars()));
}
public static string RemoveIllegaleFolderNameCharacters(this string str)
{
return string.Join("_", str.Split(Path.GetInvalidPathChars()));
}
}
}