//////////////////////////////////////////////////////////////////////////////////////////////////// // 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 newNBTOutputStream
, 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 extends Tag> clazz = tag.getType();
final ListTAG_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();
}
}