minecraft-src/net/minecraft/nbt/NbtIo.java
2025-07-04 03:45:38 +03:00

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("");
}
}
}
}