2121import com .google .gson .Gson ;
2222import javafx .concurrent .Task ;
2323
24- import java .io .File ;
2524import java .io .FileNotFoundException ;
2625import java .io .IOException ;
2726import java .net .MalformedURLException ;
@@ -74,7 +73,6 @@ public class TSS extends Task<String> {
7473 private TSS (String deviceIdentifier , String ecid , String savePath , String boardConfig , boolean includeBetas , String manualVersion , String manualIpswURL , String apnonce , String generator , boolean saveToTSSSaver , boolean saveToSHSHHost ) {
7574 this .deviceIdentifier = deviceIdentifier ;
7675 this .ecid = ecid ;
77- this .savePath = savePath ;
7876 this .boardConfig = boardConfig ;
7977 this .includeBetas = includeBetas ;
8078 this .manualVersion = manualVersion ;
@@ -83,6 +81,7 @@ private TSS(String deviceIdentifier, String ecid, String savePath, String boardC
8381 this .generator = generator ;
8482 this .saveToTSSSaver = saveToTSSSaver ;
8583 this .saveToSHSHHost = saveToSHSHHost ;
84+ this .savePath = parsePath (savePath );
8685 }
8786
8887 /**
@@ -98,7 +97,7 @@ protected String call() throws TSSException {
9897 ArrayList <String > args = constructArgs ();
9998
10099 var alreadySaved = new StringJoiner (", " );
101- var savedFor = new StringJoiner (", " );
100+ var newlySaved = new StringJoiner (", " );
102101 for (Utils .IOSVersion iosVersion : iosVersions ) {
103102 if (!Prefs .getAlwaysSaveNewBlobs () && checkAlreadySaved (iosVersion )) {
104103 alreadySaved .add (iosVersion .versionString ());
@@ -116,14 +115,14 @@ protected String call() throws TSSException {
116115 }
117116
118117 if (iosVersion .versionString () != null ) {
119- savedFor .add (iosVersion .versionString ());
118+ newlySaved .add (iosVersion .versionString ());
120119 }
121120 }
122- StringBuilder responseBuilder = new StringBuilder ();
123- if (manualIpswURL != null || savedFor .length () > 0 ) {
121+ var responseBuilder = new StringBuilder ();
122+ if (manualIpswURL != null || newlySaved .length () > 0 ) {
124123 responseBuilder .append ("Successfully saved blobs in\n " ).append (savePath );
125- if (savedFor .length () > 0 ) {
126- responseBuilder .append ("\n \n For version" ).append (iosVersions .size () == 1 ? " " : "s " ).append (savedFor );
124+ if (newlySaved .length () > 0 ) {
125+ responseBuilder .append ("\n \n For version" ).append (iosVersions .size () == 1 ? " " : "s " ).append (newlySaved );
127126 }
128127 if (alreadySaved .length () > 0 ) {
129128 responseBuilder .append ("\n \n " );
@@ -156,7 +155,7 @@ private boolean checkAlreadySaved(Utils.IOSVersion ios) {
156155 String fileName = "%s_%s_%s_%s-%s_%s.shsh2"
157156 .formatted (parseECID (), deviceIdentifier , getBoardConfig (), versionStringOnly , ios .buildid (), apnonce );
158157
159- if (Files .exists (Path .of (savePath , fileName ))) {
158+ if (Files .exists (Path .of (parsePathWithVersion ( ios ) , fileName ))) {
160159 System .out .println ("Already Saved: " + fileName );
161160 return true ;
162161 }
@@ -168,16 +167,59 @@ private long parseECID() {
168167 : Long .parseLong (ecid .startsWith ("0x" ) ? ecid .substring (2 ) : ecid , 16 );
169168 }
170169
170+ private String parsePath (String input ) {
171+ if (!input .contains ("${" )) return input ;
172+ String template = input ;
173+
174+ var variables = Map .of ("${DeviceIdentifier}" , deviceIdentifier ,
175+ "${BoardConfig}" , getBoardConfig (),
176+ "${APNonce}" , apnonce ,
177+ "${Generator}" , generator ,
178+ "${DeviceModel}" , Devices .identifierToModel (deviceIdentifier ),
179+ "${ECID}" , ecid );
180+ for (Map .Entry <String , String > entry : variables .entrySet ()) {
181+ template = template .replace (entry .getKey (), entry .getValue ());
182+ }
183+ return template ;
184+ }
185+
186+ private String parsePathWithVersion (Utils .IOSVersion ios ) {
187+ if (!savePath .contains ("${" )) return savePath ;
188+ var template = savePath ;
189+
190+ Map <String , String > variables ;
191+ if (ios .versionString () != null ) {
192+ variables = Map .of ("${FullVersionString}" , ios .versionString (),
193+ "${BuildID}" , ios .buildid (),
194+ "${MajorVersion}" , ios .versionString ().replaceFirst ("\\ ..*" , "" ));
195+ } else {
196+ variables = Map .of ("${FullVersionString}" , "UnknownVersion" ,
197+ "${BuildID}" , "UnknownBuildID" ,
198+ "${MajorVersion}" , "UnknownVersion" );
199+ }
200+ for (Map .Entry <String , String > entry : variables .entrySet ()) {
201+ template = template .replace (entry .getKey (), entry .getValue ());
202+ }
203+
204+ return template ;
205+ }
171206
172207 private void saveFor (Utils .IOSVersion iosVersion , ArrayList <String > args ) throws TSSException {
173208 final int urlIndex = args .size () - 1 ;
209+ final int pathIndex = args .size () - 3 ;
174210 Path manifest ;
175211 try {
176212 manifest = extractBuildManifest (iosVersion .ipswURL ());
177213 args .set (urlIndex , manifest .toString ());
178214 } catch (IOException e ) {
179215 throw new TSSException ("Unable to extract BuildManifest." , true , e );
180216 }
217+ try {
218+ args .set (pathIndex , parsePathWithVersion (iosVersion ));
219+ Files .createDirectories (Path .of (args .get (pathIndex )));
220+ } catch (IOException e ) {
221+ throw new TSSException ("Unable to create save directory. Try with a different save path. If you are using variables, make sure they are spelled correctly." , false , e );
222+ }
181223 try {
182224 System .out .println ("Running: " + args );
183225 String tssLog = executeProgram (args );
@@ -258,9 +300,7 @@ private List<Utils.IOSVersion> getIOSVersions() throws TSSException {
258300 private ArrayList <String > constructArgs () {
259301 ArrayList <String > args = new ArrayList <>(17 );
260302 String tsscheckerPath = Utils .getTsschecker ().getAbsolutePath ();
261- //noinspection ResultOfMethodCallIgnored
262- new File (savePath ).mkdirs ();
263- Collections .addAll (args , tsscheckerPath , "--nocache" , "--save" , "--device" , deviceIdentifier , "--ecid" , ecid , "--save-path" , savePath );
303+ Collections .addAll (args , tsscheckerPath , "--nocache" , "--save" , "--device" , deviceIdentifier , "--ecid" , ecid );
264304 Collections .addAll (args , "--boardconfig" , getBoardConfig ());
265305 if (apnonce != null ) {
266306 Collections .addAll (args , "--apnonce" , apnonce );
@@ -270,7 +310,9 @@ private ArrayList<String> constructArgs() {
270310 } else {
271311 Collections .addAll (args , "--generator" , "0x1111111111111111" );
272312 }
273- Collections .addAll (args , "--build-manifest" , "will be replaced in loop" );
313+
314+ Collections .addAll (args , "--save-path" , "will be replaced in loop" ,
315+ "--build-manifest" , "will be replaced in loop" );
274316
275317 return args ;
276318 }
@@ -294,7 +336,7 @@ && containsIgnoreCase(tsscheckerLog, "checking tss status failed")) {
294336 } else if (containsIgnoreCase (tsscheckerLog , "Could not resolve host" )) {
295337 throw new TSSException ("Saving blobs failed. Check your internet connection." , false , tsscheckerLog );
296338 } else if (containsIgnoreCase (tsscheckerLog , "can't save shsh at" )) {
297- throw new TSSException ("'" + savePath + "' is not a valid path" , false );
339+ throw new TSSException ("'" + savePath + "' is not a valid path. If you are using variables, make sure they are spelled correctly. " , false );
298340 } else if (containsIgnoreCase (tsscheckerLog , "IS NOT being signed" )) {
299341 if (manualVersion == null ) {
300342 throw new TSSException ("The " + Devices .getOSNameForType (Devices .getDeviceType (deviceIdentifier )) + " version is not being signed for device " + deviceIdentifier , false );
0 commit comments