From 57f34a9eac7f866defc13f0b32c92010956a63e6 Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 17 Mar 2021 08:23:56 -0300 Subject: [PATCH] deprecated some IO functions --- .../carpet/script/argument/FileArgument.java | 345 ++++++++++++++++++ .../carpet/script/bundled/FileModule.java | 8 +- .../java/carpet/script/bundled/Module.java | 13 +- 3 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 src/main/java/carpet/script/argument/FileArgument.java diff --git a/src/main/java/carpet/script/argument/FileArgument.java b/src/main/java/carpet/script/argument/FileArgument.java new file mode 100644 index 00000000..f3ad42fe --- /dev/null +++ b/src/main/java/carpet/script/argument/FileArgument.java @@ -0,0 +1,345 @@ +package carpet.script.argument; + +import carpet.CarpetServer; +import carpet.script.Context; +import carpet.script.LazyValue; +import carpet.script.bundled.Module; +import carpet.script.exception.InternalExpressionException; +import carpet.script.value.Value; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.PositionTracker; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.TagReaders; +import net.minecraft.util.WorldSavePath; +import org.apache.commons.io.FilenameUtils; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FileArgument +{ + public String resource; + public Type type; + public String zipContainer; + public boolean isFolder; + public boolean isShared; + public Reason reason; + + public final static Object writeIOSync = new Object(); + + public enum Type + { + RAW("raw", ".txt"), + TEXT("text", ".txt"), + NBT("nbt", ".nbt"), + JSON("json", ".json"), + FOLDER("folder", ""); + + private final String id; + private final String extension; + + public static Map of = Arrays.stream(values()).collect(Collectors.toMap(t -> t.id, t -> t)); + + Type(String id, String extension) + { + this.id = id; + this.extension = extension; + } + } + + public enum Reason + { + READ, CREATE, DELETE + } + + private FileArgument(String resource, Type type, String zipContainer, boolean isFolder, boolean isShared, Reason reason) + { + this.resource = resource; + this.type = type; + this.zipContainer = zipContainer; + this.isFolder = isFolder; + this.isShared = isShared; + this.reason = reason; + } + + public static FileArgument from(List lv, Context c, boolean isFolder, Reason reason) + { + if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments"); + String resource = recognizeResource(lv.get(0).evalValue(c), isFolder); + String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); + boolean shared = origtype.startsWith("shared_"); + String typeString = shared ? origtype.substring(7) : origtype; //len(shared_) + Type type = Type.of.get(typeString); + if (!Type.of.containsKey(typeString)) + throw new InternalExpressionException("Unsupported file type: "+origtype); + + if (type==Type.FOLDER && !isFolder) + throw new InternalExpressionException("Folder types are no supported for this IO function"); + return new FileArgument(resource, type,null, isFolder, shared, reason); + + } + + public static String recognizeResource(Value value, boolean isFolder) + { + String origfile = value.getString(); + String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9\\-+_/]", ""); + file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/")); + if (file.isEmpty() && !isFolder) + { + throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers"); + } + return file; + } + + private Path toPath(Module module) + { + if (!isShared && (module == null || module.getName() == null)) return null; + return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, resource)+type.extension); + } + + private Path moduleRootPath(Module module) + { + if (!isShared && (module == null || module.getName() == null)) return null; + return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, "")); + } + + private String getDescriptor(Module module, String res) + { + if (isShared) + { + return res.isEmpty()?"shared":"shared/"+res; + } + if (module != null && module.getName() != null) // appdata + { + return module.getName()+".data"+(res==null || res.isEmpty()?"":"/"+res); + } + throw new RuntimeException("Invalid file descriptor: "+res); + } + + public Stream listFiles(Module module) + { + Path dir = toPath(module); + if (dir == null || !Files.exists(dir)) return null; + String ext = type.extension; + try + { + return Files.list(dir). + filter(path -> isFolder?Files.isDirectory(path):path.toString().endsWith(ext)); + } + catch (IOException ignored) + { + return null; + } + } + + public Stream listFolder(Module module) + { + Stream result; + synchronized (writeIOSync) { result = listFiles(module); } + if (result == null) return null; + Path rootPath = moduleRootPath(module); + Stream strings = result.map(p -> rootPath.relativize(p).toString().replaceAll("[\\\\/]","/")); + if (type != Type.FOLDER) + return strings.map(FilenameUtils::removeExtension); + return strings; + } + + public boolean appendToTextFile(Module module, List message) + { + Path dataFile = toPath(module);//, resourceName, supportedTypes.get(type), isShared); + if (dataFile == null) return false; + if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; + synchronized (writeIOSync) + { + try + { + OutputStream out = Files.newOutputStream(dataFile, StandardOpenOption.APPEND, StandardOpenOption.CREATE); + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) + { + for (String line: message) + { + writer.append(line); + if (type == Type.TEXT) writer.newLine(); + } + } + } + catch (IOException e) + { + return false; + } + return true; + } + } + + public Tag getNbtData(Module module) // aka getData + { + Path dataFile = toPath(module); + if (dataFile == null) return null; + if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; + synchronized (writeIOSync) { return readTag(dataFile.toFile()); } + } + + //copied private method from net.minecraft.nbt.NbtIo.read() + // to read non-compound tags - these won't be compressed + public static Tag readTag(File file) + { + try + { + return NbtIo.readCompressed(file); + } + catch (IOException e) + { + // Copy of NbtIo.read(File) because that's now client-side only + if (!file.exists()) + { + return null; + } + try (DataInputStream in = new DataInputStream(new FileInputStream(file))) + { + return NbtIo.read(in); + } + catch (IOException ioException) + { + try (DataInputStream dataInput_1 = new DataInputStream(new FileInputStream(file))) + { + byte byte_1 = dataInput_1.readByte(); + if (byte_1 == 0) + { + return null; + } + else + { + dataInput_1.readUTF(); + return TagReaders.of(byte_1).read(dataInput_1, 0, PositionTracker.DEFAULT); + } + } + catch (IOException ignored) + { + } + return null; + } + } + } + + public boolean saveNbtData(Module module, Tag tag) // aka saveData + { + Path dataFile = toPath(module); + if (dataFile == null) return false; + if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; + synchronized (writeIOSync) { return writeTag(tag, dataFile.toFile()); } + } + + //copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write + public static boolean writeTag(Tag tag_1, File file) + { + File file_2 = new File(file.getAbsolutePath() + "_tmp"); + if (file_2.exists()) file_2.delete(); + + if (tag_1 instanceof CompoundTag) + { + try + { + NbtIo.writeCompressed((CompoundTag) tag_1, file_2); + } + catch (IOException e) + { + return false; + } + } + else + { + try (DataOutputStream dataOutputStream_1 = new DataOutputStream(new FileOutputStream(file_2))) + { + dataOutputStream_1.writeByte(tag_1.getType()); + if (tag_1.getType() != 0) + { + dataOutputStream_1.writeUTF(""); + tag_1.write(dataOutputStream_1); + } + } + catch (IOException e) + { + return false; + } + } + if (file.exists()) file.delete(); + if (!file.exists()) file_2.renameTo(file); + return true; + } + + public boolean dropExistingFile(Module module) + { + Path dataFile = toPath(module); + if (dataFile == null) return false; + synchronized (writeIOSync) { return dataFile.toFile().delete(); } + } + + public List listFile(Module module) + { + Path dataFile = toPath(module); + if (dataFile == null) return null; + if (!dataFile.toFile().exists()) return null; + synchronized (writeIOSync) { return listFileContent(dataFile); } + } + + public static List listFileContent(Path filePath) + { + try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { + List result = new ArrayList<>(); + for (;;) { + String line = reader.readLine(); + if (line == null) + break; + result.add(line.replaceAll("[\n\r]+","")); + } + return result; + } + catch (IOException e) + { + return null; + } + } + + public JsonElement readJsonFile(Module module) { + Path dataFile = toPath(module); + if (dataFile == null) return null; + if (!dataFile.toFile().exists()) return null; + synchronized (writeIOSync) { return readJsonContent(dataFile); } + } + + public static JsonElement readJsonContent(Path filePath) + { + try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) + { + return new JsonParser().parse(new JsonReader(reader)); + } + catch (IOException e) + { + return null; + } + } + +} diff --git a/src/main/java/carpet/script/bundled/FileModule.java b/src/main/java/carpet/script/bundled/FileModule.java index 4684b0fa..20cd65af 100644 --- a/src/main/java/carpet/script/bundled/FileModule.java +++ b/src/main/java/carpet/script/bundled/FileModule.java @@ -68,6 +68,7 @@ public class FileModule extends Module //copied private method from net.minecraft.nbt.NbtIo.read() // to read non-compound tags - these won't be compressed + @Deprecated public static Tag read(File file) { try @@ -109,6 +110,7 @@ public class FileModule extends Module } //copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write + @Deprecated public static boolean write(Tag tag_1, File file) { File file_2 = new File(file.getAbsolutePath() + "_tmp"); @@ -146,6 +148,7 @@ public class FileModule extends Module return true; } + @Deprecated public static boolean appendText(Path filePath, boolean addNewLines, List data) { try @@ -168,6 +171,7 @@ public class FileModule extends Module } + @Deprecated public static List listFileContent(Path filePath) { try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { @@ -185,7 +189,8 @@ public class FileModule extends Module return null; } } - + + @Deprecated public static JsonElement readJsonContent(Path filePath) { try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) @@ -198,6 +203,7 @@ public class FileModule extends Module } } + @Deprecated public static Stream listFiles(Path dir, String ext) { boolean folderListing = ext.equals("folder"); diff --git a/src/main/java/carpet/script/bundled/Module.java b/src/main/java/carpet/script/bundled/Module.java index 4a352e8e..ea6231b5 100644 --- a/src/main/java/carpet/script/bundled/Module.java +++ b/src/main/java/carpet/script/bundled/Module.java @@ -19,7 +19,9 @@ public abstract class Module public abstract String getName(); public abstract String getCode(); public abstract boolean isLibrary(); + @Deprecated public final static Object writeIOSync = new Object(); + @Deprecated public final static Map supportedTypes = ImmutableMap.of( "raw", ".txt", "text", ".txt", @@ -28,6 +30,7 @@ public abstract class Module "folder", "folder" ); + @Deprecated private static String getDescriptor(Module module, String file, boolean isShared) { if (isShared) @@ -41,6 +44,7 @@ public abstract class Module throw new RuntimeException("Invalid file descriptor: "+file); } + @Deprecated public static Tag getData(Module module, String file, boolean isShared) { Path dataFile = resolveResource(module, file, ".nbt", isShared); @@ -49,6 +53,7 @@ public abstract class Module synchronized (writeIOSync) { return FileModule.read(dataFile.toFile()); } } + @Deprecated public static boolean saveData(Module module, String file, Tag globalState, boolean isShared) { Path dataFile = resolveResource(module, file, ".nbt", isShared); @@ -57,6 +62,7 @@ public abstract class Module synchronized (writeIOSync) { return FileModule.write(globalState, dataFile.toFile()); } } + @Deprecated public static boolean appendToTextFile(Module module, String resourceName, String type, boolean isShared, List message) { Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); @@ -65,6 +71,7 @@ public abstract class Module synchronized (writeIOSync) { return FileModule.appendText(dataFile, type.equals("text"), message); } } + @Deprecated public static boolean dropExistingFile(Module module, String resourceName, String type, boolean isShared) { Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); @@ -72,6 +79,7 @@ public abstract class Module synchronized (writeIOSync) { return dataFile.toFile().delete(); } } + @Deprecated public static List listFile(Module module, String resourceName, String type, boolean isShared) { Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); @@ -79,7 +87,8 @@ public abstract class Module if (!dataFile.toFile().exists()) return null; synchronized (writeIOSync) { return FileModule.listFileContent(dataFile); } } - + + @Deprecated public static JsonElement readJsonFile(Module module, String resourceName, String type, boolean isShared) { Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); if (dataFile == null) return null; @@ -87,6 +96,7 @@ public abstract class Module synchronized (writeIOSync) { return FileModule.readJsonContent(dataFile); } } + @Deprecated public static Stream listFolder(Module module, String resourceName, String type, boolean isShared) { Path dir = resolveResource(module, resourceName, null, isShared); @@ -103,6 +113,7 @@ public abstract class Module return strings; } + @Deprecated private static Path resolveResource(Module module, String resourceName, String ext, boolean isShared) { if (!isShared && (module == null || module.getName() == null)) return null;