/*  RetroArch - A frontend for libretro.
 *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
 *  Copyright (C) 2011-2017 - Daniel De Matteis
 * 
 *  RetroArch 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 Found-
 *  ation, either version 3 of the License, or (at your option) any later version.
 *
 *  RetroArch 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 RetroArch.
 *  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdint.h>
#include <stddef.h>

#include <xtl.h>
#include <xbdm.h>
#include <xgraphics.h>

#include <file/file_path.h>
#include <compat/strl.h>

#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif

#ifndef IS_SALAMANDER
#include <lists/file_list.h>
#endif
#include <retro_miscellaneous.h>
#include <string/stdstring.h>

#include "../frontend_driver.h"
#include "../../defaults.h"
#include "../../file_path_special.h"
#include "../../paths.h"
#ifndef IS_SALAMANDER
#include "../../retroarch.h"
#ifdef HAVE_MENU
#include "../../menu/menu_driver.h"
#endif
#endif
#include "../../verbosity.h"

#ifdef _XBOX360

#define AURORA_LAUNCHDATA_APPID             'AUOA'
#define AURORA_LAUNCHDATA_EXECUTABLE_FUNCID        'ROMS'
#define AURORA_LAUNCHDATA_EXECUTABLE_VERSION       1

typedef struct _AURORA_LAUNCHDATA_EXECUTABLE
{
   DWORD ApplicationId;                                 //   AURORA_LAUNCHDATA_APPID
   DWORD FunctionId;                                    //   AURORA_LAUNCHDATA_EXECUTABLE_FUNCID
   DWORD FunctionVersion;                               //   AURORA_LAUNCHDATA_EXECUTABLE_VERSION
   CHAR SystemPath[0x40];                               //   /System/Harddisk0/Parition0
   CHAR RelativePath[0x104];                            //   /SomeCore/Content/
   CHAR Exectutable[0x28];                              //   SomeContent.zip
   CHAR Reserved[0x100];                                //   Reserved for future use
} AURORA_LAUNCHDATA_EXECUTABLE, *PAURORA_LAUNCH_DATA_EXECUTABLE;

#endif

#ifdef _XBOX1

#include <pshpack4.h>

#ifdef __cplusplus
extern "C" {
#endif

// Don't do __declspec(dllimport) for things like emulators
#if defined(NTSYSAPI) && defined(DONT_IMPORT_INTERNAL)
#undef NTSYSAPI
#endif
#ifdef DONT_IMPORT_INTERNAL
#define NTSYSAPI
#endif

// The normal headers don't have this...?
#define FASTCALL __fastcall

// The usual NTSTATUS
typedef LONG NTSTATUS;

// The usual NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

// Just for documentation
#define EXPORTNUM(x)


// Needed for object structures and related things
typedef CONST SHORT CSHORT;


// String types
typedef CHAR *PSZ;
typedef CONST CHAR *PCSZ;

// ANSI_STRING
// Differences from NT: None.
typedef struct _STRING {
    USHORT Length;
    USHORT MaximumLength;
    PCHAR Buffer;
} STRING;
typedef STRING *PSTRING;

typedef STRING ANSI_STRING;
typedef PSTRING PANSI_STRING;


// IO Status Block type (UNVERIFIED)
// Differences from NT: None.
typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };

    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

// APC routine
typedef
VOID
(NTAPI *PIO_APC_ROUTINE) (
    IN PVOID ApcContext,
    IN PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG Reserved
    );


// Header for dispatcher objects
// Differences from NT: None.
typedef struct _DISPATCHER_HEADER {
    UCHAR Type;
    UCHAR Absolute;
    UCHAR Size;
    UCHAR Inserted;
    LONG SignalState;
    LIST_ENTRY WaitListHead;
} DISPATCHER_HEADER;


// Object types
#define NotificationTimerObject         8
#define SynchronizationTimerObject      9
#define DpcObject                       19


// Object Attributes type
// Differences from NT: There are no Length, SecurityDescriptor, or
//     SecurityQualityOfService fields.  Also, ObjectName is ANSI, not
//     Unicode.
typedef struct _OBJECT_ATTRIBUTES {
    HANDLE RootDirectory;
    PANSI_STRING ObjectName;
    ULONG Attributes;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

// Flags for OBJECT_ATTRIBUTES::Attributes
#define OBJ_INHERIT                             0x00000002L
#define OBJ_PERMANENT                           0x00000010L
#define OBJ_EXCLUSIVE                           0x00000020L
#define OBJ_CASE_INSENSITIVE                    0x00000040L
#define OBJ_OPENIF                              0x00000080L
#define OBJ_OPENLINK                            0x00000100L
#define OBJ_KERNEL_HANDLE                       0x00000200L
#define OBJ_VALID_ATTRIBUTES                    0x000003F2L

// CreateDisposition values for NtCreateFile()
#define FILE_SUPERSEDE                          0x00000000
#define FILE_OPEN                               0x00000001
#define FILE_CREATE                             0x00000002
#define FILE_OPEN_IF                            0x00000003
#define FILE_OVERWRITE                          0x00000004
#define FILE_OVERWRITE_IF                       0x00000005
#define FILE_MAXIMUM_DISPOSITION                0x00000005

// CreateOption values for NtCreateFile()
// FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT is what CreateFile
// uses for most things when translating to NtCreateFile.
#define FILE_DIRECTORY_FILE                     0x00000001
#define FILE_WRITE_THROUGH                      0x00000002
#define FILE_SEQUENTIAL_ONLY                    0x00000004
#define FILE_NO_INTERMEDIATE_BUFFERING          0x00000008
#define FILE_SYNCHRONOUS_IO_ALERT               0x00000010
#define FILE_SYNCHRONOUS_IO_NONALERT            0x00000020
#define FILE_NON_DIRECTORY_FILE                 0x00000040
#define FILE_CREATE_TREE_CONNECTION             0x00000080
#define FILE_COMPLETE_IF_OPLOCKED               0x00000100
#define FILE_NO_EA_KNOWLEDGE                    0x00000200
#define FILE_OPEN_FOR_RECOVERY                  0x00000400
#define FILE_RANDOM_ACCESS                      0x00000800
#define FILE_DELETE_ON_CLOSE                    0x00001000
#define FILE_OPEN_BY_FILE_ID                    0x00002000
#define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
#define FILE_NO_COMPRESSION                     0x00008000
#define FILE_RESERVE_OPFILTER                   0x00100000
#define FILE_OPEN_REPARSE_POINT                 0x00200000
#define FILE_OPEN_NO_RECALL                     0x00400000
#define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
#define FILE_COPY_STRUCTURED_STORAGE            0x00000041
#define FILE_STRUCTURED_STORAGE                 0x00000441
#define FILE_VALID_OPTION_FLAGS                 0x00ffffff
#define FILE_VALID_PIPE_OPTION_FLAGS            0x00000032
#define FILE_VALID_MAILSLOT_OPTION_FLAGS        0x00000032
#define FILE_VALID_SET_FLAGS                    0x00000036


// NtQueryVolumeInformation / NtSetVolumeInformation stuff
// Type of information to retrieve; FileFsSizeInformation and
// FileFsDeviceInformation are the only ones confirmed to work.
typedef enum _FSINFOCLASS {
	FileFsVolumeInformation = 1,
	FileFsLabelInformation,
	FileFsSizeInformation,
	FileFsDeviceInformation,
	FileFsAttributeInformation,
	FileFsControlInformation,
	FileFsFullSizeInformation,
	FileFsObjectInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;

// Structure of FileFsSizeInformation
typedef struct _FILE_FS_SIZE_INFORMATION {
	LARGE_INTEGER TotalAllocationUnits;
	LARGE_INTEGER AvailableAllocationUnits;
	ULONG SectorsPerAllocationUnit;
	ULONG BytesPerSector;
} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;

#define DEVICE_TYPE ULONG

// Structure of FileFsDeviceInformation
typedef struct _FILE_FS_DEVICE_INFORMATION {                    
    DEVICE_TYPE DeviceType;                                     
    ULONG Characteristics;                                      
} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;     

// DEVICE_TYPEs (I took a guess as to which the XBOX might have.)
#define FILE_DEVICE_CD_ROM              0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
#define FILE_DEVICE_CONTROLLER          0x00000004
#define FILE_DEVICE_DISK                0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
#define FILE_DEVICE_FILE_SYSTEM         0x00000009
#define FILE_DEVICE_NULL                0x00000015
#define FILE_DEVICE_SCREEN              0x0000001c
#define FILE_DEVICE_SOUND               0x0000001d
#define FILE_DEVICE_UNKNOWN             0x00000022
#define FILE_DEVICE_VIDEO               0x00000023
#define FILE_DEVICE_VIRTUAL_DISK        0x00000024
#define FILE_DEVICE_FULLSCREEN_VIDEO    0x00000034

// Characteristics
#define FILE_REMOVABLE_MEDIA            0x00000001
#define FILE_READ_ONLY_DEVICE           0x00000002
#define FILE_FLOPPY_DISKETTE            0x00000004
#define FILE_WRITE_ONCE_MEDIA           0x00000008
#define FILE_REMOTE_DEVICE              0x00000010
#define FILE_DEVICE_IS_MOUNTED          0x00000020
#define FILE_VIRTUAL_VOLUME             0x00000040
#define FILE_AUTOGENERATED_DEVICE_NAME  0x00000080
#define FILE_DEVICE_SECURE_OPEN         0x00000100

/* Physical address
 * Differences from NT: 32 bit address instead of 64. */
typedef ULONG PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

/* NtCreateFile/NtOpenFile stuff */
#define FILE_SUPERSEDED                 0x00000000
#define FILE_OPENED                     0x00000001
#define FILE_CREATED                    0x00000002
#define FILE_OVERWRITTEN                0x00000003
#define FILE_EXISTS                     0x00000004
#define FILE_DOES_NOT_EXIST             0x00000005

// NtReadFile/NtWriteFile stuff
#define FILE_WRITE_TO_END_OF_FILE       0xffffffff
#define FILE_USE_FILE_POINTER_POSITION  0xfffffffe

// Device types
#define FILE_DEVICE_CD_ROM              0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
#define FILE_DEVICE_CONTROLLER          0x00000004
#define FILE_DEVICE_SCSI                FILE_DEVICE_CONTROLLER
#define IOCTL_SCSI_BASE                 FILE_DEVICE_CONTROLLER
#define FILE_DEVICE_DISK                0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
#define FILE_DEVICE_DVD                 0x00000033

// Access types
#define FILE_ANY_ACCESS                 0
#define FILE_READ_ACCESS                0x0001    /* file & pipe */
#define FILE_WRITE_ACCESS               0x0002    /* file & pipe */

// Method types
#define METHOD_BUFFERED                 0
#define METHOD_IN_DIRECT                1
#define METHOD_OUT_DIRECT               2
#define METHOD_NEITHER                  3

// The all-important CTL_CODE
#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

// IDE/SCSI codes
// IOCTL_SCSI_PASS_THROUGH_DIRECT is the only one known to be used.
// Differences from NT: None.
#define IOCTL_SCSI_PASS_THROUGH         CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_MINIPORT             CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_GET_INQUIRY_DATA     CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_CAPABILITIES     CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_RESCAN_BUS           CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_DUMP_POINTERS    CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_FREE_DUMP_POINTERS   CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IDE_PASS_THROUGH          CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

// Special XBOX code?
#define IOCTL_CDROM_AUTHENTICATE_DISK   CTL_CODE(FILE_DEVICE_CD_ROM, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)

/* Structure for IOCTL_SCSI_PASS_THROUGH_DIRECT
 * Differences from NT: None, believe it or not. */
typedef struct _SCSI_PASS_THROUGH_DIRECT {
    /*000*/ USHORT Length;
    /*002*/ UCHAR ScsiStatus;
    /*003*/ UCHAR PathId;
    /*004*/ UCHAR TargetId;
    /*005*/ UCHAR Lun;
    /*006*/ UCHAR CdbLength;
    /*007*/ UCHAR SenseInfoLength;
    /*008*/ UCHAR DataIn;
    /*00C*/ ULONG DataTransferLength;
    /*010*/ ULONG TimeOutValue;
    /*014*/ PVOID DataBuffer;
    /*018*/ ULONG SenseInfoOffset;
    /*01C*/ UCHAR Cdb[16];
}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;

/* DataIn fields for IOCTL_SCSI_PASS_THROUGH_DIRECT */
#define SCSI_IOCTL_DATA_OUT          0
#define SCSI_IOCTL_DATA_IN           1
#define SCSI_IOCTL_DATA_UNSPECIFIED  2

/* Kernel object type (unsure about the structure...) */
typedef struct _OBJECT_TYPE
{
	// Same prototype as ExAllocatePoolWithTag, because that's the usual one
	PVOID
	(NTAPI *AllocationFunction)(
		SIZE_T NumberOfBytes,
		ULONG Tag
		);

	// Same prototype as ExFreePool, because that's the usual one
	VOID
	(NTAPI *FreeFunction)(
		IN PVOID P
		);

	// The prototypes of these are unknown
	void *CloseFunction;
	void *DeleteFunction;
	void *ParseFunction;

	// Unknown DWORD...  Size of this object type maybe?
	void *DefaultObjectMaybe;

	// 4 letter tag for this object type
	CHAR Tag[4];
} OBJECT_TYPE;
typedef OBJECT_TYPE *POBJECT_TYPE;

// Object types
extern POBJECT_TYPE IoFileObjectType;
extern POBJECT_TYPE ExEventObjectType;
extern POBJECT_TYPE ExSemaphoreObjectType;
extern POBJECT_TYPE IoCompletionObjectType;
extern POBJECT_TYPE IoDeviceObjectType;


// *_OBJECT and related structures (mostly opaque since I'm lazy)
typedef struct _DRIVER_OBJECT {
    CSHORT Type;
    CSHORT Size;
    struct _DEVICE_OBJECT *DeviceObject;
	// ...
} DRIVER_OBJECT;
typedef DRIVER_OBJECT *PDRIVER_OBJECT;

typedef struct _DEVICE_OBJECT {
    CSHORT Type;
    USHORT Size;
    LONG ReferenceCount;
    PDRIVER_OBJECT DriverObject;
	// ...
} DEVICE_OBJECT;
typedef DEVICE_OBJECT *PDEVICE_OBJECT;

typedef struct _FILE_OBJECT {
    CSHORT Type;
    CSHORT Size;
    PDEVICE_OBJECT DeviceObject;
	// ...
} FILE_OBJECT;
typedef FILE_OBJECT *PFILE_OBJECT;


/* Thread information structures */

/* IRQL */
typedef UCHAR KIRQL, *PKIRQL;
#define PASSIVE_LEVEL 0             // Passive release level
#define LOW_LEVEL 0                 // Lowest interrupt level
#define APC_LEVEL 1                 // APC interrupt level
#define DISPATCH_LEVEL 2            // Dispatcher level

// Thread entry point
// NOTE: This is not a standard call!  You can't call this function from C code!
// You push registers like stdcall, but ebp + 4 must point to the first argument before the call!
//
// Differences from NT: 2 parameters instead of 1; strange calling convention
typedef
VOID
(NTAPI *PKSTART_ROUTINE) (
	IN PVOID StartContext1,
	IN PVOID StartContext2
	);

// Structure of a critical section
// Same as the XBOX's RTL_CRITICAL_SECTION, but with the more explicit header
typedef struct _KCRITICAL_SECTION
{
	// 000 Dispatcher header
	DISPATCHER_HEADER Header;
	// 010 Lock count of the critical section
	LONG LockCount;
	// 014 Recursion count of the critical section
	LONG RecursionCount;
	// 018 Thread ID of the thread that currently owns this critical section
	ULONG OwningThread;
} KCRITICAL_SECTION, *PKCRITICAL_SECTION;

// Structure of a thread object
typedef struct _KTHREAD
{
	// 000 Dispatcher header
	DISPATCHER_HEADER Header;
	// 010 Unknown
	BYTE unknown[0x18];
	// 028 Pointer to TLS data
	PVOID TlsData;
	// ??? just padding - real size is unknown
	BYTE unknown2[0x100];
} KTHREAD, *PKTHREAD;

// Structure of the data at FS
typedef struct _FS_STRUCTURE
{
	// 000 Current exception handler information
	PVOID *ExceptionFrame;
	// 004 Pointer to current TLS data top
	PVOID TlsDataTop;
	// 008
	BYTE unknown2[0x1C];
	// 024 Current IRQL of the OS
	KIRQL CurrentIrql;
	// 028 Thread structure of the current thread
	PKTHREAD ThreadObject;
	// ??? just padding - real size is unknown
	BYTE unknown3[0x100];
} FS_STRUCTURE, *PFS_STRUCTURE;

// DPC routine
typedef
VOID
(*PKDEFERRED_ROUTINE) (
	IN struct _KDPC *Dpc,
	IN PVOID DeferredContext,
	IN PVOID SystemArgument1,
	IN PVOID SystemArgument2
	);

// DPC information
// It's not known which of these fields are used on XBOX.
typedef struct _KDPC {
	CSHORT Type;
	UCHAR Number;
	UCHAR Importance;
	LIST_ENTRY DpcListEntry;
	PKDEFERRED_ROUTINE DeferredRoutine;
	PVOID DeferredContext;
	PVOID SystemArgument1;
	PVOID SystemArgument2;
	PULONG_PTR Lock;
} KDPC, *PKDPC;


// Timers
typedef enum _TIMER_TYPE {
    NotificationTimer,
    SynchronizationTimer
    } TIMER_TYPE;

typedef struct _KTIMER {
    DISPATCHER_HEADER Header;
    ULARGE_INTEGER DueTime;
    LIST_ENTRY TimerListEntry;
    struct _KDPC *Dpc;
    LONG Period;
} KTIMER, *PKTIMER;

/* XBE stuff
 * Not used in any exported kernel calls, but still useful.
 */

/* XBE header information */
typedef struct _XBE_HEADER
{
	// 000 "XBEH"
	CHAR Magic[4];
	// 004 RSA digital signature of the entire header area
	UCHAR HeaderSignature[256];
	// 104 Base address of XBE image (must be 0x00010000?)
	PVOID BaseAddress;
	// 108 Size of all headers combined - other headers must be within this
	ULONG HeaderSize;
	// 10C Size of entire image
	ULONG ImageSize;
	// 110 Size of this header (always 0x178?)
	ULONG XbeHeaderSize;
	// 114 Image timestamp - unknown format
	ULONG Timestamp;
	// 118 Pointer to certificate data (must be within HeaderSize)
	struct _XBE_CERTIFICATE *Certificate;
	// 11C Number of sections
	DWORD NumSections;
	// 120 Pointer to section headers (must be within HeaderSize)
	struct _XBE_SECTION *Sections;
	// 124 Initialization flags
	ULONG InitFlags;
	// 128 Entry point (XOR'd; see xboxhacker.net)
	PVOID EntryPoint;
	// 12C Pointer to TLS directory
	struct _XBE_TLS_DIRECTORY *TlsDirectory;
	// 130 Stack commit size
	ULONG StackCommit;
	// 134 Heap reserve size
	ULONG HeapReserve;
	// 138 Heap commit size
	ULONG HeapCommit;
	// 13C PE base address (?)
	PVOID PeBaseAddress;
	// 140 PE image size (?)
	ULONG PeImageSize;
	// 144 PE checksum (?)
	ULONG PeChecksum;
	// 148 PE timestamp (?)
	ULONG PeTimestamp;
	// 14C PC path and filename to EXE file from which XBE is derived
	PCSZ PcExePath;
	// 150 PC filename (last part of PcExePath) from which XBE is derived
	PCSZ PcExeFilename;
	// 154 PC filename (Unicode version of PcExeFilename)
	PWSTR PcExeFilenameUnicode;
	// 158 Pointer to kernel thunk table (XOR'd; EFB1F152 debug)
	ULONG_PTR *KernelThunkTable;
	// 15C Non-kernel import table (debug only)
	PVOID DebugImportTable;
	// 160 Number of library headers
	ULONG NumLibraries;
	// 164 Pointer to library headers
	struct _XBE_LIBRARY *Libraries;
	// 168 Pointer to kernel library header
	struct _XBE_LIBRARY *KernelLibrary;
	// 16C Pointer to XAPI library
	struct _XBE_LIBRARY *XapiLibrary;
	// 170 Pointer to logo bitmap (NULL = use default of Microsoft)
	PVOID LogoBitmap;
	// 174 Size of logo bitmap
	ULONG LogoBitmapSize;
	// 178
} XBE_HEADER, *PXBE_HEADER;

// Certificate structure
typedef struct _XBE_CERTIFICATE {
	// 000 Size of certificate
	ULONG Size;
	// 004 Certificate timestamp (unknown format)
	ULONG Timestamp;
	// 008 Title ID
	ULONG TitleId;
	// 00C Name of the game (Unicode)
	WCHAR TitleName[40];
	// 05C Alternate title ID's (0-terminated)
	ULONG AlternateTitleIds[16];
	// 09C Allowed media types - 1 bit match between XBE and media = boots
	ULONG MediaTypes;
	// 0A0 Allowed game regions - 1 bit match between this and XBOX = boots
	ULONG GameRegion;
	// 0A4 Allowed game ratings - 1 bit match between this and XBOX = boots
	ULONG GameRating;
	// 0A8 Disk number (?)
	ULONG DiskNumber;
	// 0AC Version (?)
	ULONG Version;
	// 0B0 LAN key for this game
	UCHAR LanKey[16];
	// 0C0 Signature key for this game
	UCHAR SignatureKey[16];
	// 0D0 Signature keys for the alternate title ID's
	UCHAR AlternateSignatureKeys[16][16];
	// 1D0
} XBE_CERTIFICATE, *PXBE_CERTIFICATE;

// Section headers
typedef struct _XBE_SECTION {
	// 000 Flags
	ULONG Flags;
	// 004 Virtual address (where this section loads in RAM)
	PVOID VirtualAddress;
	// 008 Virtual size (size of section in RAM; after FileSize it's 00'd)
	ULONG VirtualSize;
	// 00C File address (where in the file from which this section comes)
	ULONG FileAddress;
	// 010 File size (size of the section in the XBE file)
	ULONG FileSize;
	// 014 Pointer to section name
	PCSZ SectionName;
	// 018 Section reference count - when >= 1, section is loaded
	LONG SectionReferenceCount;
	// 01C Pointer to head shared page reference count
	WORD *HeadReferenceCount;
	// 020 Pointer to tail shared page reference count
	WORD *TailReferenceCount;
	// 024 SHA hash.  Hash DWORD containing FileSize, then hash section.
	DWORD ShaHash[5];
	// 038
} XBE_SECTION, *PXBE_SECTION;

/* TLS directory information needed later
 * Library version data needed later */

/* Initialization flags */
#define XBE_INIT_MOUNT_UTILITY          0x00000001
#define XBE_INIT_FORMAT_UTILITY         0x00000002
#define XBE_INIT_64M_RAM_ONLY           0x00000004
#define XBE_INIT_DONT_SETUP_HDD         0x00000008

/* Region codes */
#define XBE_REGION_US_CANADA            0x00000001
#define XBE_REGION_JAPAN                0x00000002
#define XBE_REGION_ELSEWHERE            0x00000004
#define XBE_REGION_DEBUG                0x80000000

/* Media types */
#define XBE_MEDIA_HDD                   0x00000001
#define XBE_MEDIA_XBOX_DVD              0x00000002
#define XBE_MEDIA_ANY_CD_OR_DVD         0x00000004
#define XBE_MEDIA_CD                    0x00000008
#define XBE_MEDIA_1LAYER_DVDROM         0x00000010
#define XBE_MEDIA_2LAYER_DVDROM         0x00000020
#define XBE_MEDIA_1LAYER_DVDR           0x00000040
#define XBE_MEDIA_2LAYER_DVDR           0x00000080
#define XBE_MEDIA_USB                   0x00000100
#define XBE_MEDIA_ALLOW_UNLOCKED_HDD    0x40000000

/* Section flags */
#define XBE_SEC_WRITABLE                0x00000001
#define XBE_SEC_PRELOAD                 0x00000002
#define XBE_SEC_EXECUTABLE              0x00000004
#define XBE_SEC_INSERTED_FILE           0x00000008
#define XBE_SEC_RO_HEAD_PAGE            0x00000010
#define XBE_SEC_RO_TAIL_PAGE            0x00000020

/* x86 page size */
#define PAGE_SIZE 0x1000

/* Native NT API calls on the XBOX */

/* PAGE_ALIGN:
 * Returns an address rounded down to the nearest page boundary.
 *
 * Differences from NT: None.
 */
#define PAGE_ALIGN(Va) ((PVOID)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)))

// NtReadFile:
// Reads a file.
//
// Differences from NT: There is no Key parameter.
NTSYSAPI
EXPORTNUM(219)
NTSTATUS
NTAPI
NtReadFile(
	IN HANDLE FileHandle,
	IN HANDLE Event OPTIONAL,
	IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
	IN PVOID ApcContext OPTIONAL,
	OUT PIO_STATUS_BLOCK IoStatusBlock,
	OUT PVOID Buffer,
	IN ULONG Length,
	IN PLARGE_INTEGER ByteOffset
	);

// NtWriteFile:
// Writes a file.
//
// Differences from NT: There is no Key parameter.
NTSYSAPI
EXPORTNUM(236)
NTSTATUS
NTAPI
NtWriteFile(
	IN HANDLE FileHandle,
	IN HANDLE Event OPTIONAL,
	IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
	IN PVOID ApcContext OPTIONAL,
	OUT PIO_STATUS_BLOCK IoStatusBlock,
	IN PVOID Buffer,
	IN ULONG Length,
	IN PLARGE_INTEGER ByteOffset
	);

// NtQueryVolumeInformation:
// Queries information about a file system.  This is not documented by
// Microsoft even under NT.
//
// Differences from NT: None known.
NTSYSAPI
EXPORTNUM(218)
NTSTATUS
NTAPI
NtQueryVolumeInformationFile(
	IN HANDLE FileHandle,
	OUT PIO_STATUS_BLOCK IoStatusBlock,
	OUT PVOID VolumeInformation,
	IN ULONG VolumeInformationLength,
	IN FS_INFORMATION_CLASS VolumeInformationClass
	);

// NtClose:
// Closes a file or other handle.
//
// Differences from NT: None.
NTSYSAPI
EXPORTNUM(187)
NTSTATUS
NTAPI
NtClose(
	IN HANDLE Handle
	);

// NtAllocateVirtualMemory:
// Allocates virtual memory.
//
// Differences from NT: There is no ProcessHandle parameter.
NTSYSAPI
EXPORTNUM(184)
NTSTATUS
NTAPI
NtAllocateVirtualMemory(
	IN OUT PVOID *BaseAddress,
	IN ULONG ZeroBits,
	IN OUT PULONG AllocationSize,
	IN ULONG AllocationType,
	IN ULONG Protect
	);

// NtFreeVirtualMemory:
// Frees virtual memory.
//
// Differences from NT: There is no ProcessHandle parameter.
NTSYSAPI
EXPORTNUM(199)
NTSTATUS
NTAPI
NtFreeVirtualMemory(
	IN OUT PVOID *BaseAddress,
	IN OUT PULONG FreeSize,
	IN ULONG FreeType
	);


// Kernel-level routines

// MmMapIoSpace:
// Maps a physical address area into the virtual address space.
// DO NOT USE MEMORY MAPPED WITH THIS AS A BUFFER TO OTHER CALLS.  For
// example, don't WriteFile or NtWriteFile these buffers.  Copy them first.
//
// Differences from NT: PhysicalAddress is 32 bit, not 64.  ProtectionType
//     specifies the page protections, but it's a Win32 PAGE_ macro instead
//     of the normal NT enumeration.  PAGE_READWRITE is probably what you
//     want...
NTSYSAPI
EXPORTNUM(177)
PVOID
NTAPI
MmMapIoSpace(
	IN PHYSICAL_ADDRESS PhysicalAddress,
	IN ULONG NumberOfBytes,
	IN ULONG ProtectionType
	);

// MmGetPhysicalAddress:
// Translates a virtual address into a physical address.
//
// Differences from NT: PhysicalAddress is 32 bit, not 64.
NTSYSAPI
EXPORTNUM(173)
PHYSICAL_ADDRESS
NTAPI
MmGetPhysicalAddress(
	IN PVOID BaseAddress
	);

// MmUnmapIoSpace:
// Unmaps a virtual address mapping made by MmMapIoSpace.
//
// Differences from NT: None.
NTSYSAPI
EXPORTNUM(183)
PVOID
NTAPI
MmUnmapIoSpace(
	IN PVOID BaseAddress,
	IN ULONG NumberOfBytes
	);

// MmAllocateContiguousMemory:
// Allocates a range of physically contiguous, cache-aligned memory from the
// non-paged pool (= main pool on XBOX).
//
// Differences from NT: HighestAcceptableAddress was deleted, opting instead
//     to not care about the highest address.
NTSYSAPI
EXPORTNUM(165)
PVOID
NTAPI
MmAllocateContiguousMemory(
	IN ULONG NumberOfBytes
	);

// MmFreeContiguousMemory:
// Frees memory allocated with MmAllocateContiguousMemory.
//
// Differences from NT: None.
NTSYSAPI
EXPORTNUM(171)
VOID
NTAPI
MmFreeContiguousMemory(
	IN PVOID BaseAddress
	);

// IoCreateSymbolicLink:
// Creates a symbolic link in the object namespace.
// NtCreateSymbolicLinkObject is much harder to use than this simple
// function, so just use this one.
//
// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING.
NTSYSAPI
EXPORTNUM(67)
NTSTATUS
NTAPI
IoCreateSymbolicLink(
	IN PANSI_STRING SymbolicLinkName,
	IN PANSI_STRING DeviceName
	);

// IoDeleteSymbolicLink:
// Creates a symbolic link in the object namespace.  Deleting symbolic links
// through the Nt* functions is a pain, so use this instead.
//
// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING.
NTSYSAPI
EXPORTNUM(69)
NTSTATUS
NTAPI
IoDeleteSymbolicLink(
	IN PANSI_STRING SymbolicLinkName
	);


// ObReferenceObjectByHandle:
// Turns a handle into a kernel object pointer.  The ObjectType parameter
// specifies what type of object it is.  This function also increments the
// object's reference count.
//
// Differences from NT: There are no DesiredAccess, AccessMode, or
//     HandleInformation parameters.
NTSYSAPI
EXPORTNUM(246)
NTSTATUS
NTAPI
ObReferenceObjectByHandle(
    IN HANDLE Handle,
    IN POBJECT_TYPE ObjectType OPTIONAL,
    OUT PVOID *Object
    );

// ObfReferenceObject/ObReferenceObject:
// Increments the object's reference count.
//
// Differences from NT: None.
#define ObReferenceObject(Object) ObfReferenceObject(Object)
NTSYSAPI
EXPORTNUM(251)
VOID
FASTCALL
ObfReferenceObject(
    IN PVOID Object
    );

// ObfDereferenceObject/ObDereferenceObject:
// Decrements the object's reference count, deleting it if it is now unused.
//
// Differences from NT: None.
#define ObDereferenceObject(a) ObfDereferenceObject(a)
NTSYSAPI
EXPORTNUM(250)
VOID
FASTCALL
ObfDereferenceObject(
    IN PVOID Object
    );

// Kernel routines only in the XBOX

// HalEnableSecureTrayEject:
// Notifies the SMBUS that ejecting the DVD-ROM should not reset the system.
// Note that this function can't really be called directly...
//
// New to the XBOX.
NTSYSAPI
EXPORTNUM(365)
VOID
NTAPI
HalEnableSecureTrayEject(
	VOID
	);

// XeLoadSection:
// Adds one to the reference count of the specified section and loads if the
// count is now above zero.
//
// New to the XBOX.
NTSYSAPI
EXPORTNUM(327)
NTSTATUS
NTAPI
XeLoadSection(
	IN OUT PXBE_SECTION section
	);

/* Error codes */
#define STATUS_SUCCESS					      0x00000000
#define STATUS_UNSUCCESSFUL				   0xC0000001
#define STATUS_UNRECOGNIZED_MEDIA		   0xC0000014

/* The SCSI input buffer was too large (not necessarily an error!) */
#define STATUS_DATA_OVERRUN				   0xC000003C
#define STATUS_INVALID_IMAGE_FORMAT       0xC000007B
#define STATUS_INSUFFICIENT_RESOURCES     0xC000009A
#define STATUS_TOO_MANY_SECRETS			   0xC0000156
#define STATUS_REGION_MISMATCH			   0xC0050001

#ifdef __cplusplus
};
#endif

#include <poppack.h>

extern "C"
{
	// Thanks and credit go to Woodoo
	extern VOID  WINAPI HalWriteSMBusValue(BYTE, BYTE, BOOL, BYTE);
	extern VOID  WINAPI HalReadSMCTrayState(DWORD* state, DWORD* count);

	// Thanks and credit go to Team Evox
	extern VOID	 WINAPI HalReturnToFirmware(DWORD);

	extern INT WINAPI XNetLoadConfigParams(LPBYTE);   
	extern INT WINAPI XNetSaveConfigParams(LPBYTE);     

	extern INT WINAPI XWriteTitleInfoNoReboot(LPVOID,LPVOID,DWORD,DWORD,LPVOID);

	extern DWORD* LaunchDataPage;  
}

#endif

static enum frontend_fork xdk_fork_mode = FRONTEND_FORK_NONE;

#ifdef _XBOX360
typedef struct _STRING 
{
    USHORT Length;
    USHORT MaximumLength;
    PCHAR Buffer;
} STRING, *PSTRING;

#ifdef __cplusplus
extern "C" {
#endif
VOID RtlInitAnsiString(PSTRING DestinationString, PCHAR SourceString);	
HRESULT ObDeleteSymbolicLink(PSTRING SymbolicLinkName);
HRESULT ObCreateSymbolicLink(PSTRING SymbolicLinkName, PSTRING DeviceName);
#ifdef __cplusplus
}
#endif

static HRESULT xbox_io_mount(const char* szDrive, char* szDevice)
{
	STRING DeviceName, LinkName;
	char szDestinationDrive[PATH_MAX_LENGTH];

	snprintf(szDestinationDrive, sizeof(szDestinationDrive),
         "\\??\\%s", szDrive);
	RtlInitAnsiString(&DeviceName, szDevice);
	RtlInitAnsiString(&LinkName, (PCHAR)szDestinationDrive);
	ObDeleteSymbolicLink(&LinkName);
	return (HRESULT)ObCreateSymbolicLink(&LinkName, &DeviceName);
}
#endif

#ifdef _XBOX1
static HRESULT xbox_io_mount(char *szDrive, char *szDevice)
{
#ifndef IS_SALAMANDER
   bool original_verbose       = verbosity_is_enabled();
#endif
   char szSourceDevice[48]     = {0};
   char szDestinationDrive[16] = {0};

   snprintf(szSourceDevice, sizeof(szSourceDevice),
         "\\Device\\%s", szDevice);
   snprintf(szDestinationDrive, sizeof(szDestinationDrive),
         "\\??\\%s", szDrive);

   STRING DeviceName =
   {
      strlen(szSourceDevice),
      strlen(szSourceDevice) + 1,
      szSourceDevice
   };

   STRING LinkName =
   {
      strlen(szDestinationDrive),
      strlen(szDestinationDrive) + 1,
      szDestinationDrive
   };

   IoCreateSymbolicLink(&LinkName, &DeviceName);

#ifndef IS_SALAMANDER
   if (original_verbose)
      verbosity_enable();
   else
      verbosity_disable();
#endif
   return S_OK;
}

static HRESULT xbox_io_unmount(char *szDrive)
{
   char szDestinationDrive[16] = {0};

   snprintf(szDestinationDrive, sizeof(szDestinationDrive),
         "\\??\\%s", szDrive);

   STRING LinkName =
   {
      strlen(szDestinationDrive),
      strlen(szDestinationDrive) + 1,
      szDestinationDrive
   };

   IoDeleteSymbolicLink(&LinkName);

   return S_OK;
}
#endif

static void frontend_xdk_get_environment_settings(int *argc, char *argv[],
      void *args, void *params_data)
{
   HRESULT ret;
   (void)ret;

#ifndef IS_SALAMANDER
   bool original_verbose       = verbosity_is_enabled();
#endif

#ifndef IS_SALAMANDER
#if defined(HAVE_LOGGER)
   logger_init();
#elif defined(HAVE_FILE_LOGGER)
   retro_main_log_file_init("/retroarch-log.txt");
#endif
#endif

#ifdef _XBOX360
   /* Detect install environment. */
   unsigned long license_mask;
   DWORD volume_device_type;

   if (XContentGetLicenseMask(&license_mask, NULL) == ERROR_SUCCESS)
   {
      XContentQueryVolumeDeviceType("GAME",&volume_device_type, NULL);

      switch(volume_device_type)
      {
         case XCONTENTDEVICETYPE_HDD: /* Launched from content package on HDD */
         case XCONTENTDEVICETYPE_MU:  /* Launched from content package on USB/Memory Unit. */
         case XCONTENTDEVICETYPE_ODD: /* Launched from content package on Optial Disc Drive. */
         default:                     /* Launched from content package on unknown device. */
            break;
      }
   }
#endif

#if defined(_XBOX1)
   strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE],
         "D:", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
   fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_CORE],
         file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config));
   fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
         g_defaults.dirs[DEFAULT_DIR_CORE],
         "savestates",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
   fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM],
         g_defaults.dirs[DEFAULT_DIR_CORE],
         "savefiles",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
   fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
         g_defaults.dirs[DEFAULT_DIR_CORE],
         "system",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
   fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
         g_defaults.dirs[DEFAULT_DIR_CORE],
         "screenshots",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
#elif defined(_XBOX360)
   strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE],
         "game:",
         sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
   strlcpy(g_defaults.path.config,
         "game:\\retroarch.cfg", sizeof(g_defaults.path.config));
   strlcpy(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
         "game:",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
   strlcpy(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
         "game:\\savestates",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
   strlcpy(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
         "game:\\playlists",
         sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
   strlcpy(g_defaults.dirs[DEFAULT_DIR_SRAM],
         "game:\\savefiles",
         sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
   strlcpy(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
         "game:\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
#endif
   fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO],
         g_defaults.dirs[DEFAULT_DIR_CORE],
         "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));

#ifndef IS_SALAMANDER
   static char path[PATH_MAX_LENGTH] = {0};
#if defined(_XBOX1)
   LAUNCH_DATA ptr;
   DWORD launch_type;

   if (XGetLaunchInfo(&launch_type, &ptr) == ERROR_SUCCESS)
   {
      char *extracted_path = NULL;
      if (launch_type == LDT_FROM_DEBUGGER_CMDLINE)
         goto exit;

      extracted_path = (char*)&ptr.Data;

      if (
            !string_is_empty(extracted_path)
            && (strstr(extracted_path, "Pool") == NULL)
            /* Hack. Unknown problem */)
      {
         /* Auto-start game */
         strlcpy(path, extracted_path, sizeof(path));
      }
   }
#elif defined(_XBOX360)
   DWORD dwLaunchDataSize;
   if (XGetLaunchDataSize(&dwLaunchDataSize) == ERROR_SUCCESS)
   {
      BYTE* pLaunchData = new BYTE[dwLaunchDataSize];
      XGetLaunchData(pLaunchData, dwLaunchDataSize);
      AURORA_LAUNCHDATA_EXECUTABLE* aurora = (AURORA_LAUNCHDATA_EXECUTABLE*)pLaunchData;
      char* extracted_path = new char[dwLaunchDataSize];
      memset(extracted_path, 0, dwLaunchDataSize);
      if (aurora->ApplicationId == AURORA_LAUNCHDATA_APPID && aurora->FunctionId == AURORA_LAUNCHDATA_EXECUTABLE_FUNCID)
      {
         if (xbox_io_mount("aurora:", aurora->SystemPath) >= 0)
            snprintf(extracted_path, dwLaunchDataSize,
                  "aurora:%s%s", aurora->RelativePath, aurora->Exectutable);
      }
      else
         snprintf(extracted_path,
               dwLaunchDataSize, "%s", pLaunchData);

      /* Auto-start game */
      if (!string_is_empty(extracted_path))
         strlcpy(path, extracted_path, sizeof(path));

      if (pLaunchData)
         delete []pLaunchData;
   }
#endif
   if (!string_is_empty(path))
   {
      struct rarch_main_wrap *args = (struct rarch_main_wrap*)params_data;

      if (args)
      {
         /* Auto-start game. */
         args->touched        = true;
         args->no_content     = false;
         args->verbose        = false;
         args->config_path    = NULL;
         args->sram_path      = NULL;
         args->state_path     = NULL;
         args->content_path   = path;
         args->libretro_path  = NULL;
      }
   }
#endif

#ifndef IS_SALAMANDER
exit:
   if (original_verbose)
      verbosity_enable();
   else
      verbosity_disable();
#endif
}

static void frontend_xdk_init(void *data)
{
   (void)data;
#if defined(_XBOX1) && !defined(IS_SALAMANDER)
   /* Mount drives */
   xbox_io_mount("A:", "cdrom0");
   xbox_io_mount("C:", "Harddisk0\\Partition0");
   xbox_io_mount("E:", "Harddisk0\\Partition1");
   xbox_io_mount("Z:", "Harddisk0\\Partition2");
   xbox_io_mount("F:", "Harddisk0\\Partition6");
   xbox_io_mount("G:", "Harddisk0\\Partition7");
#endif
}

static void frontend_xdk_exec(const char *path, bool should_load_game)
{
#ifndef IS_SALAMANDER
   bool original_verbose       = verbosity_is_enabled();
#endif
   (void)should_load_game;

#ifdef IS_SALAMANDER
   if (!string_is_empty(path))
      XLaunchNewImage(path, NULL);
#else
#ifdef _XBOX
#if defined(_XBOX1)
   LAUNCH_DATA ptr;
   memset(&ptr, 0, sizeof(ptr));

   if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
      snprintf((char*)ptr.Data, sizeof(ptr.Data), "%s", path_get(RARCH_PATH_CONTENT));

   if (!string_is_empty(path))
      XLaunchNewImage(path, !string_is_empty((const char*)ptr.Data) ? &ptr : NULL);
#elif defined(_XBOX360)
   char game_path[1024] = {0};

   if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
   {
      strlcpy(game_path, path_get(RARCH_PATH_CONTENT), sizeof(game_path));
      XSetLaunchData(game_path, MAX_LAUNCH_DATA_SIZE);
   }

   if (!string_is_empty(path))
      XLaunchNewImage(path, NULL);
#endif
#endif
#endif
#ifndef IS_SALAMANDER
   if (original_verbose)
      verbosity_enable();
   else
      verbosity_disable();
#endif
}

#ifndef IS_SALAMANDER
static bool frontend_xdk_set_fork(enum frontend_fork fork_mode)
{
   switch (fork_mode)
   {
      case FRONTEND_FORK_CORE:
         RARCH_LOG("FRONTEND_FORK_CORE\n");
         xdk_fork_mode  = fork_mode;
         break;
      case FRONTEND_FORK_CORE_WITH_ARGS:
         RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
         xdk_fork_mode  = fork_mode;
         break;
      case FRONTEND_FORK_RESTART:
         RARCH_LOG("FRONTEND_FORK_SALAMANDER_RESTART\n");
         /* NOTE: We don't implement Salamander, so just turn
          * this into FRONTEND_FORK_CORE. */
         xdk_fork_mode  = FRONTEND_FORK_CORE;
         break;
      case FRONTEND_FORK_NONE:
      default:
         return false;
   }

   return true;
}
#endif

static void frontend_xdk_exitspawn(char *s, size_t len)
{
   bool should_load_game = false;
#ifndef IS_SALAMANDER
   if (xdk_fork_mode == FRONTEND_FORK_NONE)
      return;

   switch (xdk_fork_mode)
   {
      case FRONTEND_FORK_CORE_WITH_ARGS:
         should_load_game = true;
         break;
      case FRONTEND_FORK_NONE:
      default:
         break;
   }
#endif
   frontend_xdk_exec(s, should_load_game);
}

static int frontend_xdk_get_rating(void)
{
#if defined(_XBOX360)
   return 11;
#elif defined(_XBOX1)
   return 7;
#endif
}

enum frontend_architecture frontend_xdk_get_architecture(void)
{
#if defined(_XBOX360)
   return FRONTEND_ARCH_PPC;
#elif defined(_XBOX1)
   return FRONTEND_ARCH_X86;
#else
   return FRONTEND_ARCH_NONE;
#endif
}

static int frontend_xdk_parse_drive_list(void *data, bool load_content)
{
#ifndef IS_SALAMANDER
   file_list_t *list = (file_list_t*)data;
   enum msg_hash_enums enum_idx = load_content ?
      MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
      MSG_UNKNOWN;

#if defined(_XBOX1)
   menu_entries_append_enum(list,
         "C:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
   menu_entries_append_enum(list,
         "D:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
   menu_entries_append_enum(list,
         "E:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
   menu_entries_append_enum(list,
         "F:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
   menu_entries_append_enum(list,
         "G:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
#elif defined(_XBOX360)
   menu_entries_append_enum(list,
         "game:",
         msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
         enum_idx,
         FILE_TYPE_DIRECTORY, 0, 0);
#endif
#endif

   return 0;
}

frontend_ctx_driver_t frontend_ctx_xdk = {
   frontend_xdk_get_environment_settings,
   frontend_xdk_init,
   NULL,                         /* deinit */
   frontend_xdk_exitspawn,
   NULL,                         /* process_args */
   frontend_xdk_exec,
#ifdef IS_SALAMANDER
   NULL,
#else
   frontend_xdk_set_fork,
#endif
   NULL,                         /* shutdown */
   NULL,                         /* get_name */
   NULL,                         /* get_os */
   frontend_xdk_get_rating,
   NULL,                         /* load_content */
   frontend_xdk_get_architecture,
   NULL,                         /* get_powerstate */
   frontend_xdk_parse_drive_list,
   NULL,                         /* get_mem_total */
   NULL,                         /* get_mem_free */
   NULL,                         /* install_signal_handler */
   NULL,                         /* get_sighandler_state */
   NULL,                         /* set_sighandler_state */
   NULL,                         /* destroy_sighandler_state */
   NULL,                         /* attach_console */
   NULL,                         /* detach_console */
   "xdk",
};
