diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8604c98..949f4fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,113 @@ name: Il2CppInspectorRedux Build on: [push, workflow_dispatch] jobs: - build-gui: + build-redux-gui: # this already includes stuff only relevant for linux/macos for when the gui is released on those platforms + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + + - name: Setup Node.JS + uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} + + - name: Setup Tauri dependencies (ubuntu only) + if: matrix.platform == 'ubuntu-22.04' + run: | + sudo apt-get update + sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + + - name: Install frontend dependencies + run: pnpm install + working-directory: ./Il2CppInspector.Redux.GUI.UI + + - uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-redux-gui-${{ hashFiles('**/packages.lock.json') }} + restore-keys: | + ${{ runner.os }}-nuget-redux-gui- + + - name: Restore NuGet packages + run: dotnet restore -r win-x64 ./Il2CppInspector.Redux.GUI + + # note: we embed the exe directly into the c# component, and it it is built alongside it + # in another msbuild target. + - name: Build GUI + run: dotnet publish ./Il2CppInspector.Redux.GUI/Il2CppInspector.Redux.GUI.csproj -r win-x64 --no-self-contained + + - name: Copy components to output directory + run: | + mkdir ./build_output + cp ./Il2CppInspector.Redux.GUI/bin/Release/net9.0/win-x64/publish/Il2CppInspector.Redux.GUI.exe ./build_output/ + + - name: Upload GUI Artifact + uses: actions/upload-artifact@v4 + with: + name: Il2CppInspectorRedux.GUI + path: build_output + + build-redux-cli: + runs-on: ubuntu-latest + strategy: + matrix: + dotnet-version: [ '9.0.x' ] + rid: ['win-x64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64'] + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + + - uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-cli-${{ matrix.rid }}-${{ hashFiles('**/packages.lock.json') }} + restore-keys: | + ${{ runner.os }}-nuget-cli-${{ matrix.rid }}- + + - name: Setup .NET SDK ${{ matrix.dotnet-version }} + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.dotnet-version }} + + - name: Install dependencies + run: dotnet restore -r ${{ matrix.rid }} ./Il2CppInspector.Redux.CLI + + - name: Build & Publish + run: dotnet publish -c Release --no-self-contained --no-restore -o ./${{ matrix.rid }} -r ${{ matrix.rid }} ./Il2CppInspector.Redux.CLI/Il2CppInspector.Redux.CLI.csproj + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: Il2CppInspectorRedux.CLI-${{ matrix.rid }} + path: ./${{ matrix.rid }} + + build-old-gui: runs-on: windows-latest steps: @@ -32,10 +138,10 @@ jobs: - name: Upload GUI Artifact uses: actions/upload-artifact@v4 with: - name: Il2CppInspectorRedux.GUI + name: Il2CppInspectorRedux.Old.GUI path: Il2CppInspector.GUI/bin/Release/net9.0-windows/win-x64/publish - build-cli: + build-old-cli: runs-on: ubuntu-latest strategy: matrix: @@ -73,5 +179,5 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: Il2CppInspectorRedux.CLI-${{ matrix.rid }} + name: Il2CppInspectorRedux.Old.CLI-${{ matrix.rid }} path: ./${{ matrix.rid }} diff --git a/.gitignore b/.gitignore index c5e3afa..8803027 100644 --- a/.gitignore +++ b/.gitignore @@ -268,3 +268,6 @@ paket-files/ /Il2CppInspector.sln.DotSettings /Il2CppTests/samples /Il2CppTests/TestCpp + +# for dotnet-tools.json +.config \ No newline at end of file diff --git a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs index 3652065..068b9b0 100644 --- a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs +++ b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs @@ -5,613 +5,738 @@ All rights reserved. */ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Diagnostics; using System.Text.RegularExpressions; using Il2CppInspector.Cpp.UnityHeaders; using Il2CppInspector.Model; using Il2CppInspector.Reflection; -namespace Il2CppInspector.Cpp +namespace Il2CppInspector.Cpp; + +// Class for generating C header declarations from Reflection objects (TypeInfo, etc.) +public class CppDeclarationGenerator { - // Class for generating C header declarations from Reflection objects (TypeInfo, etc.) - public class CppDeclarationGenerator - { - private readonly AppModel appModel; + private readonly AppModel appModel; - private TypeModel model => appModel.TypeModel; - private CppTypeCollection types => appModel.CppTypeCollection; + private TypeModel model => appModel.TypeModel; + private CppTypeCollection types => appModel.CppTypeCollection; - // Word size (32/64-bit) for this generator - public int WordSize => appModel.WordSizeBits; + // Word size (32/64-bit) for this generator + public int WordSize => appModel.WordSizeBits; - // Version number and header file to generate structures for - public UnityVersion UnityVersion => appModel.UnityVersion; + // Version number and header file to generate structures for + public UnityVersion UnityVersion => appModel.UnityVersion; - // How inheritance of type structs should be represented. - // Different C++ compilers lay out C++ class structures differently, - // meaning that the compiler must be known in order to generate class type structures - // with the correct layout. - public CppCompilerType InheritanceStyle; + // How inheritance of type structs should be represented. + // Different C++ compilers lay out C++ class structures differently, + // meaning that the compiler must be known in order to generate class type structures + // with the correct layout. + public readonly CppCompilerType InheritanceStyle; - public CppDeclarationGenerator(AppModel appModel) { - this.appModel = appModel; + public CppDeclarationGenerator(AppModel appModel) { + this.appModel = appModel; - InitializeNaming(); - InitializeConcreteImplementations(); + InitializeNaming(); + InitializeConcreteImplementations(); - // Configure inheritance style based on binary type; this can be overridden by setting InheritanceStyle in the object initializer - InheritanceStyle = CppCompiler.GuessFromImage(model.Package.BinaryImage); - } + // Configure inheritance style based on binary type; this can be overridden by setting InheritanceStyle in the object initializer + InheritanceStyle = CppCompiler.GuessFromImage(model.Package.BinaryImage); + } - // C type declaration used to name variables of the given C# type - private static Dictionary primitiveTypeMap = new Dictionary { - ["Boolean"] = "bool", - ["Byte"] = "uint8_t", - ["SByte"] = "int8_t", - ["Int16"] = "int16_t", - ["UInt16"] = "uint16_t", - ["Int32"] = "int32_t", - ["UInt32"] = "uint32_t", - ["Int64"] = "int64_t", - ["UInt64"] = "uint64_t", - ["IntPtr"] = "void *", - ["UIntPtr"] = "void *", - ["Char"] = "uint16_t", - ["Double"] = "double", - ["Single"] = "float" - }; + // C type declaration used to name variables of the given C# type + private static readonly Dictionary primitiveTypeMap = new() + { + ["Boolean"] = "bool", + ["Byte"] = "uint8_t", + ["SByte"] = "int8_t", + ["Int16"] = "int16_t", + ["UInt16"] = "uint16_t", + ["Int32"] = "int32_t", + ["UInt32"] = "uint32_t", + ["Int64"] = "int64_t", + ["UInt64"] = "uint64_t", + ["IntPtr"] = "void *", + ["UIntPtr"] = "void *", + ["Char"] = "uint16_t", + ["Double"] = "double", + ["Single"] = "float" + }; - public CppType AsCType(TypeInfo ti) { - // IsArray case handled by TypeNamer.GetName - if (ti.IsByRef || ti.IsPointer) { - return AsCType(ti.ElementType).AsPointer(WordSize); - } - if (ti.IsValueType) { - if (ti.IsPrimitive && primitiveTypeMap.ContainsKey(ti.Name)) { - return types.GetType(primitiveTypeMap[ti.Name]); - } - return types.GetType(TypeNamer.GetName(ti)); - } - if (ti.IsEnum) { - return types.GetType(TypeNamer.GetName(ti)); - } - return types.GetType(TypeNamer.GetName(ti) + " *"); + public CppType AsCType(TypeInfo ti) { + // IsArray case handled by TypeNamer.GetName + if (ti.IsByRef || ti.IsPointer) { + return AsCType(ti.ElementType).AsPointer(WordSize); } - // Resets the cache of visited types and pending types to output, but preserve any names we have already generated - public void Reset() { - VisitedFieldStructs.Clear(); - VisitedTypes.Clear(); - TodoFieldStructs.Clear(); - TodoTypeStructs.Clear(); + if (ti.IsValueType) { + if (ti.IsPrimitive && primitiveTypeMap.TryGetValue(ti.Name, out var value)) { + return types.GetType(value); + } + + return types.GetType(TypeNamer.GetName(ti)); } - #region Field Struct Generation - /* Generating field structures (structures for the fields of a given type) occurs in two passes. - * In the first pass (VisitFieldStructs), we walk over a type and all of the types that the resulting structure would depend on. - * In the second pass (GenerateVisitedFieldStructs), we generate all type structures in the necessary order. - * (For example: structures for value types must precede any usage of those value types for layout reasons). - */ + if (ti.IsEnum) { + return types.GetType(TypeNamer.GetName(ti)); + } - // A cache of field structures that have already been generated, to eliminate duplicate definitions - private readonly HashSet VisitedFieldStructs = new HashSet(); + return types.GetType(TypeNamer.GetName(ti) + " *"); + } - // A queue of field structures that need to be generated. - private readonly List TodoFieldStructs = new List(); + // Resets the cache of visited types and pending types to output, but preserve any names we have already generated + public void Reset() { + _visitedFieldStructs.Clear(); + _visitedTypes.Clear(); + _todoFieldStructs.Clear(); + _todoTypeStructs.Clear(); + } - // Walk over dependencies of the given type, to figure out what field structures it depends on - private void VisitFieldStructs(TypeInfo ti) { - if (VisitedFieldStructs.Contains(ti)) - return; - if (ti.IsByRef || ti.ContainsGenericParameters) - return; - VisitedFieldStructs.Add(ti); + #region Field Struct Generation + /* Generating field structures (structures for the fields of a given type) occurs in two passes. + * In the first pass (VisitFieldStructs), we walk over a type and all of the types that the resulting structure would depend on. + * In the second pass (GenerateVisitedFieldStructs), we generate all type structures in the necessary order. + * (For example: structures for value types must precede any usage of those value types for layout reasons). + */ - if (ti.BaseType != null) - VisitFieldStructs(ti.BaseType); + // A cache of field structures that have already been generated, to eliminate duplicate definitions + private readonly HashSet _visitedFieldStructs = []; - if (ti.IsArray) - VisitFieldStructs(ti.ElementType); + // A queue of field structures that need to be generated. + private readonly List _todoFieldStructs = []; - if (ti.IsEnum) - VisitFieldStructs(ti.GetEnumUnderlyingType()); + private readonly HashSet _requiredForwardDefinitionsForFields = []; - foreach (var fi in ti.DeclaredFields.Where(fi => !fi.IsStatic && !fi.IsLiteral)) + private readonly HashSet _currentVisitedFieldStructs = []; + private readonly HashSet _currentTodoFieldStructs = []; + private readonly HashSet _currentRequiredForwardDefinitions = []; + private readonly HashSet _currentlyVisitingFieldStructs = []; + + private class CircularReferenceException(TypeInfo circularType, TypeInfo parentType) : Exception("Circular reference detected") + { + public TypeInfo CircularReferencedType { get; } = circularType; + public TypeInfo ParentType { get; } = parentType; + } + + // Walk over dependencies of the given type, to figure out what field structures it depends on + private void VisitFieldStructsInner(TypeInfo ti) + { + if (_visitedFieldStructs.Contains(ti) || _currentVisitedFieldStructs.Contains(ti)) + return; + + if (ti.IsByRef || ti.ContainsGenericParameters) + return; + + _currentVisitedFieldStructs.Add(ti); + _currentlyVisitingFieldStructs.Add(ti); + + if (ti.BaseType != null) + VisitFieldStructsInner(ti.BaseType); + + if (ti.IsArray) + VisitFieldStructsInner(ti.ElementType); + + if (ti.IsEnum) + VisitFieldStructsInner(ti.GetEnumUnderlyingType()); + + foreach (var fi in ti.DeclaredFields.Where(fi => !fi.IsStatic && !fi.IsLiteral)) + ProcessTypeField(fi); + + _currentTodoFieldStructs.Add(ti); + _currentlyVisitingFieldStructs.Remove(ti); + + return; + + void ProcessTypeField(FieldInfo fi) + { + if (fi.FieldType.IsEnum || fi.FieldType.IsValueType) { - if (fi.FieldType.IsEnum || fi.FieldType.IsValueType) - VisitFieldStructs(fi.FieldType); - else if (fi.FieldType.HasElementType) - VisitFieldStructs(fi.FieldType.ElementType); + VisitFieldStructsInner(fi.FieldType); + } + else if (fi.FieldType.HasElementType) + { + var elementType = fi.FieldType.ElementType; + if (!fi.FieldType.IsPointer || !_currentRequiredForwardDefinitions.Contains(elementType)) + { + VisitFieldStructsInner(elementType); + + if (elementType.IsValueType + && elementType != ti + && _currentlyVisitingFieldStructs.Contains(elementType) + && !_currentRequiredForwardDefinitions.Contains(elementType)) + { + // this is now an issue: there is a loop, and we need to resolve it + // if the field type is a pointer, we can make a forward declaration and be done with it + // otherwise, we cannot generate these types + if (!fi.FieldType.IsPointer) + Debugger.Break(); + + throw new CircularReferenceException(elementType, ti); + } + } + } + } + } + + private void ClearCurrentFieldStructVisitState() + { + _currentTodoFieldStructs.Clear(); + _currentVisitedFieldStructs.Clear(); + _currentlyVisitingFieldStructs.Clear(); + } + + private void VisitFieldStructs(TypeInfo ti) + { + ClearCurrentFieldStructVisitState(); + + var requiredTypesToVisit = new Stack([ti]); + + while (true) + { + try + { + foreach (var typeToVisit in requiredTypesToVisit) + VisitFieldStructsInner(typeToVisit); + } + catch (CircularReferenceException ex) + { + ClearCurrentFieldStructVisitState(); + + _currentRequiredForwardDefinitions.Add(ex.CircularReferencedType); + requiredTypesToVisit.Push(ex.ParentType); + + continue; } - TodoFieldStructs.Add(ti); + break; } - // Generate the fields for the base class of all objects (Il2CppObject) - // The two fields are inlined so that we can specialize the klass member for each type object - private CppComplexType GenerateObjectStruct(string name, TypeInfo ti) { - var type = types.Struct(name); - types.AddField(type, "klass", TypeNamer.GetName(ti) + "__Class *"); - types.AddField(type, "monitor", "MonitorData *"); - return type; - } + _todoFieldStructs.AddRange(_currentTodoFieldStructs); + foreach (var visitedType in _currentVisitedFieldStructs) + _visitedFieldStructs.Add(visitedType); + + foreach (var requiredType in _currentRequiredForwardDefinitions) + _requiredForwardDefinitionsForFields.Add(requiredType); + } - // Generate structure fields for each field of a given type - private void GenerateFieldList(CppComplexType type, CppNamespace ns, TypeInfo ti) { - var namer = ns.MakeNamer(field => field.Name.ToCIdentifier()); + // Generate the fields for the base class of all objects (Il2CppObject) + // The two fields are inlined so that we can specialize the klass member for each type object + private CppComplexType GenerateObjectStruct(string name, TypeInfo ti) { + var type = types.Struct(name); + types.AddField(type, "klass", TypeNamer.GetName(ti) + "__Class *"); + types.AddField(type, "monitor", "MonitorData *"); + return type; + } + + // Generate structure fields for each field of a given type + private void GenerateFieldList(CppComplexType type, CppNamespace ns, TypeInfo ti) { + var namer = ns.MakeNamer(field => field.Name.ToCIdentifier()); + foreach (var field in ti.DeclaredFields) { + if (field.IsLiteral || field.IsStatic) + continue; + type.AddField(namer.GetName(field), AsCType(field.FieldType)); + } + } + + // Generate the C structure for a value type, such as an enum or struct + private (CppComplexType valueType, CppComplexType boxedType) GenerateValueFieldStruct(TypeInfo ti) { + CppComplexType valueType, boxedType; + string name = TypeNamer.GetName(ti); + + if (ti.IsEnum) { + // Enums should be represented using enum syntax + // They otherwise behave like value types + var namer = CreateNamespace().MakeNamer((field) => field.Name.ToCIdentifier()); + var underlyingType = AsCType(ti.GetEnumUnderlyingType()); + valueType = types.Enum(underlyingType, name); foreach (var field in ti.DeclaredFields) { - if (field.IsLiteral || field.IsStatic) - continue; - type.AddField(namer.GetName(field), AsCType(field.FieldType)); + if (field.Name != "value__") + ((CppEnumType)valueType).AddField(namer.GetName(field), field.DefaultValue); } + + boxedType = GenerateObjectStruct(name + "__Boxed", ti); + boxedType.AddField("value", AsCType(ti)); + } else { + // This structure is passed by value, so it doesn't include Il2CppObject fields. + valueType = types.Struct(name); + GenerateFieldList(valueType, CreateNamespace(), ti); + + // Also generate the boxed form of the structure which includes the Il2CppObject header. + boxedType = GenerateObjectStruct(name + "__Boxed", ti); + boxedType.AddField("fields", AsCType(ti)); + } + return (valueType, boxedType); + } + + // Generate the C structure for a reference type, such as a class or array + private (CppComplexType objectOrArrayType, CppComplexType fieldsType) GenerateRefFieldStruct(TypeInfo ti) { + var name = TypeNamer.GetName(ti); + + if (ti.IsArray) { + var klassType = ti.IsArray ? ti : ti.BaseType; + var elementType = ti.IsArray ? AsCType(ti.ElementType) : types.GetType("void *"); + var type = GenerateObjectStruct(name, klassType); + types.AddField(type, "bounds", "Il2CppArrayBounds *"); + types.AddField(type, "max_length", "il2cpp_array_size_t"); + type.AddField("vector", elementType.AsArray(32)); + return (type, null); } - // Generate the C structure for a value type, such as an enum or struct - private (CppComplexType valueType, CppComplexType boxedType) GenerateValueFieldStruct(TypeInfo ti) { - CppComplexType valueType, boxedType; - string name = TypeNamer.GetName(ti); + /* Generate a list of all base classes starting from the root */ + List baseClasses = new List(); + for (var bti = ti; bti != null; bti = bti.BaseType) + baseClasses.Add(bti); + baseClasses.Reverse(); - if (ti.IsEnum) { - // Enums should be represented using enum syntax - // They otherwise behave like value types - var namer = CreateNamespace().MakeNamer((field) => field.Name.ToCIdentifier()); - var underlyingType = AsCType(ti.GetEnumUnderlyingType()); - valueType = types.Enum(underlyingType, name); - foreach (var field in ti.DeclaredFields) { - if (field.Name != "value__") - ((CppEnumType)valueType).AddField(namer.GetName(field), field.DefaultValue); + var ns = CreateNamespace(); + + if (InheritanceStyle == CppCompilerType.MSVC) { + /* MSVC style: classes directly contain their base class as the first member. + * This causes all classes to be aligned to the alignment of their base class. */ + TypeInfo firstNonEmpty = null; + foreach (var bti in baseClasses) { + if (bti.DeclaredFields.Any(field => !field.IsStatic && !field.IsLiteral)) { + firstNonEmpty = bti; + break; } - - boxedType = GenerateObjectStruct(name + "__Boxed", ti); - boxedType.AddField("value", AsCType(ti)); + } + if (firstNonEmpty == null) { + /* This struct is completely empty. Omit __Fields entirely. */ + return (GenerateObjectStruct(name, ti), null); } else { - // This structure is passed by value, so it doesn't include Il2CppObject fields. - valueType = types.Struct(name); - GenerateFieldList(valueType, CreateNamespace(), ti); - - // Also generate the boxed form of the structure which includes the Il2CppObject header. - boxedType = GenerateObjectStruct(name + "__Boxed", ti); - boxedType.AddField("fields", AsCType(ti)); - } - return (valueType, boxedType); - } - - // Generate the C structure for a reference type, such as a class or array - private (CppComplexType objectOrArrayType, CppComplexType fieldsType) GenerateRefFieldStruct(TypeInfo ti) { - var name = TypeNamer.GetName(ti); - - if (ti.IsArray) { - var klassType = ti.IsArray ? ti : ti.BaseType; - var elementType = ti.IsArray ? AsCType(ti.ElementType) : types.GetType("void *"); - var type = GenerateObjectStruct(name, klassType); - types.AddField(type, "bounds", "Il2CppArrayBounds *"); - types.AddField(type, "max_length", "il2cpp_array_size_t"); - type.AddField("vector", elementType.AsArray(32)); - return (type, null); - } - - /* Generate a list of all base classes starting from the root */ - List baseClasses = new List(); - for (var bti = ti; bti != null; bti = bti.BaseType) - baseClasses.Add(bti); - baseClasses.Reverse(); - - var ns = CreateNamespace(); - - if (InheritanceStyle == CppCompilerType.MSVC) { - /* MSVC style: classes directly contain their base class as the first member. - * This causes all classes to be aligned to the alignment of their base class. */ - TypeInfo firstNonEmpty = null; - foreach (var bti in baseClasses) { - if (bti.DeclaredFields.Any(field => !field.IsStatic && !field.IsLiteral)) { - firstNonEmpty = bti; - break; - } - } - if (firstNonEmpty == null) { - /* This struct is completely empty. Omit __Fields entirely. */ - return (GenerateObjectStruct(name, ti), null); + CppComplexType fieldType; + if (firstNonEmpty == ti) { + /* All base classes are empty, so this class forms the root of a new hierarchy. + * We have to be a little careful: the root-most class needs to have its alignment + * set to that of Il2CppObject, but we can't explicitly include Il2CppObject + * in the hierarchy because we want to customize the type of the klass parameter. */ + var align = model.Package.BinaryImage.Bits == 32 ? 4 : 8; + fieldType = types.Struct(name + "__Fields", align); + GenerateFieldList(fieldType, ns, ti); } else { - CppComplexType fieldType; - if (firstNonEmpty == ti) { - /* All base classes are empty, so this class forms the root of a new hierarchy. - * We have to be a little careful: the root-most class needs to have its alignment - * set to that of Il2CppObject, but we can't explicitly include Il2CppObject - * in the hierarchy because we want to customize the type of the klass parameter. */ - var align = model.Package.BinaryImage.Bits == 32 ? 4 : 8; - fieldType = types.Struct(name + "__Fields", align); - GenerateFieldList(fieldType, ns, ti); - } else { - /* Include the base class fields. Alignment will be dictated by the hierarchy. */ - ns.ReserveName("_"); - fieldType = types.Struct(name + "__Fields"); - var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__Fields"]; - fieldType.AddField("_", baseFieldType); - GenerateFieldList(fieldType, ns, ti); + /* Include the base class fields. Alignment will be dictated by the hierarchy. */ + ns.ReserveName("_"); + fieldType = types.Struct(name + "__Fields"); + var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__Fields"]; + + if (baseFieldType == null) + { + // if we end up here, there is a loop in the type generation. + // this is not currently supported, so we throw an exception. + throw new InvalidOperationException($"Failed to generate type for {ti}"); } - var type = GenerateObjectStruct(name, ti); - types.AddField(type, "fields", name + "__Fields"); - return (type, fieldType); + fieldType.AddField("_", baseFieldType); + GenerateFieldList(fieldType, ns, ti); } - } else if (InheritanceStyle == CppCompilerType.GCC) { - /* GCC style: after the base class, all fields in the hierarchy are concatenated. - * This saves space (fields are "packed") but requires us to repeat fields from - * base classes. */ - ns.ReserveName("klass"); - ns.ReserveName("monitor"); var type = GenerateObjectStruct(name, ti); - foreach (var bti in baseClasses) - GenerateFieldList(type, ns, bti); - return (type, null); + types.AddField(type, "fields", name + "__Fields"); + return (type, fieldType); } - throw new InvalidOperationException("Could not generate ref field struct"); - } + } else if (InheritanceStyle == CppCompilerType.GCC) { + /* GCC style: after the base class, all fields in the hierarchy are concatenated. + * This saves space (fields are "packed") but requires us to repeat fields from + * base classes. */ + ns.ReserveName("klass"); + ns.ReserveName("monitor"); - // "Flush" the list of visited types, generating C structures for each one - private List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType)> GenerateVisitedFieldStructs() { - var structs = new List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType)>(TodoTypeStructs.Count); - foreach (var ti in TodoFieldStructs) { - if (ti.IsEnum || ti.IsValueType) { - var (valueType, boxedType) = GenerateValueFieldStruct(ti); - structs.Add((ti, valueType, boxedType, null)); - } - else { - var (objectOrArrayType, fieldsType) = GenerateRefFieldStruct(ti); - structs.Add((ti, null, objectOrArrayType, fieldsType)); - } + var type = GenerateObjectStruct(name, ti); + foreach (var bti in baseClasses) + GenerateFieldList(type, ns, bti); + return (type, null); + } + throw new InvalidOperationException("Could not generate ref field struct"); + } + + // "Flush" the list of visited types, generating C structures for each one + private List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType)> GenerateVisitedFieldStructs() { + var structs = new List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType)>(_todoTypeStructs.Count); + foreach (var ti in _todoFieldStructs) { + if (ti.IsEnum || ti.IsValueType) { + var (valueType, boxedType) = GenerateValueFieldStruct(ti); + structs.Add((ti, valueType, boxedType, null)); } - TodoFieldStructs.Clear(); - return structs; - } - #endregion - - #region Class Struct Generation - - // Concrete implementations for abstract classes, for use in looking up VTable signatures and names - private readonly Dictionary ConcreteImplementations = new Dictionary(); - /// - /// VTables for abstract types have "null" in place of abstract functions. - /// This function searches for concrete implementations so that we can properly - /// populate the abstract class VTables. - /// - private void InitializeConcreteImplementations() { - foreach (var ti in model.Types) { - if (ti.HasElementType || ti.IsAbstract || ti.IsGenericParameter) - continue; - var baseType = ti.BaseType; - while (baseType != null) { - if (baseType.IsAbstract && !ConcreteImplementations.ContainsKey(baseType)) - ConcreteImplementations[baseType] = ti; - baseType = baseType.BaseType; - } + else { + var (objectOrArrayType, fieldsType) = GenerateRefFieldStruct(ti); + structs.Add((ti, null, objectOrArrayType, fieldsType)); } } + _todoFieldStructs.Clear(); + return structs; + } + #endregion - /// - /// Obtain the vtables for a given type, with implementations of abstract methods filled in. - /// - /// - /// - private MethodBase[] GetFilledVTable(TypeInfo ti) { - MethodBase[] res = ti.GetVTable(); - /* An abstract type will have null in the vtable for abstract methods. - * In order to recover the correct method signature for such abstract - * methods, we replace the corresponding vtable slot with an - * implementation from a concrete subclass, as the name and signature - * must match. - * Note that, for the purposes of creating type structures, we don't - * care which concrete implementation we put in this table! The name - * and signature will always match that of the abstract type. - */ - if (ti.IsAbstract && ConcreteImplementations.ContainsKey(ti)) { - res = (MethodBase[])res.Clone(); - MethodBase[] impl = ConcreteImplementations[ti].GetVTable(); - for (int i = 0; i < res.Length; i++) { - if (res[i] == null) - res[i] = impl[i]; - } + #region Class Struct Generation + + // Concrete implementations for abstract classes, for use in looking up VTable signatures and names + private readonly Dictionary _concreteImplementations = new(); + /// + /// VTables for abstract types have "null" in place of abstract functions. + /// This function searches for concrete implementations so that we can properly + /// populate the abstract class VTables. + /// + private void InitializeConcreteImplementations() { + foreach (var ti in model.Types) { + if (ti.HasElementType || ti.IsAbstract || ti.IsGenericParameter) + continue; + var baseType = ti.BaseType; + while (baseType != null) { + if (baseType.IsAbstract) + _concreteImplementations.TryAdd(baseType, ti); + + baseType = baseType.BaseType; } - return res; + } + } + + /// + /// Obtain the vtables for a given type, with implementations of abstract methods filled in. + /// + /// + /// + private MethodBase[] GetFilledVTable(TypeInfo ti) { + MethodBase[] res = ti.GetVTable(); + /* An abstract type will have null in the vtable for abstract methods. + * In order to recover the correct method signature for such abstract + * methods, we replace the corresponding vtable slot with an + * implementation from a concrete subclass, as the name and signature + * must match. + * Note that, for the purposes of creating type structures, we don't + * care which concrete implementation we put in this table! The name + * and signature will always match that of the abstract type. + */ + if (ti.IsAbstract && _concreteImplementations.TryGetValue(ti, out var implementation)) { + var impl = implementation.GetVTable(); + + res = (MethodBase[])res.Clone(); + for (int i = 0; i < res.Length; i++) + { + res[i] ??= impl[i]; + } + } + return res; + } + + private readonly HashSet _visitedTypes = []; + private readonly List _todoTypeStructs = []; + + /// + /// Include the given type into this generator. This will add the given type and all types it depends on. + /// Call GenerateRemainingTypeDeclarations to produce the actual type declarations afterwards. + /// + /// + public void IncludeType(TypeInfo ti) + { + if (_visitedTypes.Contains(ti)) + return; + + if (ti.ContainsGenericParameters) + return; + + _visitedTypes.Add(ti); + + if (ti.IsArray || ti.HasElementType) + { + IncludeType(ti.ElementType); + } + else if (ti.IsEnum) + { + IncludeType(ti.GetEnumUnderlyingType()); } - private readonly HashSet VisitedTypes = new HashSet(); - private readonly List TodoTypeStructs = new List(); + // Visit all fields first, considering only value types, + // so that we can get the layout correct. + VisitFieldStructs(ti); - /// - /// Include the given type into this generator. This will add the given type and all types it depends on. - /// Call GenerateRemainingTypeDeclarations to produce the actual type declarations afterwards. - /// - /// - public void IncludeType(TypeInfo ti) { - if (VisitedTypes.Contains(ti)) - return; - if (ti.ContainsGenericParameters) - return; - VisitedTypes.Add(ti); + if (ti.BaseType != null) + IncludeType(ti.BaseType); - if (ti.IsArray) { - IncludeType(ti.ElementType); - } else if (ti.HasElementType) { - IncludeType(ti.ElementType); - } else if (ti.IsEnum) { - IncludeType(ti.GetEnumUnderlyingType()); - } + TypeNamer.GetName(ti); - // Visit all fields first, considering only value types, - // so that we can get the layout correct. - VisitFieldStructs(ti); + foreach (var fi in ti.DeclaredFields) + IncludeType(fi.FieldType); - if (ti.BaseType != null) - IncludeType(ti.BaseType); - - TypeNamer.GetName(ti); - - foreach (var fi in ti.DeclaredFields) - IncludeType(fi.FieldType); - - foreach (var mi in GetFilledVTable(ti)) - if (mi != null && !mi.ContainsGenericParameters) - IncludeMethod(mi); - - TodoTypeStructs.Add(ti); + foreach (var mi in GetFilledVTable(ti)) + { + if (mi is { ContainsGenericParameters: false }) + IncludeMethod(mi); } - // Generate the C structure for virtual function calls in a given type (the VTable) - private CppComplexType GenerateVTableStruct(TypeInfo ti) { - MethodBase[] vtable; - if (ti.IsInterface) { - /* Interface vtables are just all of the interface methods. - You might have to type a local variable manually as an - interface vtable during an interface call, but the result - should display the correct method name (with a computed - InterfaceOffset added). - */ - vtable = ti.DeclaredMethods.ToArray(); - } else { - vtable = ti.GetVTable(); - } - var name = TypeNamer.GetName(ti); - var namer = CreateNamespace().MakeNamer((i) => vtable[i]?.Name?.ToCIdentifier() ?? "__unknown"); + _todoTypeStructs.Add(ti); + } - // Il2Cpp switched to `VirtualInvokeData *vtable` in Unity 5.3.6. - // Previous versions used `MethodInfo **vtable`. - // TODO: Consider adding function types. This considerably increases the script size - // but can significantly help with reverse-engineering certain binaries. - var vtableStruct = types.Struct(name + "__VTable"); + // Generate the C structure for virtual function calls in a given type (the VTable) + private CppComplexType GenerateVTableStruct(TypeInfo ti) { + MethodBase[] vtable; + if (ti.IsInterface) { + /* Interface vtables are just all of the interface methods. + You might have to type a local variable manually as an + interface vtable during an interface call, but the result + should display the correct method name (with a computed + InterfaceOffset added). + */ + vtable = ti.DeclaredMethods.ToArray(); + } else { + vtable = ti.GetVTable(); + } + var name = TypeNamer.GetName(ti); + var namer = CreateNamespace().MakeNamer((i) => vtable[i]?.Name?.ToCIdentifier() ?? "__unknown"); - if (UnityVersion.CompareTo("5.3.6") < 0) { - for (int i = 0; i < vtable.Length; i++) { - types.AddField(vtableStruct, namer.GetName(i), "MethodInfo *"); - } - } else { - for (int i = 0; i < vtable.Length; i++) { - types.AddField(vtableStruct, namer.GetName(i), "VirtualInvokeData"); - } + // Il2Cpp switched to `VirtualInvokeData *vtable` in Unity 5.3.6. + // Previous versions used `MethodInfo **vtable`. + // TODO: Consider adding function types. This considerably increases the script size + // but can significantly help with reverse-engineering certain binaries. + var vtableStruct = types.Struct(name + "__VTable"); + + if (UnityVersion.CompareTo("5.3.6") < 0) { + for (int i = 0; i < vtable.Length; i++) { + types.AddField(vtableStruct, namer.GetName(i), "MethodInfo *"); } - return vtableStruct; + } else { + for (int i = 0; i < vtable.Length; i++) { + types.AddField(vtableStruct, namer.GetName(i), "VirtualInvokeData"); + } + } + return vtableStruct; + } + + // Generate the overall Il2CppClass-shaped structure for the given type + private (CppComplexType type, CppComplexType staticFields, CppComplexType vtable) GenerateTypeStruct(TypeInfo ti) { + var name = TypeNamer.GetName(ti); + var vtable = GenerateVTableStruct(ti); + + var statics = types.Struct(name + "__StaticFields"); + var namer = CreateNamespace().MakeNamer((field) => field.Name.ToCIdentifier()); + foreach (var field in ti.DeclaredFields) { + if (field.IsLiteral || !field.IsStatic || field.IsThreadStatic) + continue; + statics.AddField(namer.GetName(field), AsCType(field.FieldType)); } - // Generate the overall Il2CppClass-shaped structure for the given type - private (CppComplexType type, CppComplexType staticFields, CppComplexType vtable) GenerateTypeStruct(TypeInfo ti) { - var name = TypeNamer.GetName(ti); - var vtable = GenerateVTableStruct(ti); + // L-TODO: Maybe add structs for StaticThreadLocalFields? not sure how useful it would be because they are resolved at runtime - var statics = types.Struct(name + "__StaticFields"); - var namer = CreateNamespace().MakeNamer((field) => field.Name.ToCIdentifier()); - foreach (var field in ti.DeclaredFields) { - if (field.IsLiteral || !field.IsStatic || field.IsThreadStatic) - continue; - statics.AddField(namer.GetName(field), AsCType(field.FieldType)); - } + /* TODO: type the rgctx_data */ + var cls = types.Struct(name + "__Class"); + types.AddField(cls, "_0", "Il2CppClass_0"); - // L-TODO: Maybe add structs for StaticThreadLocalFields? not sure how useful it would be because they are resolved at runtime - - /* TODO: type the rgctx_data */ - var cls = types.Struct(name + "__Class"); - types.AddField(cls, "_0", "Il2CppClass_0"); - - if (UnityVersion.CompareTo("5.5.0") < 0) { - cls.AddField("vtable", vtable.AsPointer(types.WordSize)); - types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *"); - cls.AddField("static_fields", statics.AsPointer(types.WordSize)); - types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true); - types.AddField(cls, "_1", "Il2CppClass_1"); - } else { - types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *"); - cls.AddField("static_fields", statics.AsPointer(types.WordSize)); - types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true); - types.AddField(cls, "_1", "Il2CppClass_1"); - cls.AddField("vtable", vtable); - } - return (cls, statics, vtable); + if (UnityVersion.CompareTo("5.5.0") < 0) { + cls.AddField("vtable", vtable.AsPointer(types.WordSize)); + types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *"); + cls.AddField("static_fields", statics.AsPointer(types.WordSize)); + types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true); + types.AddField(cls, "_1", "Il2CppClass_1"); + } else { + types.AddField(cls, "interfaceOffsets", "Il2CppRuntimeInterfaceOffsetPair *"); + cls.AddField("static_fields", statics.AsPointer(types.WordSize)); + types.AddField(cls, "rgctx_data", "Il2CppRGCTXData *", true); + types.AddField(cls, "_1", "Il2CppClass_1"); + cls.AddField("vtable", vtable); } + return (cls, statics, vtable); + } - /// - /// Output type declarations for every type that was included since the last call to GenerateRemainingTypeDeclarations - /// Type declarations that have previously been generated by this instance of CppDeclarationGenerator will not be generated again. - /// - /// A string containing C type declarations - public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType, - CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() { + /// + /// Output type declarations for every type that was included since the last call to GenerateRemainingTypeDeclarations + /// Type declarations that have previously been generated by this instance of CppDeclarationGenerator will not be generated again. + /// + /// A string containing C type declarations + public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType, + CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() { + try + { var decl = GenerateVisitedFieldStructs().Select(s => - (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType) null, (CppComplexType) null)).ToList(); + (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType)null, + (CppComplexType)null)) + .ToList(); - foreach (var ti in TodoTypeStructs) { + foreach (var ti in _todoTypeStructs) + { var (cls, statics, vtable) = GenerateTypeStruct(ti); decl.Add((ti, null, cls, null, vtable, statics)); } - TodoTypeStructs.Clear(); return decl; } - #endregion - - #region Method Generation - - /// - /// Analyze a method and include all types that it takes and returns. - /// Must call this before generating the method's declaration with GenerateMethodDeclaration or GenerateFunctionPointer. - /// - /// - public void IncludeMethod(MethodBase method, TypeInfo declaringType = null) { - if (!method.IsStatic) - IncludeType(declaringType ?? method.DeclaringType); - - if (method is MethodInfo mi) - IncludeType(mi.ReturnType); - - foreach (var pi in method.DeclaredParameters) { - IncludeType(pi.ParameterType); - } + catch (Exception) + { + return null; } - - // Generate a C declaration for a method - private CppFnPtrType GenerateMethodDeclaration(MethodBase method, string name, TypeInfo declaringType) { - CppType retType; - if (method is MethodInfo mi) { - retType = mi.ReturnType.FullName == "System.Void" ? types["void"] : AsCType(mi.ReturnType); - } else { - retType = types["void"]; - } - - var paramNs = CreateNamespace(); - paramNs.ReserveName("method"); - var paramNamer = paramNs.MakeNamer((pi) => pi.Name == "" ? "arg" : pi.Name.ToCIdentifier()); - - var paramList = new List<(string, CppType)>(); - // Figure out the "this" param - if (method.IsStatic) { - // In older versions, static methods took a dummy this parameter - if (UnityVersion.CompareTo("2018.3.0") < 0) - paramList.Add(("this", types.GetType("void *"))); - } else { - if (declaringType.IsValueType) { - // Methods for structs take the boxed object as the this param - paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + " *"))); // + "__Boxed *"))); - } else { - paramList.Add(("this", AsCType(declaringType))); - } - } - - foreach (var pi in method.DeclaredParameters) { - paramList.Add((paramNamer.GetName(pi), AsCType(pi.ParameterType))); - } - - paramList.Add(("method", types.GetType("MethodInfo *"))); - - return new CppFnPtrType(types.WordSize, retType, paramList) {Name = name}; + finally + { + _todoTypeStructs.Clear(); + _todoFieldStructs.Clear(); } - - /// - /// Generate a declaration of the form "retType methName(argTypes argNames...)" - /// You must first visit the method using VisitMethod and then call - /// GenerateVisitedTypes in order to generate any dependent types. - /// - /// - /// - public CppFnPtrType GenerateMethodDeclaration(MethodBase method) { - return GenerateMethodDeclaration(method, GlobalNamer.GetName(method), method.DeclaringType); - } - #endregion - - #region Naming - // We try decently hard to avoid creating clashing names, and also sanitize any invalid names. - // You can customize how naming works by modifying this function. - private void InitializeNaming() { - TypeNamespace = CreateNamespace(); - TypeNamer = TypeNamespace.MakeNamer((ti) => { - if (ti.IsArray) - return TypeNamer.GetName(ti.ElementType) + "__Array"; - var name = ti.Name.ToCIdentifier(); - name = Regex.Replace(name, "__+", "_"); - // Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types - // like KeyCode, Position, ErrorType. This only applies to enums, not structs. - if (ti.IsEnum) - name += "__Enum"; - return name; - }); - - GlobalsNamespace = CreateNamespace(); - GlobalNamer = GlobalsNamespace.MakeNamer((method) => $"{TypeNamer.GetName(method.DeclaringType)}_{method.Name.ToCIdentifier()}"); - } - - private static readonly string[] ReservedCppKeywords = - [ - "_Alignas", "_Alignof", "_Atomic", "_Bool", - "_Complex", "_Generic", - "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", - "alignas", "alignof", "and", "and_eq", - "asm", "auto", "bitand", "bitor", - "bool", "break", "case", "catch", - "char", "char16_t", "char32_t", "char8_t", - "class", "co_await", "co_return", "co_yield", - "compl", "concept", "const", "const_cast", - "consteval", "constexpr", "constinit", "continue", - "decltype", "default", "delete", "do", - "double", "dynamic_cast", "else", "enum", - "explicit", "export", "extern", "false", - "final", "float", "for", "friend", - "goto", "if", "inline", "int", - "long", "mutable", "namespace", "new", - "noexcept", "not", "not_eq", "nullptr", - "operator", "or", "or_eq", "private", - "protected", "public", "reflexpr", "register", - "reinterpret_cast", "requires", "restrict", "return", - "short", "signed", "sizeof", "static", - "static_assert", "static_cast", "struct", "switch", - "synchronized", "template", "this", "thread_local", - "throw", "true", "try", "typedef", - "typeid", "typename", "union", "unsigned", - "using", "virtual", "void", "volatile", - "wchar_t", "while", "xor", "xor_eq" - ]; - - // Reserve C/C++ keywords and built-in names - private static CppNamespace CreateNamespace() { - var ns = new CppNamespace(); - /* Reserve C/C++ keywords */ - foreach (var keyword in ReservedCppKeywords) { - ns.ReserveName(keyword); - } - /* Reserve commonly defined C++ symbols for MSVC DLL projects */ - /* This is not an exhaustive list! (windows.h etc.) */ - foreach (var symbol in new[] {"_int8", "_int16", "_int32", "_int64", "DEFAULT_CHARSET", "FILETIME", "NULL", "SYSTEMTIME", "stderr", "stdin", "stdout"}) { - ns.ReserveName(symbol); - } - /* Reserve builtin keywords in IDA */ - foreach (var keyword in new [] { - "_BYTE", "_DWORD", "_OWORD", "_QWORD", "_UNKNOWN", "_WORD", - "__array_ptr", "__cdecl", "__cppobj", "__declspec", "__export", "__far", "__fastcall", "__hidden", "__huge", "__import", - "__int128", "__int16", "__int32", "__int64", "__int8", "__interrupt", "__near", "__noreturn", "__pascal", - "__ptr32", "__ptr64", "__pure", "__restrict", "__return_ptr", "__shifted", "__spoils", "__stdcall", "__struct_ptr", - "__thiscall", "__thread", "__unaligned", "__usercall", "__userpurge", - "_cs", "_ds", "_es", "_ss", "far", "flat", "near", - "Mask", "Region", "Pointer", "GC", "Time" /* wtf? */ }) { - ns.ReserveName(keyword); - } - /* Reserve builtin keywords for Ghidra */ - foreach (var keyword in new [] { "_extension" }) { - ns.ReserveName(keyword); - } - return ns; - } - - /// - /// Namespace for all types and typedefs - /// - public CppNamespace TypeNamespace { get; private set; } - - public CppNamespace.Namer TypeNamer { get; private set; } - - /// - /// Namespace for global variables and methods - /// - public CppNamespace GlobalsNamespace { get; private set; } - public CppNamespace.Namer GlobalNamer { get; private set; } - #endregion } -} + + public List GenerateRequiredForwardDefinitions() + => _requiredForwardDefinitionsForFields + .Select(x => new CppForwardDefinitionType(TypeNamer.GetName(x))) + .Cast() + .ToList(); + + #endregion + + #region Method Generation + + /// + /// Analyze a method and include all types that it takes and returns. + /// Must call this before generating the method's declaration with GenerateMethodDeclaration or GenerateFunctionPointer. + /// + /// + public void IncludeMethod(MethodBase method, TypeInfo declaringType = null) { + if (!method.IsStatic) + IncludeType(declaringType ?? method.DeclaringType); + + if (method is MethodInfo mi) + IncludeType(mi.ReturnType); + + foreach (var pi in method.DeclaredParameters) { + IncludeType(pi.ParameterType); + } + } + + // Generate a C declaration for a method + private CppFnPtrType GenerateMethodDeclaration(MethodBase method, string name, TypeInfo declaringType) { + CppType retType; + if (method is MethodInfo mi) { + retType = mi.ReturnType.FullName == "System.Void" ? types["void"] : AsCType(mi.ReturnType); + } else { + retType = types["void"]; + } + + var paramNs = CreateNamespace(); + paramNs.ReserveName("method"); + var paramNamer = paramNs.MakeNamer((pi) => pi.Name == "" ? "arg" : pi.Name.ToCIdentifier()); + + var paramList = new List<(string, CppType)>(); + // Figure out the "this" param + if (method.IsStatic) { + // In older versions, static methods took a dummy this parameter + if (UnityVersion.CompareTo("2018.3.0") < 0) + paramList.Add(("this", types.GetType("void *"))); + } else { + if (declaringType.IsValueType) { + // Methods for structs take the boxed object as the this param + paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + " *"))); // + "__Boxed *"))); + } else { + paramList.Add(("this", AsCType(declaringType))); + } + } + + foreach (var pi in method.DeclaredParameters) { + paramList.Add((paramNamer.GetName(pi), AsCType(pi.ParameterType))); + } + + paramList.Add(("method", types.GetType("MethodInfo *"))); + + return new CppFnPtrType(types.WordSize, retType, paramList) {Name = name}; + } + + /// + /// Generate a declaration of the form "retType methName(argTypes argNames...)" + /// You must first visit the method using VisitMethod and then call + /// GenerateVisitedTypes in order to generate any dependent types. + /// + /// + /// + public CppFnPtrType GenerateMethodDeclaration(MethodBase method) { + return GenerateMethodDeclaration(method, GlobalNamer.GetName(method), method.DeclaringType); + } + #endregion + + #region Naming + // We try decently hard to avoid creating clashing names, and also sanitize any invalid names. + // You can customize how naming works by modifying this function. + private void InitializeNaming() { + TypeNamespace = CreateNamespace(); + TypeNamer = TypeNamespace.MakeNamer((ti) => { + if (ti.IsArray) + return TypeNamer.GetName(ti.ElementType) + "__Array"; + var name = ti.Name.ToCIdentifier(); + name = Regex.Replace(name, "__+", "_"); + // Work around a dumb IDA bug: enums can't be named the same as certain "built-in" types + // like KeyCode, Position, ErrorType. This only applies to enums, not structs. + if (ti.IsEnum) + name += "__Enum"; + return name; + }); + + GlobalsNamespace = CreateNamespace(); + GlobalNamer = GlobalsNamespace.MakeNamer((method) => $"{TypeNamer.GetName(method.DeclaringType)}_{method.Name.ToCIdentifier()}"); + } + + private static readonly string[] ReservedCppKeywords = + [ + "_Alignas", "_Alignof", "_Atomic", "_Bool", + "_Complex", "_Generic", + "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", + "alignas", "alignof", "and", "and_eq", + "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", + "char", "char16_t", "char32_t", "char8_t", + "class", "co_await", "co_return", "co_yield", + "compl", "concept", "const", "const_cast", + "consteval", "constexpr", "constinit", "continue", + "decltype", "default", "delete", "do", + "double", "dynamic_cast", "else", "enum", + "explicit", "export", "extern", "false", + "final", "float", "for", "friend", + "goto", "if", "inline", "int", + "long", "mutable", "namespace", "new", + "noexcept", "not", "not_eq", "nullptr", + "operator", "or", "or_eq", "private", + "protected", "public", "reflexpr", "register", + "reinterpret_cast", "requires", "restrict", "return", + "short", "signed", "sizeof", "static", + "static_assert", "static_cast", "struct", "switch", + "synchronized", "template", "this", "thread_local", + "throw", "true", "try", "typedef", + "typeid", "typename", "union", "unsigned", + "using", "virtual", "void", "volatile", + "wchar_t", "while", "xor", "xor_eq" + ]; + + // Reserve C/C++ keywords and built-in names + private static CppNamespace CreateNamespace() { + var ns = new CppNamespace(); + /* Reserve C/C++ keywords */ + foreach (var keyword in ReservedCppKeywords) { + ns.ReserveName(keyword); + } + /* Reserve commonly defined C++ symbols for MSVC DLL projects */ + /* This is not an exhaustive list! (windows.h etc.) */ + foreach (var symbol in new[] {"_int8", "_int16", "_int32", "_int64", "DEFAULT_CHARSET", "FILETIME", "NULL", "SYSTEMTIME", "stderr", "stdin", "stdout"}) { + ns.ReserveName(symbol); + } + /* Reserve builtin keywords in IDA */ + foreach (var keyword in new [] { + "_BYTE", "_DWORD", "_OWORD", "_QWORD", "_UNKNOWN", "_WORD", + "__array_ptr", "__cdecl", "__cppobj", "__declspec", "__export", "__far", "__fastcall", "__hidden", "__huge", "__import", + "__int128", "__int16", "__int32", "__int64", "__int8", "__interrupt", "__near", "__noreturn", "__pascal", + "__ptr32", "__ptr64", "__pure", "__restrict", "__return_ptr", "__shifted", "__spoils", "__stdcall", "__struct_ptr", + "__thiscall", "__thread", "__unaligned", "__usercall", "__userpurge", + "_cs", "_ds", "_es", "_ss", "far", "flat", "near", + "Mask", "Region", "Pointer", "GC", "Time" /* wtf? */ }) { + ns.ReserveName(keyword); + } + /* Reserve builtin keywords for Ghidra */ + foreach (var keyword in new [] { "_extension" }) { + ns.ReserveName(keyword); + } + return ns; + } + + /// + /// Namespace for all types and typedefs + /// + public CppNamespace TypeNamespace { get; private set; } + + public CppNamespace.Namer TypeNamer { get; private set; } + + /// + /// Namespace for global variables and methods + /// + public CppNamespace GlobalsNamespace { get; private set; } + public CppNamespace.Namer GlobalNamer { get; private set; } + #endregion +} \ No newline at end of file diff --git a/Il2CppInspector.Common/Cpp/CppField.cs b/Il2CppInspector.Common/Cpp/CppField.cs index 2ac419f..631e762 100644 --- a/Il2CppInspector.Common/Cpp/CppField.cs +++ b/Il2CppInspector.Common/Cpp/CppField.cs @@ -4,8 +4,6 @@ All rights reserved. */ -using System; - namespace Il2CppInspector.Cpp { // A field in a C++ type diff --git a/Il2CppInspector.Common/Cpp/CppNamespace.cs b/Il2CppInspector.Common/Cpp/CppNamespace.cs index 6e224bf..c0168e2 100644 --- a/Il2CppInspector.Common/Cpp/CppNamespace.cs +++ b/Il2CppInspector.Common/Cpp/CppNamespace.cs @@ -5,9 +5,6 @@ All rights reserved. */ -using System; -using System.Collections.Generic; - namespace Il2CppInspector.Cpp { /// @@ -65,9 +62,9 @@ namespace Il2CppInspector.Cpp // Uniquely name an object within the parent namespace public string GetName(T t) { // If we've named this particular object before, just return that name - string name; - if (names.TryGetValue(t, out name)) + if (names.TryGetValue(t, out var name)) return name; + // Obtain the mangled name for the object name = keyFunc(t); // Check if the mangled name has been given to another object - if it has, diff --git a/Il2CppInspector.Common/Cpp/CppType.cs b/Il2CppInspector.Common/Cpp/CppType.cs index a6ebf2d..1e280e6 100644 --- a/Il2CppInspector.Common/Cpp/CppType.cs +++ b/Il2CppInspector.Common/Cpp/CppType.cs @@ -456,4 +456,14 @@ namespace Il2CppInspector.Cpp return sb.ToString(); } } + + public class CppForwardDefinitionType : CppType + { + public CppForwardDefinitionType(string name) : base(name) + { + + } + + public override string ToString(string format = "") => $"struct {Name};"; + } } diff --git a/Il2CppInspector.Common/Cpp/CppTypeCollection.cs b/Il2CppInspector.Common/Cpp/CppTypeCollection.cs index 74a00bd..867e68f 100644 --- a/Il2CppInspector.Common/Cpp/CppTypeCollection.cs +++ b/Il2CppInspector.Common/Cpp/CppTypeCollection.cs @@ -4,15 +4,11 @@ All rights reserved. */ -using System; +using Il2CppInspector.Cpp.UnityHeaders; using System.Collections; -using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.IO; -using System.Linq; using System.Text.RegularExpressions; -using Il2CppInspector.Cpp.UnityHeaders; namespace Il2CppInspector.Cpp { @@ -23,7 +19,7 @@ namespace Il2CppInspector.Cpp public Dictionary Types { get; } // All of the literal typedef aliases - public Dictionary TypedefAliases { get; } = new Dictionary(); + public Dictionary TypedefAliases { get; } = []; public CppType this[string s] => Types.ContainsKey(s)? Types[s] : TypedefAliases.ContainsKey(s)? TypedefAliases[s].AsAlias(s) : null; @@ -34,7 +30,8 @@ namespace Il2CppInspector.Cpp // Architecture width in bits (32/64) - to determine pointer sizes public int WordSize { get; } - private Dictionary complexTypeMap = new Dictionary { + private Dictionary complexTypeMap = new() + { ["struct"] = ComplexValueType.Struct, ["union"] = ComplexValueType.Union, ["enum"] = ComplexValueType.Enum @@ -44,22 +41,23 @@ namespace Il2CppInspector.Cpp private string currentGroup = string.Empty; public void SetGroup(string group) => currentGroup = group; - private static readonly List primitiveTypes = new List { - new CppType("uint8_t", 8), - new CppType("uint16_t", 16), - new CppType("uint32_t", 32), - new CppType("uint64_t", 64), - new CppType("int8_t", 8), - new CppType("int16_t", 16), - new CppType("int32_t", 32), - new CppType("int64_t", 64), - new CppType("char", 8), - new CppType("int", 32), - new CppType("float", 32), - new CppType("double", 64), - new CppType("bool", 8), - new CppType("void", 0) - }; + private static readonly List primitiveTypes = + [ + new("uint8_t", 8), + new("uint16_t", 16), + new("uint32_t", 32), + new("uint64_t", 64), + new("int8_t", 8), + new("int16_t", 16), + new("int32_t", 32), + new("int64_t", 64), + new("char", 8), + new("int", 32), + new("float", 32), + new("double", 64), + new("bool", 8), + new("void", 0) + ]; public CppTypeCollection(int wordSize) { if (wordSize != 32 && wordSize != 64) @@ -538,15 +536,18 @@ namespace Il2CppInspector.Cpp public CppComplexType Struct(string name = "", int alignmentBytes = 0) { if (!string.IsNullOrEmpty(name) && Types.TryGetValue(name, out var cppType)) return (CppComplexType) cppType; + var type = new CppComplexType(ComplexValueType.Struct) {Name = name, Group = currentGroup, AlignmentBytes = alignmentBytes}; if (!string.IsNullOrEmpty(name)) Add(type); + return type; } public CppComplexType Union(string name = "", int alignmentBytes = 0) { if (!string.IsNullOrEmpty(name) && Types.TryGetValue(name, out var cppType)) return (CppComplexType) cppType; + var type = new CppComplexType(ComplexValueType.Union) {Name = name, Group = currentGroup, AlignmentBytes = alignmentBytes}; if (!string.IsNullOrEmpty(name)) Add(type); @@ -554,9 +555,13 @@ namespace Il2CppInspector.Cpp } public CppEnumType Enum(CppType underlyingType, string name = "") { + if (!string.IsNullOrEmpty(name) && Types.TryGetValue(name, out var cppType)) + return (CppEnumType)cppType; + var type = new CppEnumType(underlyingType) {Name = name, Group = currentGroup}; if (!string.IsNullOrEmpty(name)) Add(type); + return type; } @@ -585,11 +590,17 @@ namespace Il2CppInspector.Cpp cppTypes.AddFromDeclarationText(apis); // Don't allow any of the header type names or primitive type names to be re-used - foreach (var type in cppTypes.Types.Values) - declGen?.TypeNamespace.TryReserveName(type.Name); + foreach (var type in cppTypes.Types.Keys) + { + declGen?.TypeNamespace.TryReserveName(type); + declGen?.GlobalsNamespace.TryReserveName(type); + } - foreach (var typedef in cppTypes.TypedefAliases.Values) - declGen?.GlobalsNamespace.TryReserveName(typedef.Name); + foreach (var typedef in cppTypes.TypedefAliases.Keys) + { + declGen?.TypeNamespace.TryReserveName(typedef); + declGen?.GlobalsNamespace.TryReserveName(typedef); + } cppTypes.SetGroup(""); diff --git a/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs b/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs index f0045bf..98fbbbc 100644 --- a/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs +++ b/Il2CppInspector.Common/Cpp/UnityHeaders/UnityHeaders.cs @@ -5,13 +5,14 @@ All rights reserved. */ +using Il2CppInspector.Next; +using Spectre.Console; using System; -using System.Linq; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.Linq; using System.Text.RegularExpressions; -using Il2CppInspector.Next; using VersionedSerialization; namespace Il2CppInspector.Cpp.UnityHeaders @@ -140,7 +141,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders // No il2cpp exports? Just return the earliest version from the header range // The API version may be incorrect but should be a subset of the real API and won't cause C++ compile errors if (!exports.Any()) { - Console.WriteLine("No IL2CPP API exports found in binary - IL2CPP APIs will be unavailable in C++ project"); + AnsiConsole.WriteLine("No IL2CPP API exports found in binary - IL2CPP APIs will be unavailable in C++ project"); return typeHeaders.Select(t => new UnityHeaders(t, apis.Last(a => a.VersionRange.Intersect(t.VersionRange) != null))).ToList(); @@ -161,7 +162,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders if (apiMatches.Any()) { // Intersect all API ranges with all header ranges to produce final list of possible ranges - Console.WriteLine("IL2CPP API discovery was successful"); + AnsiConsole.WriteLine("IL2CPP API discovery was successful"); return typeHeaders.SelectMany( t => apiMatches.Where(a => t.VersionRange.Intersect(a.VersionRange) != null) @@ -170,7 +171,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders // None of the possible API versions match the binary // Select the oldest API version from the group - C++ project compilation will fail - Console.WriteLine("No exact match for IL2CPP APIs found in binary - IL2CPP API availability in C++ project will be partial"); + AnsiConsole.WriteLine("No exact match for IL2CPP APIs found in binary - IL2CPP API availability in C++ project will be partial"); return typeHeaders.Select(t => new UnityHeaders(t, apis.Last(a => a.VersionRange.Intersect(t.VersionRange) != null))).ToList(); diff --git a/Il2CppInspector.Common/FileFormatStreams/AABReader.cs b/Il2CppInspector.Common/FileFormatStreams/AABReader.cs index de85280..a69a15d 100644 --- a/Il2CppInspector.Common/FileFormatStreams/AABReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/AABReader.cs @@ -4,6 +4,7 @@ All rights reserved. */ +using Spectre.Console; using System; using System.Collections.Generic; using System.IO; @@ -51,7 +52,7 @@ namespace Il2CppInspector public override IFileFormatStream this[uint index] { get { - Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}"); + AnsiConsole.WriteLine($"Extracting binary from {binaryFiles[index].FullName}"); IFileFormatStream loaded = null; // ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format diff --git a/Il2CppInspector.Common/FileFormatStreams/APKReader.cs b/Il2CppInspector.Common/FileFormatStreams/APKReader.cs index e970bed..1ad5e35 100644 --- a/Il2CppInspector.Common/FileFormatStreams/APKReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/APKReader.cs @@ -4,6 +4,7 @@ All rights reserved. */ +using Spectre.Console; using System; using System.Collections.Generic; using System.IO; @@ -51,7 +52,7 @@ namespace Il2CppInspector public override IFileFormatStream this[uint index] { get { - Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}"); + AnsiConsole.WriteLine($"Extracting binary from {binaryFiles[index].FullName}"); IFileFormatStream loaded = null; // ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format diff --git a/Il2CppInspector.Common/FileFormatStreams/ElfReader.cs b/Il2CppInspector.Common/FileFormatStreams/ElfReader.cs index 62d5654..8badedc 100644 --- a/Il2CppInspector.Common/FileFormatStreams/ElfReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/ElfReader.cs @@ -5,6 +5,7 @@ All rights reserved. */ +using Spectre.Console; using System; using System.Collections.Generic; using System.Linq; @@ -160,7 +161,7 @@ namespace Il2CppInspector } catch (Exception ex) { - Console.WriteLine($"Got exception {ex} while parsing SHT - reverting to PHT"); + AnsiConsole.WriteLine($"Got exception {ex} while parsing SHT - reverting to PHT"); preferPHT = true; SHT = []; } @@ -170,12 +171,12 @@ namespace Il2CppInspector // These can happen as a result of conversions from other formats to ELF, // or if the SHT has been deliberately stripped if (!SHT.Any()) { - Console.WriteLine("ELF binary has no SHT - reverting to PHT"); + AnsiConsole.WriteLine("ELF binary has no SHT - reverting to PHT"); preferPHT = true; } else if (SHT.All(s => conv.ULong(s.sh_addr) == 0ul)) { - Console.WriteLine("ELF binary SHT is all-zero - reverting to PHT"); + AnsiConsole.WriteLine("ELF binary SHT is all-zero - reverting to PHT"); preferPHT = true; } @@ -192,7 +193,7 @@ namespace Il2CppInspector // If the first file offset of the first PHT is zero, assume a dumped image if (PHT.Any(t => conv.ULong(t.p_vaddr) == 0ul)) { - Console.WriteLine("ELF binary appears to be a dumped memory image"); + AnsiConsole.WriteLine("ELF binary appears to be a dumped memory image"); isMemoryImage = true; } preferPHT = true; @@ -202,7 +203,7 @@ namespace Il2CppInspector else { var shtOverlap = shtShouldBeOrdered.Aggregate((x, y) => x <= y? y : ulong.MaxValue) == ulong.MaxValue; if (shtOverlap) { - Console.WriteLine("ELF binary SHT contains invalid ranges - reverting to PHT"); + AnsiConsole.WriteLine("ELF binary SHT contains invalid ranges - reverting to PHT"); preferPHT = true; } } @@ -223,7 +224,20 @@ namespace Il2CppInspector // Get dynamic table if it exists (must be done after rebasing) if (GetProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC) - DynamicTable = ReadArray>(conv.Long(PT_DYNAMIC.p_offset), (int) (conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic)))); + { + // Important: do not use p_offset here! + // Only load sections should be loaded, which should also include the memory region that contains the dynamic section. + // This just provides the virtual address of the section. + // Some binaries may use the offset here to point to a fake version of the dynamic section, + // making relocation resolution and subsequent analysis fail. + // Reference for Android: + // phdr_table_get_dynamic_section, https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker_phdr.cpp + + var dynamicAddr = conv.ULong(PT_DYNAMIC.p_vaddr); + var dynamicSize = (int)(conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic))); + + DynamicTable = ReadMappedArray>(dynamicAddr, dynamicSize); + } // Get offset of code section var codeSegment = PHT.First(x => ((Elf) x.p_flags & Elf.PF_X) == Elf.PF_X); @@ -254,21 +268,6 @@ namespace Il2CppInspector StatusUpdate("Finding relocations"); - // Two types: add value from offset in image, and add value from specified addend - foreach (var relSection in GetSections(Elf.SHT_REL)) { - reverseMapExclusions.Add(((uint) conv.Int(relSection.sh_offset), (uint) (conv.Int(relSection.sh_offset) + conv.Int(relSection.sh_size) - 1))); - rels.UnionWith( - from rel in ReadArray>(conv.Long(relSection.sh_offset), conv.Int(conv.Div(relSection.sh_size, relSection.sh_entsize))) - select new ElfReloc(rel, SHT[relSection.sh_link].sh_offset)); - } - - foreach (var relaSection in GetSections(Elf.SHT_RELA)) { - reverseMapExclusions.Add(((uint) conv.Int(relaSection.sh_offset), (uint) (conv.Int(relaSection.sh_offset) + conv.Int(relaSection.sh_size) - 1))); - rels.UnionWith( - from rela in ReadArray>(conv.Long(relaSection.sh_offset), conv.Int(conv.Div(relaSection.sh_size, relaSection.sh_entsize))) - select new ElfReloc(rela, SHT[relaSection.sh_link].sh_offset)); - } - // Relocations in dynamic section if (GetDynamicEntry(Elf.DT_REL) is elf_dynamic dt_rel) { var dt_rel_count = conv.Int(conv.Div(GetDynamicEntry(Elf.DT_RELSZ).d_un, GetDynamicEntry(Elf.DT_RELENT).d_un)); @@ -291,7 +290,7 @@ namespace Il2CppInspector } // Process relocations - var relsz = Sizeof(typeof(TSym)); + var relsz = (uint)Sizeof(typeof(TSym)); var currentRel = 0; var totalRel = rels.Count(); @@ -301,7 +300,26 @@ namespace Il2CppInspector if (currentRel % 1000 == 0) StatusUpdate($"Processing relocations ({currentRel * 100 / totalRel:F0}%)"); - var symValue = ReadObject(conv.Long(rel.SymbolTable) + conv.Long(rel.SymbolIndex) * relsz).st_value; // S + TWord symValue; + + try + { + // man this really needs a full overhaul + symValue = ReadMappedObject(conv.ULong(rel.SymbolTable) + conv.ULong(rel.SymbolIndex) * relsz) + .st_value; // S + } + catch (InvalidOperationException) + { + try + { + symValue = ReadObject(conv.Long(rel.SymbolTable) + conv.Long(rel.SymbolIndex) * relsz) + .st_value; // S + } + catch (InvalidOperationException) + { + continue; + } + } // Ignore relocations into memory addresses not mapped from the image try { @@ -344,7 +362,7 @@ namespace Il2CppInspector WriteWord(result.newValue); } } - Console.WriteLine($"Processed {rels.Count} relocations"); + AnsiConsole.WriteLine($"Processed {rels.Count} relocations"); // Build symbol and export tables processSymbols(); @@ -388,7 +406,8 @@ namespace Il2CppInspector WriteArray(conv.Long(PT_DYNAMIC.p_offset), dt); } - private void processSymbols() { + private void processSymbols() + { StatusUpdate("Processing symbols"); // Three possible symbol tables in ELF files @@ -436,7 +455,15 @@ namespace Il2CppInspector symbolTable.Clear(); var exportTable = new Dictionary(); - foreach (var pTab in pTables) { + var alreadyProcessed = new List<(TWord offset, TWord count)>(); + + foreach (var pTab in pTables) + { + if (alreadyProcessed.Any(x => + conv.ULong(x.offset) == conv.ULong(pTab.offset))) + continue; + + alreadyProcessed.Add((pTab.offset, pTab.count)); var symbol_table = ReadArray(conv.Long(pTab.offset), conv.Int(pTab.count)); foreach (var symbol in symbol_table) @@ -463,7 +490,7 @@ namespace Il2CppInspector var symbolItem = new Symbol {Name = name, Type = type, VirtualAddress = conv.ULong(symbol.st_value) }; symbolTable.TryAdd(name, symbolItem); if (symbol.st_shndx != (ushort) Elf.SHN_UNDEF) - exportTable.TryAdd(name, new Export {Name = symbolItem.DemangledName, VirtualAddress = conv.ULong(symbol.st_value)}); + exportTable.TryAdd(name, new Export {Name = symbolItem.Name, VirtualAddress = conv.ULong(symbol.st_value)}); } } diff --git a/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs b/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs index 0cb92e4..968bd72 100644 --- a/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs +++ b/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs @@ -176,7 +176,7 @@ namespace Il2CppInspector try { if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(BinaryObjectStream), typeof(LoadOptions), typeof(EventHandler) }, null) - .Invoke(null, new object[] { binaryObjectStream, loadOptions, statusCallback }) is IFileFormatStream loaded) { + .Invoke(null, [binaryObjectStream, loadOptions, statusCallback]) is IFileFormatStream loaded) { loaded.IsModified |= preProcessResult.IsStreamModified; return loaded; diff --git a/Il2CppInspector.Common/FileFormatStreams/FormatLayouts/MachO.cs b/Il2CppInspector.Common/FileFormatStreams/FormatLayouts/MachO.cs index a2c57ee..93f0292 100644 --- a/Il2CppInspector.Common/FileFormatStreams/FormatLayouts/MachO.cs +++ b/Il2CppInspector.Common/FileFormatStreams/FormatLayouts/MachO.cs @@ -6,6 +6,7 @@ using System; using NoisyCowStudios.Bin2Object; +using VersionedSerialization.Attributes; namespace Il2CppInspector { @@ -31,6 +32,7 @@ namespace Il2CppInspector LC_DYLD_INFO_ONLY = 0x80000022, LC_FUNCTION_STARTS = 0x26, LC_ENCRYPTION_INFO_64 = 0x2C, + LC_DYLD_CHAINED_FIXUPS = 0x80000034, CPU_TYPE_X86 = 7, CPU_TYPE_X86_64 = 0x01000000 + CPU_TYPE_X86, @@ -172,4 +174,47 @@ namespace Il2CppInspector public bool r_extern => ((r_data >> 27) & 1) == 1; public uint r_type => r_data >> 28; } + + [VersionedStruct] + public partial struct MachODyldChainedFixupsHeader + { + public uint FixupsVersion; + public uint StartsOffset; + public uint ImportsOffset; + public uint SymbolsOffset; + public uint ImportsCount; + public uint ImportsFormat; + public uint SymbolsFormat; + } + + [VersionedStruct] + public partial struct MachODyldChainedStartsInSegment + { + public const ushort DYLD_CHAINED_PTR_START_NONE = 0xffff; + + public uint StructSize; + public ushort PageSize; + public ushort PointerFormat; + public ulong SegmentOffset; + public uint MaxValidPointer; + public ushort PageCount; + } + + public enum MachODyldChainedPtr + { + DYLD_CHAINED_PTR_64 = 2, + DYLD_CHAINED_PTR_64_OFFSET = 6, + } + + [VersionedStruct] + public partial struct MachODyldChainedPtr64Rebase + { + private ulong _value; + + public ulong Target => _value & 0xfffffffff; + public ulong High8 => (_value >> 36) & 0xff; + public ulong Reserved => (_value >> (36 + 8)) & 0x7f; + public ulong Next => (_value >> (36 + 8 + 7)) & 0xfff; + public bool Bind => ((_value >> (36 + 8 + 7 + 12)) & 0x1) == 0x1; + } } diff --git a/Il2CppInspector.Common/FileFormatStreams/MachOReader.cs b/Il2CppInspector.Common/FileFormatStreams/MachOReader.cs index f5cfc74..8285302 100644 --- a/Il2CppInspector.Common/FileFormatStreams/MachOReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/MachOReader.cs @@ -4,12 +4,13 @@ All rights reserved. */ +using NoisyCowStudios.Bin2Object; +using Spectre.Console; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using NoisyCowStudios.Bin2Object; namespace Il2CppInspector { @@ -172,15 +173,21 @@ namespace Il2CppInspector if (encryptionInfo.CryptID != 0) throw new NotImplementedException("This Mach-O executable is encrypted with FairPlay DRM and cannot be processed. Please provide a decrypted version of the executable."); break; + + case MachO.LC_DYLD_CHAINED_FIXUPS: + var chainedFixupsInfo = ReadObject(); + ApplyChainedFixups(chainedFixupsInfo); + break; } // There might be other data after the load command so always use the specified total size to step forwards Position = startPos + loadCommand.Size; } + // Note: Some binaries do not have __mod_init_func, but instead just __init_offset with offsets to the init functions. This check is disabled. // Must find __mod_init_func - if (funcTab == null) - return false; + //if (funcTab == null) + // return false; // Process relocations foreach (var section in machoSections) { @@ -188,7 +195,7 @@ namespace Il2CppInspector // TODO: Implement Mach-O relocations if (rels.Any()) { - Console.WriteLine("Mach-O file contains relocations (feature not yet implemented)"); + AnsiConsole.WriteLine("Mach-O file contains relocations (feature not yet implemented)"); break; } } @@ -282,7 +289,7 @@ namespace Il2CppInspector : SymbolType.Unknown; if (type == SymbolType.Unknown) { - Console.WriteLine($"Unknown symbol type: {((int) ntype):x2} {value:x16} " + CxxDemangler.CxxDemangler.Demangle(name)); + AnsiConsole.WriteLine($"Unknown symbol type: {((int) ntype):x2} {value:x16} {name}"); } // Ignore duplicates @@ -290,7 +297,82 @@ namespace Il2CppInspector } } - public override uint[] GetFunctionTable() => ReadArray(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray(); + private void ApplyChainedFixups(in MachOLinkEditDataCommand info) + { + var chainedFixupsHeader = ReadVersionedObject(info.Offset); + if (chainedFixupsHeader.FixupsVersion != 0) + { + AnsiConsole.WriteLine($"Unsupported chained fixups version: {chainedFixupsHeader.FixupsVersion}"); + return; + } + + if (chainedFixupsHeader.ImportsFormat != 1 /* DYLD_CHAINED_IMPORT */) + { + AnsiConsole.WriteLine($"Unsupported chained fixups import format: {chainedFixupsHeader.ImportsFormat}"); + return; + } + + //var importsBase = info.Offset + chainedFixupsHeader.ImportsOffset; + //var imports = ReadPrimitiveArray(importsBase, + // chainedFixupsHeader.ImportsCount); + + //var symbolsBase = info.Offset + chainedFixupsHeader.SymbolsOffset; // todo: apparently this supports zlib + + var startsBase = info.Offset + chainedFixupsHeader.StartsOffset; + var segmentCount = ReadPrimitive(startsBase); + var segmentStartOffsets = ReadPrimitiveArray(startsBase + 4, segmentCount); + + foreach (var startOffset in segmentStartOffsets) + { + if (startOffset == 0) + continue; + + var startsInfo = ReadVersionedObject(startsBase + startOffset); + if (startsInfo.SegmentOffset == 0) + continue; + + var pointerFormat = (MachODyldChainedPtr)startsInfo.PointerFormat; + + var pages = ReadPrimitiveArray( + startsBase + startOffset + MachODyldChainedStartsInSegment.Size(), startsInfo.PageCount); + + for (var i = 0; i < pages.Length; i++) + { + var page = pages[i]; + if (page == MachODyldChainedStartsInSegment.DYLD_CHAINED_PTR_START_NONE) + continue; + + var chainOffset = startsInfo.SegmentOffset + (ulong)(i * startsInfo.PageSize) + page; + + while (true) + { + var currentEntry = ReadVersionedObject((long)chainOffset); + + var fixedValue = 0ul; + + if (!currentEntry.Bind) // todo: bind + { + fixedValue = pointerFormat switch + { + MachODyldChainedPtr.DYLD_CHAINED_PTR_64 + or MachODyldChainedPtr.DYLD_CHAINED_PTR_64_OFFSET + => currentEntry.High8 << 56 | currentEntry.Target, + _ => fixedValue + }; + + Write((long)chainOffset, fixedValue); + } + + if (currentEntry.Next == 0) + break; + + chainOffset += currentEntry.Next * 4; + } + } + } + } + + public override uint[] GetFunctionTable() => funcTab == null ? [] : ReadArray(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray(); public override Dictionary GetSymbolTable() => symbolTable; diff --git a/Il2CppInspector.Common/FileFormatStreams/PEReader.cs b/Il2CppInspector.Common/FileFormatStreams/PEReader.cs index f014c53..7139fd6 100644 --- a/Il2CppInspector.Common/FileFormatStreams/PEReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/PEReader.cs @@ -4,13 +4,14 @@ All rights reserved. */ +using NoisyCowStudios.Bin2Object; +using Spectre.Console; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using NoisyCowStudios.Bin2Object; namespace Il2CppInspector { @@ -102,7 +103,7 @@ namespace Il2CppInspector // Unpacking must be done starting here, one byte after the end of the headers // Packed or previously packed with Themida? This is purely for information if (sections.FirstOrDefault(x => x.Name == ".themida") is PESection _) - Console.WriteLine("Themida protection detected"); + AnsiConsole.WriteLine("Themida protection detected"); // Packed with anything (including Themida)? mightBePacked = sections.FirstOrDefault(x => x.Name == ".rdata") is null; @@ -114,26 +115,31 @@ namespace Il2CppInspector section.Name = wantedSectionTypes[section.Characteristics]; // Get base of code - GlobalOffset = pe.ImageBase + pe.BaseOfCode - sections.First(x => x.Name == ".text").PointerToRawData; + GlobalOffset = pe.ImageBase + pe.BaseOfCode - sections + .FirstOrDefault(x => x.Characteristics.HasFlag(PE.IMAGE_SCN_MEM_EXECUTE))?.PointerToRawData ?? 0; // Confirm that .rdata section begins at same place as IAT - var rData = sections.First(x => x.Name == ".rdata"); - mightBePacked |= rData.VirtualAddress != IATStart; + var rData = sections.FirstOrDefault(x => x.Name == ".rdata"); + mightBePacked |= rData == null || rData.VirtualAddress != IATStart; + if (rData != null) + { + // Calculate start of function pointer table + pFuncTable = rData.PointerToRawData + IATSize; - // Calculate start of function pointer table - pFuncTable = rData.PointerToRawData + IATSize; - - // Skip over __guard_check_icall_fptr and __guard_dispatch_icall_fptr if present, then the following zero offset - Position = pFuncTable; - if (pe is PEOptHeader32) { - while (ReadUInt32() != 0) + // Skip over __guard_check_icall_fptr and __guard_dispatch_icall_fptr if present, then the following zero offset + Position = pFuncTable; + if (pe is PEOptHeader32) + { + while (ReadUInt32() != 0) + pFuncTable += 4; pFuncTable += 4; - pFuncTable += 4; - } - else { - while (ReadUInt64() != 0) + } + else + { + while (ReadUInt64() != 0) + pFuncTable += 8; pFuncTable += 8; - pFuncTable += 8; + } } // In the fist go round, we signal that this is at least a valid PE file; we don't try to unpack yet diff --git a/Il2CppInspector.Common/FileFormatStreams/ProcessMapReader.cs b/Il2CppInspector.Common/FileFormatStreams/ProcessMapReader.cs index db30fe9..24ac35e 100644 --- a/Il2CppInspector.Common/FileFormatStreams/ProcessMapReader.cs +++ b/Il2CppInspector.Common/FileFormatStreams/ProcessMapReader.cs @@ -4,11 +4,12 @@ All rights reserved. */ +using NoisyCowStudios.Bin2Object; +using Spectre.Console; using System; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using NoisyCowStudios.Bin2Object; namespace Il2CppInspector { @@ -100,7 +101,7 @@ namespace Il2CppInspector // Get the entire remaining chunk, or to the end of the file if it doesn't contain the end of the chunk var length = (uint) Math.Min(chunk.Memory.End - memoryNext, source.Length); - Console.WriteLine($"Writing {length:x8} bytes from {Path.GetFileName(file.Name)} +{fileStart:x8} ({memoryNext:x8}) to target {il2cpp.Position:x8}"); + AnsiConsole.WriteLine($"Writing {length:x8} bytes from {Path.GetFileName(file.Name)} +{fileStart:x8} ({memoryNext:x8}) to target {il2cpp.Position:x8}"); // Can't use Stream.CopyTo as it doesn't support length parameter var buffer = new byte[length]; diff --git a/Il2CppInspector.Common/FileFormatStreams/Symbol.cs b/Il2CppInspector.Common/FileFormatStreams/Symbol.cs index 6ab330a..c7c1dc9 100644 --- a/Il2CppInspector.Common/FileFormatStreams/Symbol.cs +++ b/Il2CppInspector.Common/FileFormatStreams/Symbol.cs @@ -20,7 +20,5 @@ namespace Il2CppInspector public ulong VirtualAddress { get; set; } public string Name { get; set; } public SymbolType Type { get; set; } - - public string DemangledName => CxxDemangler.CxxDemangler.Demangle(Name); } } diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index 64b087f..cb65d57 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -6,12 +6,13 @@ */ using Il2CppInspector.Next; +using Il2CppInspector.Next.BinaryMetadata; +using Il2CppInspector.Next.Metadata; +using Spectre.Console; using System.Collections.Immutable; using System.Diagnostics; using System.Reflection; using System.Text.RegularExpressions; -using Il2CppInspector.Next.BinaryMetadata; -using Il2CppInspector.Next.Metadata; using VersionedSerialization; namespace Il2CppInspector @@ -191,7 +192,7 @@ namespace Il2CppInspector var symbols = Image.GetSymbolTable(); if (symbols.Any()) { - Console.WriteLine($"Symbol table(s) found with {symbols.Count} entries"); + AnsiConsole.WriteLine($"Symbol table(s) found with {symbols.Count} entries"); symbols.TryGetValue("g_CodeRegistration", out var code); symbols.TryGetValue("g_MetadataRegistration", out var metadata); @@ -202,13 +203,13 @@ namespace Il2CppInspector symbols.TryGetValue("_g_MetadataRegistration", out metadata); if (code != null && metadata != null) { - Console.WriteLine("Required structures acquired from symbol lookup"); + AnsiConsole.WriteLine("Required structures acquired from symbol lookup"); return (code.VirtualAddress, metadata.VirtualAddress); } else { - Console.WriteLine("No matches in symbol table"); + AnsiConsole.WriteLine("No matches in symbol table"); } } else if (symbols != null) { - Console.WriteLine("No symbol table present in binary file"); + AnsiConsole.WriteLine("No symbol table present in binary file"); } else { Console.WriteLine("Symbol table search not implemented for this binary format"); } @@ -227,12 +228,12 @@ namespace Il2CppInspector var (code, metadata) = ConsiderCode(Image, loc); if (code != 0) { RegistrationFunctionPointer = loc + Image.GlobalOffset; - Console.WriteLine("Required structures acquired from code heuristics. Initialization function: 0x{0:X16}", RegistrationFunctionPointer); + AnsiConsole.WriteLine("Required structures acquired from code heuristics. Initialization function: 0x{0:X16}", RegistrationFunctionPointer); return (code, metadata); } } - Console.WriteLine("No matches via code heuristics"); + AnsiConsole.WriteLine("No matches via code heuristics"); return null; } @@ -244,11 +245,11 @@ namespace Il2CppInspector var (codePtr, metadataPtr) = ImageScan(Metadata); if (codePtr == 0) { - Console.WriteLine("No matches via data heuristics"); + AnsiConsole.WriteLine("No matches via data heuristics"); return null; } - Console.WriteLine("Required structures acquired from data heuristics"); + AnsiConsole.WriteLine("Required structures acquired from data heuristics"); return (codePtr, metadataPtr); } @@ -274,8 +275,8 @@ namespace Il2CppInspector var pointerSize = Image.Bits == 32 ? 4u : 8u; - Console.WriteLine("CodeRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? codeRegistration & 0xffff_ffff : codeRegistration, Image.MapVATR(codeRegistration)); - Console.WriteLine("MetadataRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? metadataRegistration & 0xffff_ffff : metadataRegistration, Image.MapVATR(metadataRegistration)); + AnsiConsole.WriteLine("CodeRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? codeRegistration & 0xffff_ffff : codeRegistration, Image.MapVATR(codeRegistration)); + AnsiConsole.WriteLine("MetadataRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? metadataRegistration & 0xffff_ffff : metadataRegistration, Image.MapVATR(metadataRegistration)); // Root structures from which we find everything else CodeRegistration = Image.ReadMappedVersionedObject(codeRegistration); @@ -337,7 +338,15 @@ namespace Il2CppInspector } // Read method invoker pointer indices - one per method - MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int) module.MethodPointerCount)); + try + { + MethodInvokerIndices.Add(module, + Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int)module.MethodPointerCount)); + } + catch (InvalidOperationException) + { + MethodInvokerIndices.Add(module, [..new int[(int)module.MethodPointerCount]]); + } } } @@ -398,12 +407,21 @@ namespace Il2CppInspector var type = TypeReferences[i]; if (type.Type.IsTypeDefinitionEnum()) { - type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize; + if (type.Data.Type.PointerValue >= baseDefinitionPtr) + type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize; + + Debug.Assert(Metadata!.Types.Length > type.Data.KlassIndex); } else if (type.Type.IsGenericParameterEnum()) { - type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize; + if (type.Data.Type.PointerValue >= baseGenericPtr) + type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize; + + Debug.Assert(Metadata!.GenericParameters.Length > type.Data.KlassIndex); } + + Debug.Assert((long)type.Data.Value >= 0); + builder.Add(type); } TypeReferences = builder.MoveToImmutable(); diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 9ee970f..24e52eb 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -5,8 +5,11 @@ */ using Il2CppInspector.Next; +using Il2CppInspector.Next.BinaryMetadata; +using Il2CppInspector.Next.Metadata; using Il2CppInspector.Utils; using NoisyCowStudios.Bin2Object; +using Spectre.Console; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -14,8 +17,6 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Text; -using Il2CppInspector.Next.BinaryMetadata; -using Il2CppInspector.Next.Metadata; using VersionedSerialization; namespace Il2CppInspector @@ -410,7 +411,7 @@ namespace Il2CppInspector if (metadataFile != null) { // Extract the metadata file to memory if (!silent) - Console.WriteLine($"Extracting metadata from (archive){Path.DirectorySeparatorChar}{metadataFile.FullName}"); + AnsiConsole.WriteLine($"Extracting metadata from (archive){Path.DirectorySeparatorChar}{metadataFile.FullName}"); metadataMemoryStream = new MemoryStream(); using var metadataStream = metadataFile.Open(); @@ -428,7 +429,7 @@ namespace Il2CppInspector // IPAs will only have one binary (which may or may not be a UB covering multiple architectures) if (ipaBinaryFolder != null) { if (!silent) - Console.WriteLine($"Extracting binary from {zipStreams.First()}{Path.DirectorySeparatorChar}{binaryFiles.First().FullName}"); + AnsiConsole.WriteLine($"Extracting binary from {zipStreams.First()}{Path.DirectorySeparatorChar}{binaryFiles.First().FullName}"); // Extract the binary file or package to memory binaryMemoryStream = new MemoryStream(); @@ -531,7 +532,7 @@ namespace Il2CppInspector return null; } - Console.WriteLine("Detected metadata version " + metadata.Version); + AnsiConsole.WriteLine("Detected metadata version " + metadata.Version); // Load the il2cpp code file (try all available file formats) IFileFormatStream stream; @@ -559,16 +560,16 @@ namespace Il2CppInspector var processors = new List(); foreach (var image in stream.Images) { - Console.WriteLine("Container format: " + image.Format); - Console.WriteLine("Container endianness: " + ((BinaryObjectStream) image).Endianness); - Console.WriteLine("Architecture word size: {0}-bit", image.Bits); - Console.WriteLine("Instruction set: " + image.Arch); - Console.WriteLine("Global offset: 0x{0:X16}", image.GlobalOffset); + AnsiConsole.WriteLine("Container format: " + image.Format); + AnsiConsole.WriteLine("Container endianness: " + ((BinaryObjectStream) image).Endianness); + AnsiConsole.WriteLine("Architecture word size: {0}-bit", image.Bits); + AnsiConsole.WriteLine("Instruction set: " + image.Arch); + AnsiConsole.WriteLine("Global offset: 0x{0:X16}", image.GlobalOffset); // Architecture-agnostic load attempt try { if (Il2CppBinary.Load(image, metadata, statusCallback) is Il2CppBinary binary) { - Console.WriteLine("IL2CPP binary version " + image.Version); + AnsiConsole.WriteLine("IL2CPP binary version " + image.Version); processors.Add(new Il2CppInspector(binary, metadata)); } diff --git a/Il2CppInspector.Common/IL2CPP/Metadata.cs b/Il2CppInspector.Common/IL2CPP/Metadata.cs index c71578a..839f053 100644 --- a/Il2CppInspector.Common/IL2CPP/Metadata.cs +++ b/Il2CppInspector.Common/IL2CPP/Metadata.cs @@ -92,7 +92,7 @@ namespace Il2CppInspector // Set object versioning for Bin2Object from metadata version Version = new StructVersion(Header.Version); - if (Version < MetadataVersions.V160 || Version > MetadataVersions.V310) { + if (Version < MetadataVersions.V160 || Version > MetadataVersions.V350) { throw new InvalidOperationException($"The supplied metadata file is not of a supported version ({Header.Version})."); } @@ -215,9 +215,26 @@ namespace Il2CppInspector else { var stringLiteralList = ReadVersionedObjectArray(Header.StringLiteralOffset, Header.StringLiteralSize / Sizeof()); - StringLiterals = new string[stringLiteralList.Length]; - for (var i = 0; i < stringLiteralList.Length; i++) - StringLiterals[i] = ReadFixedLengthString(Header.StringLiteralDataOffset + stringLiteralList[i].DataIndex, (int)stringLiteralList[i].Length); + if (Version >= MetadataVersions.V350) + { + StringLiterals = new string[stringLiteralList.Length - 1]; + for (var i = 0; i < stringLiteralList.Length; i++) + { + var currentStringDataIndex = stringLiteralList[i].DataIndex; + var nextStringDataIndex = stringLiteralList[i + 1].DataIndex; + var stringLength = nextStringDataIndex - currentStringDataIndex; + + StringLiterals[i] = ReadFixedLengthString(Header.StringLiteralDataOffset + currentStringDataIndex, stringLength); + } + + } + else + { + StringLiterals = new string[stringLiteralList.Length]; + for (var i = 0; i < stringLiteralList.Length; i++) + StringLiterals[i] = ReadFixedLengthString(Header.StringLiteralDataOffset + stringLiteralList[i].DataIndex, (int)stringLiteralList[i].Length); + + } } // Post-processing hook diff --git a/Il2CppInspector.Common/Il2CppInspector.csproj b/Il2CppInspector.Common/Il2CppInspector.csproj index fa982aa..073a79c 100644 --- a/Il2CppInspector.Common/Il2CppInspector.csproj +++ b/Il2CppInspector.Common/Il2CppInspector.csproj @@ -41,10 +41,8 @@ - - - NU1605 - + + diff --git a/Il2CppInspector.Common/Model/AppModel.cs b/Il2CppInspector.Common/Model/AppModel.cs index 923e6ee..b4e0cb0 100644 --- a/Il2CppInspector.Common/Model/AppModel.cs +++ b/Il2CppInspector.Common/Model/AppModel.cs @@ -14,6 +14,7 @@ using Il2CppInspector.Cpp; using Il2CppInspector.Cpp.UnityHeaders; using Il2CppInspector.Next; using Il2CppInspector.Reflection; +using Spectre.Console; namespace Il2CppInspector.Model { @@ -40,6 +41,9 @@ namespace Il2CppInspector.Model // The types are ordered to enable the production of code output without forward dependencies public List DependencyOrderedCppTypes { get; private set; } + // Required forward definition types for the C++ type definitions + public List RequiredForwardDefinitions { get; private set; } = []; + // Composite mapping of all the .NET methods in the IL2CPP binary public MultiKeyDictionary Methods { get; } = new MultiKeyDictionary(); @@ -149,12 +153,12 @@ namespace Il2CppInspector.Model UnityHeaders = unityVersion != null ? UnityHeaders.GetHeadersForVersion(unityVersion) : UnityHeaders.GuessHeadersForBinary(TypeModel.Package.Binary).Last(); UnityVersion = unityVersion ?? UnityHeaders.VersionRange.Min; - Console.WriteLine($"Selected Unity version(s) {UnityHeaders.VersionRange} (types: {UnityHeaders.TypeHeaderResource.VersionRange}, APIs: {UnityHeaders.APIHeaderResource.VersionRange})"); + AnsiConsole.WriteLine($"Selected Unity version(s) {UnityHeaders.VersionRange} (types: {UnityHeaders.TypeHeaderResource.VersionRange}, APIs: {UnityHeaders.APIHeaderResource.VersionRange})"); // Check for matching metadata and binary versions if (UnityHeaders.MetadataVersion != Image.Version) { - Console.WriteLine($"Warning: selected version {UnityVersion} (metadata version {UnityHeaders.MetadataVersion})" + - $" does not match metadata version {Image.Version}."); + AnsiConsole.WriteLine($"Warning: selected version {UnityVersion} (metadata version {UnityHeaders.MetadataVersion})" + + $" does not match metadata version {Image.Version}."); } // Initialize declaration generator to process every type in the binary @@ -236,8 +240,18 @@ namespace Il2CppInspector.Model break; case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef: var method = TypeModel.GetMetadataUsageMethod(usage); + declarationGenerator.IncludeMethod(method); - AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations()); + var definitions = declarationGenerator.GenerateRemainingTypeDeclarations(); + if (definitions == null) + { + // if we end up here, type generation has failed + // todo: this try/catch is a massive hack to sidestep the original issue of generation failing, + // todo: this needs to be improved. + break; + } + + AddTypes(definitions); // Any method here SHOULD already be in the Methods list // but we have seen one example where this is not the case for a MethodDef @@ -247,6 +261,7 @@ namespace Il2CppInspector.Model Methods.Add(method, fnPtr, new AppMethod(method, fnPtr) { Group = Group }); } Methods[method].MethodInfoPtrAddress = address; + break; // FieldInfo is used for array initializers. @@ -294,6 +309,8 @@ namespace Il2CppInspector.Model declarationGenerator.IncludeType(type); AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations()); + RequiredForwardDefinitions = declarationGenerator.GenerateRequiredForwardDefinitions(); + // Restore stdout Console.SetOut(stdout); diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs index 89912e0..99d1e6e 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs @@ -77,6 +77,7 @@ public partial record struct Il2CppCodeRegistration [NativeInteger] [VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")] [VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")] + [VersionCondition(GreaterThan = "35.0")] public uint UnresolvedIndirectCallCount; // UnresolvedVirtualCallCount pre 29.1 [VersionCondition(GreaterThan = "22.0")] @@ -84,10 +85,12 @@ public partial record struct Il2CppCodeRegistration [VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")] [VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")] + [VersionCondition(GreaterThan = "35.0")] public Pointer UnresolvedInstanceCallWrappers; [VersionCondition(EqualTo = "29.0", IncludingTag = "2022"), VersionCondition(EqualTo = "31.0", IncludingTag = "2022")] [VersionCondition(EqualTo = "29.0", IncludingTag = "2023"), VersionCondition(EqualTo = "31.0", IncludingTag = "2023")] + [VersionCondition(GreaterThan = "35.0")] public Pointer UnresolvedStaticCallPointers; [NativeInteger] diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs index b8cb72a..0efa091 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs @@ -18,7 +18,7 @@ public partial record struct Il2CppMethodDefinition public TypeDefinitionIndex DeclaringType { get; private set; } public TypeIndex ReturnType { get; private set; } - [VersionCondition(EqualTo = "31.0")] + [VersionCondition(GreaterThan = "31.0")] public uint ReturnParameterToken { get; private set; } public ParameterIndex ParameterStart { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs index b1521fe..ebd6436 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs @@ -6,6 +6,7 @@ using StringLiteralIndex = int; [VersionedStruct] public partial record struct Il2CppStringLiteral { + [VersionCondition(LessThan = "31.0")] public uint Length { get; private set; } public StringLiteralIndex DataIndex { get; private set; } } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs index 52efe14..e72002f 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs @@ -1,4 +1,5 @@ using System.Reflection; +using VersionedSerialization; using VersionedSerialization.Attributes; namespace Il2CppInspector.Next.Metadata; @@ -32,6 +33,8 @@ public partial record struct Il2CppTypeDefinition public TypeIndex DeclaringTypeIndex { get; private set; } public TypeIndex ParentIndex { get; private set; } + + [VersionCondition(LessThan = "31.0")] public TypeIndex ElementTypeIndex { get; private set; } [VersionCondition(LessThan = "24.1")] @@ -80,4 +83,9 @@ public partial record struct Il2CppTypeDefinition public uint Token { get; private set; } public readonly bool IsValid => NameIndex != 0; + + public int GetEnumElementTypeIndex(StructVersion version) + => version >= MetadataVersions.V350 + ? ParentIndex + : ElementTypeIndex; } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/MetadataVersions.cs b/Il2CppInspector.Common/Next/MetadataVersions.cs index 11e9bf1..9a2a695 100644 --- a/Il2CppInspector.Common/Next/MetadataVersions.cs +++ b/Il2CppInspector.Common/Next/MetadataVersions.cs @@ -28,4 +28,7 @@ public static class MetadataVersions // No tag - 29.0/31.0 public static readonly string Tag2022 = "2022"; // 29.1/31.1 + + // Unity 6000.3.0a2 + public static readonly StructVersion V350 = new(35); } \ No newline at end of file diff --git a/Il2CppInspector.Common/Outputs/AssemblyShims.cs b/Il2CppInspector.Common/Outputs/AssemblyShims.cs index c111691..3446761 100644 --- a/Il2CppInspector.Common/Outputs/AssemblyShims.cs +++ b/Il2CppInspector.Common/Outputs/AssemblyShims.cs @@ -430,7 +430,7 @@ namespace Il2CppInspector.Outputs if (method.VirtualAddress.HasValue) { var args = new List<(string,object)> { ("RVA", (method.VirtualAddress.Value.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), - ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start))), + ("Offset", $"0x{model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start):X}"), ("VA", method.VirtualAddress.Value.Start.ToAddressString()) }; if (method.Definition.Slot != ushort.MaxValue) @@ -470,7 +470,7 @@ namespace Il2CppInspector.Outputs return def.AddAttribute(module, attributeAttribute, ("Name", ca.AttributeType.Name), ("RVA", (ca.VirtualAddress.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), - ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start))) + ("Offset", $"0x{model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start):X}") ); } diff --git a/Il2CppInspector.Common/Outputs/CppScaffolding.cs b/Il2CppInspector.Common/Outputs/CppScaffolding.cs index 4f15aaa..af5f294 100644 --- a/Il2CppInspector.Common/Outputs/CppScaffolding.cs +++ b/Il2CppInspector.Common/Outputs/CppScaffolding.cs @@ -44,8 +44,13 @@ namespace Il2CppInspector.Outputs // Write primitive type definitions for when we're not including other headers writeCode($""" - #define IS_LIBCLANG_DECOMPILER (defined(_IDACLANG_) || defined(_BINARYNINJA_)) - #define IS_DECOMPILER (defined(_GHIDRA_) || defined(_IDA_) || IS_LIBCLANG_DECOMPILER) + #if defined(_IDACLANG_) || defined(_BINARYNINJA_) + #define IS_LIBCLANG_DECOMPILER + #endif + + #if defined(_GHIDRA_) || defined(_IDA_) || defined(IS_LIBCLANG_DECOMPILER) + #define IS_DECOMPILER + #endif #if defined(_GHIDRA_) || defined(_IDA_) typedef unsigned __int8 uint8_t; @@ -58,7 +63,7 @@ namespace Il2CppInspector.Outputs typedef __int64 int64_t; #endif - #if IS_LIBCLANG_DECOMPILER + #if defined(IS_LIBCLANG_DECOMPILER) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; @@ -67,21 +72,26 @@ namespace Il2CppInspector.Outputs typedef short int16_t; typedef int int32_t; typedef long int64_t; + + #ifdef linux + #undef linux #endif - #if defined(_GHIDRA_) || IS_LIBCLANG_DECOMPILER + #endif + + #if defined(_GHIDRA_) || defined(IS_LIBCLANG_DECOMPILER) typedef int{_model.Package.BinaryImage.Bits}_t intptr_t; typedef uint{_model.Package.BinaryImage.Bits}_t uintptr_t; typedef uint{_model.Package.BinaryImage.Bits}_t size_t; #endif - #if !IS_DECOMPILER + #ifndef IS_DECOMPILER #define _CPLUSPLUS_ #endif """); if (_useBetterArraySize) - writeCode("#define actual_il2cpp_array_size_t il2cpp_array_size_t"); + writeCode("#define il2cpp_array_size_t actual_il2cpp_array_size_t"); writeSectionHeader("IL2CPP internal types"); writeCode(_model.UnityHeaders.GetTypeHeaderText(_model.WordSizeBits)); @@ -94,9 +104,7 @@ namespace Il2CppInspector.Outputs { int32_t size; actual_il2cpp_array_size_t value; - } better_il2cpp_array_size_t; - - #define better_il2cpp_array_size_t il2cpp_array_size_t + } il2cpp_array_size_t; """); if (_model.TargetCompiler == CppCompilerType.MSVC) @@ -115,17 +123,20 @@ namespace Il2CppInspector.Outputs } // C does not support namespaces - writeCode("#if !IS_DECOMPILER"); + writeCode("#ifndef IS_DECOMPILER"); writeCode("namespace app {"); writeCode("#endif"); writeLine(""); + writeForwardDefinitions(); + + writeTypesForGroup("Required forward definitions", "required_forward_definitions"); writeTypesForGroup("Application types from method calls", "types_from_methods"); writeTypesForGroup("Application types from generic methods", "types_from_generic_methods"); writeTypesForGroup("Application types from usages", "types_from_usages"); writeTypesForGroup("Application unused value types", "unused_concrete_types"); - writeCode("#if !IS_DECOMPILER"); + writeCode("#ifndef IS_DECOMPILER"); writeCode("}"); writeCode("#endif"); } @@ -306,19 +317,32 @@ namespace Il2CppInspector.Outputs writeLine(""); } - private void writeTypesForGroup(string header, string group) { + private void writeForwardDefinitions() + { + writeSectionHeader("Required forward definitions"); + foreach (var cppType in _model.RequiredForwardDefinitions) + writeCode(cppType.ToString()); + } + + private void writeTypesForGroup(string header, string group) + { writeSectionHeader(header); foreach (var cppType in _model.GetDependencyOrderedCppTypeGroup(group)) - if (cppType is CppEnumType) { + { + if (cppType is CppEnumType) + { // Ghidra can't process C++ enum base types writeCode("#if defined(_CPLUSPLUS_)"); writeCode(cppType.ToString()); writeCode("#else"); writeCode(cppType.ToString("c")); writeCode("#endif"); - } else { + } + else + { writeCode(cppType.ToString()); } + } } private void writeCode(string text) { diff --git a/Il2CppInspector.Common/Outputs/JSONMetadata.cs b/Il2CppInspector.Common/Outputs/JSONMetadata.cs index 57a27c0..725575b 100644 --- a/Il2CppInspector.Common/Outputs/JSONMetadata.cs +++ b/Il2CppInspector.Common/Outputs/JSONMetadata.cs @@ -217,7 +217,6 @@ namespace Il2CppInspector.Outputs foreach (var symbol in symbols) { writeObject(() => { writeName(symbol.VirtualAddress, symbol.Name); - writer.WriteString("demangledName", symbol.DemangledName); writer.WriteString("type", symbol.Type.ToString()); }); } diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/Targets/BinaryNinja.py b/Il2CppInspector.Common/Outputs/ScriptResources/Targets/BinaryNinja.py index fc2ada7..787932e 100644 --- a/Il2CppInspector.Common/Outputs/ScriptResources/Targets/BinaryNinja.py +++ b/Il2CppInspector.Common/Outputs/ScriptResources/Targets/BinaryNinja.py @@ -1,302 +1,330 @@ -from binaryninja import * +from binaryninja import ( + BinaryView, + Component, + Type, + PointerType, + TypeParser, + Platform, + Endianness, + ArrayType, + BackgroundTaskThread, + demangle_gnu3, + get_qualified_name, + SegmentFlag, + SectionSemantics, +) +from binaryninja.log import log_error -#try: -# from typing import TYPE_CHECKING -# if TYPE_CHECKING: -# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext -# import json -# import os -# import sys -# from datetime import datetime -# from typing import Literal -# bv: BinaryView = None # type: ignore -#except: -# pass +# try: +# from typing import TYPE_CHECKING +# if TYPE_CHECKING: +# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext +# import json +# import os +# import sys +# from datetime import datetime +# from typing import Literal +# bv: BinaryView = None # type: ignore +# except: +# pass CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) + class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface): - # this is implemented, - # however the write API does not seem to work properly here (possibly a bug), - # so this is disabled for now - supports_fake_string_segment: bool = False + supports_fake_string_segment: bool = True - _status: BaseStatusHandler - - _view: BinaryView - _undo_id: str - _components: dict[str, Component] - _type_cache: dict[str, Type] - _function_type_cache: dict[str, Type] + _status: BaseStatusHandler - _address_size: int - _endianness: Literal["little", "big"] + _view: BinaryView + _undo_id: str + _components: dict[str, Component] + _type_cache: dict[str, Type] + _function_type_cache: dict[str, Type] - TYPE_PARSER_OPTIONS = [ - "--target=x86_64-pc-linux", - "-x", "c++", - "-D_BINARYNINJA_=1" - ] + _address_size: int + _endianness: Literal["little", "big"] - def __init__(self, status: BaseStatusHandler): - self._status = status + TYPE_PARSER_OPTIONS = ["--target=x86_64-pc-linux", "-x", "c++", "-D_BINARYNINJA_=1"] - def _get_or_create_type(self, type: str) -> Type: - if type.startswith("struct "): - type = type[len("struct "):] - elif type.startswith("class "): - type = type[len("class "):] + def __init__(self, status: BaseStatusHandler): + self._status = status - if type in self._type_cache: - return self._type_cache[type] - - if type.endswith("*"): - base_type = self._get_or_create_type(type[:-1].strip()) + def _get_or_create_type(self, type: str) -> Type: + if type.startswith("struct "): + type = type[len("struct ") :] + elif type.startswith("class "): + type = type[len("class ") :] - parsed = PointerType.create(self._view.arch, base_type) # type: ignore - else: - parsed = self._view.get_type_by_name(type) - if parsed is None: - parsed, errors = self._view.parse_type_string(type) + if type in self._type_cache: + return self._type_cache[type] - self._type_cache[type] = parsed - return parsed + if type.endswith("*"): + base_type = self._get_or_create_type(type[:-1].strip()) - def _parse_type_source(self, types: str, filename: str | None = None): - parsed_types, errors = TypeParser.default.parse_types_from_source( - types, - filename if filename else "types.hpp", - self._view.platform if self._view.platform is not None else Platform["windows-x86_64"], - self._view, - self.TYPE_PARSER_OPTIONS - ) + parsed = PointerType.create(self._view.arch, base_type) # type: ignore + else: + parsed = self._view.get_type_by_name(type) + if parsed is None: + parsed, errors = self._view.parse_type_string(type) - if parsed_types is None: - log_error("Failed to import types.") - log_error(errors) - return None - - return parsed_types + self._type_cache[type] = parsed + return parsed - def get_script_directory(self) -> str: - return CURRENT_PATH + def _parse_type_source(self, types: str, filename: str | None = None): + parsed_types, errors = TypeParser.default.parse_types_from_source( + types, + filename if filename else "types.hpp", + self._view.platform + if self._view.platform is not None + else Platform["windows-x86_64"], + self._view, + self.TYPE_PARSER_OPTIONS, + ) - def on_start(self): - self._view = bv # type: ignore - self._undo_id = self._view.begin_undo_actions() - self._view.set_analysis_hold(True) - self._components = {} - self._type_cache = {} - self._function_type_cache = {} + if parsed_types is None: + log_error("Failed to import types.") + log_error(errors) + return None - self._address_size = self._view.address_size - self._endianness = "little" if self._view.endianness == Endianness.LittleEndian else "big" - - self._status.update_step("Parsing header") + return parsed_types - with open(os.path.join(self.get_script_directory(), "il2cpp.h"), "r") as f: - parsed_types = self._parse_type_source(f.read(), "il2cpp.hpp") - if parsed_types is None: - return + def get_script_directory(self) -> str: + return CURRENT_PATH - self._status.update_step("Importing header types", len(parsed_types.types)) + def on_start(self): + self._view = bv # type: ignore + self._undo_id = self._view.begin_undo_actions() + self._view.set_analysis_hold(True) + self._components = {} + self._type_cache = {} + self._function_type_cache = {} - def import_progress_func(progress: int, total: int): - self._status.update_progress(1) - return True + self._address_size = self._view.address_size + self._endianness = ( + "little" if self._view.endianness == Endianness.LittleEndian else "big" + ) - self._view.define_user_types([(x.name, x.type) for x in parsed_types.types], import_progress_func) + self._status.update_step("Parsing header") - def on_finish(self): - self._view.commit_undo_actions(self._undo_id) - self._view.set_analysis_hold(False) - self._view.update_analysis() + with open(os.path.join(self.get_script_directory(), "il2cpp.h"), "r") as f: + parsed_types = self._parse_type_source(f.read(), "il2cpp.hpp") + if parsed_types is None: + return - def define_function(self, address: int, end: int | None = None): - if self._view.get_function_at(address) is not None: - return - - self._view.create_user_function(address) + self._status.update_step("Importing header types", len(parsed_types.types)) - def define_data_array(self, address: int, type: str, count: int): - parsed_type = self._get_or_create_type(type) - array_type = ArrayType.create(parsed_type, count) - var = self._view.get_data_var_at(address) - if var is None: - self._view.define_user_data_var(address, array_type) - else: - var.type = array_type + def import_progress_func(progress: int, total: int): + self._status.update_progress(1) + return True - def set_data_type(self, address: int, type: str): - var = self._view.get_data_var_at(address) - dtype = self._get_or_create_type(type) - if var is None: - self._view.define_user_data_var(address, dtype) - else: - var.type = dtype + self._view.define_user_types( + [(x.name, x.type) for x in parsed_types.types], import_progress_func + ) - def set_function_type(self, address: int, type: str): - function = self._view.get_function_at(address) - if function is None: - return - - if type in self._function_type_cache: - function.type = self._function_type_cache[type] # type: ignore - else: - #log_info(f"skipping function type setting for {address}, {type}") - #pass - function.type = type.replace("this", "`this`") + def on_finish(self): + self._view.commit_undo_actions(self._undo_id) + self._view.set_analysis_hold(False) + self._view.update_analysis() - def set_data_comment(self, address: int, cmt: str): - self._view.set_comment_at(address, cmt) + def define_function(self, address: int, end: int | None = None): + if self._view.get_function_at(address) is not None: + return - def set_function_comment(self, address: int, cmt: str): - function = self._view.get_function_at(address) - if function is None: - return + self._view.create_user_function(address) - function.comment = cmt + def define_data_array(self, address: int, type: str, count: int): + parsed_type = self._get_or_create_type(type) + array_type = ArrayType.create(parsed_type, count) + var = self._view.get_data_var_at(address) + if var is None: + self._view.define_user_data_var(address, array_type) + else: + var.type = array_type - def set_data_name(self, address: int, name: str): - var = self._view.get_data_var_at(address) - if var is None: - return - - if name.startswith("_Z"): - type, demangled = demangle_gnu3(self._view.arch, name, self._view) - var.name = get_qualified_name(demangled) - else: - var.name = name + def set_data_type(self, address: int, type: str): + var = self._view.get_data_var_at(address) + dtype = self._get_or_create_type(type) + if var is None: + self._view.define_user_data_var(address, dtype) + else: + var.type = dtype - def set_function_name(self, address: int, name: str): - function = self._view.get_function_at(address) - if function is None: - return + def set_function_type(self, address: int, type: str): + function = self._view.get_function_at(address) + if function is None: + return - if name.startswith("_Z"): - type, demangled = demangle_gnu3(self._view.arch, name, self._view) - function.name = get_qualified_name(demangled) - #function.type = type - this does not work due to the generated types not being namespaced. :( - else: - function.name = name + if type in self._function_type_cache: + function.type = self._function_type_cache[type] # type: ignore + else: + # log_info(f"skipping function type setting for {address}, {type}") + # pass + function.type = type.replace("this", "`this`") - def add_cross_reference(self, from_address: int, to_address: int): - self._view.add_user_data_ref(from_address, to_address) + def set_data_comment(self, address: int, cmt: str): + self._view.set_comment_at(address, cmt) - def import_c_typedef(self, type_def: str): - self._view.define_user_type(None, type_def) + def set_function_comment(self, address: int, cmt: str): + function = self._view.get_function_at(address) + if function is None: + return - # optional - def _get_or_create_component(self, name: str): - if name in self._components: - return self._components[name] - - current = name - if current.count("/") != 0: - split_idx = current.rindex("/") - parent, child = current[:split_idx], current[split_idx:] - parent = self._get_or_create_component(name) - component = self._view.create_component(child, parent) - else: - component = self._view.create_component(name) + function.comment = cmt - self._components[name] = component - return component + def set_data_name(self, address: int, name: str): + var = self._view.get_data_var_at(address) + if var is None: + return - def add_function_to_group(self, address: int, group: str): - return - function = self._view.get_function_at(address) - if function is None: - return - - self._get_or_create_component(group).add_function(function) + if name.startswith("_Z"): + type, demangled = demangle_gnu3(self._view.arch, name, self._view) + var.name = get_qualified_name(demangled) + else: + var.name = name - def cache_function_types(self, signatures: list[str]): - function_sigs = set(signatures) - if len(function_sigs) == 0: - return - - typestr = ";\n".join(function_sigs).replace("this", "_this") + ";" - parsed_types = self._parse_type_source(typestr, "cached_types.hpp") - if parsed_types is None: - return + def set_function_name(self, address: int, name: str): + function = self._view.get_function_at(address) + if function is None: + return - # bv.parse_types_from_source returns a dict in the functions field. - # TypeParser.parse_types_from_source does not. - for function_sig, function in zip(function_sigs, parsed_types.functions): - self._function_type_cache[function_sig] = function.type + if name.startswith("_Z"): + type, demangled = demangle_gnu3(self._view.arch, name, self._view) + function.name = get_qualified_name(demangled) + # function.type = type - this does not work due to the generated types not being namespaced. :( + else: + function.name = name - # only required if supports_fake_string_segment == True - def create_fake_segment(self, name: str, size: int) -> int: - last_end_addr = self._view.mapped_address_ranges[-1].end - if last_end_addr % 0x1000 != 0: - last_end_addr += (0x1000 - (last_end_addr % 0x1000)) + def add_cross_reference(self, from_address: int, to_address: int): + self._view.add_user_data_ref(from_address, to_address) - self._view.add_user_segment(last_end_addr, size, 0, 0, SegmentFlag.SegmentContainsData) - self._view.add_user_section(name, last_end_addr, size, SectionSemantics.ReadOnlyDataSectionSemantics) - return last_end_addr - - def write_string(self, address: int, value: str) -> int: - encoded = value.encode() + b"\x00" - self._view.write(address, encoded) - return len(encoded) + def import_c_typedef(self, type_def: str): + self._view.define_user_type(None, type_def) - def write_address(self, address: int, value: int): - self._view.write(address, value.to_bytes(self._address_size, self._endianness)) + # optional + def _get_or_create_component(self, name: str): + if name in self._components: + return self._components[name] + + current = name + if current.count("/") != 0: + split_idx = current.rindex("/") + parent, child = current[:split_idx], current[split_idx:] + parent = self._get_or_create_component(name) + component = self._view.create_component(child, parent) + else: + component = self._view.create_component(name) + + self._components[name] = component + return component + + def add_function_to_group(self, address: int, group: str): + return + function = self._view.get_function_at(address) + if function is None: + return + + self._get_or_create_component(group).add_function(function) + + def cache_function_types(self, signatures: list[str]): + function_sigs = set(signatures) + if len(function_sigs) == 0: + return + + typestr = ";\n".join(function_sigs).replace("this", "_this") + ";" + parsed_types = self._parse_type_source(typestr, "cached_types.hpp") + if parsed_types is None: + return + + # bv.parse_types_from_source returns a dict in the functions field. + # TypeParser.parse_types_from_source does not. + for function_sig, function in zip(function_sigs, parsed_types.functions): + self._function_type_cache[function_sig] = function.type + + # only required if supports_fake_string_segment == True + def create_fake_segment(self, name: str, size: int) -> int: + last_end_addr = self._view.mapped_address_ranges[-1].end + if last_end_addr % 0x1000 != 0: + last_end_addr += 0x1000 - (last_end_addr % 0x1000) + + self._view.memory_map.add_memory_region( + f"mem_{name}", + last_end_addr, + bytes(size), + SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable, + ) + + self._view.add_user_section( + name, last_end_addr, size, SectionSemantics.ReadOnlyDataSectionSemantics + ) + + return last_end_addr + + def write_string(self, address: int, value: str) -> int: + encoded = value.encode() + b"\x00" + self._view.write(address, encoded) + return len(encoded) + + def write_address(self, address: int, value: int): + self._view.write(address, value.to_bytes(self._address_size, self._endianness)) class BinaryNinjaStatusHandler(BaseStatusHandler): - def __init__(self, thread: BackgroundTaskThread): - self.step = "Initializing" - self.max_items = 0 - self.current_items = 0 - self.start_time = datetime.now() - self.step_start_time = self.start_time - self.last_updated_time = datetime.min - self._thread = thread - - def initialize(self): pass + def __init__(self, thread: BackgroundTaskThread): + self.step = "Initializing" + self.max_items = 0 + self.current_items = 0 + self.start_time = datetime.now() + self.step_start_time = self.start_time + self.last_updated_time = datetime.min + self._thread = thread - def update(self): - if self.was_cancelled(): - raise RuntimeError("Cancelled script.") + def initialize(self): + pass - current_time = datetime.now() - if 0.5 > (current_time - self.last_updated_time).total_seconds(): - return + def update(self): + if self.was_cancelled(): + raise RuntimeError("Cancelled script.") - self.last_updated_time = current_time + current_time = datetime.now() + if 0.5 > (current_time - self.last_updated_time).total_seconds(): + return - step_time = current_time - self.step_start_time - total_time = current_time - self.start_time - self._thread.progress = f"Processing IL2CPP metadata: {self.step} ({self.current_items}/{self.max_items}), elapsed: {step_time} ({total_time})" + self.last_updated_time = current_time - def update_step(self, step, max_items = 0): - self.step = step - self.max_items = max_items - self.current_items = 0 - self.step_start_time = datetime.now() - self.last_updated_time = datetime.min - self.update() + step_time = current_time - self.step_start_time + total_time = current_time - self.start_time + self._thread.progress = f"Processing IL2CPP metadata: {self.step} ({self.current_items}/{self.max_items}), elapsed: {step_time} ({total_time})" - def update_progress(self, new_progress = 1): - self.current_items += new_progress - self.update() + def update_step(self, step, max_items=0): + self.step = step + self.max_items = max_items + self.current_items = 0 + self.step_start_time = datetime.now() + self.last_updated_time = datetime.min + self.update() - def was_cancelled(self): return False + def update_progress(self, new_progress=1): + self.current_items += new_progress + self.update() + + def was_cancelled(self): + return False + + def close(self): + pass - def close(self): - pass # Entry point class Il2CppTask(BackgroundTaskThread): - def __init__(self): - BackgroundTaskThread.__init__(self, "Processing IL2CPP metadata...", False) + def __init__(self): + BackgroundTaskThread.__init__(self, "Processing IL2CPP metadata...", False) - def run(self): - status = BinaryNinjaStatusHandler(self) - backend = BinaryNinjaDisassemblerInterface(status) - context = ScriptContext(backend, status) - context.process() + def run(self): + status = BinaryNinjaStatusHandler(self) + backend = BinaryNinjaDisassemblerInterface(status) + context = ScriptContext(backend, status) + context.process() -Il2CppTask().start() \ No newline at end of file + +Il2CppTask().start() diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/Targets/Ghidra.py b/Il2CppInspector.Common/Outputs/ScriptResources/Targets/Ghidra.py index df0e4a2..272f7e8 100644 --- a/Il2CppInspector.Common/Outputs/ScriptResources/Targets/Ghidra.py +++ b/Il2CppInspector.Common/Outputs/ScriptResources/Targets/Ghidra.py @@ -6,6 +6,7 @@ from ghidra.program.model.symbol import SourceType from ghidra.program.model.symbol import RefType from ghidra.app.cmd.label import DemanglerCmd from ghidra.app.services import DataTypeManagerService +from java.lang import Long #try: # from typing import TYPE_CHECKING @@ -21,6 +22,9 @@ from ghidra.app.services import DataTypeManagerService class GhidraDisassemblerInterface(BaseDisassemblerInterface): supports_fake_string_segment = False + def _to_address(self, value): + return toAddr(Long(value)) + def get_script_directory(self) -> str: return getSourceFile().getParentFile().toString() @@ -39,7 +43,7 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): # Without this, Ghidra may not analyze the binary correctly and you will just waste your time # If 0 doesn't work for you, replace it with the base address from the output of the CLI or GUI if currentProgram.getExecutableFormat().endswith('(ELF)'): - currentProgram.setImageBase(toAddr(0), True) + currentProgram.setImageBase(self._to_address(0), True) # Don't trigger decompiler setAnalysisOption(currentProgram, "Call Convention ID", "false") @@ -48,7 +52,7 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): pass def define_function(self, address: int, end: int | None = None): - address = toAddr(address) + address = self._to_address(address) # Don't override existing functions fn = getFunctionAt(address) if fn is None: @@ -61,7 +65,7 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): t = getDataTypes(type)[0] a = ArrayDataType(t, count, t.getLength()) - address = toAddr(address) + address = self._to_address(address) removeDataAt(address) createData(address, a) @@ -71,7 +75,7 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): try: t = getDataTypes(type)[0] - address = toAddr(address) + address = self._to_address(address) removeDataAt(address) createData(address, t) except: @@ -79,16 +83,16 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): def set_function_type(self, address: int, type: str): typeSig = CParserUtils.parseSignature(DataTypeManagerService@None, currentProgram, type) - ApplyFunctionSignatureCmd(toAddr(address), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram) + ApplyFunctionSignatureCmd(self._to_address(address), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram) def set_data_comment(self, address: int, cmt: str): - setEOLComment(toAddr(address), cmt) + setEOLComment(self._to_address(address), cmt) def set_function_comment(self, address: int, cmt: str): - setPlateComment(toAddr(address), cmt) + setPlateComment(self._to_address(address), cmt) def set_data_name(self, address: int, name: str): - address = toAddr(address) + address = self._to_address(address) if len(name) > 2000: print("Name length exceeds 2000 characters, skipping (%s)" % name) @@ -107,7 +111,7 @@ class GhidraDisassemblerInterface(BaseDisassemblerInterface): return self.set_data_name(address, name) def add_cross_reference(self, from_address: int, to_address: int): - self.xrefs.addMemoryReference(toAddr(from_address), toAddr(to_address), RefType.DATA, SourceType.USER_DEFINED, 0) + self.xrefs.addMemoryReference(self._to_address(from_address), self._to_address(to_address), RefType.DATA, SourceType.USER_DEFINED, 0) def import_c_typedef(self, type_def: str): # Code declarations are not supported in Ghidra diff --git a/Il2CppInspector.Common/Plugins/Internal/PluginManager.cs b/Il2CppInspector.Common/Plugins/Internal/PluginManager.cs index 991be6c..d7e53de 100644 --- a/Il2CppInspector.Common/Plugins/Internal/PluginManager.cs +++ b/Il2CppInspector.Common/Plugins/Internal/PluginManager.cs @@ -4,6 +4,11 @@ All rights reserved. */ +using Il2CppInspector.PluginAPI; +// This is the ONLY line to update when the API version changes +using Il2CppInspector.PluginAPI.V100; +using McMaster.NETCore.Plugins; +using Spectre.Console; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -12,11 +17,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using McMaster.NETCore.Plugins; -using Il2CppInspector.PluginAPI; - -// This is the ONLY line to update when the API version changes -using Il2CppInspector.PluginAPI.V100; namespace Il2CppInspector { diff --git a/Il2CppInspector.Common/Reflection/TypeInfo.cs b/Il2CppInspector.Common/Reflection/TypeInfo.cs index 21ffe19..8c991d7 100644 --- a/Il2CppInspector.Common/Reflection/TypeInfo.cs +++ b/Il2CppInspector.Common/Reflection/TypeInfo.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using Il2CppInspector.Next; using Il2CppInspector.Next.BinaryMetadata; using Il2CppInspector.Next.Metadata; @@ -784,7 +785,9 @@ namespace Il2CppInspector.Reflection // Enumerations - bit 1 of bitfield indicates this (also the baseTypeReference will be System.Enum) if (Definition.Bitfield.EnumType) { IsEnum = true; - enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.ElementTypeIndex); + + var enumUnderlyingTypeIndex = Definition.GetEnumElementTypeIndex(Assembly.Model.Package.Version); + enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, enumUnderlyingTypeIndex); } // Pass-by-reference type diff --git a/Il2CppInspector.Common/Reflection/TypeModel.cs b/Il2CppInspector.Common/Reflection/TypeModel.cs index 2cdfd7f..1dbb8b0 100644 --- a/Il2CppInspector.Common/Reflection/TypeModel.cs +++ b/Il2CppInspector.Common/Reflection/TypeModel.cs @@ -165,10 +165,9 @@ namespace Il2CppInspector.Reflection // Generic type definitions have an invoker index of -1 foreach (var method in MethodsByDefinitionIndex) { var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition); - if (index != -1) { - if (MethodInvokers[index] == null) - MethodInvokers[index] = new MethodInvoker(method, index); - + if (index != -1) + { + MethodInvokers[index] ??= new MethodInvoker(method, index); method.Invoker = MethodInvokers[index]; } } @@ -176,10 +175,11 @@ namespace Il2CppInspector.Reflection // Create method invokers sourced from generic method invoker indices foreach (var spec in GenericMethods.Keys) { if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) { - if (MethodInvokers[index] == null) - MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index); - - GenericMethods[spec].Invoker = MethodInvokers[index]; + if (index != -1) + { + MethodInvokers[index] ??= new MethodInvoker(GenericMethods[spec], index); + GenericMethods[spec].Invoker = MethodInvokers[index]; + } } } diff --git a/Il2CppInspector.Common/Utils/BlobReader.cs b/Il2CppInspector.Common/Utils/BlobReader.cs index 89e4940..882a1b9 100644 --- a/Il2CppInspector.Common/Utils/BlobReader.cs +++ b/Il2CppInspector.Common/Utils/BlobReader.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using Il2CppInspector.Next; using Il2CppInspector.Next.BinaryMetadata; using Il2CppInspector.Next.Metadata; +using Spectre.Console; namespace Il2CppInspector.Utils; @@ -122,7 +123,7 @@ public static class BlobReader } catch (InvalidDataException) { - Console.WriteLine($"Found invalid compressed int at metadata address 0x{address:x8}. Reading as normal int."); + AnsiConsole.WriteLine($"Found invalid compressed int at metadata address 0x{address:x8}. Reading as normal int."); return blob.ReadInt32(address); } } @@ -142,7 +143,7 @@ public static class BlobReader } catch (InvalidDataException) { - Console.WriteLine($"Found invalid compressed uint at metadata address 0x{address:x8}. Reading as normal uint."); + AnsiConsole.WriteLine($"Found invalid compressed uint at metadata address 0x{address:x8}. Reading as normal uint."); return blob.ReadUInt32(address); } } @@ -163,7 +164,9 @@ public static class BlobReader var typeHandle = inspector.TypeReferences[typeIndex].Data.KlassIndex; enumType = inspector.TypeDefinitions[typeHandle]; - var elementTypeHandle = inspector.TypeReferences[enumType.ElementTypeIndex].Data.KlassIndex; + var elementTypeIndex = enumType.GetEnumElementTypeIndex(inspector.Version); + + var elementTypeHandle = inspector.TypeReferences[elementTypeIndex].Data.KlassIndex; var elementType = inspector.TypeDefinitions[elementTypeHandle]; typeEnum = inspector.TypeReferences[elementType.ByValTypeIndex].Type; } diff --git a/Il2CppInspector.Redux.CLI/CliClient.cs b/Il2CppInspector.Redux.CLI/CliClient.cs new file mode 100644 index 0000000..b88f5fa --- /dev/null +++ b/Il2CppInspector.Redux.CLI/CliClient.cs @@ -0,0 +1,136 @@ +using System.Threading.Channels; +using Il2CppInspector.Redux.FrontendCore; +using Microsoft.AspNetCore.SignalR.Client; +using Spectre.Console; + +namespace Il2CppInspector.Redux.CLI; + +public class CliClient : IDisposable +{ + public bool ImportCompleted { get; private set; } + + private volatile int _finishedLoadingCount = 0; + + private readonly HubConnection _connection; + private readonly List _commandListeners = []; + + private Channel? _logMessageChannel; + + public CliClient(HubConnection connection) + { + _connection = connection; + + _commandListeners.Add(_connection.On(nameof(UiClient.ShowLogMessage), ShowLogMessage)); + _commandListeners.Add(_connection.On(nameof(UiClient.BeginLoading), BeginLoading)); + _commandListeners.Add(_connection.On(nameof(UiClient.FinishLoading), FinishLoading)); + _commandListeners.Add(_connection.On(nameof(UiClient.ShowInfoToast), ShowInfoToast)); + _commandListeners.Add(_connection.On(nameof(UiClient.ShowSuccessToast), ShowSuccessToast)); + _commandListeners.Add(_connection.On(nameof(UiClient.ShowErrorToast), ShowErrorToast)); + _commandListeners.Add(_connection.On(nameof(UiClient.OnImportCompleted), OnImportCompleted)); + } + + public async ValueTask OnUiLaunched(CancellationToken cancellationToken = default) + { + await _connection.InvokeAsync(nameof(Il2CppHub.OnUiLaunched), cancellationToken); + } + + public async ValueTask SubmitInputFiles(List inputFiles, CancellationToken cancellationToken = default) + { + await _connection.InvokeAsync(nameof(Il2CppHub.SubmitInputFiles), inputFiles, cancellationToken); + } + + public async ValueTask QueueExport(string exportTypeId, string outputDirectory, Dictionary settings, + CancellationToken cancellationToken = default) + { + await _connection.InvokeAsync(nameof(Il2CppHub.QueueExport), exportTypeId, outputDirectory, settings, cancellationToken); + } + + public async ValueTask StartExport(CancellationToken cancellationToken = default) + { + await _connection.InvokeAsync(nameof(Il2CppHub.StartExport), cancellationToken); + } + + public async ValueTask> GetPotentialUnityVersions(CancellationToken cancellationToken = default) + => await _connection.InvokeAsync>(nameof(Il2CppHub.GetPotentialUnityVersions), cancellationToken); + + public async ValueTask ExportIl2CppFiles(string outputDirectory, CancellationToken cancellationToken = default) + { + await _connection.InvokeAsync(nameof(Il2CppHub.ExportIl2CppFiles), outputDirectory, cancellationToken); + } + + public async ValueTask GetInspectorVersion(CancellationToken cancellationToken = default) + => await _connection.InvokeAsync(nameof(Il2CppHub.GetInspectorVersion), cancellationToken); + + public async ValueTask WaitForLoadingToFinishAsync(CancellationToken cancellationToken = default) + { + var currentLoadingCount = _finishedLoadingCount; + while (_finishedLoadingCount == currentLoadingCount) + await Task.Delay(10, cancellationToken); + } + + private async Task ShowLogMessage(string message) + { + if (_logMessageChannel == null) + { + AnsiConsole.MarkupLine($"[white bold]{message}[/]"); + return; + } + + await _logMessageChannel.Writer.WriteAsync(message); + } + + private void BeginLoading() + { + _logMessageChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleReader = true, + SingleWriter = true, + AllowSynchronousContinuations = true + }); + + AnsiConsole.Status() + .Spinner(Spinner.Known.Triangle) + .StartAsync("Loading", async ctx => + { + await foreach (var newLogMessage in _logMessageChannel.Reader.ReadAllAsync()) + { + ctx.Status(newLogMessage); + } + }); + } + + private void FinishLoading() + { + _logMessageChannel?.Writer.Complete(); + Interlocked.Increment(ref _finishedLoadingCount); + } + + private static void ShowInfoToast(string message) + { + AnsiConsole.MarkupLineInterpolated($"[bold white]INFO: {message}[/]"); + } + + private static void ShowSuccessToast(string message) + { + AnsiConsole.MarkupLineInterpolated($"[bold][green]SUCCESS: [/] [white]{message}[/][/]"); + } + + private static void ShowErrorToast(string message) + { + AnsiConsole.MarkupLineInterpolated($"[bold][red]ERROR: [/] [white]{message}[/][/]"); + } + + private void OnImportCompleted() + { + ImportCompleted = true; + } + + + public void Dispose() + { + GC.SuppressFinalize(this); + + foreach (var listener in _commandListeners) + listener.Dispose(); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Commands/BaseCommand.cs b/Il2CppInspector.Redux.CLI/Commands/BaseCommand.cs new file mode 100644 index 0000000..6987149 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Commands/BaseCommand.cs @@ -0,0 +1,38 @@ +using Il2CppInspector.Redux.FrontendCore; +using Microsoft.AspNetCore.SignalR.Client; +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI.Commands; + +internal abstract class BaseCommand(PortProvider portProvider) : AsyncCommand where T : CommandSettings +{ + private const string HubPath = "/il2cpp"; // TODO: Make this into a shared constant + + private readonly int _serverPort = portProvider.Port; + + protected abstract Task ExecuteAsync(CliClient client, T settings); + + public override async Task ExecuteAsync(CommandContext context, T settings) + { + var connection = new HubConnectionBuilder().WithUrl($"http://localhost:{_serverPort}{HubPath}") + .AddJsonProtocol(options => + { + options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, + FrontendCoreJsonSerializerContext.Default); + }) + .Build(); + + await connection.StartAsync(); + + int result; + using (var client = new CliClient(connection)) + { + await client.OnUiLaunched(); + result = await ExecuteAsync(client, settings); + } + + await connection.StopAsync(); + + return result; + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Commands/InteractiveCommand.cs b/Il2CppInspector.Redux.CLI/Commands/InteractiveCommand.cs new file mode 100644 index 0000000..e61447a --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Commands/InteractiveCommand.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.SignalR.Client; +using Spectre.Console; +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI.Commands; + +internal class InteractiveCommand(PortProvider portProvider) : BaseCommand(portProvider) +{ + public class Options : CommandSettings; + + protected override async Task ExecuteAsync(CliClient client, Options settings) + { + await Task.Delay(1000); + await AnsiConsole.AskAsync("meow?"); + return 0; + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Commands/ManualCommand.cs b/Il2CppInspector.Redux.CLI/Commands/ManualCommand.cs new file mode 100644 index 0000000..7bc888e --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Commands/ManualCommand.cs @@ -0,0 +1,21 @@ +using Spectre.Console; +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI.Commands; + +internal abstract class ManualCommand(PortProvider portProvider) : BaseCommand(portProvider) where T : ManualCommandOptions +{ + public override ValidationResult Validate(CommandContext context, T settings) + { + foreach (var inputPath in settings.InputPaths) + { + if (!Path.Exists(inputPath)) + return ValidationResult.Error($"Provided input path {inputPath} does not exit."); + } + + if (File.Exists(settings.OutputPath)) + return ValidationResult.Error("Provided output path already exists as a file."); + + return ValidationResult.Success(); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Commands/ManualCommandOptions.cs b/Il2CppInspector.Redux.CLI/Commands/ManualCommandOptions.cs new file mode 100644 index 0000000..b8902c8 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Commands/ManualCommandOptions.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI.Commands; + +internal class ManualCommandOptions : CommandSettings +{ + [CommandArgument(0, "")] + [Description("Paths to the input files. Will be subsequently loaded until binary and metadata were found.")] + public string[] InputPaths { get; init; } = []; + + [CommandOption("-o|--output")] + [Description("Path to the output folder")] + public string OutputPath { get; init; } = ""; +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Commands/ProcessCommand.cs b/Il2CppInspector.Redux.CLI/Commands/ProcessCommand.cs new file mode 100644 index 0000000..cd325d2 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Commands/ProcessCommand.cs @@ -0,0 +1,172 @@ +using Il2CppInspector.Cpp; +using Il2CppInspector.Redux.FrontendCore.Outputs; +using Spectre.Console; +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI.Commands; + +internal class ProcessCommand(PortProvider portProvider) : ManualCommand(portProvider) +{ + // NOTE: There might be a better option than replicating all available flags here (and in the TS UI). + // Investigate this in the future. + + public class Option : ManualCommandOptions + { + // C++ Scaffolding + [CommandOption("--output-cpp-scaffolding")] + public bool CppScaffolding { get; init; } = false; + + [CommandOption("--unity-version")] + public string? UnityVersion { get; init; } + + [CommandOption("--compiler-type")] + public CppCompilerType CompilerType { get; init; } = CppCompilerType.GCC; + + // C# stub + [CommandOption("-s|--output-csharp-stub")] + public bool CSharpStubs { get; init; } = false; + + [CommandOption("--layout")] + public CSharpLayout Layout { get; init; } = CSharpLayout.SingleFile; + + [CommandOption("--flatten-hierarchy")] + public bool FlattenHierarchy { get; init; } = false; + + [CommandOption("--sorting-mode")] + public TypeSortingMode SortingMode { get; init; } = TypeSortingMode.Alphabetical; + + [CommandOption("--suppress-metadata")] + public bool SuppressMetadata { get; init; } = false; + + [CommandOption("--compilable")] + public bool MustCompile { get; init; } = false; + + [CommandOption("--separate-assembly-attributes")] + public bool SeparateAssemblyAttributes { get; init; } = true; + + // Disassembler metadata + [CommandOption("-m|--output-disassembler-metadata")] + public bool DisassemblerMetadata { get; init; } = false; + + [CommandOption("--disassembler")] + public DisassemblerType Disassembler { get; init; } = DisassemblerType.IDA; + + // Dummy DLL output + [CommandOption("-d|--output-dummy-dlls")] + public bool DummyDlls { get; init; } = false; + + // Visual Studio solution + [CommandOption("--output-vs-solution")] + public bool VsSolution { get; init; } = false; + + [CommandOption("--unity-path")] + public string? UnityPath { get; init; } + + [CommandOption("--unity-assemblies-path")] + public string? UnityAssembliesPath { get; init; } + + [CommandOption("--extract-il2cpp-files")] + public string? ExtractIl2CppFilesPath { get; init; } + } + + protected override async Task ExecuteAsync(CliClient client, Option settings) + { + var inspectorVersion = await client.GetInspectorVersion(); + AnsiConsole.MarkupLineInterpolated($"Using inspector [gray]{inspectorVersion}[/]"); + + await client.SubmitInputFiles(settings.InputPaths.ToList()); + await client.WaitForLoadingToFinishAsync(); + if (!client.ImportCompleted) + { + AnsiConsole.MarkupLine("[bold][red]FAILED[/] to load IL2CPP data from the given inputs.[/]"); + return 1; + } + + if (settings.ExtractIl2CppFilesPath != null) + { + await client.ExportIl2CppFiles(settings.ExtractIl2CppFilesPath); + await client.WaitForLoadingToFinishAsync(); + } + + var unityVersions = await client.GetPotentialUnityVersions(); + + if (settings.CppScaffolding) + { + var directory = Path.Join(settings.OutputPath, "cpp"); + await client.QueueExport(CppScaffoldingOutput.Id, directory, new Dictionary + { + ["unityversion"] = settings.UnityVersion ?? unityVersions.First(), + ["compilertype"] = settings.CompilerType.ToString() + }); + } + + if (settings.CSharpStubs) + { + var directory = Path.Join(settings.OutputPath, "cs"); + await client.QueueExport(CSharpStubOutput.Id, directory, new Dictionary + { + ["layout"] = settings.Layout.ToString(), + ["flattenhierarchy"] = settings.FlattenHierarchy.ToString(), + ["sortingmode"] = settings.SortingMode.ToString(), + ["suppressmetadata"] = settings.SuppressMetadata.ToString(), + ["mustcompile"] = settings.MustCompile.ToString(), + ["separateassemblyattributes"] = settings.SeparateAssemblyAttributes.ToString() + }); + } + + if (settings.DisassemblerMetadata) + { + await client.QueueExport(DisassemblerMetadataOutput.Id, settings.OutputPath, + new Dictionary + { + ["disassembler"] = settings.Disassembler.ToString(), + ["unityversion"] = settings.UnityVersion ?? unityVersions.First() + }); + } + + if (settings.DummyDlls) + { + var directory = Path.Join(settings.OutputPath, "dll"); + await client.QueueExport(DummyDllOutput.Id, directory, new Dictionary + { + ["suppressmetadata"] = settings.SuppressMetadata.ToString() + }); + } + + if (settings.VsSolution) + { + var directory = Path.Join(settings.OutputPath, "vs"); + await client.QueueExport(VsSolutionOutput.Id, directory, new Dictionary + { + ["unitypath"] = settings.UnityPath ?? "", + ["unityassembliespath"] = settings.UnityAssembliesPath ?? "" + }); + } + + await client.StartExport(); + await client.WaitForLoadingToFinishAsync(); + return 0; + } + + public override ValidationResult Validate(CommandContext context, Option settings) + { + if (settings.UnityPath != null && !Path.Exists(settings.UnityPath)) + return ValidationResult.Error($"Provided Unity path {settings.UnityPath} does not exist."); + + if (settings.UnityAssembliesPath != null && !Path.Exists(settings.UnityAssembliesPath)) + return ValidationResult.Error($"Provided Unity assemblies path {settings.UnityAssembliesPath} does not exist."); + + if (settings.ExtractIl2CppFilesPath != null && File.Exists(settings.ExtractIl2CppFilesPath)) + return ValidationResult.Error( + $"Provided extracted IL2CPP files path {settings.ExtractIl2CppFilesPath} already exists as a file."); + + if (settings is + { + CppScaffolding: false, CSharpStubs: false, DisassemblerMetadata: false, DummyDlls: false, + VsSolution: false + }) + return ValidationResult.Error("At least one output format must be specified."); + + return base.Validate(context, settings); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Il2CppInspector.Redux.CLI.csproj b/Il2CppInspector.Redux.CLI/Il2CppInspector.Redux.CLI.csproj new file mode 100644 index 0000000..5ed76be --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Il2CppInspector.Redux.CLI.csproj @@ -0,0 +1,21 @@ + + + + net9.0 + enable + enable + true + false + true + + + + + + + + + + + + diff --git a/Il2CppInspector.Redux.CLI/PortProvider.cs b/Il2CppInspector.Redux.CLI/PortProvider.cs new file mode 100644 index 0000000..56f28a7 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/PortProvider.cs @@ -0,0 +1,6 @@ +namespace Il2CppInspector.Redux.CLI; + +internal sealed class PortProvider(int port) +{ + public int Port => port; +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Program.cs b/Il2CppInspector.Redux.CLI/Program.cs new file mode 100644 index 0000000..f8d8f7a --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Program.cs @@ -0,0 +1,46 @@ +using Il2CppInspector.Redux.CLI; +using Il2CppInspector.Redux.CLI.Commands; +using Il2CppInspector.Redux.FrontendCore; +using Microsoft.AspNetCore.SignalR; +using Spectre.Console.Cli; + +var builder = WebApplication.CreateSlimBuilder(); + +builder.Services.ConfigureHttpJsonOptions(options => +{ + options.SerializerOptions.TypeInfoResolverChain.Insert(0, FrontendCoreJsonSerializerContext.Default); +}); + +builder.Services.Configure(options => +{ + options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, FrontendCoreJsonSerializerContext.Default); +}); + +builder.Services.AddFrontendCore(); +builder.Logging.ClearProviders(); + +var app = builder.Build(); + +app.UseCors(); + +app.MapFrontendCore(); + +await app.StartAsync(); + +var serverUrl = app.Urls.First(); +var port = new Uri(serverUrl).Port; + +var commandServiceProvider = new ServiceCollection(); +commandServiceProvider.AddSingleton(new PortProvider(port)); + +var commandTypeRegistrar = new ServiceTypeRegistrar(commandServiceProvider); +var consoleApp = new CommandApp(commandTypeRegistrar); + +consoleApp.Configure(config => +{ + config.AddCommand("process") + .WithDescription("Processes the provided input data into one or more output formats."); +}); + +await consoleApp.RunAsync(args); +await app.StopAsync(); \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/Properties/launchSettings.json b/Il2CppInspector.Redux.CLI/Properties/launchSettings.json new file mode 100644 index 0000000..1677dac --- /dev/null +++ b/Il2CppInspector.Redux.CLI/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "profiles": { + "WSL": { + "commandName": "WSL2", + "launchUrl": "http://localhost:5118/", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "http://localhost:5118" + }, + "distributionName": "" + }, + "http": { + "commandName": "Project", + "commandLineArgs": "process -d --disassembler ghidra M:\\Downloads\\Reversing\\NotYetAnalyzedAPKs\\pokemon_friends\\libil2cpp.so M:\\Downloads\\Reversing\\NotYetAnalyzedAPKs\\pokemon_friends\\global-metadata.dat", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5118" + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json" +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/ServiceTypeRegistrar.cs b/Il2CppInspector.Redux.CLI/ServiceTypeRegistrar.cs new file mode 100644 index 0000000..a595c55 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/ServiceTypeRegistrar.cs @@ -0,0 +1,30 @@ +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI; + +public class ServiceTypeRegistrar(IServiceCollection serviceCollection) : ITypeRegistrar +{ + private readonly IServiceCollection _serviceCollection = serviceCollection; + private ServiceTypeResolver? _resolver; + + public void Register(Type service, Type implementation) + { + _serviceCollection.AddSingleton(service, implementation); + } + + public void RegisterInstance(Type service, object implementation) + { + _serviceCollection.AddSingleton(service, implementation); + } + + public void RegisterLazy(Type service, Func factory) + { + _serviceCollection.AddSingleton(service, _ => factory()); + } + + public ITypeResolver Build() + { + _resolver ??= new ServiceTypeResolver(_serviceCollection.BuildServiceProvider()); + return _resolver; + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/ServiceTypeResolver.cs b/Il2CppInspector.Redux.CLI/ServiceTypeResolver.cs new file mode 100644 index 0000000..303115c --- /dev/null +++ b/Il2CppInspector.Redux.CLI/ServiceTypeResolver.cs @@ -0,0 +1,13 @@ +using Spectre.Console.Cli; + +namespace Il2CppInspector.Redux.CLI; + +public class ServiceTypeResolver(IServiceProvider serviceProvider) : ITypeResolver +{ + private readonly IServiceProvider _serviceProvider = serviceProvider; + + public object? Resolve(Type? type) + => type == null + ? null + : _serviceProvider.GetService(type); +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.CLI/appsettings.Development.json b/Il2CppInspector.Redux.CLI/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Il2CppInspector.Redux.CLI/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Il2CppInspector.Redux.CLI/appsettings.json b/Il2CppInspector.Redux.CLI/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Il2CppInspector.Redux.CLI/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Il2CppInspector.Redux.FrontendCore/Extensions.cs b/Il2CppInspector.Redux.FrontendCore/Extensions.cs new file mode 100644 index 0000000..717c3e4 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Extensions.cs @@ -0,0 +1,54 @@ +using System.Reflection; + +namespace Il2CppInspector.Redux.FrontendCore; + +public static class Extensions +{ + internal static bool GetAsBooleanOrDefault(this Dictionary dict, string key, bool defaultValue) + { + if (dict.TryGetValue(key, out var value) && bool.TryParse(value, out var boolResult)) + return boolResult; + + return defaultValue; + } + + internal static T GetAsEnumOrDefault(this Dictionary dict, string key, T defaultValue) + where T : struct, Enum + { + if (dict.TryGetValue(key, out var value) && Enum.TryParse(value, true, out var enumResult)) + return enumResult; + + return defaultValue; + } + + internal static string? GetAssemblyVersion(this Assembly assembly) + => assembly.GetCustomAttribute()?.InformationalVersion; + + public static WebApplication MapFrontendCore(this WebApplication app) + { + app.MapHub("/il2cpp"); + return app; + } + + public static IServiceCollection AddFrontendCore(this IServiceCollection services) + { + services.AddSignalR(config => + { +#if DEBUG + config.EnableDetailedErrors = true; +#endif + }); + + return services.AddCors(options => + { + options.AddDefaultPolicy(policy => + { + policy.SetIsOriginAllowed(origin => + origin.StartsWith("http://localhost") || origin.StartsWith("http://tauri.localhost")) + .AllowAnyHeader() + .WithMethods("GET", "POST") + .AllowCredentials(); + }); + }); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/FrontendCoreJsonSerializerContext.cs b/Il2CppInspector.Redux.FrontendCore/FrontendCoreJsonSerializerContext.cs new file mode 100644 index 0000000..50e88b2 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/FrontendCoreJsonSerializerContext.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Il2CppInspector.Redux.FrontendCore; + +[JsonSerializable(typeof(string))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Dictionary))] +public partial class FrontendCoreJsonSerializerContext : JsonSerializerContext; \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Il2CppHub.cs b/Il2CppInspector.Redux.FrontendCore/Il2CppHub.cs new file mode 100644 index 0000000..35bb7ef --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Il2CppHub.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.SignalR; + +namespace Il2CppInspector.Redux.FrontendCore; + +public class Il2CppHub : Hub +{ + private const string ContextKey = "context"; + + private UiContext State + { + get + { + if (!Context.Items.TryGetValue(ContextKey, out var context) + || context is not UiContext ctx) + { + Context.Items[ContextKey] = ctx = new UiContext(); + } + + return ctx; + } + } + + private UiClient Client => new(Clients.Caller); + + public async Task OnUiLaunched() + { + await State.Initialize(Client); + } + + public async Task SubmitInputFiles(List inputFiles) + { + await State.LoadInputFiles(Client, inputFiles); + } + + public async Task QueueExport(string exportTypeId, string outputDirectory, Dictionary settings) + { + await State.QueueExport(Client, exportTypeId, outputDirectory, settings); + } + + public async Task StartExport() + { + await State.StartExport(Client); + } + + public async Task> GetPotentialUnityVersions() + { + return await State.GetPotentialUnityVersions(); + } + + public async Task ExportIl2CppFiles(string outputDirectory) + { + await State.ExportIl2CppFiles(Client, outputDirectory); + } + public async Task GetInspectorVersion() + { + return await UiContext.GetInspectorVersion(); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Il2CppInspector.Redux.FrontendCore.csproj b/Il2CppInspector.Redux.FrontendCore/Il2CppInspector.Redux.FrontendCore.csproj new file mode 100644 index 0000000..037937b --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Il2CppInspector.Redux.FrontendCore.csproj @@ -0,0 +1,16 @@ + + + + net9.0 + enable + enable + true + Library + + + + + + + + diff --git a/Il2CppInspector.Redux.FrontendCore/LoadingSession.cs b/Il2CppInspector.Redux.FrontendCore/LoadingSession.cs new file mode 100644 index 0000000..d53bb21 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/LoadingSession.cs @@ -0,0 +1,23 @@ +namespace Il2CppInspector.Redux.FrontendCore; + +public class LoadingSession : IAsyncDisposable +{ + private readonly UiClient _client; + + private LoadingSession(UiClient client) + { + _client = client; + } + + public static async Task Start(UiClient client) + { + await client.BeginLoading(); + return new LoadingSession(client); + } + + public async ValueTask DisposeAsync() + { + await _client.FinishLoading(); + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpLayout.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpLayout.cs new file mode 100644 index 0000000..3dfaa02 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpLayout.cs @@ -0,0 +1,10 @@ +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public enum CSharpLayout +{ + SingleFile, + Namespace, + Assembly, + Class, + Tree +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpStubOutput.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpStubOutput.cs new file mode 100644 index 0000000..b24c124 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/CSharpStubOutput.cs @@ -0,0 +1,66 @@ +using Il2CppInspector.Model; +using Il2CppInspector.Outputs; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public class CSharpStubOutput : IOutputFormatProvider +{ + public static string Id => "cs"; + + private class Settings(Dictionary settings) + { + public readonly CSharpLayout Layout = settings.GetAsEnumOrDefault("layout", CSharpLayout.SingleFile); + public readonly bool FlattenHierarchy = settings.GetAsBooleanOrDefault("flattenhierarchy", false); + public readonly TypeSortingMode SortingMode = settings.GetAsEnumOrDefault("sortingmode", TypeSortingMode.Alphabetical); + public readonly bool SuppressMetadata = settings.GetAsBooleanOrDefault("suppressmetadata", false); + public readonly bool MustCompile = settings.GetAsBooleanOrDefault("mustcompile", false); + public readonly bool SeperateAssemblyAttributes = settings.GetAsBooleanOrDefault("seperateassemblyattributes", true); + } + + public async Task Export(AppModel model, UiClient client, string outputPath, Dictionary settingsDict) + { + var settings = new Settings(settingsDict); + + var writer = new CSharpCodeStubs(model.TypeModel) + { + SuppressMetadata = settings.SuppressMetadata, + MustCompile = settings.MustCompile + }; + + await client.ShowLogMessage("Writing C# type definitions"); + + var outputPathFile = Path.Join(outputPath, "il2cpp.cs"); + + switch (settings.Layout, settings.SortingMode) + { + case (CSharpLayout.SingleFile, TypeSortingMode.TypeDefinitionIndex): + writer.WriteSingleFile(outputPathFile, info => info.Index); + break; + case (CSharpLayout.SingleFile, TypeSortingMode.Alphabetical): + writer.WriteSingleFile(outputPathFile, info => info.Name); + break; + + case (CSharpLayout.Namespace, TypeSortingMode.TypeDefinitionIndex): + writer.WriteFilesByNamespace(outputPath, info => info.Index, settings.FlattenHierarchy); + break; + case (CSharpLayout.Namespace, TypeSortingMode.Alphabetical): + writer.WriteFilesByNamespace(outputPath, info => info.Name, settings.FlattenHierarchy); + break; + + case (CSharpLayout.Assembly, TypeSortingMode.TypeDefinitionIndex): + writer.WriteFilesByAssembly(outputPath, info => info.Index, settings.SeperateAssemblyAttributes); + break; + case (CSharpLayout.Assembly, TypeSortingMode.Alphabetical): + writer.WriteFilesByAssembly(outputPath, info => info.Name, settings.SeperateAssemblyAttributes); + break; + + case (CSharpLayout.Class, _): + writer.WriteFilesByClass(outputPath, settings.FlattenHierarchy); + break; + + case (CSharpLayout.Tree, _): + writer.WriteFilesByClassTree(outputPath, settings.SeperateAssemblyAttributes); + break; + } + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/CppScaffoldingOutput.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/CppScaffoldingOutput.cs new file mode 100644 index 0000000..991b55e --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/CppScaffoldingOutput.cs @@ -0,0 +1,31 @@ +using Il2CppInspector.Cpp; +using Il2CppInspector.Cpp.UnityHeaders; +using Il2CppInspector.Model; +using Il2CppInspector.Outputs; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public class CppScaffoldingOutput : IOutputFormatProvider +{ + public static string Id => "cppscaffolding"; + + private class Settings(Dictionary settings) + { + public readonly string UnityVersion = settings.GetValueOrDefault("unityversion", ""); + public readonly CppCompilerType Compiler = settings.GetAsEnumOrDefault("compiler", CppCompilerType.GCC); + } + + public async Task Export(AppModel model, UiClient client, string outputPath, Dictionary settingsDict) + { + var settings = new Settings(settingsDict); + + await client.ShowLogMessage($"Building application model for Unity {settings.UnityVersion}/{settings.Compiler}"); + model.Build(new UnityVersion(settings.UnityVersion), settings.Compiler); + + await client.ShowLogMessage("Generating C++ scaffolding"); + var scaffolding = new CppScaffolding(model); + + await client.ShowLogMessage("Writing C++ scaffolding"); + scaffolding.Write(outputPath); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerMetadataOutput.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerMetadataOutput.cs new file mode 100644 index 0000000..a088908 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerMetadataOutput.cs @@ -0,0 +1,53 @@ +using Il2CppInspector.Cpp; +using Il2CppInspector.Cpp.UnityHeaders; +using Il2CppInspector.Model; +using Il2CppInspector.Outputs; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public class DisassemblerMetadataOutput : IOutputFormatProvider +{ + public static string Id => "disassemblermetadata"; + + private class Settings(Dictionary dict) + { + public readonly DisassemblerType Disassembler = dict.GetAsEnumOrDefault("disassembler", DisassemblerType.IDA); + public readonly string UnityVersion = dict.GetValueOrDefault("unityversion", ""); + } + + public async Task Export(AppModel model, UiClient client, string outputPath, Dictionary settingsDict) + { + var settings = new Settings(settingsDict); + + await client.ShowLogMessage($"Building application model for Unity {settings.UnityVersion}/{CppCompilerType.GCC}"); + model.Build(new UnityVersion(settings.UnityVersion), CppCompilerType.GCC); + + var headerPath = Path.Join(outputPath, "il2cpp.h"); + { + await client.ShowLogMessage("Generating C++ types"); + var cppScaffolding = new CppScaffolding(model, useBetterArraySize: true); + + await client.ShowLogMessage("Writing C++ types"); + cppScaffolding.WriteTypes(headerPath); + } + + var metadataPath = Path.Join(outputPath, "il2cpp.json"); + { + await client.ShowLogMessage("Generating disassembler metadata"); + var jsonMetadata = new JSONMetadata(model); + + await client.ShowLogMessage("Writing disassembler metadata"); + jsonMetadata.Write(metadataPath); + } + + if (settings.Disassembler != DisassemblerType.None) + { + var scriptPath = Path.Join(outputPath, "il2cpp.py"); + await client.ShowLogMessage($"Generating python script for {settings.Disassembler}"); + var script = new PythonScript(model); + + await client.ShowLogMessage($"Writing python script for {settings.Disassembler}"); + script.WriteScriptToFile(scriptPath, settings.Disassembler.ToString(), headerPath, metadataPath); + } + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerType.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerType.cs new file mode 100644 index 0000000..4d7e4d9 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/DisassemblerType.cs @@ -0,0 +1,9 @@ +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public enum DisassemblerType +{ + IDA, + Ghidra, + BinaryNinja, + None +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/DummyDllOutput.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/DummyDllOutput.cs new file mode 100644 index 0000000..b8b98dd --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/DummyDllOutput.cs @@ -0,0 +1,27 @@ +using Il2CppInspector.Model; +using Il2CppInspector.Outputs; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public class DummyDllOutput : IOutputFormatProvider +{ + public static string Id => "dummydlls"; + + private class Settings(Dictionary dict) + { + public readonly bool SuppressMetadata = dict.GetAsBooleanOrDefault("suppressmetadata", false); + } + + public async Task Export(AppModel model, UiClient client, string outputPath, Dictionary settingsDict) + { + var outputSettings = new Settings(settingsDict); + + await client.ShowLogMessage("Generating .NET dummy assemblies"); + var shims = new AssemblyShims(model.TypeModel) + { + SuppressMetadata = outputSettings.SuppressMetadata + }; + + shims.Write(outputPath, client.EventHandler); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/IOutputFormat.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/IOutputFormat.cs new file mode 100644 index 0000000..3df6024 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/IOutputFormat.cs @@ -0,0 +1,14 @@ +using Il2CppInspector.Model; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public interface IOutputFormat +{ + public Task Export(AppModel model, UiClient client, string outputPath, + Dictionary settingsDict); +} + +public interface IOutputFormatProvider : IOutputFormat +{ + public static abstract string Id { get; } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/OutputFormatRegistry.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/OutputFormatRegistry.cs new file mode 100644 index 0000000..0e25611 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/OutputFormatRegistry.cs @@ -0,0 +1,38 @@ +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public static class OutputFormatRegistry +{ + public static IEnumerable AvailableOutputFormats => OutputFormats.Keys; + + private static readonly Dictionary OutputFormats = []; + + public static void RegisterOutputFormat() where T : IOutputFormatProvider, new() + { + if (OutputFormats.ContainsKey(T.Id)) + throw new InvalidOperationException("An output format with this id was already registered."); + + OutputFormats[T.Id] = new T(); + } + + public static IOutputFormat GetOutputFormat(string id) + { + if (!OutputFormats.TryGetValue(id, out var format)) + throw new ArgumentException($"Failed to find output format for id {id}", nameof(id)); + + return format; + } + + private static void RegisterBuiltinOutputFormats() + { + RegisterOutputFormat(); + RegisterOutputFormat(); + RegisterOutputFormat(); + RegisterOutputFormat(); + RegisterOutputFormat(); + } + + static OutputFormatRegistry() + { + RegisterBuiltinOutputFormats(); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/TypeSortingMode.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/TypeSortingMode.cs new file mode 100644 index 0000000..a14abb1 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/TypeSortingMode.cs @@ -0,0 +1,7 @@ +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public enum TypeSortingMode +{ + Alphabetical, + TypeDefinitionIndex +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Outputs/VsSolutionOutput.cs b/Il2CppInspector.Redux.FrontendCore/Outputs/VsSolutionOutput.cs new file mode 100644 index 0000000..2dac1b0 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Outputs/VsSolutionOutput.cs @@ -0,0 +1,29 @@ +using Il2CppInspector.Model; +using Il2CppInspector.Outputs; + +namespace Il2CppInspector.Redux.FrontendCore.Outputs; + +public class VsSolutionOutput : IOutputFormatProvider +{ + public static string Id => "vssolution"; + + private class Settings(Dictionary settings) + { + public readonly string UnityPath = settings.GetValueOrDefault("unitypath", ""); + public readonly string UnityAssembliesPath = settings.GetValueOrDefault("unityassembliespath", ""); + } + + public async Task Export(AppModel model, UiClient client, string outputPath, Dictionary settingsDict) + { + var settings = new Settings(settingsDict); + + var writer = new CSharpCodeStubs(model.TypeModel) + { + MustCompile = true, + SuppressMetadata = true + }; + + await client.ShowLogMessage("Writing Visual Studio solution"); + writer.WriteSolution(outputPath, settings.UnityPath, settings.UnityAssembliesPath); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/PathHeuristics.cs b/Il2CppInspector.Redux.FrontendCore/PathHeuristics.cs new file mode 100644 index 0000000..bc0d9fb --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/PathHeuristics.cs @@ -0,0 +1,54 @@ +namespace Il2CppInspector.Redux.FrontendCore; + +public static class PathHeuristics +{ + private static readonly string[] AllowedMetadataExtensionComponents = + [ + "dat", "dec" + ]; + + private static readonly string[] AllowedMetadataNameComponents = + [ + "metadata" + ]; + + private static readonly string[] AllowedBinaryPathComponents = + [ + "GameAssembly", + "il2cpp", + "UnityFramework" + ]; + + private static readonly string[] AllowedBinaryExtensionComponents = + [ + "dll", "so", "exe", "bin", "prx", "sprx", "dylib" + ]; + + public static bool IsMetadataPath(string path) + { + var extension = Path.GetExtension(path); + if (AllowedMetadataExtensionComponents.Any(extension.Contains)) + return true; + + var filename = Path.GetFileNameWithoutExtension(path); + if (AllowedMetadataNameComponents.Any(filename.Contains)) + return true; + + return false; + } + + public static bool IsBinaryPath(string path) + { + var extension = Path.GetExtension(path); + + // empty to allow macho binaries which do not have an extension + if (extension == "" || AllowedBinaryExtensionComponents.Any(extension.Contains)) + return true; + + var filename = Path.GetFileNameWithoutExtension(path); + if (AllowedBinaryPathComponents.Any(filename.Contains)) + return true; + + return false; + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/Properties/launchSettings.json b/Il2CppInspector.Redux.FrontendCore/Properties/launchSettings.json new file mode 100644 index 0000000..6902527 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Il2CppInspector.Redux.FrontendCore": { + "commandName": "Project", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:43298;http://localhost:43299" + } + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/UiClient.cs b/Il2CppInspector.Redux.FrontendCore/UiClient.cs new file mode 100644 index 0000000..1aeb23a --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/UiClient.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.SignalR; + +namespace Il2CppInspector.Redux.FrontendCore; + +public class UiClient(ISingleClientProxy client) +{ + private EventHandler? _handler; + + public EventHandler EventHandler + { + get + { + _handler ??= (_, status) => + { +#pragma warning disable CS4014 + ShowLogMessage(status); +#pragma warning restore CS4014 + }; + + return _handler; + } + } + + public async Task ShowLogMessage(string message, CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(ShowLogMessage), message, cancellationToken); + + public async Task BeginLoading(CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(BeginLoading), cancellationToken); + + public async Task FinishLoading(CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(FinishLoading), cancellationToken); + + public async Task ShowInfoToast(string message, CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(ShowInfoToast), message, cancellationToken); + + public async Task ShowSuccessToast(string message, CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(ShowSuccessToast), message, cancellationToken); + + public async Task ShowErrorToast(string message, CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(ShowErrorToast), message, cancellationToken); + + public async Task OnImportCompleted(CancellationToken cancellationToken = default) + => await client.SendAsync(nameof(OnImportCompleted), cancellationToken); +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.FrontendCore/UiContext.cs b/Il2CppInspector.Redux.FrontendCore/UiContext.cs new file mode 100644 index 0000000..44eca27 --- /dev/null +++ b/Il2CppInspector.Redux.FrontendCore/UiContext.cs @@ -0,0 +1,251 @@ +using System.Diagnostics; +using Il2CppInspector.Cpp.UnityHeaders; +using Il2CppInspector.Model; +using Il2CppInspector.Redux.FrontendCore.Outputs; +using Il2CppInspector.Reflection; +using Inspector = Il2CppInspector.Il2CppInspector; + +namespace Il2CppInspector.Redux.FrontendCore; + +public class UiContext +{ + private const string BugReportSuffix = + """ + + + If you believe this is a bug in Il2CppInspectorRedux, please use the CLI version to generate the complete output and paste it when filing a bug report. + Do not send a screenshot of this error! + """; + + private Metadata? _metadata; + private IFileFormatStream? _binary; + private readonly List _appModels = []; + private readonly List _potentialUnityVersions = []; + + private readonly LoadOptions _loadOptions = new(); + + private readonly List<(string FormatId, string OutputDirectory, Dictionary Settings)> _queuedExports = []; + + private async Task TryLoadMetadataFromStream(UiClient client, MemoryStream stream) + { + try + { + _metadata = Metadata.FromStream(stream, client.EventHandler); + return true; + } + catch (Exception e) + { + await client.ShowErrorToast($"{e.Message}{BugReportSuffix}"); + } + + return false; + } + + private async Task TryLoadBinaryFromStream(UiClient client, MemoryStream stream) + { + await client.ShowLogMessage("Processing binary"); + + try + { + var file = FileFormatStream.Load(stream, _loadOptions, client.EventHandler) + ?? throw new InvalidOperationException("Failed to determine binary file format."); + + if (file.NumImages == 0) + throw new InvalidOperationException("Failed to find any binary images in the file"); + + _binary = file; + return true; + } + catch (Exception e) + { + await client.ShowErrorToast($"{e.Message}{BugReportSuffix}"); + } + + return false; + } + + private async Task TryInitializeInspector(UiClient client) + { + Debug.Assert(_binary != null); + Debug.Assert(_metadata != null); + + _appModels.Clear(); + + var inspectors = Inspector.LoadFromStream(_binary, _metadata, client.EventHandler); + + if (inspectors.Count == 0) + { + await client.ShowErrorToast( + """ + Failed to auto-detect any IL2CPP binary images in the provided files. + This may mean the binary file is packed, encrypted or obfuscated, that the file + is not an IL2CPP image or that Il2CppInspector was not able to automatically find the required data. + Please check the binary file in a disassembler to ensure that it is an unencrypted IL2CPP binary before submitting a bug report! + """); + + _binary = null; + return false; + } + + foreach (var inspector in inspectors) + { + await client.ShowLogMessage( + $"Building .NET type model for {inspector.BinaryImage.Format}/{inspector.BinaryImage.Arch} image"); + + try + { + var typeModel = new TypeModel(inspector); + + // Just create the app model, do not initialize it - this is done lazily depending on the exports + _appModels.Add(new AppModel(typeModel, makeDefaultBuild: false)); + } + catch (Exception e) + { + await client.ShowErrorToast($"Failed to build type model: {e.Message}{BugReportSuffix}"); + + // Clear out failed metadata and binary so subsequent loads do not use any stale data. + _metadata = null; + _binary = null; + + return false; + } + } + + _potentialUnityVersions.Clear(); + _potentialUnityVersions.AddRange(UnityHeaders.GuessHeadersForBinary(_appModels[0].Package.Binary)); + + return true; + } + + public async Task Initialize(UiClient client, CancellationToken cancellationToken = default) + { + await client.ShowSuccessToast("SignalR initialized!", cancellationToken); + } + + public async Task LoadInputFiles(UiClient client, List inputFiles, + CancellationToken cancellationToken = default) + { + await using (await LoadingSession.Start(client)) + { + var streams = Inspector.GetStreamsFromPackage(inputFiles); + if (streams != null) + { + // The input files contained a package that provides the metadata and binary. + // Use these instead of parsing all files individually. + if (!await TryLoadMetadataFromStream(client, streams.Value.Metadata)) + return; + + if (!await TryLoadBinaryFromStream(client, streams.Value.Binary)) + return; + } + else + { + foreach (var inputFile in inputFiles) + { + if (_metadata != null && _binary != null) + break; + + await client.ShowLogMessage($"Processing {inputFile}", cancellationToken); + + var data = await File.ReadAllBytesAsync(inputFile, cancellationToken); + var stream = new MemoryStream(data); + + if ( _metadata == null && PathHeuristics.IsMetadataPath(inputFile)) + { + if (await TryLoadMetadataFromStream(client, stream)) + { + await client.ShowSuccessToast($"Loaded metadata (v{_metadata!.Version}) from {inputFile}", cancellationToken); + } + } + else if (_binary == null && PathHeuristics.IsBinaryPath(inputFile)) + { + stream.Position = 0; + _loadOptions.BinaryFilePath = inputFile; + + if (await TryLoadBinaryFromStream(client, stream)) + { + await client.ShowSuccessToast($"Loaded binary from {inputFile}", cancellationToken); + } + } + } + } + + if (_metadata != null && _binary != null) + { + if (await TryInitializeInspector(client)) + { + await client.ShowSuccessToast($"Successfully loaded IL2CPP (v{_appModels[0].Package.Version}) data!", cancellationToken); + await client.OnImportCompleted(cancellationToken); + } + } + } + } + + public Task QueueExport(UiClient client, string exportFormatId, string outputDirectory, + Dictionary settings, CancellationToken cancellationToken = default) + { + _queuedExports.Add((exportFormatId, outputDirectory, settings)); + return Task.CompletedTask; + } + + public async Task StartExport(UiClient client, CancellationToken cancellationToken = default) + { + // todo: support different app model selection (when loading packages) + Debug.Assert(_appModels.Count > 0); + + await using (await LoadingSession.Start(client)) + { + var model = _appModels[0]; + + foreach (var (formatId, outputDirectory, settings) in _queuedExports) + { + try + { + var outputFormat = OutputFormatRegistry.GetOutputFormat(formatId); + await outputFormat.Export(model, client, outputDirectory, settings); + } + catch (Exception ex) + { + await client.ShowErrorToast($"Export for format {formatId} failed: {ex}", + cancellationToken); + } + } + + _queuedExports.Clear(); + } + + await client.ShowSuccessToast("Export finished", cancellationToken); + } + + public Task> GetPotentialUnityVersions() + { + return Task.FromResult(_potentialUnityVersions.Select(x => x.VersionRange.Min.ToString()).ToList()); + } + + public async Task ExportIl2CppFiles(UiClient client, string outputDirectory, CancellationToken cancellationToken = default) + { + Debug.Assert(_appModels.Count > 0); + var pkg = _appModels[0].Package; + + await using (await LoadingSession.Start(client)) + { + await Task.Run(async () => + { + Directory.CreateDirectory(outputDirectory); + + await client.ShowLogMessage("Extracting IL2CPP binary", cancellationToken); + pkg.SaveBinaryToFile(Path.Join(outputDirectory, pkg.BinaryImage.DefaultFilename)); + + await client.ShowLogMessage("Extracting IL2CPP metadata", cancellationToken); + pkg.SaveMetadataToFile(Path.Join(outputDirectory, "global-metadata.dat")); + + await client.ShowSuccessToast("Successfully extracted IL2CPP files.", cancellationToken); + }, cancellationToken); + } + } + + public static Task GetInspectorVersion() + { + return Task.FromResult(typeof(UiContext).Assembly.GetAssemblyVersion() ?? ""); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.GUI.UI/.gitignore b/Il2CppInspector.Redux.GUI.UI/.gitignore new file mode 100644 index 0000000..6635cf5 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/Il2CppInspector.Redux.GUI.UI/.prettierrc b/Il2CppInspector.Redux.GUI.UI/.prettierrc new file mode 100644 index 0000000..afcf4f3 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/.prettierrc @@ -0,0 +1,4 @@ +{ + "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], + "tabWidth": 4 +} diff --git a/Il2CppInspector.Redux.GUI.UI/components.json b/Il2CppInspector.Redux.GUI.UI/components.json new file mode 100644 index 0000000..8fb15f8 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://next.shadcn-svelte.com/schema.json", + "style": "new-york", + "tailwind": { + "config": "tailwind.config.ts", + "css": "src\\app.css", + "baseColor": "stone" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "hooks": "$lib/hooks" + }, + "typescript": true, + "registry": "https://next.shadcn-svelte.com/registry" +} diff --git a/Il2CppInspector.Redux.GUI.UI/package.json b/Il2CppInspector.Redux.GUI.UI/package.json new file mode 100644 index 0000000..9db933b --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/package.json @@ -0,0 +1,46 @@ +{ + "name": "il2cppinspectorredux", + "version": "0.1.0", + "description": "", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "tauri": "tauri" + }, + "license": "MIT", + "dependencies": { + "@microsoft/signalr": "^8.0.7", + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-dialog": "~2", + "@tauri-apps/plugin-opener": "^2" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.6", + "@sveltejs/kit": "^2.9.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/typography": "^0.5.16", + "@tauri-apps/cli": "^2", + "autoprefixer": "^10.4.20", + "bits-ui": "1.0.0-next.78", + "clsx": "^2.1.1", + "lucide-svelte": "^0.473.0", + "mode-watcher": "^0.5.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.10", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "svelte-sonner": "^0.3.28", + "tailwind-merge": "^2.6.0", + "tailwind-variants": "^0.3.1", + "tailwindcss": "^3.4.17", + "tailwindcss-animate": "^1.0.7", + "typescript": "~5.6.2", + "vite": "^6.0.3" + }, + "packageManager": "pnpm@10.0.0+sha512.b8fef5494bd3fe4cbd4edabd0745df2ee5be3e4b0b8b08fa643aa3e4c6702ccc0f00d68fa8a8c9858a735a0032485a44990ed2810526c875e416f001b17df12b" +} diff --git a/Il2CppInspector.Redux.GUI.UI/pnpm-lock.yaml b/Il2CppInspector.Redux.GUI.UI/pnpm-lock.yaml new file mode 100644 index 0000000..71235c0 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/pnpm-lock.yaml @@ -0,0 +1,2349 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@microsoft/signalr': + specifier: ^8.0.7 + version: 8.0.7 + '@tauri-apps/api': + specifier: ^2 + version: 2.2.0 + '@tauri-apps/plugin-dialog': + specifier: ~2 + version: 2.2.0 + '@tauri-apps/plugin-opener': + specifier: ^2 + version: 2.2.5 + devDependencies: + '@sveltejs/adapter-static': + specifier: ^3.0.6 + version: 3.0.8(@sveltejs/kit@2.16.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0))) + '@sveltejs/kit': + specifier: ^2.9.0 + version: 2.16.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + '@sveltejs/vite-plugin-svelte': + specifier: ^5.0.0 + version: 5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.16(tailwindcss@3.4.17) + '@tauri-apps/cli': + specifier: ^2 + version: 2.2.5 + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.5.1) + bits-ui: + specifier: 1.0.0-next.78 + version: 1.0.0-next.78(svelte@5.19.0) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-svelte: + specifier: ^0.473.0 + version: 0.473.0(svelte@5.19.0) + mode-watcher: + specifier: ^0.5.0 + version: 0.5.0(svelte@5.19.0) + prettier: + specifier: ^3.4.2 + version: 3.4.2 + prettier-plugin-svelte: + specifier: ^3.3.3 + version: 3.3.3(prettier@3.4.2)(svelte@5.19.0) + prettier-plugin-tailwindcss: + specifier: ^0.6.10 + version: 0.6.10(prettier-plugin-svelte@3.3.3(prettier@3.4.2)(svelte@5.19.0))(prettier@3.4.2) + svelte: + specifier: ^5.0.0 + version: 5.19.0 + svelte-check: + specifier: ^4.0.0 + version: 4.1.4(svelte@5.19.0)(typescript@5.6.3) + svelte-sonner: + specifier: ^0.3.28 + version: 0.3.28(svelte@5.19.0) + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + tailwind-variants: + specifier: ^0.3.1 + version: 0.3.1(tailwindcss@3.4.17) + tailwindcss: + specifier: ^3.4.17 + version: 3.4.17 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.17) + typescript: + specifier: ~5.6.2 + version: 5.6.3 + vite: + specifier: ^6.0.3 + version: 6.0.7(jiti@1.21.7)(yaml@2.7.0) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@internationalized/date@3.7.0': + resolution: {integrity: sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@microsoft/signalr@8.0.7': + resolution: {integrity: sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + + '@rollup/rollup-android-arm-eabi@4.31.0': + resolution: {integrity: sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.31.0': + resolution: {integrity: sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.31.0': + resolution: {integrity: sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.31.0': + resolution: {integrity: sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.31.0': + resolution: {integrity: sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.31.0': + resolution: {integrity: sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.31.0': + resolution: {integrity: sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.31.0': + resolution: {integrity: sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.31.0': + resolution: {integrity: sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.31.0': + resolution: {integrity: sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.31.0': + resolution: {integrity: sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.31.0': + resolution: {integrity: sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.31.0': + resolution: {integrity: sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.31.0': + resolution: {integrity: sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.31.0': + resolution: {integrity: sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.31.0': + resolution: {integrity: sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.31.0': + resolution: {integrity: sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.31.0': + resolution: {integrity: sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.31.0': + resolution: {integrity: sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==} + cpu: [x64] + os: [win32] + + '@sveltejs/adapter-static@3.0.8': + resolution: {integrity: sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==} + peerDependencies: + '@sveltejs/kit': ^2.0.0 + + '@sveltejs/kit@2.16.0': + resolution: {integrity: sha512-S9i1ZWKqluzoaJ6riYnEdbe+xJluMTMkhABouBa66GaWcAyCjW/jAc0NdJQJ/DXyK1CnP5quBW25e99MNyvLxA==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': + resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^5.0.0 + svelte: ^5.0.0 + vite: ^6.0.0 + + '@sveltejs/vite-plugin-svelte@5.0.3': + resolution: {integrity: sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.0.0 + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/typography@0.5.16': + resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tauri-apps/api@2.2.0': + resolution: {integrity: sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==} + + '@tauri-apps/cli-darwin-arm64@2.2.5': + resolution: {integrity: sha512-qdPmypQE7qj62UJy3Wl/ccCJZwsv5gyBByOrAaG7u5c/PB3QSxhNPegice2k4EHeIuApaVJOoe/CEYVgm/og2Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tauri-apps/cli-darwin-x64@2.2.5': + resolution: {integrity: sha512-8JVlCAb2c3n0EcGW7n/1kU4Rq831SsoLDD/0hNp85Um8HGIH2Mg/qos/MLOc8Qv2mOaoKcRKf4hd0I1y0Rl9Cg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tauri-apps/cli-linux-arm-gnueabihf@2.2.5': + resolution: {integrity: sha512-mzxQCqZg7ljRVgekPpXQ5TOehCNgnXh/DNWU6kFjALaBvaw4fGzc369/hV94wOt29htNFyxf8ty2DaQaYljEHw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tauri-apps/cli-linux-arm64-gnu@2.2.5': + resolution: {integrity: sha512-M9nkzx5jsSJSNpp7aSza0qv0/N13SUNzH8ysYSZ7IaCN8coGeMg2KgQ5qC6tqUVij2rbg8A/X1n0pPo/gtLx0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-arm64-musl@2.2.5': + resolution: {integrity: sha512-tFhZu950HNRLR1RM5Q9Xj5gAlA6AhyyiZgeoXGFAWto+s2jpWmmA3Qq2GUxnVDr7Xui8PF4UY5kANDIOschuwg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-x64-gnu@2.2.5': + resolution: {integrity: sha512-eaGhTQLr3EKeksGsp2tK/Ndi7/oyo3P53Pye6kg0zqXiqu8LQjg1CgvDm1l+5oit04S60zR4AqlDFpoeEtDGgw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-linux-x64-musl@2.2.5': + resolution: {integrity: sha512-NLAO/SymDxeGuOWWQZCpwoED1K1jaHUvW+u9ip+rTetnxFPLvf3zXthx4QVKfCZLdj2WLQz4cLjHyQdMDXAM+w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-win32-arm64-msvc@2.2.5': + resolution: {integrity: sha512-yG5KFbqrHfGjkAQAaaCD4i7cJklBjmMxZ2C92DEnqCOujSsEuLxrwwoKxQ4+hqEHOmF3lyX0vfqhgZcS03H38w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tauri-apps/cli-win32-ia32-msvc@2.2.5': + resolution: {integrity: sha512-G5lq+2EdxOc8ttg3uhME5t9U3hMGTxwaKz0X4DplTG2Iv4lcNWqw/AESIJVHa5a+EB+ZCC8I+yOfIykp/Cd5mQ==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@tauri-apps/cli-win32-x64-msvc@2.2.5': + resolution: {integrity: sha512-vw4fPVOo0rIQIlqw6xUvK2nwiRFBHNgayDE2Z/SomJlQJAJ1q4VgpHOPl12ouuicmTjK1gWKm7RTouQe3Nig0Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tauri-apps/cli@2.2.5': + resolution: {integrity: sha512-PaefTQUCYYqvZWdH8EhXQkyJEjQwtoy/OHGoPcZx7Gk3D3K6AtGSxZ9OlHIz3Bu5LDGgVBk36vKtHW0WYsWnbw==} + engines: {node: '>= 10'} + hasBin: true + + '@tauri-apps/plugin-dialog@2.2.0': + resolution: {integrity: sha512-6bLkYK68zyK31418AK5fNccCdVuRnNpbxquCl8IqgFByOgWFivbiIlvb79wpSXi0O+8k8RCSsIpOquebusRVSg==} + + '@tauri-apps/plugin-opener@2.2.5': + resolution: {integrity: sha512-hHsJ9RPWpZvZEPVFaL+d25gABMUMOf/A6ESXnvf/ii9guTukj58WXsAE/SOysXRIhej7kseRCxnOnIMpSCdUsQ==} + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-typescript@1.4.13: + resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==} + peerDependencies: + acorn: '>=8.9.0' + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bits-ui@1.0.0-next.78: + resolution: {integrity: sha512-jZjG2ObZ/CNyCNaXecpItC7hRXqJAgEfMhr06/eNrf3wHiiPyhdcy4OkzLcJyxeOrDyj+xma8cZTd3JRWqJdAw==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.11.0 + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001695: + resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + devalue@5.1.1: + resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.83: + resolution: {integrity: sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + + esrap@1.4.3: + resolution: {integrity: sha512-Xddc1RsoFJ4z9nR7W7BFaEPIp4UXoeQ0+077UdWLxbafMQFyU79sQJMk7kxNgRwQ9/aVgaKacCHC2pUACGwmYw==} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventsource@2.0.2: + resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} + engines: {node: '>=12.0.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-cookie@2.2.0: + resolution: {integrity: sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + inline-style-parser@0.2.4: + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lucide-svelte@0.473.0: + resolution: {integrity: sha512-Lw2+vrDmVlz/WC1/KcuCEV/1ENrHtChw4GH1cssMbbpdUFyVjZkt9S+7olCOGW8jOZJOrzZNfefV1DdaDw46jQ==} + peerDependencies: + svelte: ^3 || ^4 || ^5.0.0-next.42 + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mode-watcher@0.5.0: + resolution: {integrity: sha512-5E6fh/aXhAVv+U+DbeM0hCmskQE9u7WSmvnCRijJB/MJu7HtB73sjiCaZ9n1M8QHmzLrBFo8XBAUcWXkDm8Z9A==} + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.1 + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.1: + resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} + engines: {node: ^10 || ^12 || >=14} + + prettier-plugin-svelte@3.3.3: + resolution: {integrity: sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==} + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + + prettier-plugin-tailwindcss@0.6.10: + resolution: {integrity: sha512-ndj2WLDaMzACnr1gAYZiZZLs5ZdOeBYgOsbBmHj3nvW/6q8h8PymsXiEnKvj/9qgCCAoHyvLOisoQdIcsDvIgw==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.1: + resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} + engines: {node: '>= 14.18.0'} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.31.0: + resolution: {integrity: sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + runed@0.20.0: + resolution: {integrity: sha512-YqPxaUdWL5nUXuSF+/v8a+NkVN8TGyEGbQwTA25fLY35MR/2bvZ1c6sCbudoo1kT4CAJPh4kUkcgGVxW127WKw==} + peerDependencies: + svelte: ^5.7.0 + + runed@0.22.0: + resolution: {integrity: sha512-ZWVXWhOr0P5xdNgtviz6D1ivLUDWKLCbeC5SUEJ3zBkqLReVqWHenFxMNFeFaiC5bfxhFxyxzyzB+98uYFtwdA==} + peerDependencies: + svelte: ^5.7.0 + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + style-to-object@1.0.8: + resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svelte-check@4.1.4: + resolution: {integrity: sha512-v0j7yLbT29MezzaQJPEDwksybTE2Ups9rUxEXy92T06TiA0cbqcO8wAOwNUVkFW6B0hsYHA+oAX3BS8b/2oHtw==} + engines: {node: '>= 18.0.0'} + hasBin: true + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: '>=5.0.0' + + svelte-sonner@0.3.28: + resolution: {integrity: sha512-K3AmlySeFifF/cKgsYNv5uXqMVNln0NBAacOYgmkQStLa/UoU0LhfAACU6Gr+YYC8bOCHdVmFNoKuDbMEsppJg==} + peerDependencies: + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 + + svelte-toolbelt@0.7.0: + resolution: {integrity: sha512-i/Tv4NwAWWqJnK5H0F8y/ubDnogDYlwwyzKhrspTUFzrFuGnYshqd2g4/R43ds841wmaFiSW/HsdsdWhPOlrAA==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0 + + svelte@5.19.0: + resolution: {integrity: sha512-qvd2GvvYnJxS/MteQKFSMyq8cQrAAut28QZ39ySv9k3ggmhw4Au4Rfcsqva74i0xMys//OhbhVCNfXPrDzL/Bg==} + engines: {node: '>=18'} + + tailwind-merge@2.5.4: + resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} + + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + + tailwind-variants@0.3.1: + resolution: {integrity: sha512-krn67M3FpPwElg4FsZrOQd0U26o7UDH/QOkK8RNaiCCrr052f6YJPBUfNKnPo/s/xRzNPtv1Mldlxsg8Tb46BQ==} + engines: {node: '>=16.x', pnpm: '>=7.x'} + peerDependencies: + tailwindcss: '*' + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.17: + resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + update-browserslist-db@1.1.2: + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@6.0.7: + resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.0.5: + resolution: {integrity: sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + vite: + optional: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + engines: {node: '>= 14'} + hasBin: true + + zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/utils@0.2.9': {} + + '@internationalized/date@3.7.0': + dependencies: + '@swc/helpers': 0.5.15 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@microsoft/signalr@8.0.7': + dependencies: + abort-controller: 3.0.0 + eventsource: 2.0.2 + fetch-cookie: 2.2.0 + node-fetch: 2.7.0 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@polka/url@1.0.0-next.28': {} + + '@rollup/rollup-android-arm-eabi@4.31.0': + optional: true + + '@rollup/rollup-android-arm64@4.31.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.31.0': + optional: true + + '@rollup/rollup-darwin-x64@4.31.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.31.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.31.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.31.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.31.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.31.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.31.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.31.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.31.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.31.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.31.0': + optional: true + + '@sveltejs/adapter-static@3.0.8(@sveltejs/kit@2.16.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))': + dependencies: + '@sveltejs/kit': 2.16.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + + '@sveltejs/kit@2.16.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + '@types/cookie': 0.6.0 + cookie: 0.6.0 + devalue: 5.1.1 + esm-env: 1.2.2 + import-meta-resolve: 4.1.0 + kleur: 4.1.5 + magic-string: 0.30.17 + mrmime: 2.0.0 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.0 + svelte: 5.19.0 + vite: 6.0.7(jiti@1.21.7)(yaml@2.7.0) + + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + debug: 4.4.0 + svelte: 5.19.0 + vite: 6.0.7(jiti@1.21.7)(yaml@2.7.0) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.0)(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + debug: 4.4.0 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.17 + svelte: 5.19.0 + vite: 6.0.7(jiti@1.21.7)(yaml@2.7.0) + vitefu: 1.0.5(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)) + transitivePeerDependencies: + - supports-color + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.17 + + '@tauri-apps/api@2.2.0': {} + + '@tauri-apps/cli-darwin-arm64@2.2.5': + optional: true + + '@tauri-apps/cli-darwin-x64@2.2.5': + optional: true + + '@tauri-apps/cli-linux-arm-gnueabihf@2.2.5': + optional: true + + '@tauri-apps/cli-linux-arm64-gnu@2.2.5': + optional: true + + '@tauri-apps/cli-linux-arm64-musl@2.2.5': + optional: true + + '@tauri-apps/cli-linux-x64-gnu@2.2.5': + optional: true + + '@tauri-apps/cli-linux-x64-musl@2.2.5': + optional: true + + '@tauri-apps/cli-win32-arm64-msvc@2.2.5': + optional: true + + '@tauri-apps/cli-win32-ia32-msvc@2.2.5': + optional: true + + '@tauri-apps/cli-win32-x64-msvc@2.2.5': + optional: true + + '@tauri-apps/cli@2.2.5': + optionalDependencies: + '@tauri-apps/cli-darwin-arm64': 2.2.5 + '@tauri-apps/cli-darwin-x64': 2.2.5 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.2.5 + '@tauri-apps/cli-linux-arm64-gnu': 2.2.5 + '@tauri-apps/cli-linux-arm64-musl': 2.2.5 + '@tauri-apps/cli-linux-x64-gnu': 2.2.5 + '@tauri-apps/cli-linux-x64-musl': 2.2.5 + '@tauri-apps/cli-win32-arm64-msvc': 2.2.5 + '@tauri-apps/cli-win32-ia32-msvc': 2.2.5 + '@tauri-apps/cli-win32-x64-msvc': 2.2.5 + + '@tauri-apps/plugin-dialog@2.2.0': + dependencies: + '@tauri-apps/api': 2.2.0 + + '@tauri-apps/plugin-opener@2.2.5': + dependencies: + '@tauri-apps/api': 2.2.0 + + '@types/cookie@0.6.0': {} + + '@types/estree@1.0.6': {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-typescript@1.4.13(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + aria-query@5.3.2: {} + + autoprefixer@10.4.20(postcss@8.5.1): + dependencies: + browserslist: 4.24.4 + caniuse-lite: 1.0.30001695 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.1 + postcss-value-parser: 4.2.0 + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + + bits-ui@1.0.0-next.78(svelte@5.19.0): + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/dom': 1.6.13 + '@internationalized/date': 3.7.0 + esm-env: 1.2.2 + runed: 0.22.0(svelte@5.19.0) + svelte: 5.19.0 + svelte-toolbelt: 0.7.0(svelte@5.19.0) + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001695 + electron-to-chromium: 1.5.83 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001695: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.1 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@4.1.1: {} + + cookie@0.6.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deepmerge@4.3.1: {} + + devalue@5.1.1: {} + + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.83: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + esbuild@0.24.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + + escalade@3.2.0: {} + + esm-env@1.2.2: {} + + esrap@1.4.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + event-target-shim@5.0.1: {} + + eventsource@2.0.2: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + + fdir@6.4.3: {} + + fetch-cookie@2.2.0: + dependencies: + set-cookie-parser: 2.7.1 + tough-cookie: 4.1.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@4.3.7: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + import-meta-resolve@4.1.0: {} + + inline-style-parser@0.2.4: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.7: {} + + kleur@4.1.5: {} + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + locate-character@3.0.0: {} + + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lru-cache@10.4.3: {} + + lucide-svelte@0.473.0(svelte@5.19.0): + dependencies: + svelte: 5.19.0 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minipass@7.1.2: {} + + mode-watcher@0.5.0(svelte@5.19.0): + dependencies: + svelte: 5.19.0 + + mri@1.2.0: {} + + mrmime@2.0.0: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.8: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + package-json-from-dist@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pify@2.3.0: {} + + pirates@4.0.6: {} + + postcss-import@15.1.0(postcss@8.5.1): + dependencies: + postcss: 8.5.1 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.10 + + postcss-js@4.0.1(postcss@8.5.1): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.1 + + postcss-load-config@4.0.2(postcss@8.5.1): + dependencies: + lilconfig: 3.1.3 + yaml: 2.7.0 + optionalDependencies: + postcss: 8.5.1 + + postcss-nested@6.2.0(postcss@8.5.1): + dependencies: + postcss: 8.5.1 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.1: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier-plugin-svelte@3.3.3(prettier@3.4.2)(svelte@5.19.0): + dependencies: + prettier: 3.4.2 + svelte: 5.19.0 + + prettier-plugin-tailwindcss@0.6.10(prettier-plugin-svelte@3.3.3(prettier@3.4.2)(svelte@5.19.0))(prettier@3.4.2): + dependencies: + prettier: 3.4.2 + optionalDependencies: + prettier-plugin-svelte: 3.3.3(prettier@3.4.2)(svelte@5.19.0) + + prettier@3.4.2: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + punycode@2.3.1: {} + + querystringify@2.2.0: {} + + queue-microtask@1.2.3: {} + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.1.1: {} + + requires-port@1.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rollup@4.31.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.31.0 + '@rollup/rollup-android-arm64': 4.31.0 + '@rollup/rollup-darwin-arm64': 4.31.0 + '@rollup/rollup-darwin-x64': 4.31.0 + '@rollup/rollup-freebsd-arm64': 4.31.0 + '@rollup/rollup-freebsd-x64': 4.31.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.31.0 + '@rollup/rollup-linux-arm-musleabihf': 4.31.0 + '@rollup/rollup-linux-arm64-gnu': 4.31.0 + '@rollup/rollup-linux-arm64-musl': 4.31.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.31.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.31.0 + '@rollup/rollup-linux-riscv64-gnu': 4.31.0 + '@rollup/rollup-linux-s390x-gnu': 4.31.0 + '@rollup/rollup-linux-x64-gnu': 4.31.0 + '@rollup/rollup-linux-x64-musl': 4.31.0 + '@rollup/rollup-win32-arm64-msvc': 4.31.0 + '@rollup/rollup-win32-ia32-msvc': 4.31.0 + '@rollup/rollup-win32-x64-msvc': 4.31.0 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + runed@0.20.0(svelte@5.19.0): + dependencies: + esm-env: 1.2.2 + svelte: 5.19.0 + + runed@0.22.0(svelte@5.19.0): + dependencies: + esm-env: 1.2.2 + svelte: 5.19.0 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + set-cookie-parser@2.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + style-to-object@1.0.8: + dependencies: + inline-style-parser: 0.2.4 + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + supports-preserve-symlinks-flag@1.0.0: {} + + svelte-check@4.1.4(svelte@5.19.0)(typescript@5.6.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + chokidar: 4.0.3 + fdir: 6.4.3 + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.19.0 + typescript: 5.6.3 + transitivePeerDependencies: + - picomatch + + svelte-sonner@0.3.28(svelte@5.19.0): + dependencies: + svelte: 5.19.0 + + svelte-toolbelt@0.7.0(svelte@5.19.0): + dependencies: + clsx: 2.1.1 + runed: 0.20.0(svelte@5.19.0) + style-to-object: 1.0.8 + svelte: 5.19.0 + + svelte@5.19.0: + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.6 + acorn: 8.14.0 + acorn-typescript: 1.4.13(acorn@8.14.0) + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 1.4.3 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.17 + zimmerframe: 1.1.2 + + tailwind-merge@2.5.4: {} + + tailwind-merge@2.6.0: {} + + tailwind-variants@0.3.1(tailwindcss@3.4.17): + dependencies: + tailwind-merge: 2.5.4 + tailwindcss: 3.4.17 + + tailwindcss-animate@1.0.7(tailwindcss@3.4.17): + dependencies: + tailwindcss: 3.4.17 + + tailwindcss@3.4.17: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.1 + postcss-import: 15.1.0(postcss@8.5.1) + postcss-js: 4.0.1(postcss@8.5.1) + postcss-load-config: 4.0.2(postcss@8.5.1) + postcss-nested: 6.2.0(postcss@8.5.1) + postcss-selector-parser: 6.1.2 + resolve: 1.22.10 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@0.0.3: {} + + ts-interface-checker@0.1.13: {} + + tslib@2.8.1: {} + + typescript@5.6.3: {} + + universalify@0.2.0: {} + + update-browserslist-db@1.1.2(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + util-deprecate@1.0.2: {} + + vite@6.0.7(jiti@1.21.7)(yaml@2.7.0): + dependencies: + esbuild: 0.24.2 + postcss: 8.5.1 + rollup: 4.31.0 + optionalDependencies: + fsevents: 2.3.3 + jiti: 1.21.7 + yaml: 2.7.0 + + vitefu@1.0.5(vite@6.0.7(jiti@1.21.7)(yaml@2.7.0)): + optionalDependencies: + vite: 6.0.7(jiti@1.21.7)(yaml@2.7.0) + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + ws@7.5.10: {} + + yaml@2.7.0: {} + + zimmerframe@1.1.2: {} diff --git a/Il2CppInspector.Redux.GUI.UI/postcss.config.js b/Il2CppInspector.Redux.GUI.UI/postcss.config.js new file mode 100644 index 0000000..ba80730 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/.gitignore b/Il2CppInspector.Redux.GUI.UI/src-tauri/.gitignore new file mode 100644 index 0000000..b21bd68 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Generated by Tauri +# will have schema files for capabilities auto-completion +/gen/schemas diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.lock b/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.lock new file mode 100644 index 0000000..8151206 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.lock @@ -0,0 +1,5345 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "ashpd" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_repr", + "tokio", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.8.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.11", +] + +[[package]] +name = "cargo_toml" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" +dependencies = [ + "serde", + "toml 0.8.19", +] + +[[package]] +name = "cc" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +dependencies = [ + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cocoa" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" +dependencies = [ + "bitflags 2.8.0", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" +dependencies = [ + "bitflags 2.8.0", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.96", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.96", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.96", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.96", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.6", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "embed-resource" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.8.19", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.8.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.14", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa 1.0.14", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "il2cppinspectorredux" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-opener", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "infer" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.8.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.8.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "muda" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdae9c00e61cc0579bcac625e8ad22104c60548a025bfc972dc83868a28e1484" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 1.0.69", + "windows-sys 0.59.0", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.8.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.8.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.8.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" +dependencies = [ + "bitflags 2.8.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "open" +version = "5.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +dependencies = [ + "dunce", + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64 0.22.1", + "indexmap 2.7.1", + "quick-xml 0.32.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "windows-registry", +] + +[[package]] +name = "rfd" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a24763657bff09769a8ccf12c8b8a50416fb035fe199263b4c5071e4e3f006f" +dependencies = [ + "ashpd", + "block2", + "core-foundation", + "core-foundation-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.96", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +dependencies = [ + "itoa 1.0.14", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.14", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "softbuffer" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +dependencies = [ + "bytemuck", + "cfg_aliases", + "core-graphics", + "foreign-types", + "js-sys", + "log", + "objc2", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "wasm-bindgen", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.19", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3731d04d4ac210cd5f344087733943b9bfb1a32654387dad4d1c70de21aee2c9" +dependencies = [ + "bitflags 2.8.0", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.58.0", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f6efc261c7905839b4914889a5b25df07f0ff89c63fb4afd6ff8c96af15e4d" +dependencies = [ + "anyhow", + "bytes", + "dirs", + "dunce", + "embed_plist", + "futures-util", + "getrandom 0.2.15", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.11", + "tokio", + "tray-icon", + "url", + "urlpattern", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e950124f6779c6cf98e3260c7a6c8488a74aa6350dd54c6950fdaa349bca2df" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77894f9ddb5cb6c04fcfe8c8869ebe0aded4dabf19917118d48be4a95599ab5" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.96", + "tauri-utils", + "thiserror 2.0.11", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3240a5caed760a532e8f687be6f05b2c7d11a1d791fb53ccc08cfeb3e5308736" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.96", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5841b9a0200e954ef7457f8d327091424328891e267a97b641dc246cc54d0dec" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b59fd750551b1066744ab956a1cd6b1ea3e1b3763b0b9153ac27a044d596426" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.11", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1edf18000f02903a7c2e5997fb89aca455ecbc0acc15c6535afbb883be223" +dependencies = [ + "anyhow", + "dunce", + "glob", + "percent-encoding", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.11", + "toml 0.8.19", + "url", + "uuid", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635ed7c580dc3cdc61c94097d38ef517d749ffc0141c806d904e68e4b0cf1c2a" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.11", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-runtime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2274ef891ccc0a8d318deffa9d70053f947664d12d58b9c0d1ae5e89237e01f7" +dependencies = [ + "dpi", + "gtk", + "http", + "jni", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.11", + "url", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3707b40711d3b9f6519150869e358ffbde7c57567fb9b5a8b51150606939b2a0" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96fb10e7cc97456b2d5b9c03e335b5de5da982039a303a20d10006885e4523a0" +dependencies = [ + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever", + "http", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "regex", + "schemars", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.11", + "toml 0.8.19", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +dependencies = [ + "embed-resource", + "toml 0.7.8", +] + +[[package]] +name = "tempfile" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom 0.2.15", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa 1.0.14", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.22", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.7.1", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.7.1", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.7.1", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.24", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48a05076dd272615d03033bf04f480199f7d1b66a8ac64d75c625fc4a70c06b" +dependencies = [ + "core-graphics", + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 1.0.69", + "windows-sys 0.59.0", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +dependencies = [ + "getrandom 0.2.15", + "serde", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +dependencies = [ + "bitflags 2.8.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml 0.36.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webview2-com" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823e7ebcfaea51e78f72c87fc3b65a1e602c321f407a0b36dbb327d7bb7cd921" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.58.0", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "webview2-com-sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a82bce72db6e5ee83c68b5de1e2cd6ea195b9fbff91cb37df5884cbe3222df4" +dependencies = [ + "thiserror 1.0.69", + "windows", + "windows-core 0.58.0", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-version" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c12476c23a74725c539b24eae8bfc0dac4029c39cdb561d9f23616accd4ae26d" +dependencies = [ + "windows-targets 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wry" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e33c08b174442ff80d5c791020696f9f8b4e4a87b8cfc7494aad6167ec44e1" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.11", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.58.0", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2494e4b3f44d8363eef79a8a75fc0649efb710eef65a66b5e688a5eb4afe678a" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-util", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tokio", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.6.24", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445efc01929302aee95e2b25bbb62a301ea8a6369466e4278e58e7d1dfb23631" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519629a3f80976d89c575895b05677cbc45eaf9f70d62a364d819ba646409cc8" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.6.24", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zvariant" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e6b9b5f1361de2d5e7d9fd1ee5f6f7fcb6060618a1f82f3472f58f2b8d4be9" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "winnow 0.6.24", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573a8dd76961957108b10f7a45bac6ab1ea3e9b7fe01aff88325dc57bb8f5c8b" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd46446ea2a1f353bfda53e35f17633afa79f4fe290a611c94645c69fe96a50" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.96", + "winnow 0.6.24", +] diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.toml b/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.toml new file mode 100644 index 0000000..1383a0e --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "il2cppinspectorredux" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +# The `_lib` suffix may seem redundant but it is necessary +# to make the lib name unique and wouldn't conflict with the bin name. +# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 +name = "il2cppinspectorredux_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-opener = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tauri-plugin-dialog = "2" + diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/build.rs b/Il2CppInspector.Redux.GUI.UI/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/capabilities/default.json b/Il2CppInspector.Redux.GUI.UI/src-tauri/capabilities/default.json new file mode 100644 index 0000000..3c1ad59 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/capabilities/default.json @@ -0,0 +1,13 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capability for the main window", + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "opener:default", + "dialog:default" + ] +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128.png new file mode 100644 index 0000000..6be5e50 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128@2x.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..e81bece Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/128x128@2x.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/32x32.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/32x32.png new file mode 100644 index 0000000..a437dd5 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/32x32.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square107x107Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..0ca4f27 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square107x107Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square142x142Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..b81f820 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square142x142Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square150x150Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..624c7bf Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square150x150Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square284x284Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..c021d2b Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square284x284Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square30x30Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..6219700 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square30x30Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square310x310Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..f9bc048 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square310x310Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square44x44Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..d5fbfb2 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square44x44Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square71x71Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..63440d7 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square71x71Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square89x89Logo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..f3f705a Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/Square89x89Logo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/StoreLogo.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..4556388 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/StoreLogo.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.icns b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.icns new file mode 100644 index 0000000..12a5bce Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.icns differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.ico b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.ico new file mode 100644 index 0000000..b3636e4 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.ico differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.png b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.png new file mode 100644 index 0000000..e1cd261 Binary files /dev/null and b/Il2CppInspector.Redux.GUI.UI/src-tauri/icons/icon.png differ diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/src/lib.rs b/Il2CppInspector.Redux.GUI.UI/src-tauri/src/lib.rs new file mode 100644 index 0000000..e7deccb --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/src/lib.rs @@ -0,0 +1,20 @@ +// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ +#[tauri::command] +fn get_signalr_url() -> String { + let args: Vec = std::env::args().collect(); + if args.len() < 2 { + return String::from(""); + } + + return args[1].clone(); +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_opener::init()) + .invoke_handler(tauri::generate_handler![get_signalr_url]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/src/main.rs b/Il2CppInspector.Redux.GUI.UI/src-tauri/src/main.rs new file mode 100644 index 0000000..cb4095d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + il2cppinspectorredux_lib::run() +} diff --git a/Il2CppInspector.Redux.GUI.UI/src-tauri/tauri.conf.json b/Il2CppInspector.Redux.GUI.UI/src-tauri/tauri.conf.json new file mode 100644 index 0000000..5a6e66e --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src-tauri/tauri.conf.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Il2CppInspectorRedux", + "version": "0.1.0", + "identifier": "xyz.lukefz.il2cppinspectorredux", + "build": { + "beforeDevCommand": "pnpm dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "pnpm build", + "frontendDist": "../build" + }, + "app": { + "windows": [ + { + "title": "Il2CppInspectorRedux", + "width": 800, + "height": 600 + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/Il2CppInspector.Redux.GUI.UI/src/app.css b/Il2CppInspector.Redux.GUI.UI/src/app.css new file mode 100644 index 0000000..94e4cc5 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/app.css @@ -0,0 +1,66 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%;; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 72.22% 50.59%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 5.9% 10%; + --radius: 0.5rem; + } + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +@layer base { + :root { + --header-height: 60px; + --footer-height: 30px; + --main-height: calc(100vh - var(--header-height) - var(--footer-height)); + } +} \ No newline at end of file diff --git a/Il2CppInspector.Redux.GUI.UI/src/app.html b/Il2CppInspector.Redux.GUI.UI/src/app.html new file mode 100644 index 0000000..92e7e33 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/app.html @@ -0,0 +1,13 @@ + + + + + + + Tauri + SvelteKit + Typescript App + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/Footer.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/Footer.svelte new file mode 100644 index 0000000..477623f --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/Footer.svelte @@ -0,0 +1,33 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/Header.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/Header.svelte new file mode 100644 index 0000000..a226f86 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/Header.svelte @@ -0,0 +1,20 @@ + + +
+
+ +
+
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/loading.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/loading.svelte new file mode 100644 index 0000000..3f9e577 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/loading.svelte @@ -0,0 +1,64 @@ + + +{#if isLoading} +
+
+ +

+ {statusMessage} +

+
+
+{:else} + {@render children()} +{/if} diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/combobox.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/combobox.svelte new file mode 100644 index 0000000..ff383d0 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/combobox.svelte @@ -0,0 +1,33 @@ + + + + {setting.name.label}: {selectedLabel} + + {#each setting.values as value} + {value.label} + {/each} + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/option.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/option.svelte new file mode 100644 index 0000000..a5f78f1 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/option.svelte @@ -0,0 +1,26 @@ + + +
+ +
+ +
+
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/path-selector.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/path-selector.svelte new file mode 100644 index 0000000..44a3c8d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/settings/path-selector.svelte @@ -0,0 +1,37 @@ + + +
+ +

+ {selected === "" ? "not selected" : selected} +

+

{setting.name.label}:

+
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/button.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/button.svelte new file mode 100644 index 0000000..6353277 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/button.svelte @@ -0,0 +1,75 @@ + + + + +{#if href} + + {@render children?.()} + +{:else} + +{/if} diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/index.ts new file mode 100644 index 0000000..fb585d7 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/button/index.ts @@ -0,0 +1,17 @@ +import Root, { + type ButtonProps, + type ButtonSize, + type ButtonVariant, + buttonVariants, +} from "./button.svelte"; + +export { + Root, + type ButtonProps as Props, + // + Root as Button, + buttonVariants, + type ButtonProps, + type ButtonSize, + type ButtonVariant, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-content.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-content.svelte new file mode 100644 index 0000000..1f52856 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-content.svelte @@ -0,0 +1,16 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-description.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-description.svelte new file mode 100644 index 0000000..da02664 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-description.svelte @@ -0,0 +1,16 @@ + + +

+ {@render children?.()} +

diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-footer.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 0000000..6894149 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,16 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-header.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-header.svelte new file mode 100644 index 0000000..1baa92c --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-header.svelte @@ -0,0 +1,16 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-title.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-title.svelte new file mode 100644 index 0000000..a201620 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card-title.svelte @@ -0,0 +1,25 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card.svelte new file mode 100644 index 0000000..c7531d5 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/card.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/index.ts new file mode 100644 index 0000000..0f9084d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/card/index.ts @@ -0,0 +1,22 @@ +import Root from "./card.svelte"; +import Content from "./card-content.svelte"; +import Description from "./card-description.svelte"; +import Footer from "./card-footer.svelte"; +import Header from "./card-header.svelte"; +import Title from "./card-title.svelte"; + +export { + Root, + Content, + Description, + Footer, + Header, + Title, + // + Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, + Header as CardHeader, + Title as CardTitle, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/checkbox.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/checkbox.svelte new file mode 100644 index 0000000..3f02562 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/checkbox.svelte @@ -0,0 +1,35 @@ + + + + {#snippet children({ checked, indeterminate })} + + {#if indeterminate} + + {:else} + + {/if} + + {/snippet} + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/index.ts new file mode 100644 index 0000000..6d92d94 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/checkbox/index.ts @@ -0,0 +1,6 @@ +import Root from "./checkbox.svelte"; +export { + Root, + // + Root as Checkbox, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-dialog.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-dialog.svelte new file mode 100644 index 0000000..175d298 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-dialog.svelte @@ -0,0 +1,35 @@ + + + + + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-empty.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-empty.svelte new file mode 100644 index 0000000..eade21d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-empty.svelte @@ -0,0 +1,12 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-group.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-group.svelte new file mode 100644 index 0000000..6feb450 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-group.svelte @@ -0,0 +1,29 @@ + + + + {#if heading} + + {heading} + + {/if} + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-input.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-input.svelte new file mode 100644 index 0000000..e6c1401 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-input.svelte @@ -0,0 +1,25 @@ + + +
+ + +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-item.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-item.svelte new file mode 100644 index 0000000..3738ff2 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-item.svelte @@ -0,0 +1,19 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-link-item.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-link-item.svelte new file mode 100644 index 0000000..093dbfd --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-link-item.svelte @@ -0,0 +1,19 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-list.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-list.svelte new file mode 100644 index 0000000..10caaa7 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-list.svelte @@ -0,0 +1,16 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-separator.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-separator.svelte new file mode 100644 index 0000000..c272363 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-separator.svelte @@ -0,0 +1,12 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-shortcut.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-shortcut.svelte new file mode 100644 index 0000000..e985d5e --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command-shortcut.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command.svelte new file mode 100644 index 0000000..92bd8ca --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/command.svelte @@ -0,0 +1,21 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/index.ts new file mode 100644 index 0000000..f245003 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/command/index.ts @@ -0,0 +1,40 @@ +import { Command as CommandPrimitive } from "bits-ui"; + +import Root from "./command.svelte"; +import Dialog from "./command-dialog.svelte"; +import Empty from "./command-empty.svelte"; +import Group from "./command-group.svelte"; +import Item from "./command-item.svelte"; +import Input from "./command-input.svelte"; +import List from "./command-list.svelte"; +import Separator from "./command-separator.svelte"; +import Shortcut from "./command-shortcut.svelte"; +import LinkItem from "./command-link-item.svelte"; + +const Loading: typeof CommandPrimitive.Loading = CommandPrimitive.Loading; + +export { + Root, + Dialog, + Empty, + Group, + Item, + LinkItem, + Input, + List, + Separator, + Shortcut, + Loading, + // + Root as Command, + Dialog as CommandDialog, + Empty as CommandEmpty, + Group as CommandGroup, + Item as CommandItem, + LinkItem as CommandLinkItem, + Input as CommandInput, + List as CommandList, + Separator as CommandSeparator, + Shortcut as CommandShortcut, + Loading as CommandLoading, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-content.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-content.svelte new file mode 100644 index 0000000..b3cd753 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-content.svelte @@ -0,0 +1,38 @@ + + + + + + {@render children?.()} + + + Close + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-description.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-description.svelte new file mode 100644 index 0000000..bc048e4 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-description.svelte @@ -0,0 +1,16 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-footer.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-footer.svelte new file mode 100644 index 0000000..91ecaba --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-footer.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-header.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-header.svelte new file mode 100644 index 0000000..8d1abfc --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-header.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-overlay.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-overlay.svelte new file mode 100644 index 0000000..05c30ac --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-overlay.svelte @@ -0,0 +1,19 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-title.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-title.svelte new file mode 100644 index 0000000..9cf592c --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/dialog-title.svelte @@ -0,0 +1,16 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/index.ts new file mode 100644 index 0000000..7c2cd73 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/dialog/index.ts @@ -0,0 +1,37 @@ +import { Dialog as DialogPrimitive } from "bits-ui"; + +import Title from "./dialog-title.svelte"; +import Footer from "./dialog-footer.svelte"; +import Header from "./dialog-header.svelte"; +import Overlay from "./dialog-overlay.svelte"; +import Content from "./dialog-content.svelte"; +import Description from "./dialog-description.svelte"; + +const Root: typeof DialogPrimitive.Root = DialogPrimitive.Root; +const Trigger: typeof DialogPrimitive.Trigger = DialogPrimitive.Trigger; +const Close: typeof DialogPrimitive.Close = DialogPrimitive.Close; +const Portal: typeof DialogPrimitive.Portal = DialogPrimitive.Portal; + +export { + Root, + Title, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + Close, + // + Root as Dialog, + Title as DialogTitle, + Portal as DialogPortal, + Footer as DialogFooter, + Header as DialogHeader, + Trigger as DialogTrigger, + Overlay as DialogOverlay, + Content as DialogContent, + Description as DialogDescription, + Close as DialogClose, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/index.ts new file mode 100644 index 0000000..8bfca0b --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/index.ts @@ -0,0 +1,7 @@ +import Root from "./label.svelte"; + +export { + Root, + // + Root as Label, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/label.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/label.svelte new file mode 100644 index 0000000..247d23c --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/label/label.svelte @@ -0,0 +1,19 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/index.ts new file mode 100644 index 0000000..63aecf9 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/index.ts @@ -0,0 +1,17 @@ +import { Popover as PopoverPrimitive } from "bits-ui"; +import Content from "./popover-content.svelte"; +const Root = PopoverPrimitive.Root; +const Trigger = PopoverPrimitive.Trigger; +const Close = PopoverPrimitive.Close; + +export { + Root, + Content, + Trigger, + Close, + // + Root as Popover, + Content as PopoverContent, + Trigger as PopoverTrigger, + Close as PopoverClose, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/popover-content.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/popover-content.svelte new file mode 100644 index 0000000..f1df6fd --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/popover/popover-content.svelte @@ -0,0 +1,28 @@ + + + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/index.ts new file mode 100644 index 0000000..f419e5f --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/index.ts @@ -0,0 +1,34 @@ +import { Select as SelectPrimitive } from "bits-ui"; + +import GroupHeading from "./select-group-heading.svelte"; +import Item from "./select-item.svelte"; +import Content from "./select-content.svelte"; +import Trigger from "./select-trigger.svelte"; +import Separator from "./select-separator.svelte"; +import ScrollDownButton from "./select-scroll-down-button.svelte"; +import ScrollUpButton from "./select-scroll-up-button.svelte"; + +const Root = SelectPrimitive.Root; +const Group = SelectPrimitive.Group; + +export { + Root, + Item, + Group, + GroupHeading, + Content, + Trigger, + Separator, + ScrollDownButton, + ScrollUpButton, + // + Root as Select, + Item as SelectItem, + Group as SelectGroup, + GroupHeading as SelectGroupHeading, + Content as SelectContent, + Trigger as SelectTrigger, + Separator as SelectSeparator, + ScrollDownButton as SelectScrollDownButton, + ScrollUpButton as SelectScrollUpButton, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-content.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-content.svelte new file mode 100644 index 0000000..42e8df4 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-content.svelte @@ -0,0 +1,38 @@ + + + + + + + {@render children?.()} + + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-group-heading.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-group-heading.svelte new file mode 100644 index 0000000..170ec23 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-group-heading.svelte @@ -0,0 +1,16 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-item.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-item.svelte new file mode 100644 index 0000000..c9eeb2d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-item.svelte @@ -0,0 +1,37 @@ + + + + {#snippet children({ selected, highlighted })} + + {#if selected} + + {/if} + + {#if childrenProp} + {@render childrenProp({ selected, highlighted })} + {:else} + {label || value} + {/if} + {/snippet} + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-down-button.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-down-button.svelte new file mode 100644 index 0000000..b927d62 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-down-button.svelte @@ -0,0 +1,19 @@ + + + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-up-button.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-up-button.svelte new file mode 100644 index 0000000..75f8d79 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-scroll-up-button.svelte @@ -0,0 +1,19 @@ + + + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-separator.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-separator.svelte new file mode 100644 index 0000000..38a3ab0 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-separator.svelte @@ -0,0 +1,13 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-trigger.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-trigger.svelte new file mode 100644 index 0000000..15f0df1 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/select/select-trigger.svelte @@ -0,0 +1,24 @@ + + +span]:line-clamp-1", + className + )} + {...restProps} +> + {@render children?.()} + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/index.ts new file mode 100644 index 0000000..82442d2 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/index.ts @@ -0,0 +1,7 @@ +import Root from "./separator.svelte"; + +export { + Root, + // + Root as Separator, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/separator.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/separator.svelte new file mode 100644 index 0000000..839494d --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/separator/separator.svelte @@ -0,0 +1,22 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/index.ts new file mode 100644 index 0000000..1ad9f4a --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/index.ts @@ -0,0 +1 @@ +export { default as Toaster } from "./sonner.svelte"; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/sonner.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/sonner.svelte new file mode 100644 index 0000000..8050e04 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/sonner/sonner.svelte @@ -0,0 +1,20 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/index.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 0000000..e9e1fd7 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,18 @@ +import { Tooltip as TooltipPrimitive } from "bits-ui"; +import Content from "./tooltip-content.svelte"; + +const Root = TooltipPrimitive.Root; +const Trigger = TooltipPrimitive.Trigger; +const Provider = TooltipPrimitive.Provider; + +export { + Root, + Trigger, + Content, + Provider, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, + Provider as TooltipProvider, +}; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/tooltip-content.svelte b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 0000000..dc7251c --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,21 @@ + + + diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/export.svelte.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/export.svelte.ts new file mode 100644 index 0000000..adce14c --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/export.svelte.ts @@ -0,0 +1,26 @@ +import { signalRState } from "./signalr/api.svelte"; + +class ExportState { + hasExportQueued = false; + + async queueExport( + formatId: string, + outputDirectory: string, + options: Map, + ) { + await signalRState.api?.server.queueExport( + formatId, + outputDirectory, + options, + ); + + this.hasExportQueued = true; + } + + async startExport() { + await signalRState.api?.server.startExport(); + this.hasExportQueued = false; + } +} + +export const exportState = $state(new ExportState()); diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/settings.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/settings.ts new file mode 100644 index 0000000..1ede03b --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/settings.ts @@ -0,0 +1,32 @@ +interface StringValue { + id: string; + label: string; +} + +interface Setting { + type: "combobox" | "option" | "filepath"; + name: StringValue; + description?: string; + condition?: { + id: string; + value: string | boolean | string[]; + }; +} + +interface ComboboxSetting extends Setting { + type: "combobox"; + default?: string; + values: StringValue[]; +} + +interface OptionSetting extends Setting { + type: "option"; + default?: boolean; +} + +interface FilepathSetting extends Setting { + type: "filepath"; + directoryPath: boolean; +} + +type SettingTypes = ComboboxSetting | OptionSetting | FilepathSetting; diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/api.svelte.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/api.svelte.ts new file mode 100644 index 0000000..88ae0e3 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/api.svelte.ts @@ -0,0 +1,55 @@ +import * as signalR from "@microsoft/signalr"; +import { SignalRClientApi } from "./client-api"; +import { SignalRServerApi } from "./server-api"; +import { getSignalRUrl } from "$lib/tauri"; + +class SignalRApi { + readonly connection: signalR.HubConnection; + readonly client: SignalRClientApi; + readonly server: SignalRServerApi; + + constructor(connection: signalR.HubConnection) { + this.connection = connection; + this.client = new SignalRClientApi(connection); + this.server = new SignalRServerApi(connection); + } +} + +class SignalRState { + api = $state(); + + get apiAvailable() { + return this.api !== undefined; + } + + async start() { + const url = await getSignalRUrl(); + + const connection = new signalR.HubConnectionBuilder() + .withUrl(url) + .withAutomaticReconnect() + .build(); + + const api = new SignalRApi(connection); + + try { + await connection.start(); + } catch (ex) { + throw new Error(`Failed to start SignalR connection: ${ex}`); + } + + this.api = api; + } + + async stop() { + try { + await this.api?.connection?.stop(); + } catch (ex) { + throw new Error(`Failed to stop SignalR connection: ${ex}`); + } + + this.api = undefined; + } +} + +export const signalRState = new SignalRState(); diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/client-api.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/client-api.ts new file mode 100644 index 0000000..2a5b4b9 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/client-api.ts @@ -0,0 +1,57 @@ +import { goto } from "$app/navigation"; +import * as signalR from "@microsoft/signalr"; +import { toast } from "svelte-sonner"; + +export class SignalRClientApi { + private connection: signalR.HubConnection; + + constructor(connection: signalR.HubConnection) { + this.connection = connection; + + this.connection.on("ShowInfoToast", (message: string) => { + toast.info(message); + }); + + this.connection.on("ShowSuccessToast", (message: string) => { + toast.success(message); + }); + + this.connection.on("ShowErrorToast", (message: string) => { + toast.error(message); + }); + + // HACK: This is put here to be persistent, as the normal import screen gets killed once the loading screen begins + // todo: improve this + this.connection.on("OnImportCompleted", async () => { + await goto("/export"); + }); + } + + onLogMessageReceived( + handler: (message: string) => Promise, + ): () => void { + return this.registerHandler("ShowLogMessage", handler); + } + + onLoadingStarted(handler: () => Promise): () => void { + return this.registerHandler("BeginLoading", handler); + } + + onLoadingFinished(handler: () => Promise): () => void { + return this.registerHandler("FinishLoading", handler); + } + + onImportCompleted(handler: () => Promise): () => void { + return this.registerHandler("OnImportCompleted", handler); + } + + private registerHandler( + name: string, + handler: (...args: any[]) => Promise, + ): () => void { + this.connection.on(name, handler); + return () => { + this.connection.off(name, handler); + }; + } +} diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/server-api.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/server-api.ts new file mode 100644 index 0000000..16280ed --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/signalr/server-api.ts @@ -0,0 +1,48 @@ +import * as signalR from "@microsoft/signalr"; + +export class SignalRServerApi { + private connection: signalR.HubConnection; + + constructor(connection: signalR.HubConnection) { + this.connection = connection; + } + + async sendUiLaunched() { + return await this.connection.send("OnUiLaunched"); + } + + async submitInputFiles(inputFiles: string[]) { + return await this.connection.send("SubmitInputFiles", inputFiles); + } + + async queueExport( + exportId: string, + targetDirectory: string, + settings: Map, + ) { + return await this.connection.send( + "QueueExport", + exportId, + targetDirectory, + Object.fromEntries(settings), + ); + } + + async startExport() { + return await this.connection.send("StartExport"); + } + + async getPotentialUnityVersions(): Promise { + return await this.connection.invoke( + "GetPotentialUnityVersions", + ); + } + + async exportIl2CppFiles(targetDirectory: string) { + return await this.connection.send("ExportIl2CppFiles", targetDirectory); + } + + async getInspectorVersion(): Promise { + return await this.connection.invoke("GetInspectorVersion"); + } +} diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/tauri.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/tauri.ts new file mode 100644 index 0000000..7f4f011 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/tauri.ts @@ -0,0 +1,16 @@ +import { invoke } from "@tauri-apps/api/core"; +import { open, save } from "@tauri-apps/plugin-dialog"; + +export async function getSignalRUrl() { + const port = await invoke("get_signalr_url"); + + if (port === "") { + throw new Error("No SignalR port specified."); + } + + if (port.match(/[0-9]*/) === null) { + throw new Error("Invalid SignalR port specified."); + } + + return `http://localhost:${port}/il2cpp`; +} diff --git a/Il2CppInspector.Redux.GUI.UI/src/lib/utils.ts b/Il2CppInspector.Redux.GUI.UI/src/lib/utils.ts new file mode 100644 index 0000000..ac680b3 --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/Il2CppInspector.Redux.GUI.UI/src/routes/+layout.svelte b/Il2CppInspector.Redux.GUI.UI/src/routes/+layout.svelte new file mode 100644 index 0000000..643da3b --- /dev/null +++ b/Il2CppInspector.Redux.GUI.UI/src/routes/+layout.svelte @@ -0,0 +1,23 @@ + + + + + +
+