Allow finding schematic format by InputStream (#2249)

* Allow finding schematic format by InputStream

* .

* Don't auto-close the stream

* Fix up based on feedback

* checkstyle
This commit is contained in:
Maddy Miller 2023-04-02 14:42:39 +10:00 committed by GitHub
parent df3f7b2ae6
commit c7d559bfcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 17 deletions

View File

@ -192,5 +192,23 @@
"FIELD_NOW_FINAL"
]
}
],
"This now delegates to the InputStream method if not implemented": [
{
"type": "com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat",
"member": "Method com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat.isFormat(java.io.File)",
"changes": [
"METHOD_ABSTRACT_NOW_DEFAULT"
]
}
],
"New method added with default implementation": [
{
"type": "com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat",
"member": "Method com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat.isFormat(java.io.InputStream)",
"changes": [
"METHOD_NEW_DEFAULT"
]
}
]
}

View File

@ -256,7 +256,6 @@ default boolean clearContainerBlockContents(World world, BlockVector3 pt) {
}
/**
<<<<<<< HEAD
* Checks if this adapter supports custom biomes.
* @return if custom biomes are supported
*/

View File

@ -20,8 +20,6 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Writer;
@ -35,8 +33,6 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -72,9 +68,12 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
}
@Override
public boolean isFormat(File file) {
public boolean isFormat(InputStream inputStream) {
LinRootEntry rootEntry;
try (var stream = new DataInputStream(new GZIPInputStream(new FileInputStream(file)))) {
try {
DataInputStream stream = inputStream instanceof DataInputStream dataInputStream
? dataInputStream
: new DataInputStream(inputStream);
rootEntry = LinBinaryIO.readUsing(stream, LinRootEntry::readFrom);
} catch (Exception e) {
return false;
@ -105,8 +104,8 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
}
@Override
public boolean isFormat(File file) {
return detectOldSpongeSchematic(file, 1);
public boolean isFormat(InputStream inputStream) {
return detectOldSpongeSchematic(inputStream, 1);
}
},
SPONGE_V2_SCHEMATIC("sponge.2") {
@ -129,8 +128,8 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
}
@Override
public boolean isFormat(File file) {
return detectOldSpongeSchematic(file, 2);
public boolean isFormat(InputStream inputStream) {
return detectOldSpongeSchematic(inputStream, 2);
}
},
SPONGE_V3_SCHEMATIC("sponge.3", "sponge", "schem") {
@ -153,9 +152,12 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
}
@Override
public boolean isFormat(File file) {
public boolean isFormat(InputStream inputStream) {
LinCompoundTag root;
try (var stream = new DataInputStream(new GZIPInputStream(new FileInputStream(file)))) {
try {
DataInputStream stream = inputStream instanceof DataInputStream dataInputStream
? dataInputStream
: new DataInputStream(inputStream);
root = LinBinaryIO.readUsing(stream, LinRootEntry::readFrom).value();
} catch (Exception e) {
return false;
@ -173,9 +175,12 @@ public boolean isFormat(File file) {
},
;
private static boolean detectOldSpongeSchematic(File file, int version) {
private static boolean detectOldSpongeSchematic(InputStream inputStream, int version) {
LinRootEntry rootEntry;
try (var stream = new DataInputStream(new GZIPInputStream(new FileInputStream(file)))) {
try {
DataInputStream stream = inputStream instanceof DataInputStream dataInputStream
? dataInputStream
: new DataInputStream(inputStream);
rootEntry = LinBinaryIO.readUsing(stream, LinRootEntry::readFrom);
} catch (Exception e) {
return false;

View File

@ -23,7 +23,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* A collection of supported clipboard formats.
@ -68,7 +70,29 @@ public interface ClipboardFormat {
* @param file the file
* @return true if the given file is of this format
*/
boolean isFormat(File file);
default boolean isFormat(File file) {
try (InputStream stream = new GZIPInputStream(Files.newInputStream(file.toPath()))) {
return isFormat(stream);
} catch (IOException e) {
return false;
}
}
/**
* Return whether the given stream is of this format.
*
* @apiNote The caller is responsible for the following:
* <ul>
* <li>Closing the input stream</li>
* <li>Ensuring the data is directly readable, such as not being in GZip format</li>
* </ul>
*
* @param inputStream The stream
* @return true if the given stream is of this format
*/
default boolean isFormat(InputStream inputStream) {
return false;
}
/**
* Get the file extension this format primarily uses.

View File

@ -25,6 +25,8 @@
import com.sk89q.worldedit.WorldEdit;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -32,6 +34,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@ -80,7 +83,7 @@ public static ClipboardFormat findByAlias(String alias) {
}
/**
* Detect the format of given a file.
* Detect the format of a given file.
*
* @param file
* the file
@ -99,6 +102,29 @@ public static ClipboardFormat findByFile(File file) {
return null;
}
/**
* Detect the format of a given input stream.
*
* @apiNote The caller is responsible for ensuring the stream is in a readable format, such as removing GZip compression.
*
* @param inputStreamSupplier The input stream supplier
* @return the format, otherwise null if one cannot be detected
*/
@Nullable
public static ClipboardFormat findByInputStream(Supplier<InputStream> inputStreamSupplier) {
checkNotNull(inputStreamSupplier);
for (ClipboardFormat format : registeredFormats) {
try (var stream = inputStreamSupplier.get()) {
if (format.isFormat(stream)) {
return format;
}
} catch (IOException ignored) { }
}
return null;
}
/**
* A mapping from extensions to formats.
*