From 1766c62278915fcdf0bffcd407ad8b9ae3c9a320 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 25 Sep 2020 15:15:00 +0100 Subject: [PATCH] Attempt to recover from incorrectly-extensioned schematic reads (#660) * Attempt to recover from incorrectly-extensioned schematic reads - Should help avoid #605 (I'm assuming this is the issue) - Possible issues with the InputStream being closed/pre-read or so? Thoughts:? * more verbose checking in the first place --- .../clipboard/io/BuiltInClipboardFormat.java | 43 ++++++++++++++++++- .../extent/clipboard/io/SchematicReader.java | 28 ++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 9cce51ec8..af58a3f59 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -24,8 +24,11 @@ import com.boydti.fawe.object.io.ResettableFileInputStream; import com.boydti.fawe.object.schematic.MinecraftStructure; import com.boydti.fawe.object.schematic.PNGWriter; import com.google.common.collect.ImmutableSet; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.NamedTag; +import com.sk89q.jnbt.Tag; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -34,6 +37,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -73,7 +77,25 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public boolean isFormat(File file) { String name = file.getName().toLowerCase(); - return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce"); + if (name.endsWith(".schematic")) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Materials")) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + return name.endsWith(".mcedit") || name.endsWith(".mce"); } }, SPONGE_SCHEMATIC("sponge", "schem") { @@ -109,7 +131,24 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public boolean isFormat(File file) { String name = file.getName().toLowerCase(); - return name.endsWith(".schem") || name.endsWith(".sponge"); + if (name.endsWith(".schem") || name.endsWith(".sponge")) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Version")) { + return false; + } + } catch (Exception e) { + return false; + } + } + return false; } }, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java index 2f2c33028..9ebc7edec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java @@ -27,6 +27,7 @@ import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.clipboard.LinearClipboard; import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArraysInputStream; +import com.boydti.fawe.object.io.ResettableFileInputStream; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.entity.BaseEntity; @@ -56,7 +57,12 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockOutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -64,6 +70,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; +import java.util.zip.GZIPInputStream; import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; @@ -73,6 +80,8 @@ import static org.slf4j.LoggerFactory.getLogger; */ public class SchematicReader implements ClipboardReader { + private static final Logger log = LoggerFactory.getLogger(SchematicReader.class); + private static final NBTCompatibilityHandler[] COMPATIBILITY_HANDLERS = { new SignCompatibilityHandler(), new FlowerPotCompatibilityHandler(), @@ -218,6 +227,25 @@ public class SchematicReader implements ClipboardReader { @Override public Clipboard read(UUID uuid, Function createOutput) throws IOException { + try { + return readInternal(uuid, createOutput); + } catch (EOFException e) { + log.error("EOFException read in schematic. Did you give the schematic the wrong extension?"); + log.error("We will attempt to rectify your mistake for you and load the schematic assuming it is named .schem not .schematic"); + e.printStackTrace(); + final InputStream stream; + if (rootStream instanceof FileInputStream) { + stream = new ResettableFileInputStream((FileInputStream) rootStream); + } else { + stream = rootStream; + } + BufferedInputStream buffered = new BufferedInputStream(stream); + NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); + return (new FastSchematicReader(nbtStream)).read(uuid, createOutput); + } + } + + private Clipboard readInternal(UUID uuid, Function createOutput) throws IOException { StreamDelegate root = createDelegate(); inputStream.readNamedTagLazy(root);