aboutsummaryrefslogtreecommitdiff
path: root/src/DSi_TMD.h
diff options
context:
space:
mode:
authorJesse Talavera-Greenberg <jesse@jesse.tg>2023-07-08 16:17:30 -0400
committerGitHub <noreply@github.com>2023-07-08 22:17:30 +0200
commit0947e941b83b23b701edb31345c119f14e5ad56f (patch)
tree8162328db5d7b881fe8ed1cd9a0ea4a72e5aaf28 /src/DSi_TMD.h
parentd1ff103259bf44047b0da458cbd22d5e66a70773 (diff)
Modest cleanups for DSi_NAND (#1714)
* Add a definition for TMD files * Wrap TitleMetadata in a namespace * Add a comment * Remove TitleMetadataCertificate - melonDS ignores it anyway * Refactor the use of title metadata - Move bitwise operations on the title ID into helper methods - Use TitleMetadata objects instead of pointers to raw data * Slight cleanup in DSi_NAND - Replace some constants with sizeof - Use an NDSHeader object instead of a raw array of bytes * Add a DSi_NAND::ImportFile overload that loads a file from memory * Split most of ImportTitle into InitTitleFileStructure - It will be reused in the next commit * Add ability to import title from memory * Fix another potential issue * Fix broken DSiWare installation - The bytes of the title ID/category were being swapped in most places, but not all * Add some logging calls * Declare array sizes in DSi_TMD in decimal, not hex * Add a space after the #endif - To adhere to the style guide * Assert the size of TitleMetadataContent * Change the type of SignatureName * Don't mark the TMD structs as packed * Remove extraneous comments * Cut down some newlines
Diffstat (limited to 'src/DSi_TMD.h')
-rw-r--r--src/DSi_TMD.h119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/DSi_TMD.h b/src/DSi_TMD.h
new file mode 100644
index 0000000..12226c5
--- /dev/null
+++ b/src/DSi_TMD.h
@@ -0,0 +1,119 @@
+/*
+ Copyright 2016-2023 melonDS team
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef DSI_TMD_H
+#define DSI_TMD_H
+
+#include "types.h"
+#include <array>
+
+namespace DSi_TMD
+{
+
+struct TitleMetadataContent {
+ u8 ContentId[4]; /// Content ID (00,00,00,vv) ;lowercase/hex ;"0000000vv.app"
+ u8 ContentIndex[2]; /// Content Index (00,00)
+ u8 ContentType[2]; /// Content Type (00,01) ;aka DSi .app
+ u8 ContentSize[8]; /// Content Size (00,00,00,00,00,19,E4,00)
+ u8 ContentSha1Hash[20]; /// Content SHA1 (on decrypted ".app" file)
+
+ [[nodiscard]] u32 GetVersion() const noexcept
+ {
+ return (ContentId[0] << 24) | (ContentId[1] << 16) | (ContentId[2] << 8) | ContentId[3];
+ }
+};
+
+static_assert(sizeof(TitleMetadataContent) == 36, "TitleMetadataContent is not 36 bytes!");
+
+/// Metadata for a DSiWare title.
+/// Used to install DSiWare titles to NAND.
+/// @see https://problemkaputt.de/gbatek.htm#dsisdmmcdsiwareticketsandtitlemetadata
+struct TitleMetadata
+{
+ u32 SignatureType;
+ u8 Signature[256];
+ u8 SignatureAlignment[60];
+ char SignatureName[64];
+
+ u8 TmdVersion;
+ u8 CaCrlVersion;
+ u8 SignerCrlVersion;
+ u8 Padding0;
+
+ u8 SystemVersion[8];
+ u8 TitleId[8];
+ u32 TitleType;
+ u8 GroupId[2];
+ u8 PublicSaveSize[4];
+ u8 PrivateSaveSize[4];
+ u8 Padding1[4];
+
+ u8 SrlFlag;
+ u8 Padding2[3];
+
+ u8 AgeRatings[16];
+ u8 Padding3[30];
+
+ u32 AccessRights;
+ u16 TitleVersion;
+
+ u16 NumberOfContents; /// There's always one or zero content entries in practice
+ u16 BootContentIndex;
+ u8 Padding4[2];
+
+ TitleMetadataContent Contents;
+
+ [[nodiscard]] bool HasPublicSaveData() const noexcept { return GetPublicSaveSize() != 0; }
+ [[nodiscard]] bool HasPrivateSaveData() const noexcept { return GetPrivateSaveSize() != 0; }
+
+ [[nodiscard]] u32 GetPublicSaveSize() const noexcept
+ {
+ return (PublicSaveSize[0] << 24) | (PublicSaveSize[1] << 16) | (PublicSaveSize[2] << 8) | PublicSaveSize[3];
+ }
+
+ [[nodiscard]] u32 GetPrivateSaveSize() const noexcept
+ {
+ return (PrivateSaveSize[0] << 24) | (PrivateSaveSize[1] << 16) | (PrivateSaveSize[2] << 8) | PrivateSaveSize[3];
+ }
+
+ [[nodiscard]] u32 GetCategory() const noexcept
+ {
+ return (TitleId[0] << 24) | (TitleId[1] << 16) | (TitleId[2] << 8) | TitleId[3];
+ }
+
+ [[nodiscard]] u32 GetCategoryNoByteswap() const noexcept
+ {
+ return reinterpret_cast<const u32&>(TitleId);
+ }
+
+ [[nodiscard]] u32 GetID() const noexcept
+ {
+ return (TitleId[4] << 24) | (TitleId[5] << 16) | (TitleId[6] << 8) | TitleId[7];
+ }
+
+ [[nodiscard]] u32 GetIDNoByteswap() const noexcept
+ {
+ return *reinterpret_cast<const u32*>(&TitleId[4]);
+ }
+};
+
+static_assert(sizeof(TitleMetadata) == 520, "TitleMetadata is not 520 bytes!");
+
+}
+
+#endif // DSI_TMD_H