*Fixed crash when changing NAND emu path to USB

*Creating the missing NAND folders when needed (Allows the "Partial" Nand Emulation to work with no NAND at all on the drive)
This commit is contained in:
dimok321 2011-07-26 08:57:12 +00:00
parent 973d8b2005
commit 372717aaa0
12 changed files with 147 additions and 159 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>2.2 r1105</version> <version>2.2 r1106</version>
<release_date>201107252212</release_date> <release_date>201107260730</release_date>
<!-- // remove this line to enable arguments <!-- // remove this line to enable arguments
<arguments> <arguments>
<arg>--ios=250</arg> <arg>--ios=250</arg>

View File

@ -287,7 +287,7 @@ int DeviceHandler::PathToDriveType(const char * path)
for(int i = SD; i < MAXDEVICES; i++) for(int i = SD; i < MAXDEVICES; i++)
{ {
if(strncmp(path, DeviceName[i], strlen(DeviceName[i])) == 0) if(strncasecmp(path, DeviceName[i], strlen(DeviceName[i])) == 0)
return i; return i;
} }
@ -309,21 +309,21 @@ const char * DeviceHandler::GetFSName(int dev)
if(DeviceHandler::instance->usb1) if(DeviceHandler::instance->usb1)
partCount1 += DeviceHandler::instance->usb1->GetPartitionCount(); partCount1 += DeviceHandler::instance->usb1->GetPartitionCount();
if(dev-USB1 > partCount0 && DeviceHandler::instance->usb0) if(dev-USB1 < partCount0 && DeviceHandler::instance->usb0)
return DeviceHandler::instance->usb0->GetFSName(dev-USB1); return DeviceHandler::instance->usb0->GetFSName(dev-USB1);
else if(DeviceHandler::instance->usb1) else if(DeviceHandler::instance->usb1)
return DeviceHandler::instance->usb1->GetFSName(dev-USB1-partCount0); return DeviceHandler::instance->usb1->GetFSName(dev-USB1-partCount0);
} }
return NULL; return "";
} }
int DeviceHandler::GetUSBFilesystemType(int partition) int DeviceHandler::GetFilesystemType(int dev)
{ {
if(!instance) if(!instance)
return -1; return -1;
const char *FSName = GetUSBFSName(partition); const char *FSName = GetFSName(dev);
if(!FSName) return -1; if(!FSName) return -1;
if(strncmp(FSName, "WBFS", 4) == 0) if(strncmp(FSName, "WBFS", 4) == 0)
@ -384,20 +384,6 @@ int DeviceHandler::PartitionToPortPartition(int part)
return part; return part;
} }
const char *DeviceHandler::GetUSBFSName(int partition)
{
if(!instance)
return NULL;
const char * FSName = NULL;
PartitionHandle *handle = instance->GetUSBHandleFromPartition(partition);
if(handle)
FSName = handle->GetFSName(PartitionToPortPartition(partition));
return FSName;
}
PartitionHandle *DeviceHandler::GetUSBHandleFromPartition(int part) const PartitionHandle *DeviceHandler::GetUSBHandleFromPartition(int part) const
{ {
if(PartitionToUSBPort(part) == 0) if(PartitionToUSBPort(part) == 0)

View File

@ -84,14 +84,13 @@ class DeviceHandler
PartitionHandle * GetUSBHandleFromPartition(int part) const; PartitionHandle * GetUSBHandleFromPartition(int part) const;
static const DISC_INTERFACE *GetUSB0Interface() { return &__io_usbstorage2_port0; } static const DISC_INTERFACE *GetUSB0Interface() { return &__io_usbstorage2_port0; }
static const DISC_INTERFACE *GetUSB1Interface() { return &__io_usbstorage2_port1; } static const DISC_INTERFACE *GetUSB1Interface() { return &__io_usbstorage2_port1; }
static int GetUSBFilesystemType(int part); static int GetFilesystemType(int dev);
static int PathToDriveType(const char * path);
static const char * GetFSName(int dev); static const char * GetFSName(int dev);
static int PathToDriveType(const char * path);
static const char * PathToFSName(const char * path) { return GetFSName(PathToDriveType(path)); }; static const char * PathToFSName(const char * path) { return GetFSName(PathToDriveType(path)); };
static int PartitionToUSBPort(int part); static int PartitionToUSBPort(int part);
static u16 GetUSBPartitionCount(); static u16 GetUSBPartitionCount();
static int PartitionToPortPartition(int part); static int PartitionToPortPartition(int part);
static const char *GetUSBFSName(int partition);
private: private:
DeviceHandler() : sd(0), gca(0), gcb(0), usb0(0), usb1(0) { }; DeviceHandler() : sd(0), gca(0), gcb(0), usb0(0), usb1(0) { };
~DeviceHandler(); ~DeviceHandler();

View File

@ -30,6 +30,7 @@
#include "language/gettext.h" #include "language/gettext.h"
#include "prompts/filebrowser.h" #include "prompts/filebrowser.h"
#include "themes/CTheme.h" #include "themes/CTheme.h"
#include "gecko.h"
CustomPathsSM::CustomPathsSM() CustomPathsSM::CustomPathsSM()
: SettingsMenu(tr("Custom Paths"), &GuiOptions, MENU_NONE) : SettingsMenu(tr("Custom Paths"), &GuiOptions, MENU_NONE)
@ -236,10 +237,16 @@ int CustomPathsSM::GetMenuInternal()
//! Settings: Nand Emu Path //! Settings: Nand Emu Path
else if (ret == ++Idx) else if (ret == ++Idx)
{ {
char oldPath[sizeof(Settings.NandEmuPath)];
snprintf(oldPath, sizeof(oldPath), Settings.NandEmuPath);
titleTxt->SetText(tr( "Nand Emu Path" )); titleTxt->SetText(tr( "Nand Emu Path" ));
ChangePath(Settings.NandEmuPath, sizeof(Settings.NandEmuPath)); ChangePath(Settings.NandEmuPath, sizeof(Settings.NandEmuPath));
if(strncasecmp(DeviceHandler::PathToFSName(Settings.NandEmuPath), "FAT", 3) != 0) if(strncasecmp(DeviceHandler::PathToFSName(Settings.NandEmuPath), "FAT", 3) != 0)
WindowPrompt(tr("Warning:"), tr("Nand Emulation only works on FAT/FAT32 partitions!"), tr("OK")); {
snprintf(Settings.NandEmuPath, sizeof(Settings.NandEmuPath), oldPath);
WindowPrompt(tr("Error:"), tr("Nand Emulation only works on FAT/FAT32 partitions!"), tr("OK"));
}
} }
//! Global set back of the titleTxt after a change //! Global set back of the titleTxt after a change

View File

@ -174,7 +174,7 @@ int HardDriveSM::GetMenuInternal()
do do
{ {
Settings.partition = (Settings.partition + 1) % DeviceHandler::GetUSBPartitionCount(); Settings.partition = (Settings.partition + 1) % DeviceHandler::GetUSBPartitionCount();
fs_type = DeviceHandler::GetUSBFilesystemType(Settings.partition); fs_type = DeviceHandler::GetFilesystemType(USB1+Settings.partition);
} }
while (!IsValidPartition(fs_type, ios) && --retries > 0); while (!IsValidPartition(fs_type, ios) && --retries > 0);
@ -213,7 +213,7 @@ int HardDriveSM::GetMenuInternal()
{ {
if (++Settings.GameSplit >= GAMESPLIT_MAX) if (++Settings.GameSplit >= GAMESPLIT_MAX)
{ {
if(DeviceHandler::GetUSBFilesystemType(Settings.partition) == PART_FS_FAT) if(DeviceHandler::GetFilesystemType(USB1+Settings.partition) == PART_FS_FAT)
Settings.GameSplit = GAMESPLIT_2GB; Settings.GameSplit = GAMESPLIT_2GB;
else else
Settings.GameSplit = GAMESPLIT_NONE; Settings.GameSplit = GAMESPLIT_NONE;
@ -249,7 +249,7 @@ int HardDriveSM::GetMenuInternal()
for(int i = 0; i < partCount; ++i) for(int i = 0; i < partCount; ++i)
{ {
ShowProgress(i, partCount); ShowProgress(i, partCount);
if(DeviceHandler::GetUSBFilesystemType(i) == PART_FS_FAT) if(DeviceHandler::GetFilesystemType(USB1+i) == PART_FS_FAT)
{ {
PartitionHandle *usb = DeviceHandler::Instance()->GetUSBHandleFromPartition(i); PartitionHandle *usb = DeviceHandler::Instance()->GetUSBHandleFromPartition(i);
if(!usb) continue; if(!usb) continue;

View File

@ -26,7 +26,7 @@
#include "menu/menus.h" #include "menu/menus.h"
#include "memory/memory.h" #include "memory/memory.h"
#include "GameBooter.hpp" #include "GameBooter.hpp"
#include "nand.h" #include "NandEmu.h"
#include "SavePath.h" #include "SavePath.h"
#include "sys.h" #include "sys.h"

View File

@ -32,7 +32,7 @@ class GameList
int operator--(int i) { return operator--(); } int operator--(int i) { return operator--(); }
struct discHdr * GetCurrentSelected() const { return operator[](selectedGame); } struct discHdr * GetCurrentSelected() const { return operator[](selectedGame); }
int GetPartitionNumber(const u8 *gameid) const; int GetPartitionNumber(const u8 *gameid) const;
int GetGameFS(const u8 *gameID) const { return DeviceHandler::Instance()->GetUSBFilesystemType(GetPartitionNumber(gameID)); } int GetGameFS(const u8 *gameID) const { return DeviceHandler::Instance()->GetFilesystemType(USB1+GetPartitionNumber(gameID)); }
void RemovePartition(int part_num); void RemovePartition(int part_num);
protected: protected:
int InternalReadList(int part); int InternalReadList(int part);

View File

@ -19,7 +19,7 @@ static int FindGamePartition()
// Loop through all WBFS partitions first to check them in case IOS249 Rev < 18 // Loop through all WBFS partitions first to check them in case IOS249 Rev < 18
for(int i = 0; i < partCount; ++i) for(int i = 0; i < partCount; ++i)
{ {
if(DeviceHandler::GetUSBFilesystemType(i) != PART_FS_WBFS) if(DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_WBFS)
continue; continue;
if (WBFS_OpenPart(i) == 0) if (WBFS_OpenPart(i) == 0)
@ -36,9 +36,9 @@ static int FindGamePartition()
// Loop through FAT/NTFS/EXT partitions, and find the first partition with games on it (if there is one) // Loop through FAT/NTFS/EXT partitions, and find the first partition with games on it (if there is one)
for(int i = 0; i < partCount; ++i) for(int i = 0; i < partCount; ++i)
{ {
if(DeviceHandler::GetUSBFilesystemType(i) != PART_FS_NTFS && if(DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_NTFS &&
DeviceHandler::GetUSBFilesystemType(i) != PART_FS_FAT && DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_FAT &&
DeviceHandler::GetUSBFilesystemType(i) != PART_FS_EXT) DeviceHandler::GetFilesystemType(USB1+i) != PART_FS_EXT)
{ {
continue; continue;
} }
@ -79,9 +79,9 @@ static int PartitionChoice()
if(part_num >= 0) if(part_num >= 0)
{ {
if(IosLoader::IsWaninkokoIOS() && NandTitles.VersionOf(TITLE_ID(1, IOS_GetVersion())) < 18 && if(IosLoader::IsWaninkokoIOS() && NandTitles.VersionOf(TITLE_ID(1, IOS_GetVersion())) < 18 &&
(DeviceHandler::GetUSBFilesystemType(part_num) == PART_FS_NTFS || (DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_NTFS ||
DeviceHandler::GetUSBFilesystemType(part_num) == PART_FS_FAT || DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_FAT ||
DeviceHandler::GetUSBFilesystemType(part_num) == PART_FS_EXT)) DeviceHandler::GetFilesystemType(USB1+part_num) == PART_FS_EXT))
{ {
WindowPrompt(tr("Warning:"), tr("You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk."), tr("OK")); WindowPrompt(tr("Warning:"), tr("You are trying to select a FAT32/NTFS/EXT partition with cIOS 249 Rev < 18. This is not supported. Continue on your own risk."), tr("OK"));
} }

View File

@ -1,19 +1,29 @@
/***************************************** /*****************************************
* This code is from Mighty Channel 11 * This code is from Mighty Channel 11
* which is based on the TriiForce source. * which is based on the TriiForce source.
* Modifications by Dimok.
*****************************************/ *****************************************/
#include <stdio.h> #include <stdio.h>
#include <ogcsys.h> #include <ogcsys.h>
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>
#include "system/IosLoader.h"
#include "gecko.h" #include "gecko.h"
#include "nand.h" #include "NandEmu.h"
/* Buffer */ /* 'NAND Device' structure */
static const char fs[] ATTRIBUTE_ALIGN(32) = "/dev/fs"; typedef struct {
static const char fat[] ATTRIBUTE_ALIGN(32) = "fat"; /* Device name */
static u32 inbuf[8] ATTRIBUTE_ALIGN(32); const char *name;
/* Mode value */
u32 mode;
/* Un/mount command */
u32 mountCmd;
u32 umountCmd;
} nandDevice;
static nandDevice ndevList[] = static nandDevice ndevList[] =
{ {
@ -22,44 +32,43 @@ static nandDevice ndevList[] =
{ "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 }, { "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 },
}; };
/* Buffer */
static u32 inbuf[8] ATTRIBUTE_ALIGN(32);
static const char fs[] ATTRIBUTE_ALIGN(32) = "/dev/fs";
static const char fat[] ATTRIBUTE_ALIGN(32) = "fat";
static int mounted = 0; static int mounted = 0;
static int partition = 0; static int partition = 0;
static int fullmode = 0; static int fullmode = 0;
static char path[32] = "\0"; static char path[32] = "\0";
s32 Nand_Mount(nandDevice *dev) static s32 Nand_Mount(nandDevice *dev)
{ {
s32 fd, ret; s32 fd, ret;
u32 inlen = 0; u32 inlen = 0;
ioctlv *vector = NULL; ioctlv *vector = NULL;
u32 *buffer = NULL; u32 *buffer = NULL;
int rev = IOS_GetRevision();
/* Open FAT module */ /* Open FAT module */
fd = IOS_Open(fat, 0); fd = IOS_Open(fat, 0);
if (fd < 0) if (fd < 0)
return fd; return fd;
/* Prepare vector */ // NOTE:
if(rev >= 21 && rev < 30000) // The official cIOSX rev21 by Waninkoko ignores the partition argument
{ // and the nand is always expected to be on the 1st partition.
// NOTE: // However this way earlier d2x betas having revision 21 take in
// The official cIOSX rev21 by Waninkoko ignores the partition argument // consideration the partition argument.
// and the nand is always expected to be on the 1st partition. inlen = 1;
// However this way earlier d2x betas having revision 21 take in
// consideration the partition argument.
inlen = 1;
/* Allocate memory */ /* Allocate memory */
buffer = (u32 *)memalign(32, sizeof(u32)*3); buffer = (u32 *)memalign(32, sizeof(u32)*3);
/* Set vector pointer */ /* Set vector pointer */
vector = (ioctlv *)buffer; vector = (ioctlv *)buffer;
buffer[0] = (u32)(buffer + 2); buffer[0] = (u32)(buffer + 2);
buffer[1] = sizeof(u32); buffer[1] = sizeof(u32);
buffer[2] = (u32)partition; buffer[2] = (u32)partition;
}
/* Mount device */ /* Mount device */
ret = IOS_Ioctlv(fd, dev->mountCmd, inlen, 0, vector); ret = IOS_Ioctlv(fd, dev->mountCmd, inlen, 0, vector);
@ -75,8 +84,11 @@ s32 Nand_Mount(nandDevice *dev)
return ret; return ret;
} }
s32 Nand_Unmount(nandDevice *dev) static s32 Nand_Unmount(nandDevice *dev)
{ {
if(!IosLoader::IsD2X())
return -1;
s32 fd, ret; s32 fd, ret;
// Open FAT module // Open FAT module
@ -93,55 +105,37 @@ s32 Nand_Unmount(nandDevice *dev)
return ret; return ret;
} }
s32 Nand_Enable(nandDevice *dev) static s32 Nand_Enable(nandDevice *dev)
{ {
s32 fd, ret; s32 fd, ret;
u32 *buffer = NULL; u32 *buffer = NULL;
int rev;
// Open /dev/fs // Open /dev/fs
fd = IOS_Open(fs, 0); fd = IOS_Open(fs, 0);
if (fd < 0) if (fd < 0)
return fd; return fd;
rev = IOS_GetRevision(); //FULL NAND emulation since rev18
// Set input buffer //needed for reading images on triiforce mrc folder using ISFS commands
if(rev >= 21 && rev < 30000 && dev->mode != 0) inbuf[0] = dev->mode | fullmode;
{
//FULL NAND emulation since rev18
//needed for reading images on triiforce mrc folder using ISFS commands
inbuf[0] = dev->mode | fullmode;
}
else
{
inbuf[0] = dev->mode; //old method
}
// Enable NAND emulator // NOTE:
if(rev >= 21 && rev < 30000) // The official cIOSX rev21 by Waninkoko provides an undocumented feature
{ // to set nand path when mounting the device.
// NOTE: // This feature has been discovered during d2x development.
// The official cIOSX rev21 by Waninkoko provides an undocumented feature int pathlen = strlen(path)+1;
// to set nand path when mounting the device.
// This feature has been discovered during d2x development.
int pathlen = strlen(path)+1;
/* Allocate memory */ /* Allocate memory */
buffer = (u32 *)memalign(32, (sizeof(u32)*5)+pathlen); buffer = (u32 *)memalign(32, (sizeof(u32)*5)+pathlen);
buffer[0] = (u32)(buffer + 4); buffer[0] = (u32)(buffer + 4);
buffer[1] = sizeof(u32); // actually not used by cios buffer[1] = sizeof(u32); // actually not used by cios
buffer[2] = (u32)(buffer + 5); buffer[2] = (u32)(buffer + 5);
buffer[3] = pathlen; // actually not used by cios buffer[3] = pathlen; // actually not used by cios
buffer[4] = inbuf[0]; buffer[4] = inbuf[0];
strcpy((char*)(buffer+5), path); strcpy((char*)(buffer+5), path);
ret = IOS_Ioctlv(fd, 100, 2, 0, (ioctlv *)buffer); ret = IOS_Ioctlv(fd, 100, 2, 0, (ioctlv *)buffer);
}
else
{
ret = IOS_Ioctl(fd, 100, inbuf, sizeof(inbuf), NULL, 0);
}
/* Free memory */ /* Free memory */
if(buffer != NULL) if(buffer != NULL)
@ -153,7 +147,7 @@ s32 Nand_Enable(nandDevice *dev)
return ret; return ret;
} }
s32 Nand_Disable(void) static s32 Nand_Disable(void)
{ {
s32 fd, ret; s32 fd, ret;
@ -174,9 +168,11 @@ s32 Nand_Disable(void)
return ret; return ret;
} }
s32 Enable_Emu(int selection) s32 Enable_Emu(int selection)
{ {
if(!IosLoader::IsD2X())
return -1;
if(mounted != 0) if(mounted != 0)
return -1; return -1;
@ -204,6 +200,9 @@ s32 Enable_Emu(int selection)
s32 Disable_Emu() s32 Disable_Emu()
{ {
if(!IosLoader::IsD2X())
return -1;
if(mounted==0) if(mounted==0)
return 0; return 0;

View File

@ -0,0 +1,16 @@
#ifndef _NAND_EMU_H_
#define _NAND_EMU_H_
#define REAL_NAND 0
#define EMU_SD 1
#define EMU_USB 2
/* Prototypes */
s32 Enable_Emu(int selection);
s32 Disable_Emu();
void Set_Partition(int);
void Set_Path(const char*);
void Set_FullMode(int);
const char* Get_Path(void);
#endif

View File

@ -30,7 +30,6 @@
#include "FileOperations/fileops.h" #include "FileOperations/fileops.h"
#include "gecko.h" #include "gecko.h"
void CreateTitleTMD(const char *path, const struct discHdr *hdr) void CreateTitleTMD(const char *path, const struct discHdr *hdr)
{ {
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) hdr->id); wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) hdr->id);
@ -64,22 +63,47 @@ void CreateTitleTMD(const char *path, const struct discHdr *hdr)
free(titleTMD); free(titleTMD);
} }
void CreateSavePath(const struct discHdr *hdr) static void CreateNandPath(const char *path)
{ {
char contentPath[512]; if(CheckFile(path))
char dataPath[512];
snprintf(contentPath, sizeof(contentPath), "%s/title/00010000/%02x%02x%02x%02x/content", Settings.NandEmuPath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]);
snprintf(dataPath, sizeof(dataPath), "%s/title/00010000/%02x%02x%02x%02x/data", Settings.NandEmuPath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]);
if(CheckFile(contentPath) && CheckFile(dataPath))
return; return;
gprintf("Creating Save Path: %s\n", contentPath); gprintf("Creating Nand Path: %s\n", path);
gprintf("Creating Save Path: %s\n", dataPath); CreateSubfolder(path);
}
CreateSubfolder(contentPath);
CreateSubfolder(dataPath); void CreateSavePath(const struct discHdr *hdr)
{
strcat(contentPath, "/title.tmd"); char nandPath[512];
CreateTitleTMD(contentPath, hdr);
snprintf(nandPath, sizeof(nandPath), "%s/import", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/meta", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/shared1", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/shared2", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/sys", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/ticket", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/tmp", Settings.NandEmuPath);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/title/00010000/%02x%02x%02x%02x/data", Settings.NandEmuPath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]);
CreateNandPath(nandPath);
snprintf(nandPath, sizeof(nandPath), "%s/title/00010000/%02x%02x%02x%02x/content", Settings.NandEmuPath, hdr->id[0], hdr->id[1], hdr->id[2], hdr->id[3]);
CreateNandPath(nandPath);
strcat(nandPath, "/title.tmd");
if(!CheckFile(nandPath))
CreateTitleTMD(nandPath, hdr);
} }

View File

@ -1,43 +0,0 @@
#ifndef _NAND_H_
#define _NAND_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* 'NAND Device' structure */
typedef struct {
/* Device name */
char *name;
/* Mode value */
u32 mode;
/* Un/mount command */
u32 mountCmd;
u32 umountCmd;
} nandDevice;
#define REAL_NAND 0
#define EMU_SD 1
#define EMU_USB 2
/* Prototypes */
s32 Nand_Mount(nandDevice *);
s32 Nand_Unmount(nandDevice *);
s32 Nand_Enable(nandDevice *);
s32 Nand_Disable(void);
s32 Enable_Emu(int selection);
s32 Disable_Emu();
void Set_Partition(int);
void Set_Path(const char*);
void Set_FullMode(int);
const char* Get_Path(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif