/// <summary> /// Load all HFS0 partitions starting at the root. The calling function is expected to set stream.Position at the start of the root/first HFS0 Header (always 0xF000 for XCIs) /// </summary> /// <param name="stream"></param> /// <returns></returns> public static HFS0Root Load(string path, Stream stream) { // The "SHA-256 File System" or "HFS0" starts at offset 0xF000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure"). // Where "logo" only exists in 4.0.0+ gamecards and if "logo" exists then "normal" is empty (but still exists) Logger.Info("stream.Position = " + stream.Position); // Root HFS0 HFS0Root root = new HFS0Root(path, stream, stream.Position); // Since we just loaded the root HFS0 partition all the files inside it (FileEntries) are actually also HFS0 parititons root.Partitions = new HFS0[root.Header.NumberOfFiles]; for (int i = 0; i < root.Header.NumberOfFiles; i++) { root.Partitions[i] = new HFS0( path, root.StringTable[i], stream, root.Offset + root.HeaderSize + (long)root.FileEntries[i].Offset, // Partition offset // Partition offset (calc) // root.Offset = 0xF000 for gamecards // root.Size = 0x200 for gamecards // root.FileEntries[i].Offset = partition offset relative to root.Offset + root.Size // absolute offset for first partition = 0xF200 (long)root.FileEntries[i].Size ); } // TODO: Calculate Size (used for trimming, I think) return(root); }
/// <summary> /// Load XCI file from disk /// </summary> /// <param name="path">Path to XCI file</param> /// <param name="verify">Verify hashes and signatures</param> /// <returns></returns> public static XCI Load(string path, Keyset keyset, bool verify = true) { using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) using (BinaryReader br = new BinaryReader(fs)) { XCI xci = new XCI(path); xci.Keyset = keyset; // Gamecard Header byte[] bytes = br.ReadBytes(0x200); // sizeof XCIHeader xci.GamecardHeader = bytes.ToStruct <XCIHeader>(); if (xci.GamecardHeader.MagicString != "HEAD") { throw new Exception("Invalid GamecardHeader magic! Maybe this isn't an XCI file?"); } // TODO: Gamecard Info // TODO: Gamecard Certificate // TODO: Initial Data // HFS0, see comments in HFS0Root and HFS0Partition fs.Position = 0xF000; // start of HFS0Header xci.FileSystem = HFS0Root.Load(path, fs); return(xci); } }