Skip to content

Commit 4bc4239

Browse files
committed
Allow specifying a local IPSW file (#298)
1 parent 055d7b6 commit 4bc4239

File tree

5 files changed

+20
-8
lines changed

5 files changed

+20
-8
lines changed

.idea/codeStyles/Project.xml

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/saveactions_settings.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/airsquared/blobsaver/app/Controller.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public void helpLabelHandler(Event evt) {
275275
((Button) alert.getDialogPane().lookupButton(customOK)).setDefaultButton(true);
276276
String url = switch (labelID) {
277277
case "ipswURLHelp":
278-
alert.setContentText("Get the IPSW download URL for the iOS version from theiphonewiki.com/wiki/Beta_Firmware and paste it here.");
278+
alert.setContentText("Get the IPSW download URL for the iOS version from theiphonewiki.com/wiki/Beta_Firmware and paste it here.\n\nIf you already have the IPSW downloaded, you can also supply a 'file:' URL.");
279279
alert.setTitle("Help: IPSW URL");
280280
alert.setHeaderText("Help");
281281
yield "https://www.theiphonewiki.com/wiki/Beta_Firmware";

src/main/java/airsquared/blobsaver/app/TSS.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
import java.io.FileNotFoundException;
2525
import java.io.IOException;
2626
import java.net.MalformedURLException;
27+
import java.net.URI;
28+
import java.net.URISyntaxException;
2729
import java.net.URL;
30+
import java.nio.file.Path;
2831
import java.util.ArrayList;
2932
import java.util.Collections;
3033
import java.util.List;
@@ -41,7 +44,7 @@
4144
public class TSS extends Task<String> {
4245

4346
// note: Matcher is NOT thread safe
44-
private static final Matcher ipswURLMatcher = Pattern.compile("https?://.*apple.*\\.ipsw").matcher("");
47+
private static final Matcher ipswURLMatcher = Pattern.compile("(https?://|file:/).*\\.ipsw").matcher("");
4548
private static final Matcher versionMatcher = Pattern.compile("[0-9]+\\.[0-9]+\\.?[0-9]*(?<!\\.)").matcher("");
4649

4750
private final String deviceIdentifier;
@@ -124,9 +127,14 @@ private void checkInputs() throws TSSException {
124127
if (!ipswURLMatcher.reset(manualIpswURL).matches()) {
125128
throw new MalformedURLException("Doesn't match ipsw URL regex");
126129
}
127-
new URL(manualIpswURL);
130+
new URL(manualIpswURL); // check URL
128131
} catch (MalformedURLException e) {
129-
throw new TSSException("The IPSW URL is not valid.\n\nMake sure it starts with \"http://\" or \"https://\", has \"apple\" in it, and ends with \".ipsw\"", false, e);
132+
throw new TSSException("The IPSW URL is not valid.\n\nMake sure it's a valid URL that ends with \".ipsw\"", false, e);
133+
}
134+
if (manualIpswURL.startsWith("file:")) try {
135+
Path.of(new URI(manualIpswURL)).toRealPath(); // check URI
136+
} catch (IllegalArgumentException | URISyntaxException | IOException e) {
137+
throw new TSSException("The IPSW URL is not valid.\n\nMake sure it's a valid file URL to a local .ipsw file.", false, e);
130138
}
131139
} else if (manualVersion != null && !versionMatcher.reset(manualVersion).matches()) {
132140
throw new TSSException("Invalid version. Make sure it follows the convention X.X.X or X.X, like \"13.1\" or \"13.5.5\"", false);

src/main/java/airsquared/blobsaver/app/Utils.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.json.JSONTokener;
3939

4040
import java.io.*;
41+
import java.net.URI;
4142
import java.net.URL;
4243
import java.net.URLConnection;
4344
import java.nio.ByteBuffer;
@@ -48,6 +49,7 @@
4849
import java.nio.file.Files;
4950
import java.nio.file.Path;
5051
import java.nio.file.StandardCopyOption;
52+
import java.nio.file.StandardOpenOption;
5153
import java.util.List;
5254
import java.util.Objects;
5355
import java.util.concurrent.ExecutorService;
@@ -363,7 +365,10 @@ static final record IOSVersion(String versionString, String ipswURL, Boolean sig
363365

364366
static Path extractBuildManifest(String ipswUrl) throws IOException {
365367
Path buildManifest = Files.createTempFile("BuildManifest", ".plist");
366-
try (ZipFile ipsw = new ZipFile(new HttpChannel(new URL(ipswUrl)), "ipsw", "UTF8", true, true);
368+
SeekableByteChannel channel = ipswUrl.startsWith("file:")
369+
? Files.newByteChannel(Path.of(URI.create(ipswUrl)), StandardOpenOption.READ)
370+
: new HttpChannel(new URL(ipswUrl));
371+
try (channel; ZipFile ipsw = new ZipFile(channel, "ipsw", "UTF8", true, true);
367372
InputStream is = ipsw.getInputStream(ipsw.getEntry("BuildManifest.plist"))) {
368373
Files.copy(is, buildManifest, StandardCopyOption.REPLACE_EXISTING);
369374
}

0 commit comments

Comments
 (0)