mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-20 17:51:13 +02:00
LibKenjinx: Fix possible NullReferenceExceptions
This commit is contained in:
@@ -61,7 +61,7 @@ namespace LibKenjinx
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Try call method with single bool
|
// Try call method with single bool
|
||||||
private static bool TryCallBool(object target, string[] names, bool arg)
|
private static bool TryCallBool(object? target, string[] names, bool arg)
|
||||||
{
|
{
|
||||||
if (target == null) return false;
|
if (target == null) return false;
|
||||||
var t = target.GetType();
|
var t = target.GetType();
|
||||||
@@ -77,7 +77,7 @@ namespace LibKenjinx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try call method with single float
|
// Try call method with single float
|
||||||
private static bool TryCallFloat(object target, string[] names, float arg)
|
private static bool TryCallFloat(object? target, string[] names, float arg)
|
||||||
{
|
{
|
||||||
if (target == null) return false;
|
if (target == null) return false;
|
||||||
var t = target.GetType();
|
var t = target.GetType();
|
||||||
@@ -93,7 +93,7 @@ namespace LibKenjinx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try set property (float/double)
|
// Try set property (float/double)
|
||||||
private static bool TrySetFloatProp(object target, string[] names, float value)
|
private static bool TrySetFloatProp(object? target, string[] names, float value)
|
||||||
{
|
{
|
||||||
if (target == null) return false;
|
if (target == null) return false;
|
||||||
var t = target.GetType();
|
var t = target.GetType();
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ namespace LibKenjinx
|
|||||||
|
|
||||||
public static void InstallFirmware(Stream stream, bool isXci)
|
public static void InstallFirmware(Stream stream, bool isXci)
|
||||||
{
|
{
|
||||||
SwitchDevice?.ContentManager.InstallFirmware(stream, isXci);
|
SwitchDevice?.ContentManager?.InstallFirmware(stream, isXci);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetInstalledFirmwareVersion()
|
public static string GetInstalledFirmwareVersion()
|
||||||
{
|
{
|
||||||
var version = SwitchDevice?.ContentManager.GetCurrentFirmwareVersion();
|
var version = SwitchDevice?.ContentManager?.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
if (version != null)
|
if (version != null)
|
||||||
{
|
{
|
||||||
@@ -71,7 +71,7 @@ namespace LibKenjinx
|
|||||||
|
|
||||||
public static SystemVersion? VerifyFirmware(Stream stream, bool isXci)
|
public static SystemVersion? VerifyFirmware(Stream stream, bool isXci)
|
||||||
{
|
{
|
||||||
return SwitchDevice?.ContentManager.VerifyFirmwarePackage(stream, isXci) ?? null;
|
return SwitchDevice?.ContentManager?.VerifyFirmwarePackage(stream, isXci) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool LoadApplication(Stream stream, FileType type, Stream? updateStream = null)
|
public static bool LoadApplication(Stream stream, FileType type, Stream? updateStream = null)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace LibKenjinx
|
|||||||
{
|
{
|
||||||
public static string GetOpenedUser()
|
public static string GetOpenedUser()
|
||||||
{
|
{
|
||||||
var lastProfile = SwitchDevice?.AccountManager.LastOpenedUser;
|
var lastProfile = SwitchDevice?.AccountManager?.LastOpenedUser;
|
||||||
|
|
||||||
return lastProfile?.UserId.ToString() ?? "";
|
return lastProfile?.UserId.ToString() ?? "";
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace LibKenjinx
|
|||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
|
|
||||||
var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
var user = SwitchDevice?.AccountManager?.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
return "";
|
return "";
|
||||||
@@ -31,14 +31,14 @@ namespace LibKenjinx
|
|||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
|
|
||||||
SwitchDevice?.AccountManager.SetUserImage(uid, Convert.FromBase64String(picture));
|
SwitchDevice?.AccountManager?.SetUserImage(uid, Convert.FromBase64String(picture));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetUserName(string userId)
|
public static string GetUserName(string userId)
|
||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
|
|
||||||
var user = SwitchDevice?.AccountManager.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
var user = SwitchDevice?.AccountManager?.GetAllUsers().FirstOrDefault(x => x.UserId == uid);
|
||||||
|
|
||||||
return user?.Name ?? "";
|
return user?.Name ?? "";
|
||||||
}
|
}
|
||||||
@@ -47,36 +47,36 @@ namespace LibKenjinx
|
|||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
|
|
||||||
SwitchDevice?.AccountManager.SetUserName(uid, name);
|
SwitchDevice?.AccountManager?.SetUserName(uid, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] GetAllUsers()
|
public static string[] GetAllUsers()
|
||||||
{
|
{
|
||||||
return SwitchDevice?.AccountManager.GetAllUsers().Select(x => x.UserId.ToString()).ToArray() ??
|
return SwitchDevice?.AccountManager?.GetAllUsers().Select(x => x.UserId.ToString()).ToArray() ??
|
||||||
[];
|
[];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddUser(string userName, string picture)
|
public static void AddUser(string userName, string picture)
|
||||||
{
|
{
|
||||||
SwitchDevice?.AccountManager.AddUser(userName, Convert.FromBase64String(picture));
|
SwitchDevice?.AccountManager?.AddUser(userName, Convert.FromBase64String(picture));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeleteUser(string userId)
|
public static void DeleteUser(string userId)
|
||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
SwitchDevice?.AccountManager.DeleteUser(uid);
|
SwitchDevice?.AccountManager?.DeleteUser(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenUser(string userId)
|
public static void OpenUser(string userId)
|
||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
SwitchDevice?.AccountManager.OpenUser(uid);
|
SwitchDevice?.AccountManager?.OpenUser(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CloseUser(string userId)
|
public static void CloseUser(string userId)
|
||||||
{
|
{
|
||||||
var uid = new UserId(userId);
|
var uid = new UserId(userId);
|
||||||
SwitchDevice?.AccountManager.CloseUser(uid);
|
SwitchDevice?.AccountManager?.CloseUser(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ namespace LibKenjinx
|
|||||||
if (File.Exists(updatePath))
|
if (File.Exists(updatePath))
|
||||||
{
|
{
|
||||||
FileStream file = new(updatePath, FileMode.Open, FileAccess.Read);
|
FileStream file = new(updatePath, FileMode.Open, FileAccess.Read);
|
||||||
IFileSystem pfs = null;
|
IFileSystem pfs;
|
||||||
|
|
||||||
if (Path.GetExtension(updatePath).ToLower() == ".xci")
|
if (Path.GetExtension(updatePath).ToLower() == ".xci")
|
||||||
{
|
{
|
||||||
@@ -616,8 +616,7 @@ namespace LibKenjinx
|
|||||||
|
|
||||||
partitionFileSystem.OpenFile(ref ncaFile.Ref, ncaPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
partitionFileSystem.OpenFile(ref ncaFile.Ref, ncaPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), ncaPath);
|
if (TryOpenNca(ncaFile.Get.AsStorage(), ncaPath) is { } nca)
|
||||||
if (nca != null)
|
|
||||||
{
|
{
|
||||||
return nca.Header.TitleId.ToString("X16");
|
return nca.Header.TitleId.ToString("X16");
|
||||||
}
|
}
|
||||||
@@ -627,7 +626,7 @@ namespace LibKenjinx
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Nca TryOpenNca(IStorage ncaStorage, string containerPath)
|
private static Nca? TryOpenNca(IStorage ncaStorage, string containerPath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -661,7 +660,7 @@ namespace LibKenjinx
|
|||||||
|
|
||||||
partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
|
Nca? nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
|
||||||
if (nca == null)
|
if (nca == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -698,7 +697,7 @@ namespace LibKenjinx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ===== Amiibo Helpers (Kenjinx) =====
|
// ===== Amiibo Helpers (Kenjinx) =====
|
||||||
public static bool AmiiboLoadFromBytes(byte[] data)
|
public static bool AmiiboLoadFromBytes(byte[]? data)
|
||||||
{
|
{
|
||||||
if (data == null || data.Length == 0)
|
if (data == null || data.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -755,13 +754,13 @@ namespace LibKenjinx
|
|||||||
public class SwitchDevice : IDisposable
|
public class SwitchDevice : IDisposable
|
||||||
|
|
||||||
{
|
{
|
||||||
private readonly SystemVersion _firmwareVersion;
|
private readonly SystemVersion? _firmwareVersion;
|
||||||
private int _contextDisposeState;
|
private int _contextDisposeState;
|
||||||
public VirtualFileSystem VirtualFileSystem { get; set; }
|
public VirtualFileSystem VirtualFileSystem { get; set; }
|
||||||
public ContentManager ContentManager { get; set; }
|
public ContentManager? ContentManager { get; set; }
|
||||||
public AccountManager AccountManager { get; set; }
|
public AccountManager? AccountManager { get; set; }
|
||||||
public LibHacHorizonManager LibHacHorizonManager { get; set; }
|
public LibHacHorizonManager? LibHacHorizonManager { get; set; }
|
||||||
public UserChannelPersistence UserChannelPersistence { get; set; }
|
public UserChannelPersistence? UserChannelPersistence { get; set; }
|
||||||
public InputManager? InputManager { get; set; }
|
public InputManager? InputManager { get; set; }
|
||||||
public Switch? EmulationContext { get; set; }
|
public Switch? EmulationContext { get; set; }
|
||||||
public IHostUIHandler? HostUiHandler { get; set; }
|
public IHostUIHandler? HostUiHandler { get; set; }
|
||||||
@@ -949,7 +948,7 @@ namespace LibKenjinx
|
|||||||
// --- Prepare paths for the physical save directory (Android sandbox)
|
// --- Prepare paths for the physical save directory (Android sandbox)
|
||||||
string savesRoot = Path.Combine(
|
string savesRoot = Path.Combine(
|
||||||
AppDataManager.BaseDirPath,
|
AppDataManager.BaseDirPath,
|
||||||
Ryujinx.HLE.FileSystem.VirtualFileSystem.UserNandPath,
|
VirtualFileSystem.UserNandPath,
|
||||||
"save"
|
"save"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -963,17 +962,24 @@ namespace LibKenjinx
|
|||||||
catch { /* ignore */ }
|
catch { /* ignore */ }
|
||||||
|
|
||||||
// Call existing Horizon APIs to create/secure the saves
|
// Call existing Horizon APIs to create/secure the saves
|
||||||
var rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control);
|
if (LibHacHorizonManager != null)
|
||||||
if (rc.IsFailure())
|
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationCacheStorage. Result code {rc.ToStringWithName()}");
|
var rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control);
|
||||||
}
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationCacheStorage. Result code {rc.ToStringWithName()}");
|
||||||
|
}
|
||||||
|
|
||||||
Uid userId = AccountManager.LastOpenedUser.UserId.ToLibHacUid();
|
if (AccountManager != null)
|
||||||
rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in userId);
|
{
|
||||||
if (rc.IsFailure())
|
Uid userId = AccountManager.LastOpenedUser.UserId.ToLibHacUid();
|
||||||
{
|
rc = LibHacHorizonManager.RyujinxClient.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in userId);
|
||||||
Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationSaveData. Result code {rc.ToStringWithName()}");
|
}
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationSaveData. Result code {rc.ToStringWithName()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the after-list of save dirs and calculate the difference
|
// Get the after-list of save dirs and calculate the difference
|
||||||
@@ -1013,7 +1019,10 @@ namespace LibKenjinx
|
|||||||
File.WriteAllText(markerFile, $"{titleIdHex}\n{titleName}");
|
File.WriteAllText(markerFile, $"{titleIdHex}\n{titleName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
UpsertTitleMapNdjson(savesRoot, titleIdHex, titleName, createdSaveDirName);
|
if (createdSaveDirName != null)
|
||||||
|
{
|
||||||
|
UpsertTitleMapNdjson(savesRoot, titleIdHex, titleName, createdSaveDirName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1038,7 +1047,7 @@ namespace LibKenjinx
|
|||||||
/// - Completely rewrites the file (no unlimited size increase)
|
/// - Completely rewrites the file (no unlimited size increase)
|
||||||
/// - NEVER overwrites the folder with an empty value; attempts to determine it via markers
|
/// - NEVER overwrites the folder with an empty value; attempts to determine it via markers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void UpsertTitleMapNdjson(string savesRoot, string titleIdHex, string titleName, string createdFolder)
|
private static void UpsertTitleMapNdjson(string savesRoot, string? titleIdHex, string? titleName, string createdFolder)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(savesRoot);
|
Directory.CreateDirectory(savesRoot);
|
||||||
string mapPath = Path.Combine(savesRoot, "titleid_map.ndjson");
|
string mapPath = Path.Combine(savesRoot, "titleid_map.ndjson");
|
||||||
@@ -1092,7 +1101,7 @@ namespace LibKenjinx
|
|||||||
string effectiveFolder = createdFolder;
|
string effectiveFolder = createdFolder;
|
||||||
if (string.IsNullOrWhiteSpace(effectiveFolder))
|
if (string.IsNullOrWhiteSpace(effectiveFolder))
|
||||||
{
|
{
|
||||||
effectiveFolder = ResolveSaveFolderByMarker(savesRoot, titleIdLc);
|
effectiveFolder = ResolveSaveFolderByMarker(savesRoot, titleIdLc) ?? string.Empty;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrWhiteSpace(effectiveFolder) && !string.IsNullOrWhiteSpace(existingFolder))
|
if (string.IsNullOrWhiteSpace(effectiveFolder) && !string.IsNullOrWhiteSpace(existingFolder))
|
||||||
{
|
{
|
||||||
@@ -1122,7 +1131,7 @@ namespace LibKenjinx
|
|||||||
string finalFolder = string.IsNullOrWhiteSpace(effectiveFolder) ? (existing.Folder ?? "") : effectiveFolder;
|
string finalFolder = string.IsNullOrWhiteSpace(effectiveFolder) ? (existing.Folder ?? "") : effectiveFolder;
|
||||||
string finalTs = nowIso;
|
string finalTs = nowIso;
|
||||||
|
|
||||||
byTitleId[titleIdLc] = (finalName ?? "", finalFolder ?? "", finalTs);
|
byTitleId[titleIdLc] = (finalName, finalFolder, finalTs);
|
||||||
|
|
||||||
// 5) rewrite file (stable: sort by titleId)
|
// 5) rewrite file (stable: sort by titleId)
|
||||||
try
|
try
|
||||||
@@ -1145,7 +1154,7 @@ namespace LibKenjinx
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scans save subfolders for a TITLEID.txt whose first line equals the titleId; returns folder name or null.
|
/// Scans save subfolders for a TITLEID.txt whose first line equals the titleId; returns folder name or null.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static string ResolveSaveFolderByMarker(string savesRoot, string titleIdLc)
|
private static string? ResolveSaveFolderByMarker(string savesRoot, string titleIdLc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1159,7 +1168,7 @@ namespace LibKenjinx
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var sr = new StreamReader(marker, Encoding.UTF8, true);
|
using var sr = new StreamReader(marker, Encoding.UTF8, true);
|
||||||
string first = sr.ReadLine()?.Trim()?.ToLowerInvariant();
|
string? first = sr.ReadLine()?.Trim().ToLowerInvariant();
|
||||||
if (first == titleIdLc)
|
if (first == titleIdLc)
|
||||||
{
|
{
|
||||||
return Path.GetFileName(dir);
|
return Path.GetFileName(dir);
|
||||||
@@ -1210,7 +1219,7 @@ namespace LibKenjinx
|
|||||||
{
|
{
|
||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
ContentManager = new ContentManager(VirtualFileSystem);
|
ContentManager = new ContentManager(VirtualFileSystem);
|
||||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient);
|
AccountManager = new AccountManager(LibHacHorizonManager?.RyujinxClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,14 +55,14 @@ namespace LibKenjinx
|
|||||||
byte* xp = (byte*)xPtr;
|
byte* xp = (byte*)xPtr;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nint ptr = default;
|
nint ptr;
|
||||||
ptr = _getInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault().Handle, xPtr);
|
ptr = _getInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault().Handle, xPtr);
|
||||||
|
|
||||||
if (ptr == default)
|
if (ptr == 0)
|
||||||
{
|
{
|
||||||
ptr = _getInstanceProcAddr(nint.Zero, xPtr);
|
ptr = _getInstanceProcAddr(nint.Zero, xPtr);
|
||||||
|
|
||||||
if (ptr == default)
|
if (ptr == 0)
|
||||||
{
|
{
|
||||||
var currentDevice = ret.CurrentDevice.GetValueOrDefault().Handle;
|
var currentDevice = ret.CurrentDevice.GetValueOrDefault().Handle;
|
||||||
if (currentDevice != nint.Zero)
|
if (currentDevice != nint.Zero)
|
||||||
@@ -70,7 +70,7 @@ namespace LibKenjinx
|
|||||||
ptr = _getDeviceProcAddr(currentDevice, xPtr);
|
ptr = _getDeviceProcAddr(currentDevice, xPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr == default)
|
if (ptr == 0)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Gpu, $"Failed to get function pointer: {x}");
|
Logger.Warning?.Print(LogClass.Gpu, $"Failed to get function pointer: {x}");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user