//////////////////////////////////////////////////////////////////////////////////////////////////// // PlotSquared - A plot manager and world generator for the Bukkit API / // Copyright (c) 2014 IntellectualSites/IntellectualCrafters / // / // This program is free software; you can redistribute it and/or modify / // it under the terms of the GNU General Public License as published by / // the Free Software Foundation; either version 3 of the License, or / // (at your option) any later version. / // / // This program is distributed in the hope that it will be useful, / // but WITHOUT ANY WARRANTY; without even the implied warranty of / // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the / // GNU General Public License for more details. / // / // You should have received a copy of the GNU General Public License / // along with this program; if not, write to the Free Software Foundation, / // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA / // / // You can contact us via: support@intellectualsites.com / //////////////////////////////////////////////////////////////////////////////////////////////////// package com.intellectualcrafters.jnbt; import java.io.Closeable; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; /** *

This class writes NBT, or Named Binary Tag Tag objects to an * underlying OutputStream.

The NBT format was created by Markus Persson, and the * specification may be found at * @linktourl http://www.minecraft.net/docs/NBT.txt *

* * @author Graham Edgecombe */ public final class NBTOutputStream implements Closeable { /** * The output stream. */ private final DataOutputStream os; /** * Creates a new NBTOutputStream, which will write data to the specified underlying output stream. * * @param os The output stream. * * @throws IOException if an I/O error occurs. */ public NBTOutputStream(final OutputStream os) throws IOException { this.os = new DataOutputStream(os); } /** * Writes a tag. * * @param tag The tag to write. * * @throws IOException if an I/O error occurs. */ public void writeTag(final Tag tag) throws IOException { final int type = NBTUtils.getTypeCode(tag.getClass()); final String name = tag.getName(); final byte[] nameBytes = name.getBytes(NBTConstants.CHARSET); this.os.writeByte(type); this.os.writeShort(nameBytes.length); this.os.write(nameBytes); if (type == NBTConstants.TYPE_END) { throw new IOException("Named TAG_End not permitted."); } writeTagPayload(tag); } /** * Writes tag payload. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeTagPayload(final Tag tag) throws IOException { final int type = NBTUtils.getTypeCode(tag.getClass()); switch (type) { case NBTConstants.TYPE_END: writeEndTagPayload((EndTag) tag); break; case NBTConstants.TYPE_BYTE: writeByteTagPayload((ByteTag) tag); break; case NBTConstants.TYPE_SHORT: writeShortTagPayload((ShortTag) tag); break; case NBTConstants.TYPE_INT: writeIntTagPayload((IntTag) tag); break; case NBTConstants.TYPE_LONG: writeLongTagPayload((LongTag) tag); break; case NBTConstants.TYPE_FLOAT: writeFloatTagPayload((FloatTag) tag); break; case NBTConstants.TYPE_DOUBLE: writeDoubleTagPayload((DoubleTag) tag); break; case NBTConstants.TYPE_BYTE_ARRAY: writeByteArrayTagPayload((ByteArrayTag) tag); break; case NBTConstants.TYPE_STRING: writeStringTagPayload((StringTag) tag); break; case NBTConstants.TYPE_LIST: writeListTagPayload((ListTag) tag); break; case NBTConstants.TYPE_COMPOUND: writeCompoundTagPayload((CompoundTag) tag); break; case NBTConstants.TYPE_INT_ARRAY: writeIntArrayTagPayload((IntArrayTag) tag); break; default: throw new IOException("Invalid tag type: " + type + "."); } } /** * Writes a TAG_Byte tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeByteTagPayload(final ByteTag tag) throws IOException { this.os.writeByte(tag.getValue()); } /** * Writes a TAG_Byte_Array tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeByteArrayTagPayload(final ByteArrayTag tag) throws IOException { final byte[] bytes = tag.getValue(); this.os.writeInt(bytes.length); this.os.write(bytes); } /** * Writes a TAG_Compound tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeCompoundTagPayload(final CompoundTag tag) throws IOException { for (final Tag childTag : tag.getValue().values()) { writeTag(childTag); } this.os.writeByte((byte) 0); // end tag - better way? } /** * Writes a TAG_List tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeListTagPayload(final ListTag tag) throws IOException { final Class clazz = tag.getType(); final List tags = tag.getValue(); final int size = tags.size(); this.os.writeByte(NBTUtils.getTypeCode(clazz)); this.os.writeInt(size); for (final Tag tag1 : tags) { writeTagPayload(tag1); } } /** * Writes a TAG_String tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeStringTagPayload(final StringTag tag) throws IOException { final byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET); this.os.writeShort(bytes.length); this.os.write(bytes); } /** * Writes a TAG_Double tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeDoubleTagPayload(final DoubleTag tag) throws IOException { this.os.writeDouble(tag.getValue()); } /** * Writes a TAG_Float tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeFloatTagPayload(final FloatTag tag) throws IOException { this.os.writeFloat(tag.getValue()); } /** * Writes a TAG_Long tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeLongTagPayload(final LongTag tag) throws IOException { this.os.writeLong(tag.getValue()); } /** * Writes a TAG_Int tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeIntTagPayload(final IntTag tag) throws IOException { this.os.writeInt(tag.getValue()); } /** * Writes a TAG_Short tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeShortTagPayload(final ShortTag tag) throws IOException { this.os.writeShort(tag.getValue()); } /** * Writes a TAG_Empty tag. * * @param tag The tag. * * @throws IOException if an I/O error occurs. */ private void writeEndTagPayload(final EndTag tag) { /* empty */ } private void writeIntArrayTagPayload(final IntArrayTag tag) throws IOException { final int[] data = tag.getValue(); this.os.writeInt(data.length); for (final int element : data) { this.os.writeInt(element); } } @Override public void close() throws IOException { this.os.close(); } /** * Flush output * @throws IOException */ public void flush() throws IOException { this.os.flush(); } }