2020-07-25 06:56:35 +01:00
/*
* title . h
*
2024-04-12 10:47:36 +01:00
* Copyright ( c ) 2020 - 2024 , DarkMatterCore < pabloacurielz @ gmail . com > .
2020-07-25 06:56:35 +01:00
*
* This file is part of nxdumptool ( https : //github.com/DarkMatterCore/nxdumptool).
*
2021-03-25 19:26:58 +00:00
* nxdumptool 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 .
2020-07-25 06:56:35 +01:00
*
2021-03-25 19:26:58 +00:00
* nxdumptool 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 .
2020-07-25 06:56:35 +01:00
*
* You should have received a copy of the GNU General Public License
2021-03-25 19:26:58 +00:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2020-07-25 06:56:35 +01:00
*/
# pragma once
2021-03-24 17:25:19 +00:00
# ifndef __TITLE_H__
# define __TITLE_H__
2021-03-23 14:06:52 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2023-04-09 14:39:42 +01:00
# define TITLE_PATCH_ID_OFFSET (u64)0x800
2020-07-25 06:56:35 +01:00
2023-04-09 14:39:42 +01:00
# define TITLE_ADDONCONTENT_ID_OFFSET (u64)0x1000
2020-07-28 04:32:08 +01:00
# define TITLE_ADDONCONTENT_CONVERSION_MASK (u64)0xFFFFFFFFFFFFF000
2023-04-09 14:39:42 +01:00
# define TITLE_ADDONCONTENT_MIN_INDEX 1
# define TITLE_ADDONCONTENT_MAX_INDEX 2000
2020-07-28 04:32:08 +01:00
2023-04-09 14:39:42 +01:00
# define TITLE_DELTA_ID_OFFSET (u64)0xC00
2020-07-28 04:32:08 +01:00
2021-02-22 21:30:47 +00:00
/// Generated using ns application records and/or ncm content meta keys.
2020-07-28 04:32:08 +01:00
/// Used by the UI to display title lists.
2020-07-25 06:56:35 +01:00
typedef struct {
2020-07-28 04:32:08 +01:00
u64 title_id ; ///< Title ID from the application / system title this data belongs to.
2020-07-26 05:57:12 +01:00
NacpLanguageEntry lang_entry ; ///< UTF-8 strings in the console language.
2020-07-25 06:56:35 +01:00
u32 icon_size ; ///< JPEG icon size.
2020-07-28 04:32:08 +01:00
u8 * icon ; ///< JPEG icon data.
2020-07-25 06:56:35 +01:00
} TitleApplicationMetadata ;
Add DataTransferTaskFrame and GameCardImageDumpTaskFrame classes
DataTransferTaskFrame is a template class that's derived from brls::AppletFrame, which automatically starts a background task using an internal object belonging to a class derived from DataTransferTask. A DataTransferProgressDisplay view is used to show progress updates. If the background task hits an error, the class takes care of switching to an ErrorFrame view with the corresponding error message.
GameCardImageDumpTaskFrame is a derived class of DataTransferTaskFrame that uses a GameCardImageDumpTask object as its background task. In layman's terms, this provides a way to fully dump gamecard images using the new UI.
DataTransferTaskFrame depends on the newly added is_base_template helper from goneskiing to check if the class for the provided task is derived from DataTransferTask.
Other changes include:
* DataTransferProgressDisplay: rename setProgress() method to SetProgress().
* DataTransferTask: move post-task-execution code into its own new private method, PostExecutionCallback(), and update both OnCancelled() and OnPostExecute() callbacks to invoke it.
* DataTransferTask: update OnProgressUpdate() to allow sending a last progress update to all event subscribers even if the background task was cancelled.
* DataTransferTask: update OnProgressUpdate() to allow sending a first progress update if no data has been transferred but the total transfer size is already known.
* DataTransferTask: update OnProgressUpdate() to avoid calculating the ETA if the speed isn't greater than 0.
* DumpOptionsFrame: remove UpdateOutputStorages() method.
* DumpOptionsFrame: update class to use the cached output storage value from our RootView.
* DumpOptionsFrame: add GenerateOutputStoragesVector() method, which is used to avoid setting dummy options while initializing the output storages SelectListItem.
* DumpOptionsFrame: update UMS task callback to add the rest of the leftover logic from UpdateOutputStorages().
* DumpOptionsFrame: update RegisterButtonListener() to use a wrapper callback around the user-provided callback to check if the USB host was selected as the output storage but no USB host connection is available.
* ErrorFrame: use const references for all input string arguments.
* FileWriter: fix a localization stirng name typo.
* FileWriter: fix an exception that was previously being thrown by a fmt::format() call because of a wrong format specifier.
* FocusableItem: add a static assert to check if the provided ViewType is derived from brls::View.
* gamecard: redefine global gamecard status variable as an atomic unsigned 8-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call gamecardGetStatus().
* GameCardImageDumpOptionsFrame: define GAMECARD_TOGGLE_ITEM macro, which is used to initialize all ToggleListItem elements from the view.
* GameCardImageDumpOptionsFrame: update button callback to push a GameCardImageDumpTaskFrame view onto the borealis stack.
* GameCardImageDumpTask: move class into its own header and module files.
* GameCardImageDumpTask: update class to also take in the checksum lookup method (not yet implemented).
* GameCardImageDumpTask: update class to send its first progress update as soon as the gamecard image size is known.
* GameCardImageDumpTask: update class to avoid returning a string if the task was cancelled -- DataTransferTaskFrame offers logic to display the appropiate cancel message on its own.
* GameCardTab: update PopulateList() method to display the new version information available in TitleGameCardApplicationMetadataEntry elements as part of the generated TitlesTabItem objects.
* i18n: add new localization strings.
* OptionsTab: update background task callback logic to handle task cancellation, reflecting the changes made to DataTransferTask.
* OptionsTab: reflect changes made to DataTransferProgressDisplay.
* RootView: cache the currently selected output storage value at all times, which is propagated throughout different parts of the UI. Getter and setter helpers have been added to operate with this value.
* RootView: add GetUsbHostSpeed() helper, which can be used by child views to retrieve the USB host speed on demand.
* RootView: update UMS task callback to automatically reset the cached output storage value back to the SD card if a UMS device was previously selected.
* title: define TitleGameCardApplicationMetadataEntry struct, which also holds version-specific information retrieved from the gamecard titles.
* title: refactor titleGetGameCardApplicationMetadataEntries() to return a dynamically allocated array of TitleGameCardApplicationMetadataEntry elements.
* usb: redefine global endpoint max packet size variable as an atomic unsigned 16-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call usbIsReady().
* UsbHostTask: add GetUsbHostSpeed() method.
2024-04-29 14:26:12 +01:00
/// Used to display gamecard-specific title information.
typedef struct {
TitleApplicationMetadata * app_metadata ; ///< User application metadata.
Version version ; ///< Reflects the title version stored in the inserted gamecard.
char display_version [ 32 ] ; ///< Reflects the title display version stored in its NACP.
2024-04-30 22:01:42 +01:00
u32 dlc_count ; ///< Reflects the number of DLCs available for this application in the inserted gamecard.
Add DataTransferTaskFrame and GameCardImageDumpTaskFrame classes
DataTransferTaskFrame is a template class that's derived from brls::AppletFrame, which automatically starts a background task using an internal object belonging to a class derived from DataTransferTask. A DataTransferProgressDisplay view is used to show progress updates. If the background task hits an error, the class takes care of switching to an ErrorFrame view with the corresponding error message.
GameCardImageDumpTaskFrame is a derived class of DataTransferTaskFrame that uses a GameCardImageDumpTask object as its background task. In layman's terms, this provides a way to fully dump gamecard images using the new UI.
DataTransferTaskFrame depends on the newly added is_base_template helper from goneskiing to check if the class for the provided task is derived from DataTransferTask.
Other changes include:
* DataTransferProgressDisplay: rename setProgress() method to SetProgress().
* DataTransferTask: move post-task-execution code into its own new private method, PostExecutionCallback(), and update both OnCancelled() and OnPostExecute() callbacks to invoke it.
* DataTransferTask: update OnProgressUpdate() to allow sending a last progress update to all event subscribers even if the background task was cancelled.
* DataTransferTask: update OnProgressUpdate() to allow sending a first progress update if no data has been transferred but the total transfer size is already known.
* DataTransferTask: update OnProgressUpdate() to avoid calculating the ETA if the speed isn't greater than 0.
* DumpOptionsFrame: remove UpdateOutputStorages() method.
* DumpOptionsFrame: update class to use the cached output storage value from our RootView.
* DumpOptionsFrame: add GenerateOutputStoragesVector() method, which is used to avoid setting dummy options while initializing the output storages SelectListItem.
* DumpOptionsFrame: update UMS task callback to add the rest of the leftover logic from UpdateOutputStorages().
* DumpOptionsFrame: update RegisterButtonListener() to use a wrapper callback around the user-provided callback to check if the USB host was selected as the output storage but no USB host connection is available.
* ErrorFrame: use const references for all input string arguments.
* FileWriter: fix a localization stirng name typo.
* FileWriter: fix an exception that was previously being thrown by a fmt::format() call because of a wrong format specifier.
* FocusableItem: add a static assert to check if the provided ViewType is derived from brls::View.
* gamecard: redefine global gamecard status variable as an atomic unsigned 8-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call gamecardGetStatus().
* GameCardImageDumpOptionsFrame: define GAMECARD_TOGGLE_ITEM macro, which is used to initialize all ToggleListItem elements from the view.
* GameCardImageDumpOptionsFrame: update button callback to push a GameCardImageDumpTaskFrame view onto the borealis stack.
* GameCardImageDumpTask: move class into its own header and module files.
* GameCardImageDumpTask: update class to also take in the checksum lookup method (not yet implemented).
* GameCardImageDumpTask: update class to send its first progress update as soon as the gamecard image size is known.
* GameCardImageDumpTask: update class to avoid returning a string if the task was cancelled -- DataTransferTaskFrame offers logic to display the appropiate cancel message on its own.
* GameCardTab: update PopulateList() method to display the new version information available in TitleGameCardApplicationMetadataEntry elements as part of the generated TitlesTabItem objects.
* i18n: add new localization strings.
* OptionsTab: update background task callback logic to handle task cancellation, reflecting the changes made to DataTransferTask.
* OptionsTab: reflect changes made to DataTransferProgressDisplay.
* RootView: cache the currently selected output storage value at all times, which is propagated throughout different parts of the UI. Getter and setter helpers have been added to operate with this value.
* RootView: add GetUsbHostSpeed() helper, which can be used by child views to retrieve the USB host speed on demand.
* RootView: update UMS task callback to automatically reset the cached output storage value back to the SD card if a UMS device was previously selected.
* title: define TitleGameCardApplicationMetadataEntry struct, which also holds version-specific information retrieved from the gamecard titles.
* title: refactor titleGetGameCardApplicationMetadataEntries() to return a dynamically allocated array of TitleGameCardApplicationMetadataEntry elements.
* usb: redefine global endpoint max packet size variable as an atomic unsigned 16-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call usbIsReady().
* UsbHostTask: add GetUsbHostSpeed() method.
2024-04-29 14:26:12 +01:00
} TitleGameCardApplicationMetadataEntry ;
2021-06-01 02:12:15 +01:00
/// Generated using ncm calls.
2022-12-04 10:29:47 +00:00
/// User applications: the previous/next pointers reference other user applications with the same ID.
/// Patches: the previous/next pointers reference other patches with the same ID.
/// Add-on contents: the previous/next pointers reference sibling add-on contents.
/// Add-on content patches: the previous/next pointers reference other patches with the same ID and/or other patches for sibling add-on contents.
2020-07-28 04:32:08 +01:00
typedef struct _TitleInfo {
u8 storage_id ; ///< NcmStorageId.
NcmContentMetaKey meta_key ; ///< Used with ncm calls.
2022-03-17 12:37:24 +00:00
Version version ; ///< Holds the same value from meta_key.version.
2020-07-28 04:32:08 +01:00
u32 content_count ; ///< Content info count.
NcmContentInfo * content_infos ; ///< Content info entries from this title.
2020-10-21 05:27:48 +01:00
u64 size ; ///< Total title size.
char size_str [ 32 ] ; ///< Total title size string.
2021-01-31 09:16:05 +00:00
TitleApplicationMetadata * app_metadata ; ///< User application metadata.
2022-12-04 10:29:47 +00:00
struct _TitleInfo * previous , * next ; ///< Linked lists.
2020-07-25 06:56:35 +01:00
} TitleInfo ;
2020-07-28 04:32:08 +01:00
/// Used to deal with user applications stored in the eMMC, SD card and/or gamecard.
2022-12-04 10:29:47 +00:00
/// The previous and next pointers from the TitleInfo elements are used to traverse through multiple user applications, patches, add-on contents and or add-on content patches.
2020-07-28 04:32:08 +01:00
typedef struct {
2022-12-04 10:29:47 +00:00
TitleInfo * app_info ; ///< Pointer to a TitleInfo element for the first detected user application entry matching the provided application ID.
TitleInfo * patch_info ; ///< Pointer to a TitleInfo element for the first detected patch entry matching the provided application ID.
TitleInfo * aoc_info ; ///< Pointer to a TitleInfo element for the first detected add-on content entry matching the provided application ID.
TitleInfo * aoc_patch_info ; ///< Pointer to a TitleInfo element for the first detected add-on content patch entry matching the provided application ID.
2020-07-28 04:32:08 +01:00
} TitleUserApplicationData ;
2020-08-14 03:31:02 +01:00
typedef enum {
2021-07-23 08:24:00 +01:00
TitleNamingConvention_Full = 0 , ///< Individual titles: "{Name} [{Id}][v{Version}][{Type}]".
2022-07-30 15:25:41 +01:00
///< Gamecards: "{Name1} [{Id1}][v{Version1}] + ... + {NameN} [{IdN}][v{VersionN}]".
2021-07-23 08:24:00 +01:00
TitleNamingConvention_IdAndVersionOnly = 1 , ///< Individual titles: "{Id}_v{Version}_{Type}".
///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}".
2023-07-17 00:03:05 +01:00
TitleNamingConvention_Count = 2 ///< Total values supported by this enum.
2021-07-23 08:24:00 +01:00
} TitleNamingConvention ;
2020-08-14 03:31:02 +01:00
typedef enum {
TitleFileNameIllegalCharReplaceType_None = 0 ,
TitleFileNameIllegalCharReplaceType_IllegalFsChars = 1 ,
2023-07-17 00:03:05 +01:00
TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly = 2 ,
TitleFileNameIllegalCharReplaceType_Count = 3 ///< Total values supported by this enum.
2020-08-14 03:31:02 +01:00
} TitleFileNameIllegalCharReplaceType ;
2020-07-26 05:57:12 +01:00
/// Initializes the title interface.
bool titleInitialize ( void ) ;
2020-07-25 06:56:35 +01:00
2020-07-26 05:57:12 +01:00
/// Closes the title interface.
void titleExit ( void ) ;
2020-07-25 06:56:35 +01:00
2020-07-26 05:57:12 +01:00
/// Returns a pointer to a ncm database handle using a NcmStorageId value.
NcmContentMetaDatabase * titleGetNcmDatabaseByStorageId ( u8 storage_id ) ;
/// Returns a pointer to a ncm storage handle using a NcmStorageId value.
NcmContentStorage * titleGetNcmStorageByStorageId ( u8 storage_id ) ;
2021-06-01 02:12:15 +01:00
/// Returns a pointer to a dynamically allocated array of pointers to TitleApplicationMetadata entries, as well as their count. Returns NULL if an error occurs.
2020-07-29 22:02:21 +01:00
/// If 'is_system' is true, TitleApplicationMetadata entries from available system titles (NcmStorageId_BuiltInSystem) will be returned.
2021-03-10 13:10:43 +00:00
/// Otherwise, TitleApplicationMetadata entries from user applications with available content data (NcmStorageId_BuiltInUser, NcmStorageId_SdCard, NcmStorageId_GameCard) will be returned.
Add DataTransferTaskFrame and GameCardImageDumpTaskFrame classes
DataTransferTaskFrame is a template class that's derived from brls::AppletFrame, which automatically starts a background task using an internal object belonging to a class derived from DataTransferTask. A DataTransferProgressDisplay view is used to show progress updates. If the background task hits an error, the class takes care of switching to an ErrorFrame view with the corresponding error message.
GameCardImageDumpTaskFrame is a derived class of DataTransferTaskFrame that uses a GameCardImageDumpTask object as its background task. In layman's terms, this provides a way to fully dump gamecard images using the new UI.
DataTransferTaskFrame depends on the newly added is_base_template helper from goneskiing to check if the class for the provided task is derived from DataTransferTask.
Other changes include:
* DataTransferProgressDisplay: rename setProgress() method to SetProgress().
* DataTransferTask: move post-task-execution code into its own new private method, PostExecutionCallback(), and update both OnCancelled() and OnPostExecute() callbacks to invoke it.
* DataTransferTask: update OnProgressUpdate() to allow sending a last progress update to all event subscribers even if the background task was cancelled.
* DataTransferTask: update OnProgressUpdate() to allow sending a first progress update if no data has been transferred but the total transfer size is already known.
* DataTransferTask: update OnProgressUpdate() to avoid calculating the ETA if the speed isn't greater than 0.
* DumpOptionsFrame: remove UpdateOutputStorages() method.
* DumpOptionsFrame: update class to use the cached output storage value from our RootView.
* DumpOptionsFrame: add GenerateOutputStoragesVector() method, which is used to avoid setting dummy options while initializing the output storages SelectListItem.
* DumpOptionsFrame: update UMS task callback to add the rest of the leftover logic from UpdateOutputStorages().
* DumpOptionsFrame: update RegisterButtonListener() to use a wrapper callback around the user-provided callback to check if the USB host was selected as the output storage but no USB host connection is available.
* ErrorFrame: use const references for all input string arguments.
* FileWriter: fix a localization stirng name typo.
* FileWriter: fix an exception that was previously being thrown by a fmt::format() call because of a wrong format specifier.
* FocusableItem: add a static assert to check if the provided ViewType is derived from brls::View.
* gamecard: redefine global gamecard status variable as an atomic unsigned 8-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call gamecardGetStatus().
* GameCardImageDumpOptionsFrame: define GAMECARD_TOGGLE_ITEM macro, which is used to initialize all ToggleListItem elements from the view.
* GameCardImageDumpOptionsFrame: update button callback to push a GameCardImageDumpTaskFrame view onto the borealis stack.
* GameCardImageDumpTask: move class into its own header and module files.
* GameCardImageDumpTask: update class to also take in the checksum lookup method (not yet implemented).
* GameCardImageDumpTask: update class to send its first progress update as soon as the gamecard image size is known.
* GameCardImageDumpTask: update class to avoid returning a string if the task was cancelled -- DataTransferTaskFrame offers logic to display the appropiate cancel message on its own.
* GameCardTab: update PopulateList() method to display the new version information available in TitleGameCardApplicationMetadataEntry elements as part of the generated TitlesTabItem objects.
* i18n: add new localization strings.
* OptionsTab: update background task callback logic to handle task cancellation, reflecting the changes made to DataTransferTask.
* OptionsTab: reflect changes made to DataTransferProgressDisplay.
* RootView: cache the currently selected output storage value at all times, which is propagated throughout different parts of the UI. Getter and setter helpers have been added to operate with this value.
* RootView: add GetUsbHostSpeed() helper, which can be used by child views to retrieve the USB host speed on demand.
* RootView: update UMS task callback to automatically reset the cached output storage value back to the SD card if a UMS device was previously selected.
* title: define TitleGameCardApplicationMetadataEntry struct, which also holds version-specific information retrieved from the gamecard titles.
* title: refactor titleGetGameCardApplicationMetadataEntries() to return a dynamically allocated array of TitleGameCardApplicationMetadataEntry elements.
* usb: redefine global endpoint max packet size variable as an atomic unsigned 16-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call usbIsReady().
* UsbHostTask: add GetUsbHostSpeed() method.
2024-04-29 14:26:12 +01:00
/// The allocated buffer must be freed by the caller using free().
2020-07-28 04:32:08 +01:00
TitleApplicationMetadata * * titleGetApplicationMetadataEntries ( bool is_system , u32 * out_count ) ;
Add DataTransferTaskFrame and GameCardImageDumpTaskFrame classes
DataTransferTaskFrame is a template class that's derived from brls::AppletFrame, which automatically starts a background task using an internal object belonging to a class derived from DataTransferTask. A DataTransferProgressDisplay view is used to show progress updates. If the background task hits an error, the class takes care of switching to an ErrorFrame view with the corresponding error message.
GameCardImageDumpTaskFrame is a derived class of DataTransferTaskFrame that uses a GameCardImageDumpTask object as its background task. In layman's terms, this provides a way to fully dump gamecard images using the new UI.
DataTransferTaskFrame depends on the newly added is_base_template helper from goneskiing to check if the class for the provided task is derived from DataTransferTask.
Other changes include:
* DataTransferProgressDisplay: rename setProgress() method to SetProgress().
* DataTransferTask: move post-task-execution code into its own new private method, PostExecutionCallback(), and update both OnCancelled() and OnPostExecute() callbacks to invoke it.
* DataTransferTask: update OnProgressUpdate() to allow sending a last progress update to all event subscribers even if the background task was cancelled.
* DataTransferTask: update OnProgressUpdate() to allow sending a first progress update if no data has been transferred but the total transfer size is already known.
* DataTransferTask: update OnProgressUpdate() to avoid calculating the ETA if the speed isn't greater than 0.
* DumpOptionsFrame: remove UpdateOutputStorages() method.
* DumpOptionsFrame: update class to use the cached output storage value from our RootView.
* DumpOptionsFrame: add GenerateOutputStoragesVector() method, which is used to avoid setting dummy options while initializing the output storages SelectListItem.
* DumpOptionsFrame: update UMS task callback to add the rest of the leftover logic from UpdateOutputStorages().
* DumpOptionsFrame: update RegisterButtonListener() to use a wrapper callback around the user-provided callback to check if the USB host was selected as the output storage but no USB host connection is available.
* ErrorFrame: use const references for all input string arguments.
* FileWriter: fix a localization stirng name typo.
* FileWriter: fix an exception that was previously being thrown by a fmt::format() call because of a wrong format specifier.
* FocusableItem: add a static assert to check if the provided ViewType is derived from brls::View.
* gamecard: redefine global gamecard status variable as an atomic unsigned 8-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call gamecardGetStatus().
* GameCardImageDumpOptionsFrame: define GAMECARD_TOGGLE_ITEM macro, which is used to initialize all ToggleListItem elements from the view.
* GameCardImageDumpOptionsFrame: update button callback to push a GameCardImageDumpTaskFrame view onto the borealis stack.
* GameCardImageDumpTask: move class into its own header and module files.
* GameCardImageDumpTask: update class to also take in the checksum lookup method (not yet implemented).
* GameCardImageDumpTask: update class to send its first progress update as soon as the gamecard image size is known.
* GameCardImageDumpTask: update class to avoid returning a string if the task was cancelled -- DataTransferTaskFrame offers logic to display the appropiate cancel message on its own.
* GameCardTab: update PopulateList() method to display the new version information available in TitleGameCardApplicationMetadataEntry elements as part of the generated TitlesTabItem objects.
* i18n: add new localization strings.
* OptionsTab: update background task callback logic to handle task cancellation, reflecting the changes made to DataTransferTask.
* OptionsTab: reflect changes made to DataTransferProgressDisplay.
* RootView: cache the currently selected output storage value at all times, which is propagated throughout different parts of the UI. Getter and setter helpers have been added to operate with this value.
* RootView: add GetUsbHostSpeed() helper, which can be used by child views to retrieve the USB host speed on demand.
* RootView: update UMS task callback to automatically reset the cached output storage value back to the SD card if a UMS device was previously selected.
* title: define TitleGameCardApplicationMetadataEntry struct, which also holds version-specific information retrieved from the gamecard titles.
* title: refactor titleGetGameCardApplicationMetadataEntries() to return a dynamically allocated array of TitleGameCardApplicationMetadataEntry elements.
* usb: redefine global endpoint max packet size variable as an atomic unsigned 16-bit integer, which fixes a "status-hopping" issue previously experienced by repeating tasks running under other threads that periodically call usbIsReady().
* UsbHostTask: add GetUsbHostSpeed() method.
2024-04-29 14:26:12 +01:00
/// Returns a pointer to a dynamically allocated array of TitleGameCardApplicationMetadataEntry elements generated from gamecard user titles, as well as their count.
/// Returns NULL if an error occurs.
/// The allocated buffer must be freed by the caller using free().
TitleGameCardApplicationMetadataEntry * titleGetGameCardApplicationMetadataEntries ( u32 * out_count ) ;
2022-07-27 23:53:52 +01:00
2021-06-01 02:12:15 +01:00
/// Returns a pointer to a dynamically allocated TitleInfo element with a matching storage ID and title ID. Returns NULL if an error occurs.
2020-07-26 05:57:12 +01:00
/// If NcmStorageId_Any is used, the first entry with a matching title ID is returned.
2021-06-01 02:12:15 +01:00
/// Use titleFreeTitleInfo() to free the returned data.
2020-07-26 05:57:12 +01:00
TitleInfo * titleGetInfoFromStorageByTitleId ( u8 storage_id , u64 title_id ) ;
2020-07-25 06:56:35 +01:00
2021-06-01 02:12:15 +01:00
/// Frees a dynamically allocated TitleInfo element.
void titleFreeTitleInfo ( TitleInfo * * info ) ;
/// Populates a TitleUserApplicationData element with dynamically allocated data using a user application ID.
/// Use titleFreeUserApplicationData() to free the populated data.
2020-07-28 04:32:08 +01:00
bool titleGetUserApplicationData ( u64 app_id , TitleUserApplicationData * out ) ;
2021-06-01 02:12:15 +01:00
/// Frees data populated by titleGetUserApplicationData().
void titleFreeUserApplicationData ( TitleUserApplicationData * user_app_data ) ;
2023-05-27 19:10:35 +01:00
/// Takes an input TitleInfo object with meta type NcmContentMetaType_AddOnContent or NcmContentMetaType_DataPatch.
/// Returns a linked list of TitleInfo elements with title IDs matching the corresponding base/patch title ID, depending on the meta type of the input TitleInfo object.
/// Particularly useful to display add-on-content base/patch titles related to a specific add-on-content (patch) entry.
/// Use titleFreeTitleInfo() to free the returned data.
TitleInfo * titleGetAddOnContentBaseOrPatchList ( TitleInfo * title_info ) ;
2020-07-30 23:37:45 +01:00
/// Returns true if orphan titles are available.
2020-08-13 19:12:33 +01:00
/// Orphan titles are patches or add-on contents with no NsApplicationControlData available for their parent user application ID.
2020-07-30 23:37:45 +01:00
bool titleAreOrphanTitlesAvailable ( void ) ;
2021-06-01 02:12:15 +01:00
/// Returns a pointer to a dynamically allocated array of orphan TitleInfo entries, as well as their count. Returns NULL if an error occurs.
/// Use titleFreeOrphanTitles() to free the returned data.
TitleInfo * * titleGetOrphanTitles ( u32 * out_count ) ;
/// Frees orphan title info data returned by titleGetInfoFromOrphanTitles().
void titleFreeOrphanTitles ( TitleInfo * * * orphan_info ) ;
2020-07-30 23:37:45 +01:00
2020-10-27 21:23:19 +00:00
/// Checks if a gamecard status update has been detected by the background gamecard title info thread (e.g. after a new gamecard has been inserted, of after the current one has been taken out).
2021-06-01 02:12:15 +01:00
/// If this function returns true and functions such as titleGetInfoFromStorageByTitleId(), titleGetUserApplicationData() or titleGetInfoFromOrphanTitles() have been previously called:
/// 1. Their returned data must be freed.
2021-03-10 13:10:43 +00:00
/// 2. They must be called again.
2020-07-30 22:43:50 +01:00
bool titleIsGameCardInfoUpdated ( void ) ;
2021-06-01 02:12:15 +01:00
/// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output title dumps. Returns NULL if an error occurs.
2021-07-23 08:24:00 +01:00
char * titleGenerateFileName ( TitleInfo * title_info , u8 naming_convention , u8 illegal_char_replace_type ) ;
2020-08-14 03:31:02 +01:00
2021-06-01 02:12:15 +01:00
/// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output gamecard dumps. Returns NULL if an error occurs.
2020-08-14 03:31:02 +01:00
/// A valid gamecard must be inserted, and title info must have been loaded from it accordingly.
2021-07-23 08:24:00 +01:00
char * titleGenerateGameCardFileName ( u8 naming_convention , u8 illegal_char_replace_type ) ;
2020-08-14 03:31:02 +01:00
2022-07-12 01:27:03 +01:00
/// Returns a pointer to a string holding a user-friendly name for the provided NcmStorageId value. Returns NULL if the provided value is invalid.
const char * titleGetNcmStorageIdName ( u8 storage_id ) ;
2020-10-03 18:09:29 +01:00
/// Returns a pointer to a string holding the name of the provided NcmContentType value. Returns NULL if the provided value is invalid.
2020-07-29 22:02:21 +01:00
const char * titleGetNcmContentTypeName ( u8 content_type ) ;
2020-10-03 18:09:29 +01:00
/// Returns a pointer to a string holding the name of the provided NcmContentMetaType value. Returns NULL if the provided value is invalid.
2020-08-14 03:31:02 +01:00
const char * titleGetNcmContentMetaTypeName ( u8 content_meta_type ) ;
2020-07-25 06:56:35 +01:00
/// Miscellaneous functions.
2023-05-27 19:10:35 +01:00
NX_INLINE bool titleIsValidInfoBlock ( TitleInfo * title_info )
{
return ( title_info & & title_info - > storage_id > = NcmStorageId_GameCard & & title_info - > storage_id < = NcmStorageId_SdCard & & title_info - > meta_key . id & & \
( ( title_info - > meta_key . type > = NcmContentMetaType_SystemProgram & & title_info - > meta_key . type < = NcmContentMetaType_BootImagePackageSafe ) | | \
( title_info - > meta_key . type > = NcmContentMetaType_Application & & title_info - > meta_key . type < = NcmContentMetaType_DataPatch ) ) & & \
title_info - > content_count & & title_info - > content_infos ) ;
}
2020-07-25 06:56:35 +01:00
NX_INLINE u64 titleGetPatchIdByApplicationId ( u64 app_id )
{
2023-04-09 14:39:42 +01:00
return ( app_id + TITLE_PATCH_ID_OFFSET ) ;
2020-07-25 06:56:35 +01:00
}
NX_INLINE u64 titleGetApplicationIdByPatchId ( u64 patch_id )
{
2023-04-09 14:39:42 +01:00
return ( patch_id - TITLE_PATCH_ID_OFFSET ) ;
2020-07-25 06:56:35 +01:00
}
NX_INLINE bool titleCheckIfPatchIdBelongsToApplicationId ( u64 app_id , u64 patch_id )
{
2020-07-28 04:32:08 +01:00
return ( patch_id = = titleGetPatchIdByApplicationId ( app_id ) ) ;
}
NX_INLINE u64 titleGetAddOnContentBaseIdByApplicationId ( u64 app_id )
{
2023-04-09 14:39:42 +01:00
return ( ( app_id & TITLE_ADDONCONTENT_CONVERSION_MASK ) + TITLE_ADDONCONTENT_ID_OFFSET ) ;
2020-07-28 04:32:08 +01:00
}
2023-04-09 14:39:42 +01:00
NX_INLINE u64 titleGetAddOnContentMinIdByBaseId ( u64 aoc_base_id )
2020-07-28 04:32:08 +01:00
{
2023-04-09 14:39:42 +01:00
return ( aoc_base_id + TITLE_ADDONCONTENT_MIN_INDEX ) ;
2020-07-28 04:32:08 +01:00
}
2023-04-09 14:39:42 +01:00
NX_INLINE u64 titleGetAddOnContentMaxIdByBaseId ( u64 aoc_base_id )
2020-07-28 04:32:08 +01:00
{
2023-04-09 14:39:42 +01:00
return ( aoc_base_id + TITLE_ADDONCONTENT_MAX_INDEX ) ;
2020-07-28 04:32:08 +01:00
}
2023-04-09 14:39:42 +01:00
NX_INLINE u64 titleGetApplicationIdByAddOnContentId ( u64 aoc_id )
2020-07-28 04:32:08 +01:00
{
2023-04-09 14:39:42 +01:00
return ( ( aoc_id - TITLE_ADDONCONTENT_ID_OFFSET ) & TITLE_ADDONCONTENT_CONVERSION_MASK ) ;
2020-07-28 04:32:08 +01:00
}
2023-04-09 14:39:42 +01:00
NX_INLINE bool titleIsAddOnContentIdValid ( u64 aoc_id , u64 aoc_min_id , u64 aoc_max_id )
2020-07-28 04:32:08 +01:00
{
2023-04-09 14:39:42 +01:00
return ( aoc_min_id < = aoc_id & & aoc_id < = aoc_max_id ) ;
2020-07-25 06:56:35 +01:00
}
NX_INLINE bool titleCheckIfAddOnContentIdBelongsToApplicationId ( u64 app_id , u64 aoc_id )
{
2020-07-28 04:32:08 +01:00
u64 aoc_base_id = titleGetAddOnContentBaseIdByApplicationId ( app_id ) ;
2023-04-09 14:39:42 +01:00
u64 aoc_min_id = titleGetAddOnContentMinIdByBaseId ( aoc_base_id ) ;
2020-07-28 04:32:08 +01:00
u64 aoc_max_id = titleGetAddOnContentMaxIdByBaseId ( aoc_base_id ) ;
2023-04-09 14:39:42 +01:00
return titleIsAddOnContentIdValid ( aoc_id , aoc_min_id , aoc_max_id ) ;
2020-07-28 04:32:08 +01:00
}
NX_INLINE bool titleCheckIfAddOnContentIdsAreSiblings ( u64 aoc_id_1 , u64 aoc_id_2 )
{
u64 app_id_1 = titleGetApplicationIdByAddOnContentId ( aoc_id_1 ) ;
u64 app_id_2 = titleGetApplicationIdByAddOnContentId ( aoc_id_2 ) ;
return ( app_id_1 = = app_id_2 & & titleCheckIfAddOnContentIdBelongsToApplicationId ( app_id_1 , aoc_id_1 ) & & titleCheckIfAddOnContentIdBelongsToApplicationId ( app_id_2 , aoc_id_2 ) ) ;
2020-07-25 06:56:35 +01:00
}
2023-04-09 14:39:42 +01:00
/// Nintendo uses one-based indexes for IDs... but we won't.
NX_INLINE u64 titleGetAddOnContentIdByApplicationIdAndIndex ( u64 app_id , u16 idx )
{
return ( titleGetAddOnContentBaseIdByApplicationId ( app_id ) + 1 + idx ) ;
}
2021-01-31 09:16:05 +00:00
NX_INLINE u64 titleGetDeltaIdByApplicationId ( u64 app_id )
{
2023-04-09 14:39:42 +01:00
return ( app_id + TITLE_DELTA_ID_OFFSET ) ;
2021-01-31 09:16:05 +00:00
}
NX_INLINE u64 titleGetApplicationIdByDeltaId ( u64 delta_id )
{
2023-04-09 14:39:42 +01:00
return ( delta_id - TITLE_DELTA_ID_OFFSET ) ;
2021-01-31 09:16:05 +00:00
}
NX_INLINE bool titleCheckIfDeltaIdBelongsToApplicationId ( u64 app_id , u64 delta_id )
{
return ( delta_id = = titleGetDeltaIdByApplicationId ( app_id ) ) ;
}
Preliminar 15.x support.
This commit uses my yet unmerged libnx PR to update ncm_types.h.
PoC code hasn't been updated yet, so proper support for DLC updates will arrive at a later time.
Note to self: implement a way to provide access to loaded DataPatch TitleInfo entries (linked list hell).
* bktr: renamed bktrBucketInitializeSubStorageReadParams to bktrInitializeSubStorageReadParams to avoid redundancy, added debug code to dump BucketInfo and BucketTree tables if BucketTree storage initialization fails.
* cnmt: updated ContentMetaAddOnContentMetaExtendedHeader struct to its 15.x equivalent, added ContentMetaLegacyAddOnContentMetaExtendedHeader struct, added ContentMetaDataPatchMetaExtendedHeader struct, updated the cnmtGetRequiredTitleId and cnmtGetRequiredTitleVersion functions to support DataPatch titles, updated cnmtInitializeContext to support both the new AddOnContent extended header and DataPatch titles, added debug code to dump the whole CNMT if context initialization fails, updated cnmtGenerateAuthoringToolXml to support DataPatch titles.
* keys: updated block hashes to match 15.x keyset, use case-insensitive comparison while looking for entry names in keysReadKeysFromFile, make sure the eticket_rsa_kek is non-zero before proceeding in keysGetDecryptedEticketRsaDeviceKey.
* nca: updated NcaKeyGeneration enum, added reminder about updating NcaSignatureKeyGeneration if necessary, replaced ncaFsSectionCheckHashRegionAccess with ncaFsSectionCheckPlaintextHashRegionAccess, removed all extents checks on Patch RomFS and sparse sections, updated ncaGetFsSectionTypeName to reflect if a FS section holds a sparse layer or not.
* nca_storage: updated ncaStorageInitializeContext to avoid initializing a compressed storage if a sparse layer is also used (fixes issues with Them's Fightin' Herds), updated ncaStorageSetPatchOriginalSubStorage to enforce the presence of a compressed storage in a patch if the base FS holds a compressed storage.
* npdm: added reminder about updating NpdmSignatureKeyGeneration if necessary, updated NpdmFsAccessControlFlags enum, updated NpdmAccessibility enum, updated NpdmSystemCallId enum, fixed typos.
* title: updated all relevant functions that deal with NcmContentMetaType values to also handle DataPatch titles, added functions to handle DataPatchId values, removed titleConvertNcmContentSizeToU64 and titleConvertU64ToNcmContentSize functions in favor of ncmContentInfoSizeToU64 and ncmU64ToContentInfoSize from my unmerged libnx PR, updated internal arrays to match 15.x changes, renamed titleOrphanTitleInfoSortFunction to titleInfoEntrySortFunction and updated it to also sort entries by version and storage ID, updated titleGenerateTitleInfoEntriesForTitleStorage to sort TitleInfo entries, simplified titleDuplicateTitleInfo a bit by using macros.
2022-10-23 15:44:47 +01:00
NX_INLINE u64 titleGetDataPatchIdByAddOnContentId ( u64 aoc_id )
{
2023-04-09 14:39:42 +01:00
return ( aoc_id + TITLE_PATCH_ID_OFFSET ) ;
Preliminar 15.x support.
This commit uses my yet unmerged libnx PR to update ncm_types.h.
PoC code hasn't been updated yet, so proper support for DLC updates will arrive at a later time.
Note to self: implement a way to provide access to loaded DataPatch TitleInfo entries (linked list hell).
* bktr: renamed bktrBucketInitializeSubStorageReadParams to bktrInitializeSubStorageReadParams to avoid redundancy, added debug code to dump BucketInfo and BucketTree tables if BucketTree storage initialization fails.
* cnmt: updated ContentMetaAddOnContentMetaExtendedHeader struct to its 15.x equivalent, added ContentMetaLegacyAddOnContentMetaExtendedHeader struct, added ContentMetaDataPatchMetaExtendedHeader struct, updated the cnmtGetRequiredTitleId and cnmtGetRequiredTitleVersion functions to support DataPatch titles, updated cnmtInitializeContext to support both the new AddOnContent extended header and DataPatch titles, added debug code to dump the whole CNMT if context initialization fails, updated cnmtGenerateAuthoringToolXml to support DataPatch titles.
* keys: updated block hashes to match 15.x keyset, use case-insensitive comparison while looking for entry names in keysReadKeysFromFile, make sure the eticket_rsa_kek is non-zero before proceeding in keysGetDecryptedEticketRsaDeviceKey.
* nca: updated NcaKeyGeneration enum, added reminder about updating NcaSignatureKeyGeneration if necessary, replaced ncaFsSectionCheckHashRegionAccess with ncaFsSectionCheckPlaintextHashRegionAccess, removed all extents checks on Patch RomFS and sparse sections, updated ncaGetFsSectionTypeName to reflect if a FS section holds a sparse layer or not.
* nca_storage: updated ncaStorageInitializeContext to avoid initializing a compressed storage if a sparse layer is also used (fixes issues with Them's Fightin' Herds), updated ncaStorageSetPatchOriginalSubStorage to enforce the presence of a compressed storage in a patch if the base FS holds a compressed storage.
* npdm: added reminder about updating NpdmSignatureKeyGeneration if necessary, updated NpdmFsAccessControlFlags enum, updated NpdmAccessibility enum, updated NpdmSystemCallId enum, fixed typos.
* title: updated all relevant functions that deal with NcmContentMetaType values to also handle DataPatch titles, added functions to handle DataPatchId values, removed titleConvertNcmContentSizeToU64 and titleConvertU64ToNcmContentSize functions in favor of ncmContentInfoSizeToU64 and ncmU64ToContentInfoSize from my unmerged libnx PR, updated internal arrays to match 15.x changes, renamed titleOrphanTitleInfoSortFunction to titleInfoEntrySortFunction and updated it to also sort entries by version and storage ID, updated titleGenerateTitleInfoEntriesForTitleStorage to sort TitleInfo entries, simplified titleDuplicateTitleInfo a bit by using macros.
2022-10-23 15:44:47 +01:00
}
NX_INLINE u64 titleGetAddOnContentIdByDataPatchId ( u64 data_patch_id )
{
2023-04-09 14:39:42 +01:00
return ( data_patch_id - TITLE_PATCH_ID_OFFSET ) ;
Preliminar 15.x support.
This commit uses my yet unmerged libnx PR to update ncm_types.h.
PoC code hasn't been updated yet, so proper support for DLC updates will arrive at a later time.
Note to self: implement a way to provide access to loaded DataPatch TitleInfo entries (linked list hell).
* bktr: renamed bktrBucketInitializeSubStorageReadParams to bktrInitializeSubStorageReadParams to avoid redundancy, added debug code to dump BucketInfo and BucketTree tables if BucketTree storage initialization fails.
* cnmt: updated ContentMetaAddOnContentMetaExtendedHeader struct to its 15.x equivalent, added ContentMetaLegacyAddOnContentMetaExtendedHeader struct, added ContentMetaDataPatchMetaExtendedHeader struct, updated the cnmtGetRequiredTitleId and cnmtGetRequiredTitleVersion functions to support DataPatch titles, updated cnmtInitializeContext to support both the new AddOnContent extended header and DataPatch titles, added debug code to dump the whole CNMT if context initialization fails, updated cnmtGenerateAuthoringToolXml to support DataPatch titles.
* keys: updated block hashes to match 15.x keyset, use case-insensitive comparison while looking for entry names in keysReadKeysFromFile, make sure the eticket_rsa_kek is non-zero before proceeding in keysGetDecryptedEticketRsaDeviceKey.
* nca: updated NcaKeyGeneration enum, added reminder about updating NcaSignatureKeyGeneration if necessary, replaced ncaFsSectionCheckHashRegionAccess with ncaFsSectionCheckPlaintextHashRegionAccess, removed all extents checks on Patch RomFS and sparse sections, updated ncaGetFsSectionTypeName to reflect if a FS section holds a sparse layer or not.
* nca_storage: updated ncaStorageInitializeContext to avoid initializing a compressed storage if a sparse layer is also used (fixes issues with Them's Fightin' Herds), updated ncaStorageSetPatchOriginalSubStorage to enforce the presence of a compressed storage in a patch if the base FS holds a compressed storage.
* npdm: added reminder about updating NpdmSignatureKeyGeneration if necessary, updated NpdmFsAccessControlFlags enum, updated NpdmAccessibility enum, updated NpdmSystemCallId enum, fixed typos.
* title: updated all relevant functions that deal with NcmContentMetaType values to also handle DataPatch titles, added functions to handle DataPatchId values, removed titleConvertNcmContentSizeToU64 and titleConvertU64ToNcmContentSize functions in favor of ncmContentInfoSizeToU64 and ncmU64ToContentInfoSize from my unmerged libnx PR, updated internal arrays to match 15.x changes, renamed titleOrphanTitleInfoSortFunction to titleInfoEntrySortFunction and updated it to also sort entries by version and storage ID, updated titleGenerateTitleInfoEntriesForTitleStorage to sort TitleInfo entries, simplified titleDuplicateTitleInfo a bit by using macros.
2022-10-23 15:44:47 +01:00
}
NX_INLINE bool titleCheckIfDataPatchIdBelongsToAddOnContentId ( u64 aoc_id , u64 data_patch_id )
{
return ( data_patch_id = = titleGetDataPatchIdByAddOnContentId ( aoc_id ) ) ;
}
NX_INLINE u64 titleGetApplicationIdByDataPatchId ( u64 data_patch_id )
{
return titleGetApplicationIdByAddOnContentId ( titleGetAddOnContentIdByDataPatchId ( data_patch_id ) ) ;
}
NX_INLINE bool titleCheckIfDataPatchIdBelongsToApplicationId ( u64 app_id , u64 data_patch_id )
{
return titleCheckIfAddOnContentIdBelongsToApplicationId ( app_id , titleGetAddOnContentIdByDataPatchId ( data_patch_id ) ) ;
}
2022-12-04 10:29:47 +00:00
NX_INLINE bool titleCheckIfDataPatchIdsAreSiblings ( u64 data_patch_id_1 , u64 data_patch_id_2 )
{
u64 app_id_1 = titleGetApplicationIdByDataPatchId ( data_patch_id_1 ) ;
u64 app_id_2 = titleGetApplicationIdByDataPatchId ( data_patch_id_2 ) ;
return ( app_id_1 = = app_id_2 & & titleCheckIfDataPatchIdBelongsToApplicationId ( app_id_1 , data_patch_id_1 ) & & titleCheckIfDataPatchIdBelongsToApplicationId ( app_id_2 , data_patch_id_2 ) ) ;
}
2020-09-19 07:59:31 +01:00
NX_INLINE u32 titleGetContentCountByType ( TitleInfo * info , u8 content_type )
{
if ( ! info | | ! info - > content_count | | ! info - > content_infos | | content_type > NcmContentType_DeltaFragment ) return 0 ;
2022-07-05 02:04:28 +01:00
2020-09-19 07:59:31 +01:00
u32 cnt = 0 ;
2022-07-05 02:04:28 +01:00
2020-09-19 07:59:31 +01:00
for ( u32 i = 0 ; i < info - > content_count ; i + + )
{
if ( info - > content_infos [ i ] . content_type = = content_type ) cnt + + ;
}
2022-07-05 02:04:28 +01:00
2020-09-19 07:59:31 +01:00
return cnt ;
}
2020-07-26 05:57:12 +01:00
NX_INLINE NcmContentInfo * titleGetContentInfoByTypeAndIdOffset ( TitleInfo * info , u8 content_type , u8 id_offset )
{
if ( ! info | | ! info - > content_count | | ! info - > content_infos | | content_type > NcmContentType_DeltaFragment ) return NULL ;
2022-07-05 02:04:28 +01:00
2020-07-26 05:57:12 +01:00
for ( u32 i = 0 ; i < info - > content_count ; i + + )
{
2020-10-14 19:58:33 +01:00
NcmContentInfo * cur_content_info = & ( info - > content_infos [ i ] ) ;
if ( cur_content_info - > content_type = = content_type & & cur_content_info - > id_offset = = id_offset ) return cur_content_info ;
2020-07-26 05:57:12 +01:00
}
2022-07-05 02:04:28 +01:00
2020-07-26 05:57:12 +01:00
return NULL ;
}
2020-10-21 05:27:48 +01:00
NX_INLINE u32 titleGetCountFromInfoBlock ( TitleInfo * title_info )
{
if ( ! title_info ) return 0 ;
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
u32 count = 1 ;
TitleInfo * cur_info = title_info - > previous ;
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
while ( cur_info )
{
count + + ;
cur_info = cur_info - > previous ;
}
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
cur_info = title_info - > next ;
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
while ( cur_info )
{
count + + ;
cur_info = cur_info - > next ;
}
2022-07-05 02:04:28 +01:00
2020-10-21 05:27:48 +01:00
return count ;
}
2021-03-23 14:06:52 +00:00
# ifdef __cplusplus
}
2021-03-24 17:25:19 +00:00
# endif
# endif /* __TITLE_H__ */