diff --git a/src/main/java/sh/rhiobet/lalafin/path/PathFactory.java b/src/main/java/sh/rhiobet/lalafin/path/PathFactory.java index 4ccc754..424de13 100644 --- a/src/main/java/sh/rhiobet/lalafin/path/PathFactory.java +++ b/src/main/java/sh/rhiobet/lalafin/path/PathFactory.java @@ -8,6 +8,7 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.List; +import java.util.stream.Collectors; import sh.rhiobet.lalafin.api.configuration.FileApiConfiguration; @@ -22,8 +23,22 @@ public class PathFactory { } else { java.nio.file.Path rootFolderPath = Paths.get(this.fileApiConfiguration.directory()); - if (names.size() > 1 && names.get(names.size() - 2).getPath().endsWith(".zip")) { - return new ZipEntryPath(names, rootFolderPath); + int zipIndex = -1; + for (int i = 0; i < names.size(); i++) { + if (names.get(i).getPath().endsWith(".zip")) { + zipIndex = i; + break; + } + } + + if (zipIndex >= 0 && zipIndex < names.size() - 1) { + FileSystemPath zipFilePath = + new FileSystemPath(names.subList(0, zipIndex + 1), rootFolderPath); + String zipEntryName = names.stream() + .skip(zipIndex + 1) + .map(PathSegment::getPath) + .collect(Collectors.joining("/")); + return new ZipEntryPath(zipFilePath, zipEntryName); } else { return new FileSystemPath(names, rootFolderPath); } @@ -38,7 +53,8 @@ public class PathFactory { if (decoded.equals(current)) break; current = decoded; } - return current.contains("/") || current.contains("\0") || current.equals("..") || current.equals("."); + return current.contains("/") || current.contains("\0") || current.equals("..") + || current.equals("."); }); } } diff --git a/src/main/java/sh/rhiobet/lalafin/path/ZipEntryPath.java b/src/main/java/sh/rhiobet/lalafin/path/ZipEntryPath.java index 68b0f8e..a708d2c 100644 --- a/src/main/java/sh/rhiobet/lalafin/path/ZipEntryPath.java +++ b/src/main/java/sh/rhiobet/lalafin/path/ZipEntryPath.java @@ -6,11 +6,15 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.stream.Stream; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.jboss.resteasy.reactive.common.util.Encode; public final class ZipEntryPath implements Path { + private long size = 0; + private boolean exists = false; + FileSystemPath zipFilePath; List segments; @@ -38,20 +42,18 @@ public final class ZipEntryPath implements Path { @Override public long getSize() { - try (ZipFile zipFile = new ZipFile(this.zipFilePath.absolutePath.toFile())) { - return zipFile.getEntry(this.segments.getLast()).getSize(); - } catch (IOException ignored) { - return 0; - } + if (this.size == 0) { + fetchEntryData(); + } + return this.size; } @Override public boolean exists() { - try (ZipFile zipFile = new ZipFile(this.zipFilePath.absolutePath.toFile())) { - return zipFile.getEntry(segments.getLast()) != null; - } catch (IOException ignored) { - return false; + if (!this.exists) { + fetchEntryData(); } + return this.exists; } @Override @@ -70,63 +72,74 @@ public final class ZipEntryPath implements Path { return new ZipEntryInputStream(zipFile, zipFile.getInputStream(zipFile.getEntry(this.segments.getLast()))); } -} - -class ZipEntryInputStream extends InputStream { - private final ZipFile zipFile; - private final InputStream is; - - public ZipEntryInputStream(ZipFile zipFile, InputStream is) { - this.zipFile = zipFile; - this.is = is; - } - - @Override - public int read() throws IOException { - return this.is.read(); - } - - @Override - public int read(byte[] buf) throws IOException { - return this.is.read(buf); - } - - @Override - public int read(byte[] buf, int off, int len) throws IOException { - return this.is.read(buf, off, len); - } - - @Override - public byte[] readAllBytes() throws IOException { - return this.is.readAllBytes(); - } - - @Override - public byte[] readNBytes(int len) throws IOException { - return this.is.readNBytes(len); - } - - @Override - public int readNBytes(byte[] buf, int off, int len) throws IOException { - return this.is.readNBytes(buf, off, len); - } - - @Override - public long skip(long n) throws IOException { - return this.is.skip(n); - } - - @Override - public int available() throws IOException { - return this.is.available(); - } - - @Override - public void close() throws IOException { - try { - this.is.close(); - } finally { - this.zipFile.close(); - } - } + + private void fetchEntryData() { + try (ZipFile zipFile = new ZipFile(this.zipFilePath.absolutePath.toFile())) { + ZipEntry zipEntry = zipFile.getEntry(this.segments.getLast()); + this.exists = zipEntry != null; + + if (this.exists) { + this.size = zipEntry.getSize(); + } + } catch (IOException ignored) { } + } + + private class ZipEntryInputStream extends InputStream { + private final ZipFile zipFile; + private final InputStream is; + + public ZipEntryInputStream(ZipFile zipFile, InputStream is) { + this.zipFile = zipFile; + this.is = is; + } + + @Override + public int read() throws IOException { + return this.is.read(); + } + + @Override + public int read(byte[] buf) throws IOException { + return this.is.read(buf); + } + + @Override + public int read(byte[] buf, int off, int len) throws IOException { + return this.is.read(buf, off, len); + } + + @Override + public byte[] readAllBytes() throws IOException { + return this.is.readAllBytes(); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + return this.is.readNBytes(len); + } + + @Override + public int readNBytes(byte[] buf, int off, int len) throws IOException { + return this.is.readNBytes(buf, off, len); + } + + @Override + public long skip(long n) throws IOException { + return this.is.skip(n); + } + + @Override + public int available() throws IOException { + return this.is.available(); + } + + @Override + public void close() throws IOException { + try { + this.is.close(); + } finally { + this.zipFile.close(); + } + } + } } diff --git a/src/main/java/sh/rhiobet/lalafin/thumbnail/ThumbnailPathPlugin.java b/src/main/java/sh/rhiobet/lalafin/thumbnail/ThumbnailPathPlugin.java index cc61226..e3eb5b5 100644 --- a/src/main/java/sh/rhiobet/lalafin/thumbnail/ThumbnailPathPlugin.java +++ b/src/main/java/sh/rhiobet/lalafin/thumbnail/ThumbnailPathPlugin.java @@ -5,6 +5,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Optional; +import java.util.regex.Pattern; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -62,7 +63,8 @@ public class ThumbnailPathPlugin extends PathAccessor implements PathPlugin { private Optional getThumbnailPath(Path path) { try { return Files.list(getAbsolutePath(path).getParent().resolve(".thumbnails")) - .filter(f -> f.getFileName().toString().matches("^" + path.getFilename() + "(\\.[^.]+)*$")) + .filter(f -> f.getFileName().toString() + .matches("^" + Pattern.quote(path.getFilename()) + "(\\.[^.]+)*$")) .findFirst(); } catch (IOException ignored) { return Optional.empty();