diff --git a/hactoolnet/Program.cs b/hactoolnet/Program.cs index 0c3d477d..f9072f9e 100644 --- a/hactoolnet/Program.cs +++ b/hactoolnet/Program.cs @@ -59,7 +59,7 @@ namespace hactoolnet var sdfs = new SdFs(keyset, args[2]); var ncas = sdfs.ReadAllNca().ToArray(); - var metadata = new List(); + var metadata = new List(); using (var progress = new ProgressBar()) { @@ -76,12 +76,24 @@ namespace hactoolnet var path = Path.Combine("meta", entry.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); var file = pfs0.GetFile(entry.Index); - metadata.Add(file); + + metadata.Add(new Cnmt(new MemoryStream(file))); File.WriteAllBytes(path, file); - progress.LogMessage(path); } } } + + foreach (var meta in metadata.OrderBy(x => x.TitleId)) + { + progress.LogMessage($"{meta.TitleId:X16} v{meta.TitleVersion} {meta.Type}"); + + foreach (var content in meta.ContentEntries) + { + // Add an actual hexdump function + progress.LogMessage($" {BitConverter.ToString(content.NcaId).Replace("-", "")}.nca {content.Type}"); + } + progress.LogMessage(""); + } } } } diff --git a/libhac/Cnmt.cs b/libhac/Cnmt.cs new file mode 100644 index 00000000..050a778b --- /dev/null +++ b/libhac/Cnmt.cs @@ -0,0 +1,82 @@ +using System.IO; + +namespace libhac +{ + public class Cnmt + { + public ulong TitleId { get; set; } + public uint TitleVersion { get; set; } + public TitleType Type { get; set; } + public byte FieldD { get; set; } + public int TableOffset { get; set; } + public int ContentEntryCount { get; set; } + public int MetaEntryCount { get; set; } + + public CnmtContentEntry[] ContentEntries { get; set; } + + public Cnmt(Stream file) + { + using (var reader = new BinaryReader(file)) + { + TitleId = reader.ReadUInt64(); + TitleVersion = reader.ReadUInt32(); + Type = (TitleType)reader.ReadByte(); + FieldD = reader.ReadByte(); + TableOffset = reader.ReadUInt16(); + ContentEntryCount = reader.ReadUInt16(); + MetaEntryCount = reader.ReadUInt16(); + file.Position += 12; + file.Position += TableOffset; + + ContentEntries = new CnmtContentEntry[ContentEntryCount]; + + for (int i = 0; i < ContentEntryCount; i++) + { + ContentEntries[i] = new CnmtContentEntry(reader); + } + } + } + } + + public class CnmtContentEntry + { + public byte[] Hash { get; set; } + public byte[] NcaId { get; set; } + public long Size { get; set; } + public CnmtContentType Type { get; set; } + + public CnmtContentEntry(BinaryReader reader) + { + Hash = reader.ReadBytes(0x20); + NcaId = reader.ReadBytes(0x10); + Size = reader.ReadUInt32(); + Size |= ((long)reader.ReadUInt16() << 32); + Type = (CnmtContentType)reader.ReadByte(); + reader.BaseStream.Position += 1; + } + } + + public enum CnmtContentType + { + Meta, + Program, + Data, + Control, + OfflineManualHtml, + LegalHtml, + UpdatePatch + } + + public enum TitleType + { + SystemProgram = 1, + SystemDataArchive, + SystemUpdate, + FirmwarePackageA, + FirmwarePackageB, + RegularApplication = 0x80, + UpdateTitle, + AddOnContent, + DeltaTitle + } +}