Skip to content

Commit

Permalink
Improved input handling for contents fetched from a URL
Browse files Browse the repository at this point in the history
  • Loading branch information
Col-E committed Sep 29, 2024
1 parent 6640d53 commit af6116f
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package software.coley.recaf.services.workspace.io;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.slf4j.Logger;
Expand All @@ -14,7 +15,9 @@
import software.coley.recaf.info.builder.FileInfoBuilder;
import software.coley.recaf.info.properties.builtin.*;
import software.coley.recaf.services.Service;
import software.coley.recaf.util.*;
import software.coley.recaf.util.IOUtil;
import software.coley.recaf.util.ModulesIOUtil;
import software.coley.recaf.util.StringUtil;
import software.coley.recaf.util.android.DexIOUtil;
import software.coley.recaf.util.io.ByteSource;
import software.coley.recaf.util.io.ByteSources;
Expand All @@ -25,6 +28,7 @@
import java.io.File;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.net.URI;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
Expand All @@ -44,7 +48,7 @@ public class BasicResourceImporter implements ResourceImporter, Service {

@Inject
public BasicResourceImporter(@Nonnull InfoImporter infoImporter,
@Nonnull ResourceImporterConfig config) {
@Nonnull ResourceImporterConfig config) {
this.infoImporter = infoImporter;
this.config = config;
}
Expand All @@ -61,10 +65,13 @@ public BasicResourceImporter(@Nonnull InfoImporter infoImporter,
*
* @return Read resource.
*/
private WorkspaceResource handleSingle(WorkspaceFileResourceBuilder builder,
String pathName, ByteSource source) throws IOException {
private WorkspaceResource handleSingle(@Nonnull WorkspaceFileResourceBuilder builder,
@Nonnull String pathName, @Nonnull ByteSource source) throws IOException {
// Read input as raw info in order to determine file-type.
Info readInfo = infoImporter.readInfo(pathName.substring(pathName.lastIndexOf('/') + 1), source);
PathAndName pathAndName = PathAndName.fromString(pathName);
String name = pathAndName.name;
Path localPath = pathAndName.path;
Info readInfo = infoImporter.readInfo(name, source);

// Check if it is a single class.
if (readInfo.isClass()) {
Expand All @@ -80,14 +87,15 @@ private WorkspaceResource handleSingle(WorkspaceFileResourceBuilder builder,
.withName(readAsJvmClass.getName() + ".class")
.withRawContent(readAsJvmClass.getBytecode())
.build();
InputFilePathProperty.set(fileInfo, Paths.get(pathName)); // Associate input path with the read value.
if (localPath != null)
InputFilePathProperty.set(fileInfo, localPath); // Associate input path with the read value.
return builder.withFileInfo(fileInfo)
.withJvmClassBundle(bundle)
.build();
}

// Associate input path with the read value.
InputFilePathProperty.set(readInfo, Paths.get(pathName));
if (localPath != null) InputFilePathProperty.set(readInfo, localPath);

// Must be some non-class type of file.
FileInfo readInfoAsFile = readInfo.asFile();
Expand Down Expand Up @@ -250,13 +258,13 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
}

private void addInfo(BasicJvmClassBundle classes,
BasicFileBundle files,
Map<String, AndroidClassBundle> androidClassBundles,
NavigableMap<Integer, JvmClassBundle> versionedJvmClassBundles,
Map<String, WorkspaceFileResource> embeddedResources,
ByteSource infoSource,
String pathName,
Info info) {
BasicFileBundle files,
Map<String, AndroidClassBundle> androidClassBundles,
NavigableMap<Integer, JvmClassBundle> versionedJvmClassBundles,
Map<String, WorkspaceFileResource> embeddedResources,
ByteSource infoSource,
String pathName,
Info info) {
if (info.isClass()) {
// Must be a JVM class since Android classes do not exist in single-file form.
JvmClassInfo classInfo = info.asClass().asJvmClass();
Expand Down Expand Up @@ -428,7 +436,7 @@ private void addInfo(BasicJvmClassBundle classes,
* Target file bundle for fallback item placement.
*/
private void deduplicateClass(JvmClassInfo existingClass, JvmClassInfo currentClass,
BasicJvmClassBundle classes, BasicFileBundle files) {
BasicJvmClassBundle classes, BasicFileBundle files) {
String className = currentClass.getName();
String existingPrefix = PathPrefixProperty.get(existingClass);
String existingSuffix = PathSuffixProperty.get(existingClass);
Expand Down Expand Up @@ -589,11 +597,16 @@ public WorkspaceResource importResource(@Nonnull Path path) throws IOException {
@Override
public WorkspaceResource importResource(@Nonnull URL url) throws IOException {
// Extract name from URL
String path = url.getFile();
if (path.isEmpty())
String path;
if (url.getProtocol().equals("file")) {
path = url.getFile();
if (path.isEmpty())
path = url.toString();
if (path.charAt(0) == '/')
path = path.substring(1);
} else {
path = url.toString();
if (path.charAt(0) == '/')
path = path.substring(1);
}

// Load content, parse into resource.
byte[] bytes = IOUtil.toByteArray(url.openStream());
Expand All @@ -612,4 +625,53 @@ public String getServiceId() {
public ResourceImporterConfig getServiceConfig() {
return config;
}

private record PathAndName(@Nullable Path path, @Nonnull String name) {
@Nonnull
private static PathAndName fromString(@Nonnull String pathName) {
if (pathName.contains("://")) {
// Absolute URI paths
if (pathName.startsWith("file://")) {
return fromUriString(pathName);
} else {
// Probably something like "https://foo.com/bar.zip"
// Try normalizing a simple name out of it if possible.
while (pathName.endsWith("/")) pathName = pathName.substring(0, pathName.length() - 1);
String name = pathName.substring(pathName.lastIndexOf('/') + 1);
if (!name.matches("\\w+")) name = "remote";
return new PathAndName(null, name);
}
} else if (pathName.startsWith("file:./")) {
// Relative URI paths
return fromUriString(pathName);
} else {
// Probably local file paths
Path localPath;
try {
// Try and resolve a file path to the give path-name.
// In some cases the input name is a remote resource not covered by the block above,
// so we don't really care if it fails. That just means it is a remote resource of some kind.
localPath = Paths.get(pathName);
} catch (Throwable t) {
localPath = null;
}
return new PathAndName(localPath, pathName.substring(pathName.lastIndexOf('/') + 1));
}
}

@Nonnull
private static PathAndName fromUriString(@Nonnull String pathName) {
String name;
Path localPath;
name = pathName.substring(pathName.lastIndexOf('/') + 1);
try {
// Try and resolve a file path to the give path-name.
// It should be an absolute path.
localPath = Paths.get(URI.create(pathName));
} catch (Throwable t) {
localPath = null;
}
return new PathAndName(localPath, name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import org.kordamp.ikonli.carbonicons.CarbonIcons;
import org.slf4j.Logger;
import software.coley.recaf.analytics.logging.Logging;
Expand Down Expand Up @@ -70,8 +72,8 @@ public OpenUrlPopup(@Nonnull WorkspaceManager workspaceManager, @Nonnull Resourc
return false;
}
}).thenAcceptAsync((result) -> {
input.setDisable(false);
if (result) {
input.setDisable(false);
close();
} else {
Animations.animateFailure(input, 1000);
Expand All @@ -82,15 +84,20 @@ public OpenUrlPopup(@Nonnull WorkspaceManager workspaceManager, @Nonnull Resourc
input.setPromptText("https://example.com/application.jar");
input.setOnAction(e -> load.getOnAction().handle(e));

input.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
load.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

GridPane layout = new GridPane(8, 8);
ColumnConstraints e = new ColumnConstraints(0, -1, Double.MAX_VALUE);
e.setHgrow(Priority.ALWAYS);
layout.getColumnConstraints().add(e);
layout.add(input, 0, 0);
layout.add(load, 0, 1);
layout.setPadding(new Insets(10));
layout.setAlignment(Pos.TOP_CENTER);

input.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
load.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
layout.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

setMinWidth(300);
setMinHeight(90);
setTitle(get("menu.file.openurl"));
Expand Down

0 comments on commit af6116f

Please sign in to comment.