diff --git a/README.md b/README.md index a9198ba3..99caf328 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ Most content is imported and exported using a standard `IStorage` interface. Thi For example, the files from a title stored on the external SD card can be read or extracted in this way. `NAX0 Reader` -> `NCA Reader` -> `RomFS Reader` -> `Individual Files` +## Getting Started + +[Library Overview and Samples](docs/getting-started.md) + # hactoolnet hactoolnet is an example program that uses LibHac. It is used in a similar manner to [hactool](https://github.com/SciresM/hactool). @@ -21,11 +25,13 @@ Options: -r, --raw Keep raw data, don't unpack. -y, --verify Verify all hashes in the input file. -h, --enablehash Enable hash checks when reading the input file. + -d, --dev Decrypt with development keys instead of retail. -k, --keyset Load keys from an external file. - -t, --intype=type Specify input file type [nca, xci, romfs, pk11, pk21, ini1, kip1, switchfs, save, ndv0, keygen, romfsbuild] + -t, --intype=type Specify input file type [nca, xci, romfs, pfs0, pk11, pk21, ini1, kip1, switchfs, save, ndv0, keygen, romfsbuild, pfsbuild] --titlekeys Load title keys from an external file. NCA options: --plaintext Specify file path for saving a decrypted copy of the NCA. + --header Specify Header file path. --section0 Specify Section 0 file path. --section1 Specify Section 1 file path. --section2 Specify Section 2 file path. @@ -46,6 +52,12 @@ RomFS options: RomFS creation options: Input path must be a directory --outfile Specify created RomFS file path. +Partition FS options: + --outdir Specify extracted FS directory path. +Partition FS creation options: + Input path must be a directory + --outfile Specify created Partition FS file path. + --hashedfs Create a hashed Partition FS (HFS0). XCI options: --rootdir Specify root XCI directory path. --updatedir Specify update XCI directory path. @@ -81,7 +93,9 @@ Save data options: --outdir Specify directory path to save contents to. --debugoutdir Specify directory path to save intermediate data to for debugging. --sign Sign the save file. (Requires device_key in key file) + --trim Trim garbage data in the save file. (Requires device_key in key file) --listfiles List files in save file. + --repack Replaces the contents of the save data with the specified directory. --replacefile Replaces a file in the save data NDV0 (Delta) options: Input delta patch can be a delta NCA file or a delta fragment file. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..ea2c251e --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,115 @@ +# Getting Started + +## LibHac Interfaces + +LibHac uses several interfaces for reading and writing data and files. These are based off the interfaces used by Horizon OS. + +### IStorage + +`IStorage` is an interface that LibHac uses for reading and writing data. +An `IStorage` is similar to a .NET `Stream`, but an `IStorage` does not keep track of its position. An offset must be provided on every read. + +`IStorage` uses byte Spans for reading and writing data. The length of the data read or written is equal to the length of the provided span. + +### IFile + +`IFile` is similar to `IStorage` with slight differences. +- `IFile` can automatically grow if data is written past the end of the file. `IStorage` does not grow by default. +- When more bytes are requested than there are bytes available, +`IFile` will read as many bytes as it can and return the number of bytes read. `IStorage` will throw an exception. + +### IFileSystem + +This is an interface for representing a standard file system. It provides functionality for reading files, navigating the file system, creating files, etc. + +## Using LibHac + +### Loading Keys + +Most of LibHac's functionality requires a `Keyset` object that holds encryption keys required for reading content. + +This can be done by loading keys from an external text file, or by creating a new `Keyset` and copying the keys into it. +``` +Keyset keyset = ExternalKeys.ReadKeyFile("common_key_file", "title_key_file", "console_key_file"); +``` + +The text files should follow the format as specified [here](../KEYS.md). + +### Reading an NCA + +Open an NCA and get an `IStorage` of the decrypted file. +``` +using (IStorage inFile = new LocalStorage("filename.nca", FileAccess.Read)) +{ + var nca = new Nca(keyset, inFile); + + IStorage decryptedNca = nca.OpenDecryptedNca(); +} +``` + +Open an NCA's code section. +``` +using (IStorage inFile = new LocalStorage("filename.nca", FileAccess.Read)) +{ + var nca = new Nca(keyset, inFile); + + IStorage section = nca.OpenStorage(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); +} +``` + +Open an NCA's data section as an `IFileSystem`. +``` +using (IStorage inFile = new LocalStorage("filename.nca", FileAccess.Read)) +{ + var nca = new Nca(keyset, inFile); + + IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); +} +``` + +Extension methods are provided for common operations on LibHac interfaces. + +`IFileSystem.CopyFileSystem` will fully copy the contents of one `IFileSystem` to another. +``` +using (IStorage inFile = new LocalStorage("filename.nca", FileAccess.Read)) +{ + var nca = new Nca(keyset, inFile); + var outFileSystem = new LocalFileSystem("extracted_path"); + + IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + fileSystem.CopyFileSystem(outFileSystem); +} +``` + +Open a patched NCA. +``` +using (IStorage baseFile = new LocalStorage("base.nca", FileAccess.Read)) +using (IStorage patchFile = new LocalStorage("base.nca", FileAccess.Read)) +{ + var baseNca = new Nca(keyset, baseFile); + var patchNca = new Nca(keyset, patchFile); + + IFileSystem fileSystem = baseNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Data, + IntegrityCheckLevel.ErrorOnInvalid); +} +``` + +### IFileSystem Operations + +Open a file and read the first 0x4000 bytes. +``` +using (IStorage inFile = new LocalStorage("filename.nca", FileAccess.Read)) +{ + var nca = new Nca(keyset, inFile); + IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + var buffer = new byte[0x4000]; + + IFile myFile = fileSystem.OpenFile("/my/file/path.ext", OpenMode.Read); + int bytesRead = myFile.Read(buffer, 0); +} +``` + +An `IDirectory` can be used to enumerate the file system entries in a directory. + +... \ No newline at end of file