package net.minecraft.server.packs; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Sets; import com.mojang.logging.LogUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.annotation.Nullable; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.resources.IoSupplier; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; public class FilePackResources extends AbstractPackResources { static final Logger LOGGER = LogUtils.getLogger(); private final FilePackResources.SharedZipFileAccess zipFileAccess; private final String prefix; FilePackResources(PackLocationInfo p_332104_, FilePackResources.SharedZipFileAccess p_298373_, String p_256076_) { super(p_332104_); this.zipFileAccess = p_298373_; this.prefix = p_256076_; } private static String getPathFromLocation(PackType p_250585_, ResourceLocation p_251470_) { return String.format(Locale.ROOT, "%s/%s/%s", p_250585_.getDirectory(), p_251470_.getNamespace(), p_251470_.getPath()); } @Nullable @Override public IoSupplier getRootResource(String... p_248514_) { return this.getResource(String.join("/", p_248514_)); } @Override public IoSupplier getResource(PackType p_249605_, ResourceLocation p_252147_) { return this.getResource(getPathFromLocation(p_249605_, p_252147_)); } private String addPrefix(String p_299206_) { return this.prefix.isEmpty() ? p_299206_ : this.prefix + "/" + p_299206_; } @Nullable private IoSupplier getResource(String p_251795_) { ZipFile zipfile = this.zipFileAccess.getOrCreateZipFile(); if (zipfile == null) { return null; } else { ZipEntry zipentry = zipfile.getEntry(this.addPrefix(p_251795_)); return zipentry == null ? null : IoSupplier.create(zipfile, zipentry); } } @Override public Set getNamespaces(PackType p_10238_) { ZipFile zipfile = this.zipFileAccess.getOrCreateZipFile(); if (zipfile == null) { return Set.of(); } else { Enumeration enumeration = zipfile.entries(); Set set = Sets.newHashSet(); String s = this.addPrefix(p_10238_.getDirectory() + "/"); while (enumeration.hasMoreElements()) { ZipEntry zipentry = enumeration.nextElement(); String s1 = zipentry.getName(); String s2 = extractNamespace(s, s1); if (!s2.isEmpty()) { if (ResourceLocation.isValidNamespace(s2)) { set.add(s2); } else { LOGGER.warn("Non [a-z0-9_.-] character in namespace {} in pack {}, ignoring", s2, this.zipFileAccess.file); } } } return set; } } @VisibleForTesting public static String extractNamespace(String p_298682_, String p_300360_) { if (!p_300360_.startsWith(p_298682_)) { return ""; } else { int i = p_298682_.length(); int j = p_300360_.indexOf(47, i); return j == -1 ? p_300360_.substring(i) : p_300360_.substring(i, j); } } @Override public void close() { this.zipFileAccess.close(); } @Override public void listResources(PackType p_250500_, String p_249598_, String p_251613_, PackResources.ResourceOutput p_250655_) { ZipFile zipfile = this.zipFileAccess.getOrCreateZipFile(); if (zipfile != null) { Enumeration enumeration = zipfile.entries(); String s = this.addPrefix(p_250500_.getDirectory() + "/" + p_249598_ + "/"); String s1 = s + p_251613_ + "/"; while (enumeration.hasMoreElements()) { ZipEntry zipentry = enumeration.nextElement(); if (!zipentry.isDirectory()) { String s2 = zipentry.getName(); if (s2.startsWith(s1)) { String s3 = s2.substring(s.length()); ResourceLocation resourcelocation = ResourceLocation.tryBuild(p_249598_, s3); if (resourcelocation != null) { p_250655_.accept(resourcelocation, IoSupplier.create(zipfile, zipentry)); } else { LOGGER.warn("Invalid path in datapack: {}:{}, ignoring", p_249598_, s3); } } } } } } public static class FileResourcesSupplier implements Pack.ResourcesSupplier { private final File content; public FileResourcesSupplier(Path p_301133_) { this(p_301133_.toFile()); } public FileResourcesSupplier(File p_299311_) { this.content = p_299311_; } @Override public PackResources openPrimary(PackLocationInfo p_336235_) { FilePackResources.SharedZipFileAccess filepackresources$sharedzipfileaccess = new FilePackResources.SharedZipFileAccess(this.content); return new FilePackResources(p_336235_, filepackresources$sharedzipfileaccess, ""); } @Override public PackResources openFull(PackLocationInfo p_332542_, Pack.Metadata p_333099_) { FilePackResources.SharedZipFileAccess filepackresources$sharedzipfileaccess = new FilePackResources.SharedZipFileAccess(this.content); PackResources packresources = new FilePackResources(p_332542_, filepackresources$sharedzipfileaccess, ""); List list = p_333099_.overlays(); if (list.isEmpty()) { return packresources; } else { List list1 = new ArrayList<>(list.size()); for (String s : list) { list1.add(new FilePackResources(p_332542_, filepackresources$sharedzipfileaccess, s)); } return new CompositePackResources(packresources, list1); } } } static class SharedZipFileAccess implements AutoCloseable { final File file; @Nullable private ZipFile zipFile; private boolean failedToLoad; SharedZipFileAccess(File p_300196_) { this.file = p_300196_; } @Nullable ZipFile getOrCreateZipFile() { if (this.failedToLoad) { return null; } else { if (this.zipFile == null) { try { this.zipFile = new ZipFile(this.file); } catch (IOException ioexception) { FilePackResources.LOGGER.error("Failed to open pack {}", this.file, ioexception); this.failedToLoad = true; return null; } } return this.zipFile; } } @Override public void close() { if (this.zipFile != null) { IOUtils.closeQuietly(this.zipFile); this.zipFile = null; } } @Override protected void finalize() throws Throwable { this.close(); super.finalize(); } } }