425 lines
10 KiB
Java
425 lines
10 KiB
Java
package net.minecraft.nbt;
|
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
import java.io.BufferedOutputStream;
|
|
import java.io.DataInput;
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutput;
|
|
import java.io.DataOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.io.UTFDataFormatException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.LinkOption;
|
|
import java.nio.file.OpenOption;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.StandardOpenOption;
|
|
import java.util.zip.GZIPInputStream;
|
|
import java.util.zip.GZIPOutputStream;
|
|
import net.minecraft.CrashReport;
|
|
import net.minecraft.CrashReportCategory;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.util.DelegateDataOutput;
|
|
import net.minecraft.util.FastBufferedInputStream;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class NbtIo {
|
|
private static final OpenOption[] SYNC_OUTPUT_OPTIONS = new OpenOption[]{
|
|
StandardOpenOption.SYNC, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
|
|
};
|
|
|
|
public static CompoundTag readCompressed(Path path, NbtAccounter accounter) throws IOException {
|
|
InputStream inputStream = Files.newInputStream(path);
|
|
|
|
CompoundTag var4;
|
|
try {
|
|
InputStream inputStream2 = new FastBufferedInputStream(inputStream);
|
|
|
|
try {
|
|
var4 = readCompressed(inputStream2, accounter);
|
|
} catch (Throwable var8) {
|
|
try {
|
|
inputStream2.close();
|
|
} catch (Throwable var7) {
|
|
var8.addSuppressed(var7);
|
|
}
|
|
|
|
throw var8;
|
|
}
|
|
|
|
inputStream2.close();
|
|
} catch (Throwable var9) {
|
|
if (inputStream != null) {
|
|
try {
|
|
inputStream.close();
|
|
} catch (Throwable var6) {
|
|
var9.addSuppressed(var6);
|
|
}
|
|
}
|
|
|
|
throw var9;
|
|
}
|
|
|
|
if (inputStream != null) {
|
|
inputStream.close();
|
|
}
|
|
|
|
return var4;
|
|
}
|
|
|
|
private static DataInputStream createDecompressorStream(InputStream zippedStream) throws IOException {
|
|
return new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(zippedStream)));
|
|
}
|
|
|
|
private static DataOutputStream createCompressorStream(OutputStream outputSteam) throws IOException {
|
|
return new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(outputSteam)));
|
|
}
|
|
|
|
public static CompoundTag readCompressed(InputStream zippedStream, NbtAccounter accounter) throws IOException {
|
|
DataInputStream dataInputStream = createDecompressorStream(zippedStream);
|
|
|
|
CompoundTag var3;
|
|
try {
|
|
var3 = read(dataInputStream, accounter);
|
|
} catch (Throwable var6) {
|
|
if (dataInputStream != null) {
|
|
try {
|
|
dataInputStream.close();
|
|
} catch (Throwable var5) {
|
|
var6.addSuppressed(var5);
|
|
}
|
|
}
|
|
|
|
throw var6;
|
|
}
|
|
|
|
if (dataInputStream != null) {
|
|
dataInputStream.close();
|
|
}
|
|
|
|
return var3;
|
|
}
|
|
|
|
public static void parseCompressed(Path path, StreamTagVisitor visitor, NbtAccounter accounter) throws IOException {
|
|
InputStream inputStream = Files.newInputStream(path);
|
|
|
|
try {
|
|
InputStream inputStream2 = new FastBufferedInputStream(inputStream);
|
|
|
|
try {
|
|
parseCompressed(inputStream2, visitor, accounter);
|
|
} catch (Throwable var9) {
|
|
try {
|
|
inputStream2.close();
|
|
} catch (Throwable var8) {
|
|
var9.addSuppressed(var8);
|
|
}
|
|
|
|
throw var9;
|
|
}
|
|
|
|
inputStream2.close();
|
|
} catch (Throwable var10) {
|
|
if (inputStream != null) {
|
|
try {
|
|
inputStream.close();
|
|
} catch (Throwable var7) {
|
|
var10.addSuppressed(var7);
|
|
}
|
|
}
|
|
|
|
throw var10;
|
|
}
|
|
|
|
if (inputStream != null) {
|
|
inputStream.close();
|
|
}
|
|
}
|
|
|
|
public static void parseCompressed(InputStream zippedStream, StreamTagVisitor visitor, NbtAccounter accounter) throws IOException {
|
|
DataInputStream dataInputStream = createDecompressorStream(zippedStream);
|
|
|
|
try {
|
|
parse(dataInputStream, visitor, accounter);
|
|
} catch (Throwable var7) {
|
|
if (dataInputStream != null) {
|
|
try {
|
|
dataInputStream.close();
|
|
} catch (Throwable var6) {
|
|
var7.addSuppressed(var6);
|
|
}
|
|
}
|
|
|
|
throw var7;
|
|
}
|
|
|
|
if (dataInputStream != null) {
|
|
dataInputStream.close();
|
|
}
|
|
}
|
|
|
|
public static void writeCompressed(CompoundTag compoundTag, Path path) throws IOException {
|
|
OutputStream outputStream = Files.newOutputStream(path, SYNC_OUTPUT_OPTIONS);
|
|
|
|
try {
|
|
OutputStream outputStream2 = new BufferedOutputStream(outputStream);
|
|
|
|
try {
|
|
writeCompressed(compoundTag, outputStream2);
|
|
} catch (Throwable var8) {
|
|
try {
|
|
outputStream2.close();
|
|
} catch (Throwable var7) {
|
|
var8.addSuppressed(var7);
|
|
}
|
|
|
|
throw var8;
|
|
}
|
|
|
|
outputStream2.close();
|
|
} catch (Throwable var9) {
|
|
if (outputStream != null) {
|
|
try {
|
|
outputStream.close();
|
|
} catch (Throwable var6) {
|
|
var9.addSuppressed(var6);
|
|
}
|
|
}
|
|
|
|
throw var9;
|
|
}
|
|
|
|
if (outputStream != null) {
|
|
outputStream.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Writes and compresses a compound tag to a GNU zipped file.
|
|
* @see #writeCompressed(CompoundTag, File)
|
|
*/
|
|
public static void writeCompressed(CompoundTag compoundTag, OutputStream outputStream) throws IOException {
|
|
DataOutputStream dataOutputStream = createCompressorStream(outputStream);
|
|
|
|
try {
|
|
write(compoundTag, dataOutputStream);
|
|
} catch (Throwable var6) {
|
|
if (dataOutputStream != null) {
|
|
try {
|
|
dataOutputStream.close();
|
|
} catch (Throwable var5) {
|
|
var6.addSuppressed(var5);
|
|
}
|
|
}
|
|
|
|
throw var6;
|
|
}
|
|
|
|
if (dataOutputStream != null) {
|
|
dataOutputStream.close();
|
|
}
|
|
}
|
|
|
|
public static void write(CompoundTag compoundTag, Path path) throws IOException {
|
|
OutputStream outputStream = Files.newOutputStream(path, SYNC_OUTPUT_OPTIONS);
|
|
|
|
try {
|
|
OutputStream outputStream2 = new BufferedOutputStream(outputStream);
|
|
|
|
try {
|
|
DataOutputStream dataOutputStream = new DataOutputStream(outputStream2);
|
|
|
|
try {
|
|
write(compoundTag, dataOutputStream);
|
|
} catch (Throwable var10) {
|
|
try {
|
|
dataOutputStream.close();
|
|
} catch (Throwable var9) {
|
|
var10.addSuppressed(var9);
|
|
}
|
|
|
|
throw var10;
|
|
}
|
|
|
|
dataOutputStream.close();
|
|
} catch (Throwable var11) {
|
|
try {
|
|
outputStream2.close();
|
|
} catch (Throwable var8) {
|
|
var11.addSuppressed(var8);
|
|
}
|
|
|
|
throw var11;
|
|
}
|
|
|
|
outputStream2.close();
|
|
} catch (Throwable var12) {
|
|
if (outputStream != null) {
|
|
try {
|
|
outputStream.close();
|
|
} catch (Throwable var7) {
|
|
var12.addSuppressed(var7);
|
|
}
|
|
}
|
|
|
|
throw var12;
|
|
}
|
|
|
|
if (outputStream != null) {
|
|
outputStream.close();
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public static CompoundTag read(Path path) throws IOException {
|
|
if (!Files.exists(path, new LinkOption[0])) {
|
|
return null;
|
|
} else {
|
|
InputStream inputStream = Files.newInputStream(path);
|
|
|
|
CompoundTag var3;
|
|
try {
|
|
DataInputStream dataInputStream = new DataInputStream(inputStream);
|
|
|
|
try {
|
|
var3 = read(dataInputStream, NbtAccounter.unlimitedHeap());
|
|
} catch (Throwable var7) {
|
|
try {
|
|
dataInputStream.close();
|
|
} catch (Throwable var6) {
|
|
var7.addSuppressed(var6);
|
|
}
|
|
|
|
throw var7;
|
|
}
|
|
|
|
dataInputStream.close();
|
|
} catch (Throwable var8) {
|
|
if (inputStream != null) {
|
|
try {
|
|
inputStream.close();
|
|
} catch (Throwable var5) {
|
|
var8.addSuppressed(var5);
|
|
}
|
|
}
|
|
|
|
throw var8;
|
|
}
|
|
|
|
if (inputStream != null) {
|
|
inputStream.close();
|
|
}
|
|
|
|
return var3;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads a compound tag from a file. The size of the file can be infinite.
|
|
*/
|
|
public static CompoundTag read(DataInput input) throws IOException {
|
|
return read(input, NbtAccounter.unlimitedHeap());
|
|
}
|
|
|
|
/**
|
|
* Reads a compound tag from a file. The size of the file is limited by the {@code accounter}.
|
|
* @throws RuntimeException if the size of the file is larger than the maximum amount of bytes specified by the {@code accounter}
|
|
*/
|
|
public static CompoundTag read(DataInput input, NbtAccounter accounter) throws IOException {
|
|
Tag tag = readUnnamedTag(input, accounter);
|
|
if (tag instanceof CompoundTag) {
|
|
return (CompoundTag)tag;
|
|
} else {
|
|
throw new IOException("Root tag must be a named compound tag");
|
|
}
|
|
}
|
|
|
|
public static void write(CompoundTag compoundTag, DataOutput output) throws IOException {
|
|
writeUnnamedTagWithFallback(compoundTag, output);
|
|
}
|
|
|
|
public static void parse(DataInput input, StreamTagVisitor visitor, NbtAccounter accounter) throws IOException {
|
|
TagType<?> tagType = TagTypes.getType(input.readByte());
|
|
if (tagType == EndTag.TYPE) {
|
|
if (visitor.visitRootEntry(EndTag.TYPE) == StreamTagVisitor.ValueResult.CONTINUE) {
|
|
visitor.visitEnd();
|
|
}
|
|
} else {
|
|
switch (visitor.visitRootEntry(tagType)) {
|
|
case HALT:
|
|
default:
|
|
break;
|
|
case BREAK:
|
|
StringTag.skipString(input);
|
|
tagType.skip(input, accounter);
|
|
break;
|
|
case CONTINUE:
|
|
StringTag.skipString(input);
|
|
tagType.parse(input, visitor, accounter);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Tag readAnyTag(DataInput input, NbtAccounter accounter) throws IOException {
|
|
byte b = input.readByte();
|
|
return (Tag)(b == 0 ? EndTag.INSTANCE : readTagSafe(input, accounter, b));
|
|
}
|
|
|
|
public static void writeAnyTag(Tag tag, DataOutput output) throws IOException {
|
|
output.writeByte(tag.getId());
|
|
if (tag.getId() != 0) {
|
|
tag.write(output);
|
|
}
|
|
}
|
|
|
|
public static void writeUnnamedTag(Tag tag, DataOutput output) throws IOException {
|
|
output.writeByte(tag.getId());
|
|
if (tag.getId() != 0) {
|
|
output.writeUTF("");
|
|
tag.write(output);
|
|
}
|
|
}
|
|
|
|
public static void writeUnnamedTagWithFallback(Tag tag, DataOutput output) throws IOException {
|
|
writeUnnamedTag(tag, new NbtIo.StringFallbackDataOutput(output));
|
|
}
|
|
|
|
@VisibleForTesting
|
|
public static Tag readUnnamedTag(DataInput input, NbtAccounter accounter) throws IOException {
|
|
byte b = input.readByte();
|
|
if (b == 0) {
|
|
return EndTag.INSTANCE;
|
|
} else {
|
|
StringTag.skipString(input);
|
|
return readTagSafe(input, accounter, b);
|
|
}
|
|
}
|
|
|
|
private static Tag readTagSafe(DataInput input, NbtAccounter accounter, byte type) {
|
|
try {
|
|
return TagTypes.getType(type).load(input, accounter);
|
|
} catch (IOException var6) {
|
|
CrashReport crashReport = CrashReport.forThrowable(var6, "Loading NBT data");
|
|
CrashReportCategory crashReportCategory = crashReport.addCategory("NBT Tag");
|
|
crashReportCategory.setDetail("Tag type", type);
|
|
throw new ReportedNbtException(crashReport);
|
|
}
|
|
}
|
|
|
|
public static class StringFallbackDataOutput extends DelegateDataOutput {
|
|
public StringFallbackDataOutput(DataOutput dataOutput) {
|
|
super(dataOutput);
|
|
}
|
|
|
|
@Override
|
|
public void writeUTF(String string) throws IOException {
|
|
try {
|
|
super.writeUTF(string);
|
|
} catch (UTFDataFormatException var3) {
|
|
Util.logAndPauseIfInIde("Failed to write NBT String", var3);
|
|
super.writeUTF("");
|
|
}
|
|
}
|
|
}
|
|
}
|