| package net.querz.nbt.io; |
| |
| import net.querz.io.MaxDepthIO; |
| import net.querz.nbt.tag.ByteArrayTag; |
| import net.querz.nbt.tag.ByteTag; |
| import net.querz.nbt.tag.CompoundTag; |
| import net.querz.nbt.tag.DoubleTag; |
| import net.querz.nbt.tag.EndTag; |
| import net.querz.nbt.tag.FloatTag; |
| import net.querz.nbt.tag.IntArrayTag; |
| import net.querz.nbt.tag.IntTag; |
| import net.querz.nbt.tag.ListTag; |
| import net.querz.nbt.tag.LongArrayTag; |
| import net.querz.nbt.tag.LongTag; |
| import net.querz.nbt.tag.ShortTag; |
| import net.querz.nbt.tag.StringTag; |
| import net.querz.nbt.tag.Tag; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.lang.reflect.Array; |
| import java.util.Map; |
| import java.util.regex.Pattern; |
| |
| /** |
| * SNBTWriter creates an SNBT String. |
| * |
| * */ |
| public final class SNBTWriter implements MaxDepthIO { |
| |
| private static final Pattern NON_QUOTE_PATTERN = Pattern.compile("[a-zA-Z_.+\\-]+"); |
| |
| private Writer writer; |
| |
| private SNBTWriter(Writer writer) { |
| this.writer = writer; |
| } |
| |
| public static void write(Tag<?> tag, Writer writer, int maxDepth) throws IOException { |
| new SNBTWriter(writer).writeAnything(tag, maxDepth); |
| } |
| |
| public static void write(Tag<?> tag, Writer writer) throws IOException { |
| write(tag, writer, Tag.DEFAULT_MAX_DEPTH); |
| } |
| |
| private void writeAnything(Tag<?> tag, int maxDepth) throws IOException { |
| switch (tag.getID()) { |
| case EndTag.ID: |
| //do nothing |
| break; |
| case ByteTag.ID: |
| writer.append(Byte.toString(((ByteTag) tag).asByte())).write('b'); |
| break; |
| case ShortTag.ID: |
| writer.append(Short.toString(((ShortTag) tag).asShort())).write('s'); |
| break; |
| case IntTag.ID: |
| writer.write(Integer.toString(((IntTag) tag).asInt())); |
| break; |
| case LongTag.ID: |
| writer.append(Long.toString(((LongTag) tag).asLong())).write('l'); |
| break; |
| case FloatTag.ID: |
| writer.append(Float.toString(((FloatTag) tag).asFloat())).write('f'); |
| break; |
| case DoubleTag.ID: |
| writer.append(Double.toString(((DoubleTag) tag).asDouble())).write('d'); |
| break; |
| case ByteArrayTag.ID: |
| writeArray(((ByteArrayTag) tag).getValue(), ((ByteArrayTag) tag).length(), "B"); |
| break; |
| case StringTag.ID: |
| writer.write(escapeString(((StringTag) tag).getValue())); |
| break; |
| case ListTag.ID: |
| writer.write('['); |
| for (int i = 0; i < ((ListTag<?>) tag).size(); i++) { |
| writer.write(i == 0 ? "" : ","); |
| writeAnything(((ListTag<?>) tag).get(i), decrementMaxDepth(maxDepth)); |
| } |
| writer.write(']'); |
| break; |
| case CompoundTag.ID: |
| writer.write('{'); |
| boolean first = true; |
| for (Map.Entry<String, Tag<?>> entry : (CompoundTag) tag) { |
| writer.write(first ? "" : ","); |
| writer.append(escapeString(entry.getKey())).write(':'); |
| writeAnything(entry.getValue(), decrementMaxDepth(maxDepth)); |
| first = false; |
| } |
| writer.write('}'); |
| break; |
| case IntArrayTag.ID: |
| writeArray(((IntArrayTag) tag).getValue(), ((IntArrayTag) tag).length(), "I"); |
| break; |
| case LongArrayTag.ID: |
| writeArray(((LongArrayTag) tag).getValue(), ((LongArrayTag) tag).length(), "L"); |
| break; |
| default: |
| throw new IOException("unknown tag with id \"" + tag.getID() + "\""); |
| } |
| } |
| |
| private void writeArray(Object array, int length, String prefix) throws IOException { |
| writer.append('[').append(prefix).write(';'); |
| for (int i = 0; i < length; i++) { |
| writer.append(i == 0 ? "" : ",").write(Array.get(array, i).toString()); |
| } |
| writer.write(']'); |
| } |
| |
| public static String escapeString(String s) { |
| if (!NON_QUOTE_PATTERN.matcher(s).matches()) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append('"'); |
| for (int i = 0; i < s.length(); i++) { |
| char c = s.charAt(i); |
| if (c == '\\' || c == '"') { |
| sb.append('\\'); |
| } |
| sb.append(c); |
| } |
| sb.append('"'); |
| return sb.toString(); |
| } |
| return s; |
| } |
| } |