11using System . Diagnostics ;
2+ using System . Diagnostics . CodeAnalysis ;
23using Eto . Drawing ;
34using Eto . Forms ;
45using Refresher . Accessors ;
@@ -12,7 +13,7 @@ namespace Refresher.UI;
1213public abstract class IntegratedPatchForm : PatchForm < Patcher >
1314{
1415 private readonly DropDown _gameDropdown ;
15- private readonly TextBox _outputField ;
16+ private readonly TextBox ? _outputField ;
1617
1718 private string _tempFile ;
1819 private string _usrDir ;
@@ -21,18 +22,22 @@ public abstract class IntegratedPatchForm : PatchForm<Patcher>
2122
2223 protected override TableLayout FormPanel { get ; }
2324
25+ [ SuppressMessage ( "ReSharper" , "VirtualMemberCallInConstructor" ) ]
2426 protected IntegratedPatchForm ( string subtitle ) : base ( subtitle )
2527 {
2628 this . FormPanel = new TableLayout ( new List < TableRow >
2729 {
28- // ReSharper disable once VirtualMemberCallInConstructor
2930 this . AddRemoteField ( ) ,
3031 AddField ( "Game to patch" , out this . _gameDropdown ) ,
3132 AddField ( "Server URL" , out this . UrlField ) ,
32- AddField ( "Identifier (EBOOT.<value>.elf)" , out this . _outputField ) ,
3333 } ) ;
34+
35+ if ( ! this . ShouldReplaceExecutable )
36+ {
37+ this . FormPanel . Rows . Add ( AddField ( "Identifier (EBOOT.<value>.elf)" , out this . _outputField ) ) ;
38+ this . _outputField ! . PlaceholderText = "refresh" ;
39+ }
3440
35- this . _outputField . PlaceholderText = "refresh" ;
3641 this . _gameDropdown . SelectedValueChanged += this . GameChanged ;
3742
3843 this . InitializePatcher ( ) ;
@@ -93,13 +98,21 @@ protected void GameChanged(object? sender, EventArgs ev)
9398
9499 string licenseDir = Path . Join ( Path . GetTempPath ( ) , "refresher-" + Random . Shared . Next ( ) ) ;
95100 Directory . CreateDirectory ( licenseDir ) ;
96- IEnumerable < string > licenseFiles = this . Accessor . GetFilesInDirectory ( Path . Combine ( "home" , "00000001" , "exdata" ) ) ;
97-
98- foreach ( string licenseFile in licenseFiles )
101+
102+ // if this is a NP game then download RIFs/RAPs, disc copies don't need anything else
103+ if ( game . TitleId . StartsWith ( 'N' ) )
99104 {
100- if ( ! licenseFile . Contains ( game . TitleId ) ) continue ;
101- string downloadedFile = this . Accessor . DownloadFile ( licenseFile ) ;
102- File . Move ( downloadedFile , Path . Join ( licenseDir , Path . GetFileName ( licenseFile ) ) ) ;
105+ // TODO: the first user might not have the licenses necessary, should download from all users
106+ IEnumerable < string > licenseFiles = this . Accessor . GetFilesInDirectory ( Path . Combine ( "home" , "00000001" , "exdata" ) ) ;
107+ foreach ( string licenseFile in licenseFiles )
108+ {
109+ // only download if it contains our game's title id
110+ // TODO: determine content id directly so we skip dlc licenses
111+ if ( ! licenseFile . Contains ( game . TitleId ) ) continue ;
112+
113+ string downloadedFile = this . Accessor . DownloadFile ( licenseFile ) ;
114+ File . Move ( downloadedFile , Path . Join ( licenseDir , Path . GetFileName ( licenseFile ) ) ) ;
115+ }
103116 }
104117
105118 this . LogMessage ( $ "EBOOT Path: { ebootPath } ") ;
@@ -123,11 +136,38 @@ protected void GameChanged(object? sender, EventArgs ev)
123136
124137 public override void CompletePatch ( object ? sender , EventArgs e ) {
125138 Debug . Assert ( this . Accessor != null ) ;
126- string identifier = string . IsNullOrWhiteSpace ( this . _outputField . Text ) ? this . _outputField . PlaceholderText : this . _outputField . Text ;
127139
128- string destination = Path . Combine ( this . _usrDir , $ "EBOOT.{ identifier } .elf") ;
140+ string ? identifier = string . IsNullOrWhiteSpace ( this . _outputField ? . Text ) ? this . _outputField ? . PlaceholderText : this . _outputField ? . Text ;
141+ identifier ??= "" ;
142+
143+ string fileToUpload ;
144+ if ( this . NeedsResign )
145+ {
146+ string encryptedTempFile = Path . GetTempFileName ( ) ;
147+ LibSceToolSharp . SetDiscEncryptOptions ( ) ;
148+ LibSceToolSharp . Encrypt ( this . _tempFile , encryptedTempFile ) ;
149+
150+ fileToUpload = encryptedTempFile ;
151+ }
152+ else
153+ {
154+ fileToUpload = this . _tempFile ;
155+ }
156+
157+ string destinationFile = this . ShouldReplaceExecutable ? "EBOOT.BIN" : $ "EBOOT.{ identifier } .BIN";
158+ string destination = Path . Combine ( this . _usrDir , destinationFile ) ;
159+
160+ // if we're replacing the executable, back it up to EBOOT.BIN.ORIG before we do so
161+ if ( this . ShouldReplaceExecutable )
162+ {
163+ string backup = destination + ".ORIG" ;
164+ if ( ! this . Accessor . FileExists ( backup ) )
165+ this . Accessor . DuplicateFile ( destination , backup ) ;
166+
167+ this . Accessor . RemoveFile ( destination ) ;
168+ }
129169
130- this . Accessor . UploadFile ( this . _tempFile , destination ) ;
170+ this . Accessor . UploadFile ( fileToUpload , destination ) ;
131171 MessageBox . Show ( $ "Successfully patched EBOOT! It was saved to '{ destination } '.") ;
132172
133173 // Re-initialize patcher so we can patch with the same parameters again
@@ -136,4 +176,6 @@ public override void CompletePatch(object? sender, EventArgs e) {
136176 }
137177
138178 protected abstract TableRow AddRemoteField ( ) ;
179+ protected abstract bool NeedsResign { get ; }
180+ protected abstract bool ShouldReplaceExecutable { get ; }
139181}
0 commit comments