mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add content storage and content meta DB interfaces
This commit is contained in:
parent
e9376efba7
commit
c3dfaf14e8
13 changed files with 439 additions and 115 deletions
|
@ -1,6 +1,8 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using LibHac.Fs.NcaUtils;
|
||||
using LibHac.Ncm;
|
||||
using ContentType = LibHac.Ncm.ContentType;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
|
@ -8,7 +10,7 @@ namespace LibHac
|
|||
{
|
||||
public ulong TitleId { get; }
|
||||
public TitleVersion TitleVersion { get; }
|
||||
public TitleType Type { get; }
|
||||
public ContentMetaType Type { get; }
|
||||
public byte FieldD { get; }
|
||||
public int TableOffset { get; }
|
||||
public int ContentEntryCount { get; }
|
||||
|
@ -34,8 +36,8 @@ namespace LibHac
|
|||
{
|
||||
TitleId = reader.ReadUInt64();
|
||||
uint version = reader.ReadUInt32();
|
||||
Type = (TitleType)reader.ReadByte();
|
||||
TitleVersion = new TitleVersion(version, Type < TitleType.Application);
|
||||
Type = (ContentMetaType)reader.ReadByte();
|
||||
TitleVersion = new TitleVersion(version, Type < ContentMetaType.Application);
|
||||
FieldD = reader.ReadByte();
|
||||
TableOffset = reader.ReadUInt16();
|
||||
ContentEntryCount = reader.ReadUInt16();
|
||||
|
@ -44,16 +46,16 @@ namespace LibHac
|
|||
|
||||
switch (Type)
|
||||
{
|
||||
case TitleType.Application:
|
||||
case ContentMetaType.Application:
|
||||
ApplicationTitleId = TitleId;
|
||||
PatchTitleId = reader.ReadUInt64();
|
||||
MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true);
|
||||
break;
|
||||
case TitleType.Patch:
|
||||
case ContentMetaType.Patch:
|
||||
ApplicationTitleId = reader.ReadUInt64();
|
||||
MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true);
|
||||
break;
|
||||
case TitleType.AddOnContent:
|
||||
case ContentMetaType.AddOnContent:
|
||||
ApplicationTitleId = reader.ReadUInt64();
|
||||
MinimumApplicationVersion = new TitleVersion(reader.ReadUInt32());
|
||||
break;
|
||||
|
@ -74,7 +76,7 @@ namespace LibHac
|
|||
MetaEntries[i] = new CnmtContentMetaEntry(reader);
|
||||
}
|
||||
|
||||
if (Type == TitleType.Patch)
|
||||
if (Type == ContentMetaType.Patch)
|
||||
{
|
||||
ExtendedData = new CnmtExtended(reader);
|
||||
}
|
||||
|
@ -89,7 +91,7 @@ namespace LibHac
|
|||
public byte[] Hash { get; set; }
|
||||
public byte[] NcaId { get; set; }
|
||||
public long Size { get; set; }
|
||||
public CnmtContentType Type { get; set; }
|
||||
public ContentType Type { get; set; }
|
||||
|
||||
public CnmtContentEntry() { }
|
||||
|
||||
|
@ -99,7 +101,7 @@ namespace LibHac
|
|||
NcaId = reader.ReadBytes(0x10);
|
||||
Size = reader.ReadUInt32();
|
||||
Size |= (long)reader.ReadUInt16() << 32;
|
||||
Type = (CnmtContentType)reader.ReadByte();
|
||||
Type = (ContentType)reader.ReadByte();
|
||||
reader.BaseStream.Position += 1;
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +110,7 @@ namespace LibHac
|
|||
{
|
||||
public ulong TitleId { get; }
|
||||
public TitleVersion Version { get; }
|
||||
public CnmtContentType Type { get; }
|
||||
public ContentType Type { get; }
|
||||
|
||||
public CnmtContentMetaEntry() { }
|
||||
|
||||
|
@ -116,7 +118,7 @@ namespace LibHac
|
|||
{
|
||||
TitleId = reader.ReadUInt64();
|
||||
Version = new TitleVersion(reader.ReadUInt32(), true);
|
||||
Type = (CnmtContentType)reader.ReadByte();
|
||||
Type = (ContentType)reader.ReadByte();
|
||||
reader.BaseStream.Position += 3;
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +201,7 @@ namespace LibHac
|
|||
{
|
||||
public ulong TitleId { get; }
|
||||
public TitleVersion Version { get; }
|
||||
public TitleType Type { get; }
|
||||
public ContentMetaType Type { get; }
|
||||
public byte[] Hash { get; }
|
||||
public short ContentCount { get; }
|
||||
public short CnmtPrevMetaEntryField32 { get; }
|
||||
|
@ -209,7 +211,7 @@ namespace LibHac
|
|||
{
|
||||
TitleId = reader.ReadUInt64();
|
||||
Version = new TitleVersion(reader.ReadUInt32());
|
||||
Type = (TitleType)reader.ReadByte();
|
||||
Type = (ContentMetaType)reader.ReadByte();
|
||||
reader.BaseStream.Position += 3;
|
||||
Hash = reader.ReadBytes(0x20);
|
||||
ContentCount = reader.ReadInt16();
|
||||
|
@ -265,8 +267,8 @@ namespace LibHac
|
|||
public long SizeOld { get; }
|
||||
public long SizeNew { get; }
|
||||
public short FragmentCount { get; }
|
||||
public CnmtContentType Type { get; }
|
||||
public CnmtDeltaType DeltaType { get; }
|
||||
public ContentType Type { get; }
|
||||
public UpdateType DeltaType { get; }
|
||||
public int FragmentSetInfoField30 { get; }
|
||||
|
||||
|
||||
|
@ -281,8 +283,8 @@ namespace LibHac
|
|||
SizeNew = reader.ReadUInt32();
|
||||
|
||||
FragmentCount = reader.ReadInt16();
|
||||
Type = (CnmtContentType)reader.ReadByte();
|
||||
DeltaType = (CnmtDeltaType)reader.ReadByte();
|
||||
Type = (ContentType)reader.ReadByte();
|
||||
DeltaType = (UpdateType)reader.ReadByte();
|
||||
FragmentSetInfoField30 = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
@ -291,14 +293,14 @@ namespace LibHac
|
|||
{
|
||||
public byte[] NcaId { get; }
|
||||
public long Size { get; }
|
||||
public CnmtContentType Type { get; }
|
||||
public ContentType Type { get; }
|
||||
|
||||
public CnmtPrevContent(BinaryReader reader)
|
||||
{
|
||||
NcaId = reader.ReadBytes(0x10);
|
||||
Size = reader.ReadUInt32();
|
||||
Size |= (long)reader.ReadUInt16() << 32;
|
||||
Type = (CnmtContentType)reader.ReadByte();
|
||||
Type = (ContentType)reader.ReadByte();
|
||||
reader.BaseStream.Position += 1;
|
||||
}
|
||||
}
|
||||
|
@ -314,35 +316,4 @@ namespace LibHac
|
|||
FragmentIndex = reader.ReadInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public enum CnmtContentType
|
||||
{
|
||||
Meta,
|
||||
Program,
|
||||
Data,
|
||||
Control,
|
||||
HtmlDocument,
|
||||
LegalInformation,
|
||||
DeltaFragment
|
||||
}
|
||||
|
||||
public enum CnmtDeltaType
|
||||
{
|
||||
Delta,
|
||||
Replace,
|
||||
NewContent
|
||||
}
|
||||
|
||||
public enum TitleType
|
||||
{
|
||||
SystemProgram = 1,
|
||||
SystemData,
|
||||
SystemUpdate,
|
||||
BootImagePackage,
|
||||
BootImagePackageSafe,
|
||||
Application = 0x80,
|
||||
Patch,
|
||||
AddOnContent,
|
||||
Delta
|
||||
}
|
||||
}
|
||||
|
|
101
src/LibHac/Common/Id128.cs
Normal file
101
src/LibHac/Common/Id128.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic 128-bit ID value.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct Id128 : IEquatable<Id128>, IComparable<Id128>, IComparable
|
||||
{
|
||||
public readonly ulong High;
|
||||
public readonly ulong Low;
|
||||
|
||||
public static Id128 InvalidId = new Id128(0, 0);
|
||||
|
||||
public Id128(ulong high, ulong low)
|
||||
{
|
||||
High = high;
|
||||
Low = low;
|
||||
}
|
||||
|
||||
public Id128(ReadOnlySpan<byte> uid)
|
||||
{
|
||||
ReadOnlySpan<ulong> longs = MemoryMarshal.Cast<byte, ulong>(uid);
|
||||
|
||||
High = longs[0];
|
||||
Low = longs[1];
|
||||
}
|
||||
|
||||
public bool Equals(Id128 other)
|
||||
{
|
||||
return High == other.High && Low == other.Low;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Fs.UserId other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (High.GetHashCode() * 397) ^ Low.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(Id128 other)
|
||||
{
|
||||
// ReSharper disable ImpureMethodCallOnReadonlyValueField
|
||||
int highComparison = High.CompareTo(other.High);
|
||||
if (highComparison != 0) return highComparison;
|
||||
return Low.CompareTo(other.Low);
|
||||
// ReSharper restore ImpureMethodCallOnReadonlyValueField
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is null) return 1;
|
||||
return obj is Id128 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Id128)}");
|
||||
}
|
||||
|
||||
public void ToBytes(Span<byte> output)
|
||||
{
|
||||
Span<ulong> longs = MemoryMarshal.Cast<byte, ulong>(output);
|
||||
|
||||
longs[0] = High;
|
||||
longs[1] = Low;
|
||||
}
|
||||
|
||||
public static bool operator ==(Id128 left, Id128 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Id128 left, Id128 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
public static bool operator <(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) < 0;
|
||||
}
|
||||
|
||||
public static bool operator >(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) > 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >=(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -516,7 +516,7 @@ namespace LibHac.Fs.NcaUtils
|
|||
return Header.VerifySignature1(Keyset.NcaHdrFixedKeyModulus);
|
||||
}
|
||||
|
||||
internal void GenerateAesCounter(int sectionIndex, CnmtContentType type, int minorVersion)
|
||||
internal void GenerateAesCounter(int sectionIndex, Ncm.ContentType type, int minorVersion)
|
||||
{
|
||||
int counterType;
|
||||
int counterVersion;
|
||||
|
@ -527,14 +527,14 @@ namespace LibHac.Fs.NcaUtils
|
|||
|
||||
switch (type)
|
||||
{
|
||||
case CnmtContentType.Program:
|
||||
case Ncm.ContentType.Program:
|
||||
counterType = sectionIndex + 1;
|
||||
break;
|
||||
case CnmtContentType.HtmlDocument:
|
||||
counterType = (int)CnmtContentType.HtmlDocument;
|
||||
case Ncm.ContentType.HtmlDocument:
|
||||
counterType = (int)Ncm.ContentType.HtmlDocument;
|
||||
break;
|
||||
case CnmtContentType.LegalInformation:
|
||||
counterType = (int)CnmtContentType.LegalInformation;
|
||||
case Ncm.ContentType.LegalInformation:
|
||||
counterType = (int)Ncm.ContentType.LegalInformation;
|
||||
break;
|
||||
default:
|
||||
counterType = 0;
|
||||
|
|
47
src/LibHac/Fs/RightsId.cs
Normal file
47
src/LibHac/Fs/RightsId.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct RightsId : IEquatable<RightsId>, IComparable<RightsId>, IComparable
|
||||
{
|
||||
public readonly Id128 Id;
|
||||
|
||||
public RightsId(ulong high, ulong low)
|
||||
{
|
||||
Id = new Id128(high, low);
|
||||
}
|
||||
|
||||
public RightsId(ReadOnlySpan<byte> uid)
|
||||
{
|
||||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public bool Equals(RightsId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is RightsId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(RightsId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is null) return 1;
|
||||
return obj is RightsId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(RightsId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public static bool operator ==(RightsId left, RightsId right) => left.Equals(right);
|
||||
public static bool operator !=(RightsId left, RightsId right) => !left.Equals(right);
|
||||
|
||||
public static bool operator <(RightsId left, RightsId right) => left.CompareTo(right) < 0;
|
||||
public static bool operator >(RightsId left, RightsId right) => left.CompareTo(right) > 0;
|
||||
public static bool operator <=(RightsId left, RightsId right) => left.CompareTo(right) <= 0;
|
||||
public static bool operator >=(RightsId left, RightsId right) => left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
|
@ -1,66 +1,47 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct UserId : IEquatable<UserId>, IComparable<UserId>, IComparable
|
||||
{
|
||||
public readonly ulong High;
|
||||
public readonly ulong Low;
|
||||
public readonly Id128 Id;
|
||||
|
||||
public UserId(ulong high, ulong low)
|
||||
{
|
||||
High = high;
|
||||
Low = low;
|
||||
Id = new Id128(high, low);
|
||||
}
|
||||
|
||||
public UserId(ReadOnlySpan<byte> uid)
|
||||
{
|
||||
ReadOnlySpan<ulong> longs = MemoryMarshal.Cast<byte, ulong>(uid);
|
||||
|
||||
High = longs[0];
|
||||
Low = longs[1];
|
||||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public bool Equals(UserId other)
|
||||
{
|
||||
return High == other.High && Low == other.Low;
|
||||
}
|
||||
public bool Equals(UserId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is UserId other && Equals(other);
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is UserId other && Equals(other);
|
||||
}
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (High.GetHashCode() * 397) ^ Low.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(UserId other)
|
||||
{
|
||||
// ReSharper disable ImpureMethodCallOnReadonlyValueField
|
||||
int highComparison = High.CompareTo(other.High);
|
||||
if (highComparison != 0) return highComparison;
|
||||
return Low.CompareTo(other.Low);
|
||||
// ReSharper restore ImpureMethodCallOnReadonlyValueField
|
||||
}
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(UserId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return 1;
|
||||
if (obj is null) return 1;
|
||||
return obj is UserId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(UserId)}");
|
||||
}
|
||||
|
||||
public void ToBytes(Span<byte> output)
|
||||
{
|
||||
Span<ulong> longs = MemoryMarshal.Cast<byte, ulong>(output);
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
longs[0] = High;
|
||||
longs[1] = Low;
|
||||
}
|
||||
public static bool operator ==(UserId left, UserId right) => left.Equals(right);
|
||||
public static bool operator !=(UserId left, UserId right) => !left.Equals(right);
|
||||
|
||||
public static bool operator <(UserId left, UserId right) => left.CompareTo(right) < 0;
|
||||
public static bool operator >(UserId left, UserId right) => left.CompareTo(right) > 0;
|
||||
public static bool operator <=(UserId left, UserId right) => left.CompareTo(right) <= 0;
|
||||
public static bool operator >=(UserId left, UserId right) => left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
||||
|
|
40
src/LibHac/Ncm/ContentEnums.cs
Normal file
40
src/LibHac/Ncm/ContentEnums.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
namespace LibHac.Ncm
|
||||
{
|
||||
public enum ContentType : byte
|
||||
{
|
||||
Meta = 0,
|
||||
Program = 1,
|
||||
Data = 2,
|
||||
Control = 3,
|
||||
HtmlDocument = 4,
|
||||
LegalInformation = 5,
|
||||
DeltaFragment = 6
|
||||
}
|
||||
|
||||
public enum ContentMetaType : byte
|
||||
{
|
||||
SystemProgram = 1,
|
||||
SystemData = 2,
|
||||
SystemUpdate = 3,
|
||||
BootImagePackage = 4,
|
||||
BootImagePackageSafe = 5,
|
||||
Application = 0x80,
|
||||
Patch = 0x81,
|
||||
AddOnContent = 0x82,
|
||||
Delta = 0x83
|
||||
}
|
||||
|
||||
public enum ContentMetaAttribute : byte
|
||||
{
|
||||
None = 0,
|
||||
IncludesExFatDriver = 1,
|
||||
Rebootless = 2
|
||||
}
|
||||
|
||||
public enum UpdateType : byte
|
||||
{
|
||||
ApplyAsDelta = 0,
|
||||
Overwrite = 1,
|
||||
Create = 2
|
||||
}
|
||||
}
|
47
src/LibHac/Ncm/ContentId.cs
Normal file
47
src/LibHac/Ncm/ContentId.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct ContentId : IEquatable<ContentId>, IComparable<ContentId>, IComparable
|
||||
{
|
||||
public readonly Id128 Id;
|
||||
|
||||
public ContentId(ulong high, ulong low)
|
||||
{
|
||||
Id = new Id128(high, low);
|
||||
}
|
||||
|
||||
public ContentId(ReadOnlySpan<byte> uid)
|
||||
{
|
||||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public bool Equals(ContentId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is ContentId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(ContentId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is null) return 1;
|
||||
return obj is ContentId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ContentId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public static bool operator ==(ContentId left, ContentId right) => left.Equals(right);
|
||||
public static bool operator !=(ContentId left, ContentId right) => !left.Equals(right);
|
||||
|
||||
public static bool operator <(ContentId left, ContentId right) => left.CompareTo(right) < 0;
|
||||
public static bool operator >(ContentId left, ContentId right) => left.CompareTo(right) > 0;
|
||||
public static bool operator <=(ContentId left, ContentId right) => left.CompareTo(right) <= 0;
|
||||
public static bool operator >=(ContentId left, ContentId right) => left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ namespace LibHac.Ncm
|
|||
{
|
||||
public ulong TitleId { get; private set; }
|
||||
public uint Version { get; private set; }
|
||||
public byte Type { get; private set; }
|
||||
public byte Flags { get; private set; }
|
||||
public ContentMetaType Type { get; private set; }
|
||||
public ContentMetaAttribute Attributes { get; private set; }
|
||||
|
||||
public int ExportSize => 0x10;
|
||||
private bool _isFrozen;
|
||||
|
@ -20,8 +20,8 @@ namespace LibHac.Ncm
|
|||
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(output, TitleId);
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(8), Version);
|
||||
output[0xC] = Type;
|
||||
output[0xD] = Flags;
|
||||
output[0xC] = (byte)Type;
|
||||
output[0xD] = (byte)Attributes;
|
||||
}
|
||||
|
||||
public void FromBytes(ReadOnlySpan<byte> input)
|
||||
|
@ -31,8 +31,8 @@ namespace LibHac.Ncm
|
|||
|
||||
TitleId = BinaryPrimitives.ReadUInt64LittleEndian(input);
|
||||
Version = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(8));
|
||||
Type = input[0xC];
|
||||
Flags = input[0xD];
|
||||
Type = (ContentMetaType)input[0xC];
|
||||
Attributes = (ContentMetaAttribute)input[0xD];
|
||||
}
|
||||
|
||||
public void Freeze() => _isFrozen = true;
|
||||
|
@ -40,7 +40,7 @@ namespace LibHac.Ncm
|
|||
public bool Equals(ContentMetaKey other)
|
||||
{
|
||||
return other != null && TitleId == other.TitleId && Version == other.Version &&
|
||||
Type == other.Type && Flags == other.Flags;
|
||||
Type == other.Type && Attributes == other.Attributes;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
|
@ -56,7 +56,7 @@ namespace LibHac.Ncm
|
|||
int hashCode = TitleId.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ (int)Version;
|
||||
hashCode = (hashCode * 397) ^ Type.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Flags.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Attributes.GetHashCode();
|
||||
return hashCode;
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ namespace LibHac.Ncm
|
|||
if (versionComparison != 0) return versionComparison;
|
||||
int typeComparison = Type.CompareTo(other.Type);
|
||||
if (typeComparison != 0) return typeComparison;
|
||||
return Flags.CompareTo(other.Flags);
|
||||
return Attributes.CompareTo(other.Attributes);
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
|
20
src/LibHac/Ncm/ContentMetaStructs.cs
Normal file
20
src/LibHac/Ncm/ContentMetaStructs.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 1)]
|
||||
public struct ContentInfo
|
||||
{
|
||||
public ContentId contentId;
|
||||
public uint size1;
|
||||
public ushort size2;
|
||||
private ContentType contentType;
|
||||
private byte IdOffset;
|
||||
}
|
||||
|
||||
public class ApplicationContentMetaKey
|
||||
{
|
||||
public ContentMetaKey Key { get; set; }
|
||||
public ulong TitleId { get; set; }
|
||||
}
|
||||
}
|
32
src/LibHac/Ncm/IContentMetaDatabase.cs
Normal file
32
src/LibHac/Ncm/IContentMetaDatabase.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
public interface IContentMetaDatabase
|
||||
{
|
||||
Result Set(ContentMetaKey key, ReadOnlySpan<byte> value);
|
||||
Result Get(out long valueSize, ContentMetaKey key, Span<byte> valueBuffer);
|
||||
Result Remove(ContentMetaKey key);
|
||||
Result GetContentIdByType(out ContentId contentId, ContentMetaKey key, ContentType type);
|
||||
Result ListContentInfo(out int count, Span<ContentInfo> outInfo, ContentMetaKey key, int startIndex);
|
||||
|
||||
Result List(out int totalEntryCount, out int matchedEntryCount, Span<ContentMetaKey> keys, ContentMetaType type,
|
||||
ulong applicationTitleId, ulong minTitleId, ulong maxTitleId, ContentMetaAttribute attributes);
|
||||
|
||||
Result GetLatestContentMetaKey(out ContentMetaKey key, ulong titleId);
|
||||
Result ListApplication(out int totalEntryCount, out int matchedEntryCount, Span<ApplicationContentMetaKey> keys, ContentMetaType type);
|
||||
Result Has(out bool hasKey, ContentMetaKey key);
|
||||
Result HasAll(out bool hasAllKeys, ReadOnlySpan<ContentMetaKey> key);
|
||||
Result GetSize(out long size, ContentMetaKey key);
|
||||
Result GetRequiredSystemVersion(out int version, ContentMetaKey key);
|
||||
Result GetPatchId(out ulong titleId, ContentMetaKey key);
|
||||
Result DisableForcibly();
|
||||
Result LookupOrphanContent(Span<bool> outOrphaned, ReadOnlySpan<ContentId> contentIds);
|
||||
Result Commit();
|
||||
Result HasContent(out bool hasContent, ContentMetaKey key, ContentId contentId);
|
||||
Result ListContentMetaInfo(out int entryCount, Span<ContentMetaKey> outInfo, ContentMetaKey key, int startIndex);
|
||||
Result GetAttributes(out ContentMetaAttribute attributes, ContentMetaKey key);
|
||||
Result GetRequiredApplicationVersion(out int version, ContentMetaKey key);
|
||||
//Result GetContentIdByTypeAndIdOffset(out ContentId contentId, ContentMetaKey key, ContentType type, byte idOffset);
|
||||
}
|
||||
}
|
37
src/LibHac/Ncm/IContentStorage.cs
Normal file
37
src/LibHac/Ncm/IContentStorage.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
public interface IContentStorage
|
||||
{
|
||||
Result GeneratePlaceHolderId(out PlaceHolderId placeHolderId);
|
||||
Result CreatePlaceHolder(PlaceHolderId placeHolderId, ContentId contentId, long fileSize);
|
||||
Result DeletePlaceHolder(PlaceHolderId placeHolderId);
|
||||
Result HasPlaceHolder(out bool hasPlaceHolder, PlaceHolderId placeHolderId);
|
||||
Result WritePlaceHolder(PlaceHolderId placeHolderId, long offset, ReadOnlySpan<byte> buffer);
|
||||
Result Register(PlaceHolderId placeHolderId, ContentId contentId);
|
||||
Result Delete(ContentId contentId);
|
||||
Result Has(out bool hasContent, ContentId contentId);
|
||||
Result GetPath(Span<byte> outPath, ContentId contentId);
|
||||
Result GetPlaceHolderPath(Span<byte> outPath, PlaceHolderId placeHolderId);
|
||||
Result CleanupAllPlaceHolder();
|
||||
Result ListPlaceHolder(out int count, Span<PlaceHolderId> placeHolderIds);
|
||||
Result GetContentCount(out int count);
|
||||
Result ListContentId(out int count, Span<ContentId> contentIds, int startOffset);
|
||||
Result GetSizeFromContentId(out long size, ContentId contentId);
|
||||
Result DisableForcibly();
|
||||
Result RevertToPlaceHolder(PlaceHolderId placeHolderId, ContentId oldContentId, ContentId newContentId);
|
||||
Result SetPlaceHolderSize(PlaceHolderId placeHolderId, long size);
|
||||
Result ReadContentIdFile(Span<byte> buffer, long size, ContentId contentId, long offset);
|
||||
Result GetRightsIdFromPlaceHolderId(out RightsId rightsId, out byte keyGeneration, PlaceHolderId placeHolderId);
|
||||
Result GetRightsIdFromContentId(out RightsId rightsId, out byte keyGeneration, ContentId contentId);
|
||||
Result WriteContentForDebug(ContentId contentId, long offset, ReadOnlySpan<byte> buffer);
|
||||
Result GetFreeSpaceSize(out long size);
|
||||
Result GetTotalSpaceSize(out long size);
|
||||
Result FlushPlaceHolder();
|
||||
//Result GetSizeFromPlaceHolderId(out long size, PlaceHolderId placeHolderId);
|
||||
//Result RepairInvalidFileAttribute();
|
||||
//Result GetRightsIdFromPlaceHolderIdWithCache(out RightsId rightsId, out byte keyGeneration, PlaceHolderId placeHolderId, out ContentId cacheContentId);
|
||||
}
|
||||
}
|
47
src/LibHac/Ncm/PlaceHolderId.cs
Normal file
47
src/LibHac/Ncm/PlaceHolderId.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct PlaceHolderId : IEquatable<PlaceHolderId>, IComparable<PlaceHolderId>, IComparable
|
||||
{
|
||||
public readonly Id128 Id;
|
||||
|
||||
public PlaceHolderId(ulong high, ulong low)
|
||||
{
|
||||
Id = new Id128(high, low);
|
||||
}
|
||||
|
||||
public PlaceHolderId(ReadOnlySpan<byte> uid)
|
||||
{
|
||||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public bool Equals(PlaceHolderId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is PlaceHolderId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(PlaceHolderId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj is null) return 1;
|
||||
return obj is PlaceHolderId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(PlaceHolderId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public static bool operator ==(PlaceHolderId left, PlaceHolderId right) => left.Equals(right);
|
||||
public static bool operator !=(PlaceHolderId left, PlaceHolderId right) => !left.Equals(right);
|
||||
|
||||
public static bool operator <(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) < 0;
|
||||
public static bool operator >(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) > 0;
|
||||
public static bool operator <=(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) <= 0;
|
||||
public static bool operator >=(PlaceHolderId left, PlaceHolderId right) => left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using LibHac.Fs;
|
||||
using LibHac.Fs.NcaUtils;
|
||||
using LibHac.Fs.Save;
|
||||
using LibHac.Ncm;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
|
@ -81,7 +82,7 @@ namespace LibHac
|
|||
nca = new SwitchFsNca(new Nca(Keyset, storage));
|
||||
|
||||
nca.NcaId = GetNcaFilename(fileEntry.Name, nca);
|
||||
string extension = nca.Nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca";
|
||||
string extension = nca.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta ? ".cnmt.nca" : ".nca";
|
||||
nca.Filename = nca.NcaId + extension;
|
||||
}
|
||||
catch (MissingKeyException ex)
|
||||
|
@ -131,7 +132,7 @@ namespace LibHac
|
|||
|
||||
private void ReadTitles()
|
||||
{
|
||||
foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == ContentType.Meta))
|
||||
foreach (SwitchFsNca nca in Ncas.Values.Where(x => x.Nca.Header.ContentType == Fs.NcaUtils.ContentType.Meta))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -160,11 +161,11 @@ namespace LibHac
|
|||
|
||||
switch (content.Type)
|
||||
{
|
||||
case CnmtContentType.Program:
|
||||
case CnmtContentType.Data:
|
||||
case Ncm.ContentType.Program:
|
||||
case Ncm.ContentType.Data:
|
||||
title.MainNca = contentNca;
|
||||
break;
|
||||
case CnmtContentType.Control:
|
||||
case Ncm.ContentType.Control:
|
||||
title.ControlNca = contentNca;
|
||||
break;
|
||||
}
|
||||
|
@ -201,7 +202,7 @@ namespace LibHac
|
|||
|
||||
private void CreateApplications()
|
||||
{
|
||||
foreach (Title title in Titles.Values.Where(x => x.Metadata.Type >= TitleType.Application))
|
||||
foreach (Title title in Titles.Values.Where(x => x.Metadata.Type >= ContentMetaType.Application))
|
||||
{
|
||||
Cnmt meta = title.Metadata;
|
||||
ulong appId = meta.ApplicationTitleId;
|
||||
|
@ -229,7 +230,7 @@ namespace LibHac
|
|||
|
||||
private string GetNcaFilename(string name, SwitchFsNca nca)
|
||||
{
|
||||
if (nca.Nca.Header.ContentType != ContentType.Meta || !name.EndsWith(".cnmt.nca"))
|
||||
if (nca.Nca.Header.ContentType != Fs.NcaUtils.ContentType.Meta || !name.EndsWith(".cnmt.nca"))
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(name);
|
||||
}
|
||||
|
@ -343,16 +344,16 @@ namespace LibHac
|
|||
|
||||
switch (title.Metadata.Type)
|
||||
{
|
||||
case TitleType.Application:
|
||||
case ContentMetaType.Application:
|
||||
Main = title;
|
||||
break;
|
||||
case TitleType.Patch:
|
||||
case ContentMetaType.Patch:
|
||||
Patch = title;
|
||||
break;
|
||||
case TitleType.AddOnContent:
|
||||
case ContentMetaType.AddOnContent:
|
||||
AddOnContent.Add(title);
|
||||
break;
|
||||
case TitleType.Delta:
|
||||
case ContentMetaType.Delta:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue