Python library to parse several Nintendo 3DS files
Project description
PyCTR
Python library to interact with Nintendo 3DS files.
The API is not yet stable. If you decide to use this, you should stick to a specific version on pypi, or store a copy locally, until it is stable.
Documentation is being updated over time and is published on Read the Docs. Most classes and functions have docstrings.
Support is provided on GitHub Discussions or Discord (info, invite link).
Supported types
- Application metadata and containers
- CDN contents ("tmd" next to other contents)
- CTR Cart Image (".3ds", ".cci")
- CTR Importable Archive (".cia")
- NCCH (".cxi", ".cfa", ".ncch", ".app")
- Title Metadata ("*.tmd")
- SMDH icon ("*.smdh", "icon.bin")
- Application contents
- Executable Filesystem (".exefs", "exefs.bin")
- Read-only Filesystem (".romfs", "romfs.bin")
- User files
- NAND ("nand.bin")
- SD card filesystem ("Nintendo 3DS" directory)
- DISA (save) and DIFF (extdata) containers
- NOT the Inner Fat yet! This is for the wrappers around them.
License
pyctr
is under the MIT license.
v0.7.0 - September 3, 2023
Highlights
Python 3.8 or later is now required, up from 3.6.1.
A new pyctr.type.config
package with save
and blocks
modules was added. These allow for reading the config savegame, both to read the raw blocks, and to parse the data into a usable format.
A new nand
module with the NAND
class is added to read and write to NAND images. This only provides raw access (for FAT32, try nathanhi/pyfatfs).
RomFSReader
initialization performance was improved, especially with RomFS files containing large amounts of files or directories.
Documentation is being added and improved over time. Check it on Read the Docs.
Changelog
- Add the module
pyctr.type.configsave
with the classConfigSaveReader
(module name changed in a future commit) - Implement
to_bytes
andremove_block
inConfigSaveReader
- Split
pyctr.type.configsave
into two packages:pyctr.type.config.blocks
andpyctr.type.config.save
- New
ConfigSaveBlockParser
class with 3 methods:get_username
,get_user_time_offset
, andget_system_model
(plus convenience functionsload
andfrom_file
so aConfigSaveParser
doesn't need to be manually created) - New enum:
SystemModel
- Both
ConfigSaveReader
andConfigSaveBlockParser
are importable frompyctr.type.config
- New
- Add
flush
toSubsectionIO
- Optimize
CTRFileIO
to re-use existing cipher object when possible (seeking invalidates the current one) - Optimize
RomFSReader
by reading entire directory and file metadata at once before traversing, significantly reducing the amount of read calls to the underlying file - Optimize
RomFSReader
to reduce the read calls for the header (once for raw lv3, twice for IVFC) - Check for unformatted saves in
DISA
(the first 0x20 bytes are all NULL and the rest is garbage) - Remove
crypto_method == 0
check for NCCH files usingfixed_crypto_key
- Add
nand
module withNAND
class, to read and write to a NAND image - Add
__slots__
to a bunch of classes (CCIReader
,CDNReader
,CIAReader
,ExeFSReader
,NAND
,NCCHReader
,RomFSReader
,SDFilesystem
,SDTitleReader
,SMDH
,ConfigSaveReader
,TypeReaderBase
,TypeReaderCryptoBase
) - Update copyright year
- Various documentation and type hint changes
- Add new
FilePath
andFilePathOrObject
types
- Add new
- Add
__slots__
toSubsectionIO
andSplitFileMerger
- Add some tests for
romfs
andsmdh
- Load all boot9 keys in
CryptoEngine.setup_keys_from_boot9
- Moved package metadata to
setup.cfg
- Fix setting fixed keys in
CryptoEngine
and add debug logging to key setting - Separate NCSD header loading from
NAND
to a separate classNANDNCSDHeader
- Refactor the
nand
module andNAND
class:- Add support for virtual sections (things that are not NCSD partitions)
- Rename
open_ncsd_partition
tooprn_raw_section
- Add custom section IDs that always point to the correct partition, regardless of its physical location
- Add custom section ID for GodMode9 bonus volume
- Add documentation files created with sphinx-autodoc
- Switch Sphinx theme to rtd, add example-cia, add info to index page
- Move RomFS header loading in
RomFSReader
to a newRomFSLv3Header
class - Many different documentation changes or additions
- Require Python 3.8
- Create new and update documentation pages -
example-nand
andpyctr.type.nand
- Fix
closefd
being default to True always inNAND
- Create documentation page for
pyctr.type.sd
- Create documentation page for
pyctr.fileio
- Create documentation page for
pyctr.util
- Fixes to
ConfigSaveReader
:data_offset
is not hardcoded to0x41E4
, it's based on the amount of data from the blocks- CFG adds data to save from end to start when the block data is > 4 bytes, so now we are replicating this behavior and generating a proper
data_offset
and data sorting when usingto_bytes
- Added sanity checks while parsing a config save
set_block
previously didn't allowedNone
in flags despite being stated to default to0xE
- New attribute for SMDH:
SMDH.region_lockout
, with a new NamedTupleSMDHRegionLockout
- New attribute for CCIReader:
CCIReader.cart_region
, with a new EnumCCICartRegion
ConfigSaveReader.set_block
will now check Block IDs, flags, and sizes against a known list of blocks- Passing
strict=True
toset_block
will bypass this
- Passing
KNOWN_BLOCKS
inpyctr.type.config.save
was changed to have values be dicts with "flags" and "size" keys (instead of plain tuples)- Switch
get_*
andset_*
to getters and setters in `pyctr.type.config.blocks- e.g.
username
instead ofget_username
andset_username
- e.g.
- Add new
from_bytes
and__bytes__
methods toAppTitle
to load title structures (and modifySMDH
to use this now)
v0.6.0 - January 26, 2022
Highlights
Pillow is now an optional dependency. It is available through the extra feature images
. This means to use pyctr[images]
when adding to setup.py
, requirements.txt
, or pip install
.
SMDH icon data is stored into an array like [[(1, 2, 3), (4, 5, 6), ...]]
. It can be used with other libraries like the pure-python pypng, for example:
from pyctr.type.cia import CIAReader
from itertools import chain
import png
my_cia = CIAReader('game.cia')
# pypng expects an array like [[1, 2, 3, 4, 5, 6, ...]] so we need to flatten the inner lists
img = png.from_array(
(chain.from_iterable(x) for x in my_cia.contents[0].exefs.icon.icon_large_array),
'RGB', {'width': 48, 'height': 48}
)
img.save('icon.png')
Changelog
- Move around object attribute initialization in cci, cdn, cia, and sdtitle, to prevent extra exceptions if an error is raised early
- Use
open_raw_section
internally when initializing aCIAReader
object, instead of manually seeking and reading - Make Pillow an optional dependency and make SMDH load icon data into an array (useful for other libraries like pypng)
- New functions in
smdh
:rgb565_to_rgb888_tuple
,load_tiled_rgb565_to_array
,rgb888_array_to_image
- Init arguments for
SMDH
were changed to accept icon data arrays instead of PillowImage
objects - Pillow is added to
extras_require
under the featureimages
- New functions in
- Documentation tweaks to
smdh
- Remove unused import in
cia
v0.5.1 - June 28, 2021
- Fix arbitrary reads in the first 0x10 block of
CBCFileIO
v0.5.0 - June 26, 2021
Highlights
A new sdtitle
module with SDTitleReader
is added to read titles installed on an SD card. When used directly, it works with contents that are not SD encrypted. To open a title on a 3DS SD card that is SD encrypted, a new method is added to sd.SDFilesystem
: open_title
.
SMDH icons are now loaded using Pillow.
SMDH flags are now loaded.
The ExeFS in NCCH contents is now fully decrypted properly. This means there is no longer garbage at the last block of the .code
section for titles that use extra NCCH keys. This was achieved by rewriting the ExeFS section to concatenate multiple file-like objects that use different keyslots with a new class, SplitFileMerger
.
Changelog
- Add
_raise_if_file_closed_generic
topyctr.common
- Add
SplitFileMerger
topyctr.fileio
to merge multiple file-like objects into one (currently no support for writing) - Support closing all subfiles in
SplitFileMerger
- Rewrite ExeFS handling in
NCCHReader
to useSplitFileMerger
to merge multipleSubsectionIO
files to handle the parts that use different encryption, and updateFullDecrypted
to use it when reading ExeFS - Add
from_bytes
classmethod toNCCHFlags
- Always use the internal ExeFS file object when reading it for FullDecrypted
- Add docstrings to
NCCHFlags
- Add dependency on
Pillow>=8.2
- Load SMDH icons using Pillow/PIL, stored in new attributes in the
SMDH
class:icon_small
,icon_large
- Load SMDH flags into a new
SMDHFlags
class - Add
isfile
andisdir
methods toSDFilesystem
, convert path to string insd.normalize_sd_path
to make it easier to use anyos.PathLike
object (e.g.pathlib.PurePosixPath
) - Add
sdtitle
module withSDTitleReader
class, to read titles installed to the SD card inside "Nintendo 3DS" - Add
open_title
method toSDFilesystem
to open a title usingSDTitleReader
, and a newMissingTitleError
exception - Update type hints in
sd
v0.4.7 - April 20, 2021
- Use absolute paths in
CDNReader
- Use absolute paths in
SDFilesystem
- Make
SubsectionIO
objects hashable (if the underlying file object is) - Make sure two different
CTRFileIO
,TWLCTRFileIO
, andCBCFileIO
return different hashes, even with the same reader + key + iv/counter - Add
TWLCTRFileIO
tocrypto.engine.__all__
- Use a
frozenset
on a closedCDNReader
object's internal open files set - Don't set
__del__
directly toclose
inTypeReaderBase
, in caseclose
is overridden - Auto-close opened files based on a reader when the reader closes (applies to
CCIReader
,CIAReader
,ExeFSReader
,NCCHReader
, andRomFSReader
) - Add new pseudo-keyslot
NCCHExtraKey
to store the second keyslot data for NCCH contents- This is important because there exist titles that use Original NCCH but with a seed. Before this change, the key in the
NCCH
keyslot would be overwritten, causing everything but the special regions (ExeFS .code and RomFS) to be improperly decrypted.
- This is important because there exist titles that use Original NCCH but with a seed. Before this change, the key in the
- Use
NCCHExtraKey
for the second keyslot instead of the actual keyslot inNCCHReader
- Set
_open_files
before opening the file inTypeReaderBase
to prevent an additional error if opening the file fails - Don't set KeyX and KeyY separately if fixed crypto key is used without an extra crypto method
- Fix sections in
CCIReader
not opening, raising an error
v0.4.6 - March 1, 2021
- Add pycryptodomex version requiremenet range (
>=3.9,<4
) - Fix using bytes file paths for
CDNReader
andSDFilesystem
- Support auto-closing underlying file for
CTRFileIO
andCBCFileIO
- Make
CTRFileIO
andCBCFileIO
objects hashable (if the underlying file object is) - Update
CDNReader
to re-open files instead of using shared file objects, and internally open all files throughCDNReader.open_raw_section
(fixes #6) - Store encrypted and decrypted OTP in
CryptoEngine
asotp_enc
andotp_dec
, and addotp_keys_set
to check if an OTP was set - Verify OTP magic after decryption in
CryptoEngine.setup_keys_from_otp
- Make
CryptoEngine.otp_device_id
require OTP (raising an exception instead of returning None) - Add
TWLCTRFileIO
as a subclass ofCTRFileIO
which handles the special read/write crypto specific to TWLNAND
v0.4.5 - October 24, 2020
- Fix loading RomFS from a filename in
RomFSReader
- Fix loading ExeFS from a filename in
ExeFSReader
v0.4.4 - September 20, 2020
- Support loading a decrypted titlekey for
CDNReader
- Remove unused
sections
attribute fromCDNReader
- Add
available_sections
toCDNReader
to provide a list of sections available in the title - Add
__author__
,__copyright__
,__license__
,__version__
, andversion_info
topyctr.__init__
v0.4.3 - July 28, 2020
- Fix endianness issue when converting a
TitleMetadataReader
object tobytes
v0.4.2 - July 28, 2020
- Don't assume a Cygwin environment is Windows
- Change keyslot for New 3DS key sector keys from 0x11 to 0x43
- This adds a new Keyslot enum item:
Keyslot.New3DSKeySector
- This adds a new Keyslot enum item:
- Document more methods in pyctr.crypto.engine
- Add new
fileio.CloseWrapper
class to provide access to a file object while preventing closing it directly - Use
CloseWrapper
inCDNReader.open_raw_section
v0.4.1 - July 11, 2020
- Support NCCH contents with fixed crypto key (zerokey and fixed system key)
- CryptoEngine adds these to fake keyslots 0x41 and 0x42 respectively.
- Fixed setting up keyslot 0x11, used for decrypting the New 3DS key sector
v0.4.0 - July 10, 2020
- Add DISA/DIFF reading and writing under
pyctr.type.save
- This does NOT include Inner FAT support yet.
- This can read and write to IVFC level 4. For now, external tools can be used to read or write to the Inner FAT.
- Add CDN reading under
pyctr.type.cdn
- Add more docstrings to various modules
- Add seed parameters to ncch, cia, and cdn
- Rename
Keyslot.UDSLocalWAN
toKeyslot.UDSLocalWLAN
- Many other internal changes done months ago
v0.3.1 - April 8, 2020
- Fix
setup.py
not including subpackages
v0.3.0 - April 8, 2020
- Document more classes, methods, and attributes
- Add a
pyctr.crypto.seeddb
module for central SeedDB management- Loading SeedDB in
NCCHReader
is now removed
- Loading SeedDB in
- Add new
TypeReaderBase
andTypeReaderCryptoBase
for reader types that use a single file - Fix
PathLike
error inNCCHReader
andRomFSReader
- Changed type of
partition_id
andprogram_id
inNCCHReader
tostr
- Some other changes. I'll get better at documenting this!
v0.2.1 - April 3, 2020
- Remove debug print in
SDFilesystem.open
v0.2.0 - April 3, 2020
- Add the module
pyctr.type.sd
with the classSDFilesystem
- Add docstrings to
pyctr.crypto
- Allow
os.PathLike
,str
, andbytes
as file paths in most methods - Allow Windows-style paths in
CryptoEngine.sd_path_to_iv
v0.1.0 - January 27, 2020
Initial standalone release. All previous commits are in the ninfs repo.
The MIT License (MIT)
Copyright (c) 2017-2023 Ian Burgwin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pyctr-0.7.0.tar.gz
.
File metadata
- Download URL: pyctr-0.7.0.tar.gz
- Upload date:
- Size: 79.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3798d118bc002e1bfabb36b0d44f2f430bade2aa6727ebb93ddb025f64f4a5c0 |
|
MD5 | eb417c3fab31fe8d19699588fce4cad3 |
|
BLAKE2b-256 | 6c11a1bb081a4d9751dd70403a911ebab307c61a1e7301c41793f8a8e6e9fc28 |
File details
Details for the file pyctr-0.7.0-py3-none-any.whl
.
File metadata
- Download URL: pyctr-0.7.0-py3-none-any.whl
- Upload date:
- Size: 96.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | acb353f5421ee9f03a1dc47d93b1c217cf861bbe003102e80991140c8bec1aef |
|
MD5 | c503bd8fc0f3d986cb10ef6eaaf905e7 |
|
BLAKE2b-256 | 9e32f4ad79df9e21134bffaba60d34911b4f33583c60dc4bc99525a039588563 |