diff --git a/gui/cfg_edit.pas b/gui/cfg_edit.pas index 877972a3..95feaebb 100644 --- a/gui/cfg_edit.pas +++ b/gui/cfg_edit.pas @@ -445,6 +445,8 @@ begin begin A:=TStringArray(Obj); + TListBox(control).Items.Clear; + if (Length(A.values)>0) then For i:=0 to High(A.values) do begin diff --git a/gui/game_info.pas b/gui/game_info.pas index 85edb7d3..c1534b93 100644 --- a/gui/game_info.pas +++ b/gui/game_info.pas @@ -264,16 +264,20 @@ type TGameStartupInfo=class(TAbstractObject) public - FReader :Boolean; - FPipe :THandle; - FConfInfo :TConfigInfo; - FGameItem :TGameItem; - FLocalDir :RawByteString; - FhasParamSfo:Integer; + FReader :Boolean; + FPipe :THandle; + FConfInfo :TConfigInfo; + FGameItem :TGameItem; + FLocalDir :RawByteString; + FhasParamSfo :Integer; + FDownloadMb_0:DWORD; + FDownloadMb_1:DWORD; published - property Pipe :THandle read FPipe write FPipe; - property LocalDir:RawByteString read FLocalDir write FLocalDir; - property hasParamSfo:Integer read FhasParamSfo write FhasParamSfo; + property Pipe :THandle read FPipe write FPipe; + property LocalDir :RawByteString read FLocalDir write FLocalDir; + property hasParamSfo :Integer read FhasParamSfo write FhasParamSfo; + property DownloadMb_0:DWORD read FDownloadMb_0 write FDownloadMb_0; + property DownloadMb_1:DWORD read FDownloadMb_1 write FDownloadMb_1; public Constructor Create(Reader:Boolean); reintroduce; Destructor Destroy; override; diff --git a/gui/game_mount.pas b/gui/game_mount.pas index 872e4554..8489d4b6 100644 --- a/gui/game_mount.pas +++ b/gui/game_mount.pas @@ -5,11 +5,28 @@ unit game_mount; interface uses - game_info; + game_info, + kern_mtx; + +type + TGameMountConfig=class + LocalDir:RawByteString; + TitleId :String[10]; + // + mount_mtx:mtx; + // + TemporaryMount:Boolean; + // + DownloadKb:array[0..1] of QWORD; + // + Constructor Create; + function GetTemporaryTitleIdFile:RawByteString; + function GetAppTemporaryFolder:RawByteString; + function GetAppDownloadFolder(i:Byte):RawByteString; + end; var - g_LocalDir:RawByteString=''; - g_TitleId :String[10] ='?????????'#0; + GameMountConfig:TGameMountConfig; procedure InitMount(GameStartupInfo:TGameStartupInfo); @@ -19,6 +36,7 @@ function TemporaryDataMount (mountPoint:pchar;format:Boolean):Integer; function TemporaryDataUnmount(mountPoint:pchar):Integer; function TemporaryDataFormat (mountPoint:pchar):Integer; function TemporaryDataGetAvailableSpaceKb(mountPoint:pchar;availableSpaceKb:PQWORD):Integer; +function DownloadDataGetAvailableSpaceKb (mountPoint:pchar;availableSpaceKb:PQWORD):Integer; implementation @@ -28,12 +46,56 @@ uses LazFileUtils, strings, errno, - kern_mtx, vfs_mountroot, subr_backtrace; +function unix_to_host(const name:RawByteString):RawByteString; var - mount_mtx:mtx; + i:Integer; +begin + Result:=name; + if (DirectorySeparator<>'/') then + For i:=1 to Length(Result) do + begin + if (Result[i]='/') then + begin + Result[i]:=DirectorySeparator; + end; + end; +end; + +Constructor TGameMountConfig.Create; +begin + LocalDir:=''; + TitleId :='?????????'#0; + // + mtx_init(mount_mtx,'mount_mtx'); +end; + +function TGameMountConfig.GetTemporaryTitleIdFile:RawByteString; +const + TEMP_FILE='/system_data/game/tempdata.dat'; +begin + Result:=ExcludeTrailingPathDelimiter(LocalDir)+unix_to_host(TEMP_FILE); +end; + +function TGameMountConfig.GetAppTemporaryFolder:RawByteString; +const + APP_TEMP ='/app_tmp/'; +begin + Result:=ExcludeTrailingPathDelimiter(LocalDir)+unix_to_host(APP_TEMP); +end; + +function TGameMountConfig.GetAppDownloadFolder(i:Byte):RawByteString; +const + APP_DOWNLOAD='%s/user/download/%s/download%d.dat'; // On PS4 these are files, on the emulator, folders +begin + Result:=Format(unix_to_host(APP_DOWNLOAD),[ + ExcludeTrailingPathDelimiter(LocalDir), + TitleId, + i + ]); +end; function get_errno_str(err:Integer):RawByteString; begin @@ -74,21 +136,6 @@ begin end; end; -function unix_to_host(const name:RawByteString):RawByteString; -var - i:Integer; -begin - Result:=name; - if (DirectorySeparator<>'/') then - For i:=1 to Length(Result) do - begin - if (Result[i]='/') then - begin - Result[i]:=DirectorySeparator; - end; - end; -end; - const MM_CREATE =-1; MM_GAME =0; @@ -206,9 +253,14 @@ const (term:True) ); + DOWNLOAD_DIRS:array[0..1] of pchar=( + '/download0', + '/download1' + ); + procedure InitMount(GameStartupInfo:TGameStartupInfo); var - err:Integer; + i,err:Integer; fs_iterator:t_mount_dir_iterator; @@ -217,6 +269,23 @@ var fs_src:RawByteString; begin + with GameStartupInfo.FGameItem.GameInfo do + begin + if (TitleId='') then + begin + TitleId:='?????????'; + end; + end; + + //save to global + GameMountConfig:=TGameMountConfig.Create; + GameMountConfig.LocalDir:=GameStartupInfo.LocalDir; + GameMountConfig.TitleId :=GameStartupInfo.FGameItem.GameInfo.TitleId; + + GameMountConfig.DownloadKb[0]:=GameStartupInfo.DownloadMb_0*1024; + GameMountConfig.DownloadKb[1]:=GameStartupInfo.DownloadMb_1*1024; + //save to global + //temp hack err:=mount_into_sandbox('ufs','/savedata0','savedata',nil,0,True); @@ -224,18 +293,6 @@ begin fs_source[MM_FIRMWARE]:=ExcludeTrailingPathDelimiter(GameStartupInfo.FGameItem.FMountList.firmware); fs_source[MM_LOCAL ]:=ExcludeTrailingPathDelimiter(GameStartupInfo.LocalDir); - //save to global - g_LocalDir:=GameStartupInfo.LocalDir; - - with GameStartupInfo.FGameItem.GameInfo do - begin - if (TitleId<>'') then - begin - g_TitleId:=TitleId; - end; - end; - //save to global - //--sandbox-- fs_iterator.init(@SANDBOX_DIRS); repeat @@ -265,10 +322,20 @@ begin until (not fs_iterator.next(err)); //--sandbox-- + //download + For i:=0 to High(GameMountConfig.DownloadKb) do + if (GameMountConfig.DownloadKb[i]<>0) then + begin + fs_src:=GameMountConfig.GetAppDownloadFolder(i); + ForceDirectories(fs_src); + + err:=mount_into_sandbox('ufs',DOWNLOAD_DIRS[i],pchar(fs_src),nil,0,False); + end; + //download + //UPDATE: sandbox root IS NOT read-only //err:=vfs_mount_path('ufs','/','/',nil,MNT_RDONLY or MNT_UPDATE); - mtx_init(mount_mtx,'mount_mtx'); end; const @@ -277,19 +344,13 @@ const TEMP0:pchar='/temp0'; - TEMP_FILE='/system_data/game/tempdata.dat'; - APP_TEMP ='/app_tmp/'; - -var - TemporaryMount:Boolean=False; - Function ReadTemporaryTitleId:RawByteString; var fs_src:RawByteString; F:THandle; s:Integer; begin - fs_src:=ExcludeTrailingPathDelimiter(g_LocalDir)+unix_to_host(TEMP_FILE); + fs_src:=GameMountConfig.GetTemporaryTitleIdFile; F:=FileOpen(fs_src,fmOpenRead); if (F=THandle(-1)) then Exit(''); @@ -316,7 +377,7 @@ var fs_dir:RawByteString; F:THandle; begin - fs_src:=ExcludeTrailingPathDelimiter(g_LocalDir)+unix_to_host(TEMP_FILE); + fs_src:=GameMountConfig.GetTemporaryTitleIdFile; fs_dir:=ExtractFilePath(fs_src); ForceDirectories(fs_dir); @@ -536,7 +597,8 @@ begin end; //Very approximate size - Result:=files_size+ + Result:=c_block_size+ + files_size+ AlignUp(dirent_size,c_block_size)+ AlignUp(inode_count,c_inodes_per_block)*c_block_size; end; @@ -558,14 +620,14 @@ var fs_src:RawByteString; ValidTitleId:Boolean; begin - mtx_lock(mount_mtx); + mtx_lock(GameMountConfig.mount_mtx); - if TemporaryMount then + if GameMountConfig.TemporaryMount then begin Result:=EBUSY; end else begin - fs_src:=ExcludeTrailingPathDelimiter(g_LocalDir)+unix_to_host(APP_TEMP); + fs_src:=GameMountConfig.GetAppTemporaryFolder; ForceDirectories(fs_src); Result:=vfs_mountroot.mount_into_sandbox('ufs',TEMP0,pchar(fs_src),nil,0); @@ -573,9 +635,9 @@ begin if (Result=0) then begin strlcopy(mountPoint,TEMP0,MOUNT_MAXSIZE); - TemporaryMount:=True; + GameMountConfig.TemporaryMount:=True; - ValidTitleId:=(ReadTemporaryTitleId=g_TitleId); + ValidTitleId:=(ReadTemporaryTitleId=GameMountConfig.TitleId); if format or (not ValidTitleId) then begin @@ -584,29 +646,29 @@ begin if (not ValidTitleId) then begin - SaveTemporaryTitleId(g_TitleId); + SaveTemporaryTitleId(GameMountConfig.TitleId); end; end; end; - mtx_unlock(mount_mtx); + mtx_unlock(GameMountConfig.mount_mtx); end; function TemporaryDataUnmount(mountPoint:pchar):Integer; begin if (strlcomp(mountPoint,TEMP0,MOUNT_MAXSIZE)<>0) then Exit(ENOTDIR); - mtx_lock(mount_mtx); + mtx_lock(GameMountConfig.mount_mtx); - if TemporaryMount then + if GameMountConfig.TemporaryMount then begin Result:=vfs_mountroot.unmount_from_sandbox(TEMP0,0); if (Result=0) then begin - TemporaryMount:=False; + GameMountConfig.TemporaryMount:=False; end; end else @@ -614,7 +676,7 @@ begin Result:=ENOTDIR; end; - mtx_unlock(mount_mtx); + mtx_unlock(GameMountConfig.mount_mtx); end; function TemporaryDataFormat(mountPoint:pchar):Integer; @@ -623,11 +685,11 @@ var begin if (strlcomp(mountPoint,TEMP0,MOUNT_MAXSIZE)<>0) then Exit(ENOTDIR); - mtx_lock(mount_mtx); + mtx_lock(GameMountConfig.mount_mtx); - if TemporaryMount then + if GameMountConfig.TemporaryMount then begin - fs_src:=ExcludeTrailingPathDelimiter(g_LocalDir)+unix_to_host(APP_TEMP); + fs_src:=GameMountConfig.GetAppTemporaryFolder; Result:=FormatMount(fs_src); end else @@ -635,7 +697,7 @@ begin Result:=ENOTDIR; end; - mtx_unlock(mount_mtx); + mtx_unlock(GameMountConfig.mount_mtx); end; function TemporaryDataGetAvailableSpaceKb(mountPoint:pchar;availableSpaceKb:PQWORD):Integer; @@ -647,11 +709,11 @@ var begin if (strlcomp(mountPoint,TEMP0,MOUNT_MAXSIZE)<>0) then Exit(ENOTDIR); - mtx_lock(mount_mtx); + mtx_lock(GameMountConfig.mount_mtx); - if TemporaryMount then + if GameMountConfig.TemporaryMount then begin - fs_src:=ExcludeTrailingPathDelimiter(g_LocalDir)+unix_to_host(APP_TEMP); + fs_src:=GameMountConfig.GetAppTemporaryFolder; size:=GetDirectorySizeLikePFS(fs_src); size:=size div 1024; //to KB @@ -672,9 +734,53 @@ begin Result:=ENOTDIR; end; - mtx_unlock(mount_mtx); + mtx_unlock(GameMountConfig.mount_mtx); end; +function DownloadDataGetAvailableSpaceKb(mountPoint:pchar;availableSpaceKb:PQWORD):Integer; +var + i:Byte; + size:QWORD; + fs_src:RawByteString; +begin + if (strlcomp(mountPoint,DOWNLOAD_DIRS[0],MOUNT_MAXSIZE)=0) then + begin + i:=0; + end else + if (strlcomp(mountPoint,DOWNLOAD_DIRS[1],MOUNT_MAXSIZE)=0) then + begin + i:=1; + end else + begin + Exit(ENOTDIR); + end; + + if (GameMountConfig.DownloadKb[i]=0) then + begin + Exit(ENOTDIR); + end; + + mtx_lock(GameMountConfig.mount_mtx); + + fs_src:=GameMountConfig.GetAppDownloadFolder(i); + + size:=GetDirectorySizeLikePFS(fs_src); + size:=size div 1024; //to KB + + if (size>GameMountConfig.DownloadKb[i]) then + begin + size:=0; + end else + begin + size:=GameMountConfig.DownloadKb[i]-size; + end; + + availableSpaceKb^:=size; + + mtx_unlock(GameMountConfig.mount_mtx); + + Result:=0; +end; end. diff --git a/gui/game_run.pas b/gui/game_run.pas index ad241db1..3df0b49d 100644 --- a/gui/game_run.pas +++ b/gui/game_run.pas @@ -16,6 +16,7 @@ uses host_ipc, host_ipc_interface, md_host_ipc, + param_sfo_gui, game_info, game_mount; @@ -26,7 +27,7 @@ type FConfInfo:TConfigInfo; FGameItem:TGameItem; - FhasParamSfo:Integer; + FParamSfo:TParamSfoFile; end; TGameProcessSimple=class(TGameProcess) @@ -568,7 +569,15 @@ begin GameStartupInfo.FGameItem:=cfg.FGameItem; GameStartupInfo.LocalDir :=GetAppConfigDir(False); - GameStartupInfo.hasParamSfo:=cfg.FhasParamSfo; + GameStartupInfo.hasParamSfo:=ord(cfg.FParamSfo<>nil); + + if (cfg.FParamSfo<>nil) then + begin + GameStartupInfo.DownloadMb_0:=cfg.FParamSfo.GetUInt('DOWNLOAD_DATA_SIZE'); + GameStartupInfo.DownloadMb_1:=cfg.FParamSfo.GetUInt('DOWNLOAD_DATA_SIZE_1'); + end; + + //// SetStdHandle(STD_OUTPUT_HANDLE,cfg.hOutput); SetStdHandle(STD_ERROR_HANDLE ,cfg.hError ); diff --git a/gui/main.pas b/gui/main.pas index ab0f12d0..5c90b34f 100644 --- a/gui/main.pas +++ b/gui/main.pas @@ -666,6 +666,7 @@ begin cfg.FConfInfo:=FConfigInfo; cfg.FGameItem:=Item; + cfg.FParamSfo:=FParamSfo; FGameProcess:=run_item(cfg); @@ -1426,7 +1427,7 @@ begin cfg.FConfInfo:=FConfigInfo; cfg.FGameItem:=Item; - cfg.FhasParamSfo:=ord(ParamSfo<>nil); + cfg.FParamSfo:=ParamSfo; if Item.FLock then Exit; diff --git a/src/ps4_libsceappcontent.pas b/src/ps4_libsceappcontent.pas index 745f5aa2..bda6cec1 100644 --- a/src/ps4_libsceappcontent.pas +++ b/src/ps4_libsceappcontent.pas @@ -254,12 +254,7 @@ begin if not InitAppContent then Exit(SCE_APP_CONTENT_ERROR_NOT_INITIALIZED); if (mountPoint=nil) or (availableSpaceKb=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER); - { - _sig_lock; - Result:=GetDownloadAvailableSpaceKb(PChar(mountPoint),availableSpaceKb); - _sig_unlock; - } - Result:=-1; + Result:=px2ce(DownloadDataGetAvailableSpaceKb(pchar(mountPoint),availableSpaceKb)); end; function ps4_sceAppContentGetEntitlementKey(serviceLabel:SceNpServiceLabel;