2025-11-24 22:52:51 +03:00

185 lines
7.1 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.serialization.DataResult
* org.apache.commons.io.FilenameUtils
*/
package net.minecraft.util;
import com.mojang.serialization.DataResult;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.SharedConstants;
import org.apache.commons.io.FilenameUtils;
public class FileUtil {
private static final Pattern COPY_COUNTER_PATTERN = Pattern.compile("(<name>.*) \\((<count>\\d*)\\)", 66);
private static final int MAX_FILE_NAME = 255;
private static final Pattern RESERVED_WINDOWS_FILENAMES = Pattern.compile(".*\\.|(?:COM|CLOCK\\$|CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\\..*)?", 2);
private static final Pattern STRICT_PATH_SEGMENT_CHECK = Pattern.compile("[-._a-z0-9]+");
public static String sanitizeName(String baseName) {
for (char replacer : SharedConstants.ILLEGAL_FILE_CHARACTERS) {
baseName = baseName.replace(replacer, '_');
}
return baseName.replaceAll("[./\"]", "_");
}
public static String findAvailableName(Path baseDir, String baseName, String suffix) throws IOException {
if (!FileUtil.isPathPartPortable((String)(baseName = FileUtil.sanitizeName((String)baseName)))) {
baseName = "_" + (String)baseName + "_";
}
Matcher matcher = COPY_COUNTER_PATTERN.matcher((CharSequence)baseName);
int count = 0;
if (matcher.matches()) {
baseName = matcher.group("name");
count = Integer.parseInt(matcher.group("count"));
}
if (((String)baseName).length() > 255 - suffix.length()) {
baseName = ((String)baseName).substring(0, 255 - suffix.length());
}
while (true) {
Object nameToTest = baseName;
if (count != 0) {
String countSuffix = " (" + count + ")";
int length = 255 - countSuffix.length();
if (((String)nameToTest).length() > length) {
nameToTest = ((String)nameToTest).substring(0, length);
}
nameToTest = (String)nameToTest + countSuffix;
}
nameToTest = (String)nameToTest + suffix;
Path fullPath = baseDir.resolve((String)nameToTest);
try {
Path created = Files.createDirectory(fullPath, new FileAttribute[0]);
Files.deleteIfExists(created);
return baseDir.relativize(created).toString();
}
catch (FileAlreadyExistsException e) {
++count;
continue;
}
break;
}
}
public static boolean isPathNormalized(Path path) {
Path normalized = path.normalize();
return normalized.equals(path);
}
public static boolean isPathPortable(Path path) {
for (Path part : path) {
if (FileUtil.isPathPartPortable(part.toString())) continue;
return false;
}
return true;
}
public static boolean isPathPartPortable(String name) {
return !RESERVED_WINDOWS_FILENAMES.matcher(name).matches();
}
public static Path createPathToResource(Path resourceDirectory, String resource, String extension) {
String path = resource + extension;
Path relativeResourcePath = Paths.get(path, new String[0]);
if (relativeResourcePath.endsWith(extension)) {
throw new InvalidPathException(path, "empty resource name");
}
return resourceDirectory.resolve(relativeResourcePath);
}
public static String getFullResourcePath(String filename) {
return FilenameUtils.getFullPath((String)filename).replace(File.separator, "/");
}
public static String normalizeResourcePath(String filename) {
return FilenameUtils.normalize((String)filename).replace(File.separator, "/");
}
public static DataResult<List<String>> decomposePath(String path) {
int segmentEnd = path.indexOf(47);
if (segmentEnd == -1) {
return switch (path) {
case "", ".", ".." -> DataResult.error(() -> "Invalid path '" + path + "'");
default -> !FileUtil.containsAllowedCharactersOnly(path) ? DataResult.error(() -> "Invalid path '" + path + "'") : DataResult.success(List.of(path));
};
}
ArrayList<String> result = new ArrayList<String>();
int segmentStart = 0;
boolean lastSegment = false;
while (true) {
String segment;
switch (segment = path.substring(segmentStart, segmentEnd)) {
case "":
case ".":
case "..": {
return DataResult.error(() -> "Invalid segment '" + segment + "' in path '" + path + "'");
}
}
if (!FileUtil.containsAllowedCharactersOnly(segment)) {
return DataResult.error(() -> "Invalid segment '" + segment + "' in path '" + path + "'");
}
result.add(segment);
if (lastSegment) {
return DataResult.success(result);
}
segmentStart = segmentEnd + 1;
if ((segmentEnd = path.indexOf(47, segmentStart)) != -1) continue;
segmentEnd = path.length();
lastSegment = true;
}
}
public static Path resolvePath(Path root, List<String> segments) {
int size = segments.size();
return switch (size) {
case 0 -> root;
case 1 -> root.resolve(segments.get(0));
default -> {
String[] rest = new String[size - 1];
for (int i = 1; i < size; ++i) {
rest[i - 1] = segments.get(i);
}
yield root.resolve(root.getFileSystem().getPath(segments.get(0), rest));
}
};
}
private static boolean containsAllowedCharactersOnly(String segment) {
return STRICT_PATH_SEGMENT_CHECK.matcher(segment).matches();
}
public static boolean isValidPathSegment(String segment) {
return !segment.equals("..") && !segment.equals(".") && FileUtil.containsAllowedCharactersOnly(segment);
}
public static void validatePath(String ... path) {
if (path.length == 0) {
throw new IllegalArgumentException("Path must have at least one element");
}
for (String segment : path) {
if (FileUtil.isValidPathSegment(segment)) continue;
throw new IllegalArgumentException("Illegal segment " + segment + " in path " + Arrays.toString(path));
}
}
public static void createDirectoriesSafe(Path dir) throws IOException {
Files.createDirectories(Files.exists(dir, new LinkOption[0]) ? dir.toRealPath(new LinkOption[0]) : dir, new FileAttribute[0]);
}
}