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
This commit is contained in:
dordsor21 2020-09-25 15:15:00 +01:00 committed by GitHub
parent 65747bf8f8
commit 1766c62278
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 2 deletions

View File

@ -24,8 +24,11 @@ import com.boydti.fawe.object.io.ResettableFileInputStream;
import com.boydti.fawe.object.schematic.MinecraftStructure; import com.boydti.fawe.object.schematic.MinecraftStructure;
import com.boydti.fawe.object.schematic.PNGWriter; import com.boydti.fawe.object.schematic.PNGWriter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -34,6 +37,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@ -73,7 +77,25 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override @Override
public boolean isFormat(File file) { public boolean isFormat(File file) {
String name = file.getName().toLowerCase(); 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<String, Tag> 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") { SPONGE_SCHEMATIC("sponge", "schem") {
@ -109,7 +131,24 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override @Override
public boolean isFormat(File file) { public boolean isFormat(File file) {
String name = file.getName().toLowerCase(); 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<String, Tag> schematic = schematicTag.getValue();
if (!schematic.containsKey("Version")) {
return false;
}
} catch (Exception e) {
return false;
}
}
return false;
} }
}, },

View File

@ -27,6 +27,7 @@ import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard; import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.boydti.fawe.object.io.ResettableFileInputStream;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.entity.BaseEntity; 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 com.sk89q.worldedit.world.registry.LegacyMapper;
import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
@ -64,6 +70,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger; import static org.slf4j.LoggerFactory.getLogger;
@ -73,6 +80,8 @@ import static org.slf4j.LoggerFactory.getLogger;
*/ */
public class SchematicReader implements ClipboardReader { public class SchematicReader implements ClipboardReader {
private static final Logger log = LoggerFactory.getLogger(SchematicReader.class);
private static final NBTCompatibilityHandler[] COMPATIBILITY_HANDLERS = { private static final NBTCompatibilityHandler[] COMPATIBILITY_HANDLERS = {
new SignCompatibilityHandler(), new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(), new FlowerPotCompatibilityHandler(),
@ -218,6 +227,25 @@ public class SchematicReader implements ClipboardReader {
@Override @Override
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException { public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> 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<BlockVector3, Clipboard> createOutput) throws IOException {
StreamDelegate root = createDelegate(); StreamDelegate root = createDelegate();
inputStream.readNamedTagLazy(root); inputStream.readNamedTagLazy(root);