mirror of
https://github.com/GreemDev/Ryujinx
synced 2025-01-26 15:27:10 +01:00
Some small fixes
The data now loads but SMBU says it can't be loaded The date time is for some reason in the future idk why still working on it
This commit is contained in:
parent
6b155f5fbe
commit
46f8b8fa85
3 changed files with 90 additions and 72 deletions
|
@ -3,9 +3,11 @@ using Ryujinx.HLE.HOS.Services.Nfc.Nfp;
|
|||
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
||||
using Ryujinx.HLE.HOS.Tamper;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
|
@ -64,17 +66,24 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
byte[] writeDate = new byte[2];
|
||||
byte[] writeCounter = new byte[2];
|
||||
byte formData = 0;
|
||||
byte[] applicationAreas = new byte[212];
|
||||
byte[] applicationAreas = new byte[216];
|
||||
byte[] appid = new byte[2];
|
||||
byte[] SettingsBytes = new byte[2];
|
||||
//// apply to decrypt bytes self.data[304:308] = self._calculate_crc32(self.data[308:520]).to_bytes(4, "little")
|
||||
//byte[] crc32Bytes = new byte[212];
|
||||
//Array.Copy(decryptedFileBytes, 308, crc32Bytes, 0, 212);
|
||||
//byte[] toApply = BitConverter.GetBytes(CalculateCRC32(crc32Bytes));
|
||||
//Array.Reverse(crc32Bytes);
|
||||
//Array.Copy(toApply, 0, decryptedFileBytes, 304, 4);
|
||||
|
||||
// Reading specific pages and parsing bytes
|
||||
for (int page = 0; page < 128; page++) // NTAG215 has 128 pages
|
||||
for (int page = 0; page < 134; page++) // NTAG215 has 128 pages
|
||||
{
|
||||
int pageStartIdx = page * 4; // Each page is 4 bytes
|
||||
byte[] pageData = new byte[4];
|
||||
bool isEncrypted = IsPageEncrypted(page);
|
||||
byte[] sourceBytes = isEncrypted ? decryptedFileBytes : fileBytes;
|
||||
Array.Copy(sourceBytes, pageStartIdx, pageData, 0, 4);
|
||||
|
||||
// Special handling for specific pages
|
||||
switch (page)
|
||||
{
|
||||
|
@ -86,6 +95,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
byte internalValue = pageData[1];
|
||||
Console.WriteLine($"Page 2: BCC1 + Internal Value 0x{internalValue:X2} (Expected 0x48).");
|
||||
break;
|
||||
case 5:
|
||||
// byte 0 amd 1 are settings
|
||||
Array.Copy(pageData, 0, SettingsBytes, 0, 2);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// Bytes 0 and 1 are init date, bytes 2 and 3 are write date
|
||||
|
@ -126,22 +139,28 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
case 66:
|
||||
// Bytes 0 and 1 are write counter
|
||||
Array.Copy(pageData, 0, writeCounter, 0, 2);
|
||||
// bytes 2 and 3 are appid
|
||||
Array.Copy(pageData, 2, appid, 0, 2);
|
||||
break;
|
||||
|
||||
// Pages 76 to 127 are application areas
|
||||
case >= 76 and <= 127:
|
||||
case >= 76 and <= 129:
|
||||
int appAreaOffset = (page - 76) * 4;
|
||||
Array.Copy(pageData, 0, applicationAreas, appAreaOffset, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Debugging
|
||||
string titleIdStr = BitConverter.ToString(titleId).Replace("-", "");
|
||||
uint titleIdStr = BitConverter.ToUInt32(titleId, 0);
|
||||
string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", "");
|
||||
string variationStr = BitConverter.ToString(variation).Replace("-", "");
|
||||
string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", "");
|
||||
string formDataStr = formData.ToString("X2");
|
||||
string setIDStr = BitConverter.ToString(setID).Replace("-", "");
|
||||
uint settingsStr = BitConverter.ToUInt16(SettingsBytes, 0);
|
||||
|
||||
string nickName = Encoding.BigEndianUnicode.GetString(nickNameBytes).TrimEnd('\0');
|
||||
string head = usedCharacterStr + variationStr;
|
||||
string tail = amiiboIDStr + setIDStr + "02";
|
||||
|
@ -161,6 +180,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
Console.WriteLine($"Nickname: {nickName}");
|
||||
Console.WriteLine($"Init Date: {initDateStr}");
|
||||
Console.WriteLine($"Write Date: {writeDateStr}");
|
||||
Console.WriteLine($"Settings: {settingsStr}");
|
||||
Console.WriteLine("Length of Application Areas: " + applicationAreas.Length);
|
||||
|
||||
VirtualAmiiboFile virtualAmiiboFile = new VirtualAmiiboFile
|
||||
{
|
||||
|
@ -168,9 +189,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
TagUuid = uid,
|
||||
AmiiboId = finalID
|
||||
};
|
||||
|
||||
DateTime initDateTime = DateTimeFromBytes(initDate);
|
||||
DateTime writeDateTime = DateTimeFromBytes(writeDate);
|
||||
ushort initDateValue = BitConverter.ToUInt16(initDate, 0);
|
||||
ushort writeDateValue = BitConverter.ToUInt16(writeDate, 0);
|
||||
DateTime initDateTime = DateTimeFromTag(initDateValue);
|
||||
DateTime writeDateTime = DateTimeFromTag(writeDateValue);
|
||||
|
||||
Console.WriteLine($"Parsed Init Date: {initDateTime}");
|
||||
Console.WriteLine($"Parsed Write Date: {writeDateTime}");
|
||||
|
@ -178,18 +200,44 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
virtualAmiiboFile.FirstWriteDate = initDateTime;
|
||||
virtualAmiiboFile.LastWriteDate = writeDateTime;
|
||||
virtualAmiiboFile.WriteCounter = BitConverter.ToUInt16(writeCounter, 0);
|
||||
|
||||
// Parse application areas
|
||||
//List<VirtualAmiiboApplicationArea> applicationAreasList = ParseAmiiboData(applicationAreas);
|
||||
List<VirtualAmiiboApplicationArea> applicationAreasList = new List<VirtualAmiiboApplicationArea>();
|
||||
virtualAmiiboFile.ApplicationAreas = applicationAreasList;
|
||||
|
||||
// Save the virtual Amiibo file
|
||||
VirtualAmiibo.SaveAmiiboFile(virtualAmiiboFile);
|
||||
|
||||
VirtualAmiibo.applicationBytes = applicationAreas;
|
||||
return virtualAmiiboFile;
|
||||
}
|
||||
|
||||
public static uint CalculateCRC32(byte[] input)
|
||||
{
|
||||
// Setup CRC 32 table
|
||||
uint p0 = 0xEDB88320u | 0x80000000u;
|
||||
uint[] u0 = new uint[0x100];
|
||||
|
||||
for (uint i = 1; i < 0x100; i++)
|
||||
{
|
||||
uint t0 = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if ((t0 & 1) != 0)
|
||||
{
|
||||
t0 = (t0 >> 1) ^ p0;
|
||||
}
|
||||
else
|
||||
{
|
||||
t0 >>= 1;
|
||||
}
|
||||
}
|
||||
u0[i] = t0;
|
||||
}
|
||||
|
||||
// Calculate CRC32 from table
|
||||
uint t = 0x0;
|
||||
foreach (byte k in input)
|
||||
{
|
||||
t = (t >> 8) ^ u0[(k ^ t) & 0xFF];
|
||||
}
|
||||
|
||||
return t ^ 0xFFFFFFFFu;
|
||||
}
|
||||
|
||||
private static string GetKeyRetailBinPath()
|
||||
{
|
||||
return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin");
|
||||
|
@ -197,37 +245,25 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
|
||||
public static bool IsPageEncrypted(int page)
|
||||
{
|
||||
return (page >= 6 && page <= 9) || (page >= 43 && page <= 84);
|
||||
// 0-4 are not encrypted, 5-12 is encrypted, 13-39 is not encrypted,
|
||||
// 40-129 is encrypted, and 130-134 is not encrypted.
|
||||
|
||||
return (page >= 5 && page <= 12) || (page >= 40 && page <= 129);
|
||||
}
|
||||
|
||||
public static DateTime DateTimeFromBytes(byte[] date)
|
||||
public static DateTime DateTimeFromTag(ushort value)
|
||||
{
|
||||
if (date == null || date.Length != 2)
|
||||
{
|
||||
Console.WriteLine("Invalid date bytes.");
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
ushort value = BitConverter.ToUInt16(date, 0);
|
||||
|
||||
int day = value & 0x1F;
|
||||
int month = (value >> 5) & 0x0F;
|
||||
int year = (value >> 9) & 0x7F;
|
||||
|
||||
try
|
||||
{
|
||||
return new DateTime(2000 + year, month, day);
|
||||
var day = value & 0x1F;
|
||||
var month = (value >> 5) & 0x0F;
|
||||
var year = (value >> 9) & 0x7F;
|
||||
return new DateTime(1970 + year, month, day);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Invalid date values extracted.");
|
||||
return DateTime.MinValue;
|
||||
return DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<VirtualAmiiboApplicationArea> ParseAmiiboData(byte[] decryptedData)
|
||||
{
|
||||
return JsonSerializer.Deserialize<List<VirtualAmiiboApplicationArea>>(decryptedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,35 +79,5 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Bin
|
|||
break; // Stop if no overflow
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime ParseDate(byte[] data, int offset)
|
||||
{
|
||||
ushort year = BitConverter.ToUInt16(data, offset);
|
||||
byte month = data[offset + 2];
|
||||
byte day = data[offset + 3];
|
||||
byte hour = data[offset + 4];
|
||||
byte minute = data[offset + 5];
|
||||
byte second = data[offset + 6];
|
||||
|
||||
return new DateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
public List<object> ParseApplicationAreas(byte[] data, int startOffset, int areaSize)
|
||||
{
|
||||
var areas = new List<object>();
|
||||
for (int i = 0; i < 8; i++) // Assuming 8 areas
|
||||
{
|
||||
int offset = startOffset + (i * areaSize);
|
||||
string applicationId = BitConverter.ToString(data[offset..(offset + 4)]).Replace("-", "");
|
||||
byte[] areaData = data[(offset + 4)..(offset + areaSize)];
|
||||
areas.Add(new VirtualAmiiboApplicationArea
|
||||
{
|
||||
ApplicationAreaId = uint.Parse(applicationId),
|
||||
ApplicationArea = areaData
|
||||
});
|
||||
}
|
||||
|
||||
return areas;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
{
|
||||
static class VirtualAmiibo
|
||||
{
|
||||
private static uint _openedApplicationAreaId;
|
||||
|
||||
public static uint _openedApplicationAreaId;
|
||||
public static byte[] applicationBytes = new byte[0];
|
||||
private static readonly AmiiboJsonSerializerContext _serializerContext = AmiiboJsonSerializerContext.Default;
|
||||
|
||||
public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid)
|
||||
{
|
||||
if (useRandomUuid)
|
||||
|
@ -103,6 +102,11 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
|
||||
{
|
||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||
if (applicationBytes.Length > 0)
|
||||
{
|
||||
_openedApplicationAreaId = applicationAreaId;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId))
|
||||
{
|
||||
|
@ -116,6 +120,12 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
|
||||
public static byte[] GetApplicationArea(string amiiboId)
|
||||
{
|
||||
if (applicationBytes.Length > 0)
|
||||
{
|
||||
byte[] bytes = applicationBytes;
|
||||
applicationBytes = new byte[0];
|
||||
return bytes;
|
||||
}
|
||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||
|
||||
foreach (VirtualAmiiboApplicationArea applicationArea in virtualAmiiboFile.ApplicationAreas)
|
||||
|
@ -209,5 +219,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");
|
||||
JsonHelper.SerializeToFile(filePath, virtualAmiiboFile, _serializerContext.VirtualAmiiboFile);
|
||||
}
|
||||
|
||||
public static bool SaveFileExists(VirtualAmiiboFile virtualAmiiboFile) => File.Exists(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue