CNMT: Difference between revisions

Liam (talk | contribs)
Update header and extended header - next is extended data
No edit summary
 
(18 intermediate revisions by 5 users not shown)
Line 1: Line 1:
This is the metadata file that ends in <code>".cnmt{.nca}"</code> or <code>"meta0.ncd"</code>. This seems to replace the TMD format.
This is the metadata file that ends in <code>".cnmt{.nca}"</code> or <code>"meta0.ncd"</code>. This seems to replace the TMD format.


There's at least 9 different filenames used for ".cnmt":
The official name for CNMT is "PackagedContentMeta".
* "Application_{lower-case hex titleID}.cnmt"
 
* "Patch_{lower-case hex titleID}.cnmt"
= PackagedContentMetaHeader =
* "AddOnContent_{lower-case hex titleID}.cnmt"
This is "nn::ncm::PackagedContentMetaHeader".
* "SystemUpdate_{hex titleID}.cnmt"
* "SystemData_{lower-case hex titleID}.cnmt"
* "SystemProgram_{lower-case hex titleID}.cnmt"
* "BootImagePackage_{lower-case hex titleID}.cnmt"
* "BootImagePackageSafe_{lower-case hex titleID}.cnmt"
* "Delta_{lower-case hex titleID}.cnmt"


== Header ==
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 21: Line 14:
| 0x0
| 0x0
| 0x8
| 0x8
| Title ID
| Id
|-
|-
| 0x8
| 0x8
| 0x4
| 0x4
| [[Title_list|Version]]
| Version
|-
|-
| 0xC
| 0xC
| 0x1
| 0x1
| [[NCM_services#Title_Types|Meta Type]]
| [[NCM_services#ContentMetaType|ContentMetaType]]
|-
|-
| 0xD
| 0xD
| 0x1
| 0x1
| Unused
| [17.0.0+] [[NCM_services#ContentMetaPlatform|ContentMetaPlatform]] ([1.0.0-16.1.0] Reserved)
|-
|-
| 0xE
| 0xE
| 0x2
| 0x2
| Extended Header Size
| ExtendedHeaderSize
|-
|-
| 0x10
| 0x10
| 0x2
| 0x2
| Content Count
| ContentCount
|-
|-
| 0x12
| 0x12
| 0x2
| 0x2
| Content Meta Count
| ContentMetaCount
|-
|-
| 0x14
| 0x14
| 0x1
| 0x1
| Attributes (0=None, 1=IncludesExFatDriver, 2=Rebootless)
| [[NCM_services#ContentMetaAttributes|ContentMetaAttributes]]
|-
|-
| 0x15
| 0x15
| 0x3
| 0x3
| Unused
| Reserved
|-
|-
| 0x18
| 0x18
| 0x4
| 0x4
| Required Download System Version
| RequiredDownloadSystemVersion
|-
|-
| 0x1C
| 0x1C
| 0x4
| 0x4
| Unused
| Reserved
|}
|}


== SystemUpdate Extended Header ==
= SystemUpdateMetaExtendedHeader =
This is "nn::ncm::SystemUpdateMetaExtendedHeader".
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 73: Line 68:
| 0x0
| 0x0
| 0x4
| 0x4
| Extended Header Size
| ExtendedDataSize
|}
|}


== Application Extended Header ==
= ApplicationMetaExtendedHeader =
This is "nn::ncm::ApplicationMetaExtendedHeader".
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 85: Line 82:
| 0x0
| 0x0
| 0x8
| 0x8
| Patch ID
| PatchId
|-
|-
| 0x8
| 0x8
| 0x4
| 0x4
| Required System Version
| RequiredSystemVersion
|-
| 0xC
| 0x4
| RequiredApplicationVersion
|}
|}


== Patch Extended Header ==
= PatchMetaExtendedHeader =
This is "nn::ncm::PatchMetaExtendedHeader".
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 101: Line 104:
| 0x0
| 0x0
| 0x8
| 0x8
| Application ID
| ApplicationId
|-
|-
| 0x8
| 0x8
| 0x4
| 0x4
| Required System Version
| RequiredSystemVersion
|-
|-
| 0xC
| 0xC
| 0x4
| 0x4
| Extended Data Size
| ExtendedDataSize
|-
| 0x10
| 0x8
| Reserved
|}
 
= AddOnContentMetaExtendedHeader =
This is "nn::ncm::AddOnContentMetaExtendedHeader".
 
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x8
| ApplicationId
|-
| 0x8
| 0x4
| RequiredApplicationVersion
|-
| 0xC
| 0x1
| [15.0.0+] ContentAccessibilities ([1.0.0-14.1.2] Reserved)
|-
| 0xD
| 0x3
| Reserved
|-
|-
| 0x10
| 0x10
| 0x8
| 0x8
| Unused
| [15.0.0+] DataPatchId
|}
|}


== AddOnContent Extended Header ==
= DeltaMetaExtendedHeader =
This is "nn::ncm::DeltaMetaExtendedHeader".
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 125: Line 160:
| 0x0
| 0x0
| 0x8
| 0x8
| Application ID
| ApplicationId
|-
|-
| 0x8
| 0x8
| 0x4
| 0x4
| Required Application Version
| ExtendedDataSize
|-
|-
| 0xC
| 0xC
| 0x4
| 0x4
| Unused
| Reserved
|}
|}


== Delta Extended Header ==
= DataPatchMetaExtendedHeader =
This is "nn::ncm::DataPatchMetaExtendedHeader".
 
This was added with [15.0.0+].
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 145: Line 184:
| 0x0
| 0x0
| 0x8
| 0x8
| Application ID
| DataId
|-
|-
| 0x8
| 0x8
| 0x8
| ApplicationId
|-
| 0x10
| 0x4
| 0x4
| Extended Data Size
| RequiredApplicationVersion
|-
|-
| 0xC
| 0x14
| 0x4
| 0x4
| Unused
| ExtendedDataSize
|-
| 0x18
| 0x8
| Reserved
|}
|}


== Content records ==
= PackagedContentInfo =
This is "nn::ncm::PackagedContentInfo".


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 166: Line 214:
| 0x0
| 0x0
| 0x20
| 0x20
| Hash
| Hash (SHA256 of the referenced content)
|-
|-
| 0x20
| 0x20
| 0x10
| 0x10
| Content ID
| ContentId
|-
|-
| 0x30
| 0x30
| 0x6
| [15.0.0+] 0x5 ([1.0.0-14.1.2] 0x6)
| Size
| Size
|-
| 0x35
| 0x1
| [15.0.0+] ContentAttributes
|-
|-
| 0x36
| 0x36
| 0x1
| 0x1
| Title Type (0=Meta, 1=Program, 2=Data, 3=Control, 4=[[Internet_Browser|HtmlDocument]], 5=[[Internet_Browser|LegalInformation]], 6=[[NCA_Format|DeltaFragment]])
| [[NCM_services#ContentType|ContentType]]
|-
|-
| 0x37
| 0x37
| 0x1
| 0x1
| Id Offset
| IdOffset
|}
|}


== Meta records ==
= ContentMetaInfo =
This is "nn::ncm::ContentMetaInfo".


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 195: Line 248:
| 0x0
| 0x0
| 0x8
| 0x8
| Title ID
| Id
|-
|-
| 0x8
| 0x8
Line 203: Line 256:
| 0xC
| 0xC
| 0x1
| 0x1
| [[NCM_services#Title_Types|Meta Type]]
| [[NCM_services#ContentMetaType|ContentMetaType]]
|-
|-
| 0xD
| 0xD
| 0x1
| 0x1
| Attributes (0=None, 1=IncludesExFatDriver, 2=Rebootless)
| [[NCM_services#ContentMetaAttributes|ContentMetaAttributes]]
|-
|-
| 0xE
| 0xE
| 0x2
| 0x2
| Unused
| Reserved
|}
|}


This is used for SystemUpdate, see here: [[NCM_services#ReadEntryMetaRecords]].
This is used for SystemUpdate, see here: [[NCM_services#ReadEntryMetaRecords]].


== Extended data ==
= SystemUpdateMetaExtendedData =
 
This is "nn::ncm::SystemUpdateMetaExtendedData".
Patch-type cnmt files include an extended data section.  


If the Version field is 1, the format is:
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 227: Line 280:
|-
|-
| 0x0
| 0x0
| 4
| 0x4
| Number of previous cnmt entries.
| Version
|-
|-
| 0x4
| 0x4
| 4
| 0x4
| Number of previous delta entries.
| VariationCount
|-
|-
| 0x8
| 0x8
| 4
| 0x20 * VariationCount
| Number of delta info entries.
| [[#FirmwareVariationInfo|FirmwareVariationInfo]] (Version 1)
|}
 
If the Version field is 2, the format is:
{| class="wikitable" border="1"
|-
|-
| 0xC
! Offset
| 4
! Size
| Number of delta application info entries.
! Description
|-
|-
| 0x10
| 0x0
| 4
| 0x4
| Number of previous content entries.
| Version
|-
|-
| 0x14
| 0x4
| 4
| 0x4
| Number of delta content entries.
| VariationCount
|-
|-
| 0x18
| 0x8
| 4
| 0x4 * VariationCount
| Unused?
| FirmwareVariationId
|-
|-
| 0x1C
| Variable
| 0x38*X
| 0x20 * VariationCount
| Previous cnmt entries
| [[#FirmwareVariationInfo|FirmwareVariationInfo]] (Version 2)
|-
|-
|  
| Variable
| 0x28*X
| 0x10 * MetaCount (from [[#FirmwareVariationInfo|FirmwareVariationInfo]] (Version 2))
| Previous delta entries
| [[#ContentMetaInfo|ContentMetaInfo]] (if ReferToBase is False)
|}
 
== FirmwareVariationInfo ==
This is "FirmwareVariationInfo ".
 
If the Version field is 1, the format is:
{| class="wikitable" border="1"
|-
|-
|
! Offset
| 0x28*X
! Size
| Delta info entries
! Description
|-
|-
|  
| 0x0
| 0x34*X
| 0x4
| Delta application info entries
| FirmwareVariationId
|-
|-
|  
| 0x4
| 0x18*X
| 0x1C
| Previous content entries
| Reserved
|}
 
If the Version field is 2, the format is:
{| class="wikitable" border="1"
|-
|-
|
! Offset
| 0x38*X
! Size
| Delta content entries. (Standard content records)
! Description
|-
|-
|  
| 0x0
| 4
| 0x1
| Unknown
| ReferToBase (0=False, 1=True)
|-
|-
|  
| 0x1
| 4
| 0x3
| Unknown
| Reserved
|-
|-
|  
| 0x4
| 4
| 0x4
| Unknown
| MetaCount
|-
|-
| 0x8
| 0x18
| Reserved
|}
|}


== Previous cnmt records ==
= PatchMetaExtendedData =
 
This is "nn::ncm::PatchMetaExtendedData".
Each entry is 0x38 bytes:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 303: Line 373:
|-
|-
| 0x0
| 0x0
| 8
| 0x4
| Title ID
| PatchHistoryHeaderCount
|-
| 0x4
| 0x4
| PatchDeltaHistoryCount
|-
|-
| 0x8
| 0x8
| 4
| 0x4
| Title version
| PatchDeltaHeaderCount
|-
|-
| 0xC
| 0xC
| 1
| 0x4
| Type (see [[NCM_services#Title_Types|Title Types]])
| FragmentSetCount
|-
| 0x10
| 0x4
| PatchHistoryContentInfoCount
|-
|-
| 0xD
| 0x14
| 3
| 0x4
| Unused?
| PatchDeltaPackagedContentInfoCount
|-
| 0x18
| 0x4
| Reserved
|-
| 0x1C
| 0x38 * PatchHistoryHeaderCount
| [[#PatchHistoryHeader|PatchHistoryHeader]]
|-
| Variable
| 0x28 * PatchDeltaHistoryCount
| [[#PatchDeltaHistory|PatchDeltaHistory]]
|-
|-
| 0x10
| Variable
| 32
| 0x28 * PatchDeltaHeaderCount
| Hash
| [[#PatchDeltaHeader|PatchDeltaHeader]]
|-
|-
| 0x30
| Variable
| 2
| 0x34 * FragmentSetCount
| Unknown
| [[#FragmentSet|FragmentSet]]
|-
|-
| 0x32
| Variable
| 2
| 0x18 * PatchHistoryContentInfoCount
| Unused?
| [[#PackagedContentInfo|PatchHistoryContentInfo]] ([[#PackagedContentInfo|PackagedContentInfo]] without the Hash entry)
|-
|-
| 0x34
| Variable
| 4
| 0x38 * PatchDeltaPackagedContentInfoCount
| Unused?
| [[#PackagedContentInfo|PatchDeltaPackagedContentInfo]]
|-
|-
| Variable
| 0x4 * FragmentIndicatorCount (from [[#FragmentSet|FragmentSet]])
| [[#FragmentIndicator|FragmentIndicator]]
|}
|}


This contains information on previous metadata files.
== PatchHistoryHeader ==
This is "nn::ncm::PatchHistoryHeader".


== Previous delta records ==
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x10
| ContentMetaKey
|-
| 0x10
| 0x20
| Digest
|-
| 0x30
| 0x2
| ContentInfoCount
|-
| 0x32
| 0x6
| Reserved
|}


Each entry is 0x28 bytes:
== PatchDeltaHistory ==
This is "nn::ncm::PatchDeltaHistory".


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 349: Line 465:
|-
|-
| 0x0
| 0x0
| 8
| 0x8
| Old title ID
| SourcePatchId
|-
|-
| 0x8
| 0x8
| 8
| 0x8
| New title ID
| DestinationPatchId
|-
|-
| 0x10
| 0x10
| 4
| 0x4
| Old title version
| SourceVersion
|-
|-
| 0x14
| 0x14
| 4
| 0x4
| New title version
| DestinationVersion
|-
|-
| 0x18
| 0x18
| 8
| 0x8
| Size
| DownloadSize
|-
|-
| 0x20
| 0x20
| 8
| 0x8
| Unused?
| Reserved
|-
|}
|}


This contains information on previous delta patches.
== PatchDeltaHeader ==
 
This is "nn::ncm::PatchDeltaHeader".
== Delta info records ==
 
Each entry is 0x28 bytes:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 387: Line 499:
|-
|-
| 0x0
| 0x0
| 8
| 0x8
| Old title ID
| SourcePatchId
|-
|-
| 0x8
| 0x8
| 8
| 8
| New title ID
| DestinationPatchId
|-
|-
| 0x10
| 0x10
| 4
| 0x4
| Old title version
| SourceVersion
|-
|-
| 0x14
| 0x14
| 4
| 0x4
| New title version
| DestinationVersion
|-
|-
| 0x18
| 0x18
| 8
| 0x2
| Some sort of index?
| FragmentSetCount
|-
| 0x1A
| 0x6
| Reserved
|-
|-
| 0x20
| 0x20
| 8
| 0x2
| Some sort of index?
| ContentInfoCount
|-
|-
| 0x22
| 0x6
| Reserved
|}
|}


This contains information on the current delta patch.
== FragmentSet ==
 
This is "nn::ncm::FragmentSet".
== Delta application info records ==
 
Each entry is 0x34 bytes:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 425: Line 541:
|-
|-
| 0x0
| 0x0
| 16
| 0x10
| Old NcaId
| SourceContentId
|-
|-
| 0x10
| 0x10
| 16
| 0x10
| New NcaId
| DestinationContentId
|-
|-
| 0x20
| 0x20
| 6
| 0x6
| Old size
| SourceSize
|-
|-
| 0x26
| 0x26
| 2
| 0x6
| Upper 2 bytes of the new size
| DestinationSize
|-
| 0x28
| 4
| Lower 4 bytes of the new size
|-
|-
| 0x2C
| 0x2C
| 2
| 0x2
| Unknown
| FragmentIndicatorCount
|-
|-
| 0x2E
| 0x2E
| 1
| 0x1
| Type (see [[NCM_services#Title_Types|Title Types]])
| [[NCM_services#ContentMetaType|FragmentTargetContentType]]
|-
|-
| 0x2F
| 0x2F
| 1
| 0x1
| ? bit0 set = don't install?
| UpdateType (0=ApplyAsDelta, 1=Overwrite, 2=Create)
|-
|-
| 0x30
| 0x30
| 4
| 0x4
| Unused?
| Reserved
|-
|}
|}


This contains information on how to apply deltas to the previous patch.
== FragmentIndicator ==
This is "nn::ncm::FragmentIndicator".


== Previous content records ==
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x2
| ContentInfoIndex
|-
| 0x2
| 0x2
| FragmentIndex
|}


Each entry is 0x18 bytes:
= DeltaMetaExtendedData =
This is "nn::ncm::DeltaMetaExtendedData".


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 475: Line 601:
|-
|-
| 0x0
| 0x0
| 16
| 0x8
| NcaId
| SourcePatchId
|-
| 0x8
| 0x8
| DestinationPatchId
|-
|-
| 0x10
| 0x10
| 6
| 0x4
| Size
| SourceVersion
|-
| 0x14
| 0x4
| DestinationVersion
|-
| 0x18
| 0x2
| FragmentSetCount
|-
| 0x1A
| 0x6
| Reserved
|-
| 0x20
| 0x34 * FragmentSetCount
| [[#FragmentSet|FragmentSet]]
|-
|-
| 0x16
| Variable
| 1
| 0x4 * FragmentIndicatorCount (from [[#FragmentSet|FragmentSet]])
| Type (see [[NCM_services#Title_Types|Title Types]])
| [[#FragmentIndicator|FragmentIndicator]]
|}
 
= Digest =
{| class="wikitable" border="1"
|-
|-
| 0x17
! Offset
| 1
! Size
|
! Description
|-
|-
| 0x0
| 0x20
| Digest
|}
|}


This contains information on previous title content from earlier patches.
This is a SHA-256 hash always found at the end of the file. The hash is calculated over the CNMT file's contents, but this is only done for the development version of the file which results in its production version counterpart sharing the same hash value.