pyctr.type.cci module

Module for interacting with CTR Cart Image (CCI) files.

exception pyctr.type.cci.CCIError[source]

Bases: PyCTRError

Generic error for CCI operations.

exception pyctr.type.cci.InvalidCCIError[source]

Bases: CCIError

Invalid CCI header exception.

class pyctr.type.cci.CCISection(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: IntEnum

Partition indexes in a CCI.

Header = -3

Header of the CCI file.

CardInfo = -2

Card Info Header. https://www.3dbrew.org/wiki/NCSD#Card_Info_Header

DevInfo = -1

Development Card Info Header. Some flashcarts use this for “private headers” which are unique to each produced game card.

Application = 0

Main application CXI.

Manual = 1

Manual CFA. It has a RomFS with a single “Manual.bcma” file inside.

DownloadPlayChild = 2

Download Play Child CFA. It has a RomFS with CIA files that are sent to other Nintendo 3DS systems using Download Play. Most games only contain one.

Unk3 = 3

Never seems to be used in practice.

Unk4 = 4

Never seems to be used in practice.

Unk5 = 5

Never seems to be used in practice.

UpdateNew3DS = 6

Update CFA for New Nintendo 3DS systems. It has a RomFS with a “SNAKE” directory, then contains the same as UpdateOld3DS. Any Title IDs in “cup_list” that are not in this partition are loaded from UpdateOld3DS.

UpdateOld3DS = 7

Update CFA for Old Nintendo 3DS systems. It has a RomFS with a “cup_list” file that is 0x800 bytes and is a list of Title IDs in the update. The rest are CIA files with matching Title ID filenames.

class pyctr.type.cci.CCIRegion(section, offset, size)[source]

Bases: NamedTuple

Parameters:
section: CCISection

Alias for field number 0

offset: int

Alias for field number 1

size: int

Alias for field number 2

class pyctr.type.cci.CCICartRegion(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

USA = 'USA'
EUR = 'EUR'
JPN = 'JPN'
CHN = 'CHN'
KOR = 'KOR'
TWN = 'TWN'
Unknown = 'Unknown'
class pyctr.type.cci.CCIReader(file, *, fs=None, closefd=None, case_insensitive=True, dev=False, load_contents=True, assume_decrypted=False)[source]

Bases: TypeReaderBase

Reads the contents of CCI files, usually dumps from Nintendo 3DS game cards.

A CCI file can contain 8 partitions; in practice, only 0, 1, 2, 6 and 7 seem to be used.

Note that a custom CryptoEngine object cannot be given, as it can only store keys for a single NCCHReader. To use a custom one, set load_contents to False, then load each section manually with open_raw_section.

Parameters:
  • file (FilePathOrObject) – A file path or a file-like object with the CCI data.

  • case_insensitive (bool) – Use case-insensitive paths for the RomFS of each NCCH container.

  • dev (bool) – Use devunit keys.

  • load_contents (bool) – Load each partition with NCCHReader.

  • assume_decrypted (bool) – Assume each NCCH content is decrypted. Needed if the image was decrypted without fixing the NCCH flags.

  • fs (Optional[FS]) –

  • closefd (bool) –

sections: Dict[CCISection, CCIRegion]

A list of CCIRegion objects containing the offset and size of each partition.

contents: Dict[CCISection, NCCHReader]

A list of NCCHReader objects for each partition.

media_id: str

Same as the Title ID of the application.

image_size: int

Image size in bytes. This does not always match the file size on disk.

cart_region: CCICartRegion

Region that the game card is for. This is detected by checking the files in the Update RomFS.

open_raw_section(section)[source]

Open a raw CCI section for reading.

Parameters:

section (CCISection) – The section to open.

Returns:

A file-like object that reads from the section.

Return type:

SubsectionIO